mirror of
https://github.com/Fission-AI/OpenSpec.git
synced 2026-10-02 05:24:34 +08:00
fix(config): label the update workflow in the picker; drop "expanded-profile" wording (#1632)
* fix(config): label the update workflow in the picker and drop "expanded-profile" wording The config workflow picker builds each row's label from WORKFLOW_PROMPT_META in src/commands/config.ts. The table had entries for 11 of the 12 workflows but not `update`, so `openspec config` rendered that row as the raw id `update` with a `Workflow: update` placeholder description. Since `update` is one of the six core workflows, every user who opens the picker saw it. Add the missing `update` entry so the row reads "Update change / Revise the planning artifacts of an existing change". Also reword the update-change workflow template, which called `/opsx:continue` and `/opsx:new` "expanded-profile" workflows. There is no "expanded" profile; the only profile values the product stores are `core` and `custom`. They are now described as "optional" workflows. Regenerated the committed skills.sh mirror and parity hashes accordingly. Harden with a regression test asserting every ALL_WORKFLOWS id has real picker metadata (no raw-id name, no "Workflow:" placeholder), so a future workflow addition can't silently reintroduce the fallback. Closes #1627 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * chore: regenerate skills and parity hashes after rebase onto main Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
4b114aade9
commit
207f3cc515
@@ -15,7 +15,7 @@ Revise a change's existing planning artifacts and keep them coherent. Never edit
|
||||
|
||||
**Input**: Optionally specify a change name. If omitted, check if it can be inferred from conversation context. If vague or ambiguous you MUST prompt for available changes.
|
||||
|
||||
`/openspec-continue-change` is an expanded-profile workflow and may not be installed. Before suggesting it anywhere below, verify that it is available. If it is unavailable, `openspec status --change "<name>" --json` shows the next artifact and `openspec instructions "<artifact-id>" --change "<name>" --json` explains how to create it.
|
||||
`/openspec-continue-change` is an optional workflow and may not be installed. Before suggesting it anywhere below, verify that it is available. If it is unavailable, `openspec status --change "<name>" --json` shows the next artifact and `openspec instructions "<artifact-id>" --change "<name>" --json` explains how to create it.
|
||||
|
||||
**Steps**
|
||||
|
||||
@@ -87,4 +87,4 @@ After each invocation, show:
|
||||
- Edit only the concrete files in `existingOutputPaths`; never write to a glob `resolvedOutputPath`.
|
||||
- Do not advance the build frontier: no new artifacts, no new files under glob artifacts - that is `/openspec-continue-change`'s job.
|
||||
- Confirm every edit with the user before writing.
|
||||
- If the request changes the change's *intent* rather than refining it, first verify whether the expanded-profile `/openspec-new-change` workflow is available. If it is, recommend starting fresh with `/openspec-new-change` (the "Update vs. Start Fresh" heuristic). If it is unavailable, ask for a distinct unused change name and recommend `openspec new change "<new-change-name>"` instead.
|
||||
- If the request changes the change's *intent* rather than refining it, first verify whether the optional `/openspec-new-change` workflow is available. If it is, recommend starting fresh with `/openspec-new-change` (the "Update vs. Start Fresh" heuristic). If it is unavailable, ask for a distinct unused change name and recommend `openspec new change "<new-change-name>"` instead.
|
||||
|
||||
@@ -44,7 +44,7 @@ interface WorkflowPromptMeta {
|
||||
description: string;
|
||||
}
|
||||
|
||||
const WORKFLOW_PROMPT_META: Record<string, WorkflowPromptMeta> = {
|
||||
export const WORKFLOW_PROMPT_META: Record<string, WorkflowPromptMeta> = {
|
||||
propose: {
|
||||
name: 'Propose change',
|
||||
description: 'Create proposal, design, and tasks from a request',
|
||||
@@ -65,6 +65,10 @@ const WORKFLOW_PROMPT_META: Record<string, WorkflowPromptMeta> = {
|
||||
name: 'Apply tasks',
|
||||
description: 'Implement tasks from the current change',
|
||||
},
|
||||
update: {
|
||||
name: 'Update change',
|
||||
description: 'Revise the planning artifacts of an existing change',
|
||||
},
|
||||
ff: {
|
||||
name: 'Fast-forward',
|
||||
description: 'Run a faster implementation workflow',
|
||||
|
||||
@@ -17,7 +17,7 @@ ${STORE_SELECTION_GUIDANCE}
|
||||
|
||||
**Input**: Optionally specify a change name. If omitted, check if it can be inferred from conversation context. If vague or ambiguous you MUST prompt for available changes.
|
||||
|
||||
\`/opsx:continue\` is an expanded-profile workflow and may not be installed. Before suggesting it anywhere below, verify that it is available. If it is unavailable, \`openspec status --change "<name>" --json\` shows the next artifact and \`openspec instructions "<artifact-id>" --change "<name>" --json\` explains how to create it.
|
||||
\`/opsx:continue\` is an optional workflow and may not be installed. Before suggesting it anywhere below, verify that it is available. If it is unavailable, \`openspec status --change "<name>" --json\` shows the next artifact and \`openspec instructions "<artifact-id>" --change "<name>" --json\` explains how to create it.
|
||||
|
||||
**Steps**
|
||||
|
||||
@@ -89,7 +89,7 @@ After each invocation, show:
|
||||
- Edit only the concrete files in \`existingOutputPaths\`; never write to a glob \`resolvedOutputPath\`.
|
||||
- Do not advance the build frontier: no new artifacts, no new files under glob artifacts - that is \`/opsx:continue\`'s job.
|
||||
- Confirm every edit with the user before writing.
|
||||
- If the request changes the change's *intent* rather than refining it, first verify whether the expanded-profile \`/opsx:new\` workflow is available. If it is, recommend starting fresh with \`/opsx:new\` (the "Update vs. Start Fresh" heuristic). If it is unavailable, ask for a distinct unused change name and recommend \`openspec new change "<new-change-name>"\` instead.`,
|
||||
- If the request changes the change's *intent* rather than refining it, first verify whether the optional \`/opsx:new\` workflow is available. If it is, recommend starting fresh with \`/opsx:new\` (the "Update vs. Start Fresh" heuristic). If it is unavailable, ask for a distinct unused change name and recommend \`openspec new change "<new-change-name>"\` instead.`,
|
||||
license: 'MIT',
|
||||
compatibility: 'Requires openspec CLI.',
|
||||
metadata: { author: 'openspec', version: '1.0' },
|
||||
@@ -108,7 +108,7 @@ ${STORE_SELECTION_GUIDANCE}
|
||||
|
||||
**Input**: Optionally specify a change name after \`/opsx:update\` (e.g., \`/opsx:update add-auth\`). If omitted, check if it can be inferred from conversation context. If vague or ambiguous you MUST prompt for available changes.
|
||||
|
||||
\`/opsx:continue\` is an expanded-profile workflow and may not be installed. Before suggesting it anywhere below, verify that it is available. If it is unavailable, \`openspec status --change "<name>" --json\` shows the next artifact and \`openspec instructions "<artifact-id>" --change "<name>" --json\` explains how to create it.
|
||||
\`/opsx:continue\` is an optional workflow and may not be installed. Before suggesting it anywhere below, verify that it is available. If it is unavailable, \`openspec status --change "<name>" --json\` shows the next artifact and \`openspec instructions "<artifact-id>" --change "<name>" --json\` explains how to create it.
|
||||
|
||||
**Steps**
|
||||
|
||||
@@ -180,6 +180,6 @@ After each invocation, show:
|
||||
- Edit only the concrete files in \`existingOutputPaths\`; never write to a glob \`resolvedOutputPath\`.
|
||||
- Do not advance the build frontier: no new artifacts, no new files under glob artifacts - that is \`/opsx:continue\`'s job.
|
||||
- Confirm every edit with the user before writing.
|
||||
- If the request changes the change's *intent* rather than refining it, first verify whether the expanded-profile \`/opsx:new\` workflow is available. If it is, recommend starting fresh with \`/opsx:new\` (the "Update vs. Start Fresh" heuristic). If it is unavailable, ask for a distinct unused change name and recommend \`openspec new change "<new-change-name>"\` instead.`
|
||||
- If the request changes the change's *intent* rather than refining it, first verify whether the optional \`/opsx:new\` workflow is available. If it is, recommend starting fresh with \`/opsx:new\` (the "Update vs. Start Fresh" heuristic). If it is unavailable, ask for a distinct unused change name and recommend \`openspec new change "<new-change-name>"\` instead.`
|
||||
};
|
||||
}
|
||||
|
||||
@@ -395,3 +395,24 @@ describe('config profile command', () => {
|
||||
expect(result.success).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('workflow picker labels', () => {
|
||||
it('gives every workflow a friendly label instead of the raw-id fallback', async () => {
|
||||
const { WORKFLOW_PROMPT_META } = await import('../../src/commands/config.js');
|
||||
const { ALL_WORKFLOWS } = await import('../../src/core/profiles.js');
|
||||
|
||||
for (const workflow of ALL_WORKFLOWS) {
|
||||
const meta = WORKFLOW_PROMPT_META[workflow];
|
||||
// A missing entry is exactly what made `update` render as its raw id
|
||||
// with a `Workflow: update` placeholder in the config picker (#1627).
|
||||
expect(meta, `missing picker metadata for "${workflow}"`).toBeDefined();
|
||||
expect(meta!.name, `label for "${workflow}" must not be the raw id`).not.toBe(workflow);
|
||||
expect(meta!.name.length, `label for "${workflow}" must be non-empty`).toBeGreaterThan(0);
|
||||
expect(
|
||||
meta!.description.startsWith('Workflow:'),
|
||||
`description for "${workflow}" must not be the placeholder`
|
||||
).toBe(false);
|
||||
expect(meta!.description.length, `description for "${workflow}" must be non-empty`).toBeGreaterThan(0);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -302,7 +302,7 @@ describe('InitCommand', () => {
|
||||
|
||||
for (const [content, continueReference] of updateVariants) {
|
||||
const availabilityGuidance = content.indexOf(
|
||||
`${continueReference} is an expanded-profile workflow and may not be installed`
|
||||
`${continueReference} is an optional workflow and may not be installed`
|
||||
);
|
||||
const nextReference = content.indexOf(
|
||||
continueReference,
|
||||
|
||||
@@ -61,8 +61,8 @@ const EXPECTED_FUNCTION_HASHES: Record<string, string> = {
|
||||
getOpsxProposeSkillTemplate: '24623c066f97e34b957d448d1f9a9e8b8a13da3dfce45d45671f6226a2534848',
|
||||
getOpsxProposeCommandTemplate: 'e67ba591efb0fecacb2229d06dfa84af18b825fab8a7b01377279e4f09a06ce4',
|
||||
getFeedbackSkillTemplate: 'd7d83c5f7fc2b92fe8f4588a5bf2d9cb315e4c73ec19bcd5ef28270906319a0d',
|
||||
getUpdateChangeSkillTemplate: '7aa7351aca25fe2d8d29df4339ca2c768e32c6a59596316bb451831447fa15fc',
|
||||
getOpsxUpdateCommandTemplate: 'fdc8ba0502910f74e85044e450906f189e939ffd70d5e85b7307a6ec33805148',
|
||||
getUpdateChangeSkillTemplate: '7dc8abc6f64c58bf34d7581ed4ab095a3b7a53cb372349bee2d840db58622819',
|
||||
getOpsxUpdateCommandTemplate: 'e2388521b22f92f74561df9a0c2f98e1fa4d265af93b5ba26f42fb47a6c5bfed',
|
||||
};
|
||||
|
||||
const EXPECTED_GENERATED_SKILL_CONTENT_HASHES: Record<string, string> = {
|
||||
@@ -77,7 +77,7 @@ const EXPECTED_GENERATED_SKILL_CONTENT_HASHES: Record<string, string> = {
|
||||
'openspec-verify-change': 'af9be013dcbe8c6d8f6d9ab10c893fbd03f4c62933c384d82f63894dd0ceb84f',
|
||||
'openspec-onboard': 'd53403b4910ab64307862ccf97e70bd8f7174ee44508088fb239c880f0939331',
|
||||
'openspec-propose': '25d08ed4f031770cea219604167d76bca9f3e89fe0c2f545263674482c6f13f0',
|
||||
'openspec-update-change': '5ee000a8bf5507a553fbb9ed666625d11986f9c0bf14edb495648554a4d1c53c',
|
||||
'openspec-update-change': '586547406aca94422dfeb3ffedce6c01049429b743f57ce829baa79ebc714d51',
|
||||
};
|
||||
|
||||
// Intentionally excludes getFeedbackSkillTemplate: this list only models templates
|
||||
|
||||
@@ -80,7 +80,7 @@ describe('update-change templates', () => {
|
||||
it('explains the optional continue workflow before suggesting it', () => {
|
||||
for (const [label, body] of bodies) {
|
||||
const availabilityGuidance = body.indexOf(
|
||||
'`/opsx:continue` is an expanded-profile workflow and may not be installed'
|
||||
'`/opsx:continue` is an optional workflow and may not be installed'
|
||||
);
|
||||
const firstSuggestion = body.indexOf(
|
||||
'`/opsx:continue`',
|
||||
@@ -110,7 +110,7 @@ describe('update-change templates', () => {
|
||||
expect(body, label).not.toContain('openspec new change "<name>"');
|
||||
|
||||
const newAvailabilityCheck = body.indexOf(
|
||||
'first verify whether the expanded-profile `/opsx:new` workflow is available'
|
||||
'first verify whether the optional `/opsx:new` workflow is available'
|
||||
);
|
||||
const newRecommendation = body.indexOf('recommend starting fresh with `/opsx:new`');
|
||||
expect(newAvailabilityCheck, label).toBeGreaterThanOrEqual(0);
|
||||
|
||||
Reference in New Issue
Block a user