Skip to content

Commit 57353f3

Browse files
committed
chore(ui-merge): objectui's prompt files move to the root .github/prompts/, and check:prompt-keys reads them there
VS Code reads prompt files from the workspace root's .github/prompts/, and objectui's nested .github/ is being retired. The three *.prompt.md files move unchanged. check-prompt-component-keys derives its registry under the objectui root and now reads the prompts under a separate root. promptsRoot() is the repository root. analyze() takes it as an option, and a fixture tree passes one directory for both roots, so the fixture cases are unchanged. The CLI defaults to the repository root and has a --prompts-root flag. The live-tree cases read the root prompts. Two new cases cover the move: no prompt file is left under the objectui root, and the bare command, as CI runs it, passes. The markdown-test-inputs ledger drops the three prompt paths from the two entries that declared them; they are no longer under the objectui tree. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A6SEitNngAMugGbuJHWsDS
1 parent c65ee39 commit 57353f3

6 files changed

Lines changed: 54 additions & 13 deletions

File tree

File renamed without changes.

‎ui/scripts/__tests__/check-prompt-component-keys.test.ts‎

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
*/
2424

2525
import { describe, expect, it } from 'vitest';
26+
import { execFileSync } from 'node:child_process';
2627
import fs from 'node:fs';
2728
import os from 'node:os';
2829
import path from 'node:path';
@@ -39,12 +40,15 @@ import {
3940
partitionRegistry,
4041
placeholderSites,
4142
promptFiles,
43+
promptsRoot,
4244
scanPromptKeys,
4345
scanPromptSections,
4446
} from '../check-prompt-component-keys.mjs';
4547
import { INDIRECT_REGISTRATIONS, deriveRegistryKeys } from '../check-doc-component-types.mjs';
4648

4749
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..');
50+
/** The repository root, whose `.github/prompts/` the live prompts sit in (objectstack#25712). */
51+
const livePrompts = promptsRoot(repoRoot);
4852
const SCRIPT = 'scripts/check-prompt-component-keys.mjs';
4953

5054
interface Finding {
@@ -270,12 +274,29 @@ describe('the repository this gate guards', () => {
270274
});
271275

272276
it('has a prompt surface with Keys bullets in it', () => {
273-
expect(promptFiles(repoRoot).length).toBeGreaterThan(0);
274-
expect(scanPromptKeys(repoRoot).bullets).toBeGreaterThan(0);
277+
expect(promptFiles(livePrompts).length).toBeGreaterThan(0);
278+
expect(scanPromptKeys(livePrompts).bullets).toBeGreaterThan(0);
279+
});
280+
281+
it('reads the prompts at the repository root, and no copy is left under the objectui root', () => {
282+
// objectstack#25712 moved them from `ui/.github/prompts/` to the root
283+
// `.github/prompts/`, where VS Code reads prompt files. A second copy left
284+
// behind would be the stale twin the next edit lands in.
285+
expect(livePrompts).toBe(path.resolve(repoRoot, '..'));
286+
expect(fs.existsSync(path.join(livePrompts, PROMPT_DIR))).toBe(true);
287+
expect(promptFiles(repoRoot), 'a prompt file is still under the objectui root').toEqual([]);
275288
});
276289

277290
it('passes — every key the prompts teach is answered by a real renderer', () => {
278-
expect((analyze(repoRoot) as { findings: Finding[] }).findings).toEqual([]);
291+
expect((analyze(repoRoot, { promptsRoot: livePrompts }) as { findings: Finding[] }).findings).toEqual([]);
292+
});
293+
294+
it('passes as CI runs it — the bare command reads the repository root prompts', () => {
295+
// The root `Lint UI` job runs `pnpm --dir ui run check:prompt-keys` with no
296+
// arguments, so the CLI's own default is the code path that gates.
297+
const out = execFileSync('node', [SCRIPT], { cwd: repoRoot, encoding: 'utf8' });
298+
expect(out).toMatch(/^Scanned [1-9]\d* prompt file\(s\) under \.github\/prompts/);
299+
expect(out).toContain('OK Every key taught as available');
279300
});
280301
});
281302

