diff --git a/.changeset/scaffold-explore-transitions.md b/.changeset/scaffold-explore-transitions.md new file mode 100644 index 0000000000..ac85484bcf --- /dev/null +++ b/.changeset/scaffold-explore-transitions.md @@ -0,0 +1,5 @@ +--- +"@fission-ai/openspec": patch +--- + +When exploration turns into a new change, generated explore guidance now instructs agents to run `openspec new change` before writing requested artifacts. This preserves the required `.openspec.yaml` metadata instead of letting an agent create an incomplete change directory by hand. After the user accepts a capture, explore also creates the requested artifacts without requiring another workflow command. diff --git a/skills/openspec-explore/SKILL.md b/skills/openspec-explore/SKILL.md index 7bf71157cf..8633e4d255 100644 --- a/skills/openspec-explore/SKILL.md +++ b/skills/openspec-explore/SKILL.md @@ -11,7 +11,7 @@ metadata: Enter explore mode. Think deeply. Visualize freely. Follow the conversation wherever it goes. -**IMPORTANT: Explore mode is for thinking, not implementing.** You may read files, search code, and investigate the codebase, but you must NEVER write code or implement features. If the user asks you to implement something, remind them to exit explore mode first and create a change proposal. You MAY create OpenSpec artifacts (proposals, designs, specs) if the user asks—that's capturing thinking, not implementing. +**IMPORTANT: Explore mode is for thinking, not implementing.** You may read files, search code, and investigate the codebase, but you must NEVER write code or implement features. If the user asks you to implement something, remind them to exit explore mode first and create a change proposal. You MAY create OpenSpec artifacts (proposals, designs, specs) if the user asks—that's capturing thinking, not implementing. For a new change, scaffold it first as described below. **This is a stance, not a workflow.** There are no fixed steps, no required sequence, no mandatory outputs. You're a thinking partner helping the user explore. @@ -106,6 +106,15 @@ Think freely. When insights crystallize, you might offer: - "This feels solid enough to start a change. Want me to create a proposal?" - Or keep exploring - no pressure to formalize +If the user asks you to capture the exploration as a new change, transition seamlessly into the requested capture: + +1. Run `openspec new change ""` (with `--store ` when applicable) before creating any artifacts. Never create a new change directory under `openspec/changes/` by hand; the CLI scaffold creates required metadata such as `.openspec.yaml`. Keep the selected `--store ` on every applicable follow-up `status` and `instructions` command. +2. Run `openspec status --change "" --json` (append the confirmed `--store ""` only for a registered standalone store), then process the requested artifacts in dependency order. For each requested artifact that is `ready`, run `openspec instructions "" --change "" --json` (append the confirmed `--store ""` only for a registered standalone store). Before creating a requested artifact, evaluate any condition in its own `instruction` against the explored change; record a deliberate skip instead when the condition does not apply. If a requested artifact is blocked by a direct prerequisite the user did not request, run `openspec instructions "" --change "" --json` (append the confirmed `--store ""` only for a registered standalone store) for that prerequisite whether it is `ready` or `blocked`. If its own `instruction` states a condition, evaluate that condition against the explored change and record a deliberate skip only when the condition does not apply. If the condition applies, or the prerequisite is not conditional, treat it as a normal prerequisite and ask before expanding the capture. Do not create an unrequested prerequisite unless the user approves. +3. Follow the returned `template` and `instruction` fields. Read completed dependency files listed in `dependencies`, and apply `context` and `rules` as constraints without copying them into the artifact. If the instruction delegates creation to a specific skill or command, invoke it; otherwise write the artifact to `resolvedOutputPath`, using the instruction to choose a concrete path when it is a glob. Verify that the selected concrete output exists. +4. After creating each artifact, re-run `openspec status --change "" --json` (append the confirmed `--store ""` only for a registered standalone store) and continue until every requested artifact is `done`, `skipped`, or was deliberately skipped because its own `instruction` stated a condition that did not apply. Tell the user about a deliberate conditional skip, remember it, and do not reconsider it. Dependencies are enablers, not gates: if a requested artifact is still `blocked` only because you deliberately skipped a conditional prerequisite, run `openspec instructions "" --change "" --json` (append the confirmed `--store ""` only for a registered standalone store) despite the blocked status, then create it using step 3 only when those recorded conditional skips are its sole missing dependencies. If a requested artifact is blocked by a prerequisite the user did not ask to capture and cannot be conditionally skipped, explain that dependency and ask before expanding the capture. + +Capture the artifact(s) the user requested without asking them to invoke another workflow command. If they asked only to start a change, stop after scaffolding and show its status. + ### When a change exists If the user mentions a change or you detect one is relevant: @@ -290,6 +299,7 @@ But this summary is optional. Sometimes the thinking IS the value. - **Don't rush** - Discovery is thinking time, not task time - **Don't force structure** - Let patterns emerge naturally - **Don't auto-capture** - Offer to save insights, don't just do it +- **Don't manually scaffold changes** - Never create a new change directory under `openspec/changes/` by hand. Always use `openspec new change ""` (with `--store ` when applicable) so required metadata such as `.openspec.yaml` is created before writing artifacts. - **Do visualize** - A good diagram is worth many paragraphs - **Do explore the codebase** - Ground discussions in reality - **Do question assumptions** - Including the user's and your own diff --git a/src/core/templates/workflows/explore.ts b/src/core/templates/workflows/explore.ts index e13344b44b..d3a9b5c518 100644 --- a/src/core/templates/workflows/explore.ts +++ b/src/core/templates/workflows/explore.ts @@ -13,7 +13,7 @@ export function getExploreSkillTemplate(): SkillTemplate { description: 'Enter explore mode - a thinking partner for exploring ideas, investigating problems, and clarifying requirements. Use when the user wants to think through something before or during a change.', instructions: `Enter explore mode. Think deeply. Visualize freely. Follow the conversation wherever it goes. -**IMPORTANT: Explore mode is for thinking, not implementing.** You may read files, search code, and investigate the codebase, but you must NEVER write code or implement features. If the user asks you to implement something, remind them to exit explore mode first and create a change proposal. You MAY create OpenSpec artifacts (proposals, designs, specs) if the user asks—that's capturing thinking, not implementing. +**IMPORTANT: Explore mode is for thinking, not implementing.** You may read files, search code, and investigate the codebase, but you must NEVER write code or implement features. If the user asks you to implement something, remind them to exit explore mode first and create a change proposal. You MAY create OpenSpec artifacts (proposals, designs, specs) if the user asks—that's capturing thinking, not implementing. For a new change, scaffold it first as described below. **This is a stance, not a workflow.** There are no fixed steps, no required sequence, no mandatory outputs. You're a thinking partner helping the user explore. @@ -108,6 +108,15 @@ Think freely. When insights crystallize, you might offer: - "This feels solid enough to start a change. Want me to create a proposal?" - Or keep exploring - no pressure to formalize +If the user asks you to capture the exploration as a new change, transition seamlessly into the requested capture: + +1. Run \`openspec new change ""\` (with \`--store \` when applicable) before creating any artifacts. Never create a new change directory under \`openspec/changes/\` by hand; the CLI scaffold creates required metadata such as \`.openspec.yaml\`. Keep the selected \`--store \` on every applicable follow-up \`status\` and \`instructions\` command. +2. Run \`openspec status --change "" --json\` (append the confirmed \`--store ""\` only for a registered standalone store), then process the requested artifacts in dependency order. For each requested artifact that is \`ready\`, run \`openspec instructions "" --change "" --json\` (append the confirmed \`--store ""\` only for a registered standalone store). Before creating a requested artifact, evaluate any condition in its own \`instruction\` against the explored change; record a deliberate skip instead when the condition does not apply. If a requested artifact is blocked by a direct prerequisite the user did not request, run \`openspec instructions "" --change "" --json\` (append the confirmed \`--store ""\` only for a registered standalone store) for that prerequisite whether it is \`ready\` or \`blocked\`. If its own \`instruction\` states a condition, evaluate that condition against the explored change and record a deliberate skip only when the condition does not apply. If the condition applies, or the prerequisite is not conditional, treat it as a normal prerequisite and ask before expanding the capture. Do not create an unrequested prerequisite unless the user approves. +3. Follow the returned \`template\` and \`instruction\` fields. Read completed dependency files listed in \`dependencies\`, and apply \`context\` and \`rules\` as constraints without copying them into the artifact. If the instruction delegates creation to a specific skill or command, invoke it; otherwise write the artifact to \`resolvedOutputPath\`, using the instruction to choose a concrete path when it is a glob. Verify that the selected concrete output exists. +4. After creating each artifact, re-run \`openspec status --change "" --json\` (append the confirmed \`--store ""\` only for a registered standalone store) and continue until every requested artifact is \`done\`, \`skipped\`, or was deliberately skipped because its own \`instruction\` stated a condition that did not apply. Tell the user about a deliberate conditional skip, remember it, and do not reconsider it. Dependencies are enablers, not gates: if a requested artifact is still \`blocked\` only because you deliberately skipped a conditional prerequisite, run \`openspec instructions "" --change "" --json\` (append the confirmed \`--store ""\` only for a registered standalone store) despite the blocked status, then create it using step 3 only when those recorded conditional skips are its sole missing dependencies. If a requested artifact is blocked by a prerequisite the user did not ask to capture and cannot be conditionally skipped, explain that dependency and ask before expanding the capture. + +Capture the artifact(s) the user requested without asking them to invoke another workflow command. If they asked only to start a change, stop after scaffolding and show its status. + ### When a change exists If the user mentions a change or you detect one is relevant: @@ -292,6 +301,7 @@ But this summary is optional. Sometimes the thinking IS the value. - **Don't rush** - Discovery is thinking time, not task time - **Don't force structure** - Let patterns emerge naturally - **Don't auto-capture** - Offer to save insights, don't just do it +- **Don't manually scaffold changes** - Never create a new change directory under \`openspec/changes/\` by hand. Always use \`openspec new change ""\` (with \`--store \` when applicable) so required metadata such as \`.openspec.yaml\` is created before writing artifacts. - **Do visualize** - A good diagram is worth many paragraphs - **Do explore the codebase** - Ground discussions in reality - **Do question assumptions** - Including the user's and your own`, @@ -309,7 +319,7 @@ export function getOpsxExploreCommandTemplate(): CommandTemplate { tags: ['workflow', 'explore', 'experimental', 'thinking'], content: `Enter explore mode. Think deeply. Visualize freely. Follow the conversation wherever it goes. -**IMPORTANT: Explore mode is for thinking, not implementing.** You may read files, search code, and investigate the codebase, but you must NEVER write code or implement features. If the user asks you to implement something, remind them to exit explore mode first and create a change proposal. You MAY create OpenSpec artifacts (proposals, designs, specs) if the user asks—that's capturing thinking, not implementing. +**IMPORTANT: Explore mode is for thinking, not implementing.** You may read files, search code, and investigate the codebase, but you must NEVER write code or implement features. If the user asks you to implement something, remind them to exit explore mode first and create a change proposal. You MAY create OpenSpec artifacts (proposals, designs, specs) if the user asks—that's capturing thinking, not implementing. For a new change, scaffold it first as described below. **This is a stance, not a workflow.** There are no fixed steps, no required sequence, no mandatory outputs. You're a thinking partner helping the user explore. @@ -413,6 +423,15 @@ Think freely. When insights crystallize, you might offer: - "This feels solid enough to start a change. Want me to create a proposal?" - Or keep exploring - no pressure to formalize +If the user asks you to capture the exploration as a new change, transition seamlessly into the requested capture: + +1. Run \`openspec new change ""\` (with \`--store \` when applicable) before creating any artifacts. Never create a new change directory under \`openspec/changes/\` by hand; the CLI scaffold creates required metadata such as \`.openspec.yaml\`. Keep the selected \`--store \` on every applicable follow-up \`status\` and \`instructions\` command. +2. Run \`openspec status --change "" --json\` (append the confirmed \`--store ""\` only for a registered standalone store), then process the requested artifacts in dependency order. For each requested artifact that is \`ready\`, run \`openspec instructions "" --change "" --json\` (append the confirmed \`--store ""\` only for a registered standalone store). Before creating a requested artifact, evaluate any condition in its own \`instruction\` against the explored change; record a deliberate skip instead when the condition does not apply. If a requested artifact is blocked by a direct prerequisite the user did not request, run \`openspec instructions "" --change "" --json\` (append the confirmed \`--store ""\` only for a registered standalone store) for that prerequisite whether it is \`ready\` or \`blocked\`. If its own \`instruction\` states a condition, evaluate that condition against the explored change and record a deliberate skip only when the condition does not apply. If the condition applies, or the prerequisite is not conditional, treat it as a normal prerequisite and ask before expanding the capture. Do not create an unrequested prerequisite unless the user approves. +3. Follow the returned \`template\` and \`instruction\` fields. Read completed dependency files listed in \`dependencies\`, and apply \`context\` and \`rules\` as constraints without copying them into the artifact. If the instruction delegates creation to a specific skill or command, invoke it; otherwise write the artifact to \`resolvedOutputPath\`, using the instruction to choose a concrete path when it is a glob. Verify that the selected concrete output exists. +4. After creating each artifact, re-run \`openspec status --change "" --json\` (append the confirmed \`--store ""\` only for a registered standalone store) and continue until every requested artifact is \`done\`, \`skipped\`, or was deliberately skipped because its own \`instruction\` stated a condition that did not apply. Tell the user about a deliberate conditional skip, remember it, and do not reconsider it. Dependencies are enablers, not gates: if a requested artifact is still \`blocked\` only because you deliberately skipped a conditional prerequisite, run \`openspec instructions "" --change "" --json\` (append the confirmed \`--store ""\` only for a registered standalone store) despite the blocked status, then create it using step 3 only when those recorded conditional skips are its sole missing dependencies. If a requested artifact is blocked by a prerequisite the user did not ask to capture and cannot be conditionally skipped, explain that dependency and ask before expanding the capture. + +Capture the artifact(s) the user requested without asking them to invoke another workflow command. If they asked only to start a change, stop after scaffolding and show its status. + ### When a change exists If the user mentions a change or you detect one is relevant: @@ -477,6 +496,7 @@ When things crystallize, you might offer a summary - but it's optional. Sometime - **Don't rush** - Discovery is thinking time, not task time - **Don't force structure** - Let patterns emerge naturally - **Don't auto-capture** - Offer to save insights, don't just do it +- **Don't manually scaffold changes** - Never create a new change directory under \`openspec/changes/\` by hand. Always use \`openspec new change ""\` (with \`--store \` when applicable) so required metadata such as \`.openspec.yaml\` is created before writing artifacts. - **Do visualize** - A good diagram is worth many paragraphs - **Do explore the codebase** - Ground discussions in reality - **Do question assumptions** - Including the user's and your own` diff --git a/test/core/templates/explore.test.ts b/test/core/templates/explore.test.ts index 9a94d8a25a..280077da83 100644 --- a/test/core/templates/explore.test.ts +++ b/test/core/templates/explore.test.ts @@ -15,6 +15,20 @@ const bodies: Array<[string, string]> = [ ['command', command.content], ]; +function newChangeTransition(body: string, label: string): string { + const start = body.indexOf('### When no change exists'); + const end = body.indexOf('### When a change exists'); + + expect(start, label).toBeGreaterThanOrEqual(0); + expect(end, label).toBeGreaterThan(start); + + return body.slice(start, end); +} + +function occurrenceCount(body: string, value: string): number { + return body.split(value).length - 1; +} + describe('explore templates', () => { // Regression for #696: explore never loaded the project's declared // context, so it reasoned without the tech stack, conventions, and @@ -65,4 +79,196 @@ describe('explore templates', () => { ); } }); + + it('scaffolds a new change before capturing exploration artifacts (#668, #720)', () => { + for (const [label, body] of bodies) { + const transition = newChangeTransition(body, label); + + expect(transition, label).toContain('openspec new change ""'); + expect(transition, label).toContain( + 'Never create a new change directory under `openspec/changes/` by hand' + ); + expect(transition, label).toContain('`.openspec.yaml`'); + expect(transition, label).not.toContain( + 'Never create files or directories directly under `openspec/changes/`' + ); + } + }); + + it('retains the selected store throughout the capture transition (#668, #720)', () => { + for (const [label, body] of bodies) { + const transition = newChangeTransition(body, label); + const scaffold = transition.indexOf('1. Run `openspec new change ""`'); + const retainStore = transition.indexOf( + 'Keep the selected `--store ` on every applicable follow-up `status` and `instructions` command' + ); + const initialStatus = transition.indexOf( + '2. Run `openspec status --change "" --json`' + ); + + expect(retainStore, label).toBeGreaterThan(scaffold); + expect(initialStatus, label).toBeGreaterThan(retainStore); + expect( + occurrenceCount( + transition, + '(append the confirmed `--store ""` only for a registered standalone store)' + ), + label + ).toBe(5); + } + }); + + it('continues an accepted transition through the requested artifact (#668)', () => { + for (const [label, body] of bodies) { + const transition = newChangeTransition(body, label); + + expect(transition, label).toContain('openspec status --change "" --json'); + expect(transition, label).toContain( + 'openspec instructions "" --change "" --json' + ); + expect(transition, label).toContain('Capture the artifact(s) the user requested'); + expect(transition, label).toContain( + 'without asking them to invoke another workflow command' + ); + expect(transition, label).toContain( + 'process the requested artifacts in dependency order' + ); + expect(transition, label).toContain( + 'After creating each artifact, re-run `openspec status --change "" --json`' + ); + expect(transition, label).toContain( + 'If the instruction delegates creation to a specific skill or command' + ); + expect(transition, label).toContain( + 'Verify that the selected concrete output exists' + ); + } + }); + + it('keeps the seamless capture steps ordered (#668, #720)', () => { + for (const [label, body] of bodies) { + const transition = newChangeTransition(body, label); + const scaffold = transition.indexOf('1. Run `openspec new change ""`'); + const initialStatus = transition.indexOf( + '2. Run `openspec status --change "" --json`' + ); + const readyInstructions = transition.indexOf( + 'For each requested artifact that is `ready`, run `openspec instructions' + ); + const verifyOutput = transition.indexOf( + 'Verify that the selected concrete output exists' + ); + const refreshStatus = transition.indexOf( + 'After creating each artifact, re-run `openspec status' + ); + + expect(scaffold, label).toBeGreaterThanOrEqual(0); + expect(initialStatus, label).toBeGreaterThan(scaffold); + expect(readyInstructions, label).toBeGreaterThan(initialStatus); + expect(verifyOutput, label).toBeGreaterThan(readyInstructions); + expect(refreshStatus, label).toBeGreaterThan(verifyOutput); + expect(occurrenceCount(transition, 'openspec new change ""'), label).toBe(1); + expect( + occurrenceCount(transition, 'openspec status --change "" --json'), + label + ).toBe(2); + expect( + occurrenceCount(transition, 'openspec instructions ""'), + label + ).toBe(2); + expect( + occurrenceCount(transition, 'openspec instructions ""'), + label + ).toBe(1); + expect( + occurrenceCount(transition, 'Verify that the selected concrete output exists'), + label + ).toBe(1); + expect( + occurrenceCount(transition, 'After creating each artifact, re-run `openspec status'), + label + ).toBe(1); + } + }); + + it('stops after scaffolding when the user requests only a new change (#668)', () => { + for (const [label, body] of bodies) { + const transition = newChangeTransition(body, label); + expect(transition, label).toContain( + 'If they asked only to start a change, stop after scaffolding and show its status' + ); + } + }); + + it('uses dependency context and artifact constraints during capture (#668)', () => { + for (const [label, body] of bodies) { + const transition = newChangeTransition(body, label); + + expect(transition, label).toContain( + 'Read completed dependency files listed in `dependencies`' + ); + expect(transition, label).toContain('apply `context` and `rules` as constraints'); + expect(transition, label).toContain('without copying them into the artifact'); + } + }); + + it('handles conditional prerequisites without deadlocking capture (#668)', () => { + for (const [label, body] of bodies) { + const transition = newChangeTransition(body, label); + const requestedInstructions = transition.indexOf( + 'For each requested artifact that is `ready`, run `openspec instructions' + ); + const evaluateRequestedCondition = transition.indexOf( + 'Before creating a requested artifact, evaluate any condition in its own `instruction`' + ); + const inspectPrerequisite = transition.indexOf( + 'run `openspec instructions ""' + ); + const evaluateCondition = transition.indexOf( + 'evaluate that condition against the explored change' + ); + const recordSkip = transition.indexOf( + 'record a deliberate skip only when the condition does not apply' + ); + const requireExpansion = transition.indexOf( + 'If the condition applies, or the prerequisite is not conditional' + ); + const approvalGuard = transition.indexOf( + 'Do not create an unrequested prerequisite unless the user approves' + ); + + expect(transition, label).toContain( + 'run `openspec instructions "" --change "" --json` (append the confirmed `--store ""` only for a registered standalone store) for that prerequisite whether it is `ready` or `blocked`' + ); + expect(transition, label).toContain( + 'record a deliberate skip instead when the condition does not apply' + ); + expect(transition, label).toContain( + 'record a deliberate skip only when the condition does not apply' + ); + expect(transition, label).toContain( + 'If the condition applies, or the prerequisite is not conditional, treat it as a normal prerequisite' + ); + expect(transition, label).toContain('Do not create an unrequested prerequisite'); + expect(transition, label).toContain( + 'deliberately skipped because its own `instruction` stated a condition that did not apply' + ); + expect(transition, label).toContain('remember it, and do not reconsider it'); + expect(transition, label).toContain('Dependencies are enablers, not gates'); + expect(transition, label).toContain( + 'run `openspec instructions "" --change "" --json` (append the confirmed `--store ""` only for a registered standalone store) despite the blocked status' + ); + expect(transition, label).toContain( + 'only when those recorded conditional skips are its sole missing dependencies' + ); + expect(transition, label).toContain('cannot be conditionally skipped'); + expect(requestedInstructions, label).toBeGreaterThanOrEqual(0); + expect(evaluateRequestedCondition, label).toBeGreaterThan(requestedInstructions); + expect(inspectPrerequisite, label).toBeGreaterThan(evaluateRequestedCondition); + expect(evaluateCondition, label).toBeGreaterThan(inspectPrerequisite); + expect(recordSkip, label).toBeGreaterThan(evaluateCondition); + expect(requireExpansion, label).toBeGreaterThan(recordSkip); + expect(approvalGuard, label).toBeGreaterThan(requireExpansion); + } + }); }); diff --git a/test/core/templates/skill-templates-parity.test.ts b/test/core/templates/skill-templates-parity.test.ts index 8adb04a051..3d2a11d3ca 100644 --- a/test/core/templates/skill-templates-parity.test.ts +++ b/test/core/templates/skill-templates-parity.test.ts @@ -37,14 +37,14 @@ import { import { STORE_SELECTION_GUIDANCE } from '../../../src/core/templates/workflows/store-selection.js'; const EXPECTED_FUNCTION_HASHES: Record = { - getExploreSkillTemplate: 'fd45923f8d9eecb8896c17d5ce6d309302132e289132c680d5b3b4d6490501e8', + getExploreSkillTemplate: 'ecfbf91e9e448cd760d02c710b93a41eaeab4a2f26316704afa4ca43859990b6', getNewChangeSkillTemplate: '935f6335e2d4b7d1bd4f0538c88386350c25e8b16e11b627556262229583ca51', getContinueChangeSkillTemplate: 'ed41e2356af7aad6ef760f60fad19c6843cefe436d8f90084dcba4dbc6bf7272', getApplyChangeSkillTemplate: 'e5fc093637d3100a61acf934553002a5e9f5bccab5110136d7680af4133f7351', getFfChangeSkillTemplate: 'fc2a45a08533ee9c7ab30fdab5f832b7d440070048e2a153f03db1620dc379bb', getSyncSpecsSkillTemplate: 'f90032dbeb3a647b451139e12624753057018986df000159499dadc2c3d0965a', getOnboardSkillTemplate: '0b0f9559e21e73a7acfb7e61b403b20080f10ba169d2330c6d55618ce1759a42', - getOpsxExploreCommandTemplate: '0f9af4120cfa7a8f273eebe7c0ddb56fd7c8705b28d1b1d48e1964a26b91d02f', + getOpsxExploreCommandTemplate: '1893639d2e95ae41ed537da97e9bbcc0f5f7c95626c94beec58ebb508f05f3b5', getOpsxNewCommandTemplate: '08e784e52ac2c146975a874257c589d88e93efbd83dc4d79253c8525f5c3064f', getOpsxContinueCommandTemplate: 'ae964cd00f6ca332fd7f9428a577ade75be279f50431d5f60ece8172e8d1a4b1', getOpsxApplyCommandTemplate: 'd879b0430f756b9dbc5a1a1348a34409b2fcd453eeae7add4bf9f421616c2ad1', @@ -65,7 +65,7 @@ const EXPECTED_FUNCTION_HASHES: Record = { }; const EXPECTED_GENERATED_SKILL_CONTENT_HASHES: Record = { - 'openspec-explore': '87a93d0d748c071982ed2199719f00b2885db94d4ac11ae9f12f79909777660c', + 'openspec-explore': '13c6e3a671258606c43a6c698344a1c77abcd7a8d174193d816043c3451b758f', 'openspec-new-change': '579d432771703f947a331a6ed288bf9c6660ca015fcd376d76f19b6ac7683082', 'openspec-continue-change': '5c34be8194cdb4c5158335e47aece71143e8a22bfb4179dba47fd8aaf436d395', 'openspec-apply-change': '1726319cd4305a47f9c827acaeb84a9de57f7e44aba9ed60869c1758338e18ae',