@@ -526,7 +547,7 @@ describe('`Protocol Placeholders:` is judged the other way round', () => {
526547
// ── 7. the live tree, under the widened model ────────────────────────────────
527548

528549
describe('the prompt surface this gate now reads', () => {
529-
const scan = () => scanPromptKeys(repoRoot) as {
550+
const scan = () => scanPromptKeys(livePrompts) as {
530551
sites: { key: string; label: string; expect: string; scope: string }[];
531552
bullets: number;
532553
blocks: number;
@@ -572,7 +593,7 @@ describe('the prompt surface this gate now reads', () => {
572593
for (const tombstone of ['user:profile', 'ai:chat_window', 'view:kanban', 'view:gantt', 'view:map']) {
573594
expect(taught.has(tombstone), `${tombstone} must stay in prose, never in a judged list`).toBe(false);
574595
}
575-
const prompt = fs.readFileSync(path.join(repoRoot, PROMPT_DIR, 'component.prompt.md'), 'utf8');
596+
const prompt = fs.readFileSync(path.join(livePrompts, PROMPT_DIR, 'component.prompt.md'), 'utf8');
576597
for (const tombstone of ['user:profile', 'ai:chat_window', 'view:kanban']) {
577598
expect(prompt, `${tombstone} tombstone must still be written down`).toContain(`\`${tombstone}\``);
578599
}
@@ -682,7 +703,7 @@ describe('a `## N.` section\'s `### X.` headings must run A, B, C, … without a
682703
// ── 9. the live tree, under the letter-run pin ───────────────────────────────
683704

684705
describe('the letter runs on the live prompt surface', () => {
685-
const sections = () => scanPromptSections(repoRoot) as {
706+
const sections = () => scanPromptSections(livePrompts) as {
686707
file: string;
687708
section: string;
688709
entries: { letter: string; line: number; text: string }[];

‎ui/scripts/check-prompt-component-keys.mjs‎

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
* (objectui#8929).
1414
*
1515
* Run: node scripts/check-prompt-component-keys.mjs (`pnpm check:prompt-keys`)
16+
* [--root <objectui root>] [--prompts-root <dir holding .github/prompts>]
1617
* Exit: 0 = every taught key resolves to a real component
1718
* 1 = a taught key resolves to nothing, or resolves only to the
1819
* placeholder panel, or this gate's own derivation collapsed
@@ -136,9 +137,21 @@ import { closesFence, openFence } from './markdown-fence-scan.mjs';
136137

137138
const scriptDir = dirname(fileURLToPath(import.meta.url));
138139

139-
/** The instruction surface this gate reads. */
140+
/** The instruction surface this gate reads, under `promptsRoot()`. */
140141
export const PROMPT_DIR = '.github/prompts';
141142

143+
/**
144+
* Where `PROMPT_DIR` lives: the repository root, not the objectui root. VS Code
145+
* reads prompt files from the workspace root's `.github/prompts/`, so they moved
146+
* there from `ui/.github/prompts/` when objectui's nested `.github/` was retired
147+
* (objectstack#25712). The registry the keys are judged against stays under the
148+
* objectui root, which is why `analyze()` takes the two roots separately. A
149+
* fixture tree that holds both passes one directory for both.
150+
*/
151+
export function promptsRoot(root = resolve(scriptDir, '..')) {
152+
return resolve(root, '..');
153+
}
154+
142155
/** The namespace `INDIRECT_REGISTRATIONS` gives the opt-in placeholder module. */
143156
export const PLACEHOLDER_NAMESPACE = 'protocol-placeholder';
144157

@@ -475,8 +488,13 @@ export function letterRunFindings(runs) {
475488
/**
476489
* Judge the prompt surface. Throws when an input is missing, because a gate
477490
* that cannot see its inputs must not report a pass.
491+
*
492+
* `root` is the objectui root the registry is derived from; the prompts are read
493+
* under `options.promptsRoot`, which defaults to `root` itself (a fixture tree).
494+
* The real tree passes `promptsRoot()`.
478495
*/
479496
export function analyze(root, options = {}) {
497+
const prompts = options.promptsRoot ?? root;
480498
const registry = deriveRegistryKeys(root, options);
481499
if (registry.findings.length > 0) {
482500
const lines = registry.findings.map((f) => ` ${f.reason} at ${f.site}: ${f.detail}`);
@@ -507,7 +525,7 @@ export function analyze(root, options = {}) {
507525
throw new Error('the derivation produced no authorable keys — refusing to judge against an empty set.');
508526
}
509527

510-
const { sites: taught, bullets, blocks, emptyBlocks } = scanPromptKeys(root);
528+
const { sites: taught, bullets, blocks, emptyBlocks } = scanPromptKeys(prompts);
511529
if (bullets === 0) {
512530
throw new Error(
513531
`no \`**Keys:**\` bullet was found under ${PROMPT_DIR}. The surface this gate reads is gone or ` +
@@ -523,7 +541,7 @@ export function analyze(root, options = {}) {
523541
);
524542
}
525543

526-
const sections = scanPromptSections(root);
544+
const sections = scanPromptSections(prompts);
527545
const runs = lettered(sections);
528546
if (sections.length > 0 && runs.length === 0) {
529547
throw new Error(
@@ -549,7 +567,7 @@ export function analyze(root, options = {}) {
549567
return {
550568
findings,
551569
counters: {
552-
promptFiles: promptFiles(root).length,
570+
promptFiles: promptFiles(prompts).length,
553571
bullets,
554572
blocks,
555573
keys: taught.length,
@@ -594,10 +612,12 @@ if (isEntrypoint(import.meta.url)) {
594612
return index > -1 ? process.argv[index + 1] : null;
595613
};
596614
const root = resolve(argOf('--root') ?? resolve(scriptDir, '..'));
615+
// A `--root` fixture tree holds its own prompts unless told otherwise.
616+
const prompts = resolve(argOf('--prompts-root') ?? (argOf('--root') ? root : promptsRoot()));
597617

598618
let result;
599619
try {
600-
result = analyze(root);
620+
result = analyze(root, { promptsRoot: prompts });
601621
} catch (error) {
602622
console.error(
603623
`x ${error.message}\n\n` +

‎ui/scripts/markdown-test-inputs.mjs‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -962,7 +962,7 @@ export const ADJUDICATED = new Map([
962962
[
963963
'scripts/__tests__/ci-cd-pipeline-doc.test.ts',
964964
{
965-
reads: ['.github/prompts/component.prompt.md', '.github/prompts/engine.prompt.md', '.github/prompts/ui-library.prompt.md', 'CONTRIBUTING.md', 'content/docs/guide/ci-cd-pipeline.md'],
965+
reads: ['CONTRIBUTING.md', 'content/docs/guide/ci-cd-pipeline.md'],
966966
walker: 'not-markdown: `.github/workflows/*.yml`',
967967
},
968968
],
@@ -1004,7 +1004,7 @@ export const ADJUDICATED = new Map([
10041004
[
10051005
'scripts/__tests__/dollar-dialect-alias-census.test.ts',
10061006
{
1007-
reads: ['./*', '.changeset/**', '.claude/skills/**', '.github/prompts/component.prompt.md', '.github/prompts/engine.prompt.md', '.github/prompts/ui-library.prompt.md', 'apps/**', 'content/docs/**', 'docs/ARCHITECTURE.md', 'docs/CONSOLE-STREAMLINING-SUMMARY.md', 'docs/adr/**', 'docs/audits/**', 'examples/**', 'packages/**', 'patches/README.md', 'skills/objectui/**'],
1007+
reads: ['./*', '.changeset/**', '.claude/skills/**', 'apps/**', 'content/docs/**', 'docs/ARCHITECTURE.md', 'docs/CONSOLE-STREAMLINING-SUMMARY.md', 'docs/adr/**', 'docs/audits/**', 'examples/**', 'packages/**', 'patches/README.md', 'skills/objectui/**'],
10081008
},
10091009
],
10101010
[

0 commit comments

Comments
 (0)