@seanmars/tospec 0.24.0 → 0.26.0-beta
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +241 -0
- package/README.md +10 -6
- package/assets/dashboard/lib/derive.js +11 -5
- package/assets/dashboard/lib/store.js +4 -2
- package/assets/dashboard/views/change.js +5 -3
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +42 -7
- package/dist/cli/index.js.map +1 -1
- package/dist/commands/config.d.ts.map +1 -1
- package/dist/commands/config.js +213 -100
- package/dist/commands/config.js.map +1 -1
- package/dist/commands/dashboard.d.ts +9 -0
- package/dist/commands/dashboard.d.ts.map +1 -1
- package/dist/commands/dashboard.js +77 -21
- package/dist/commands/dashboard.js.map +1 -1
- package/dist/commands/decision.d.ts +38 -1
- package/dist/commands/decision.d.ts.map +1 -1
- package/dist/commands/decision.js +303 -27
- package/dist/commands/decision.js.map +1 -1
- package/dist/commands/metrics.d.ts +3 -4
- package/dist/commands/metrics.d.ts.map +1 -1
- package/dist/commands/metrics.js +3 -5
- package/dist/commands/metrics.js.map +1 -1
- package/dist/commands/shared-output.d.ts +24 -0
- package/dist/commands/shared-output.d.ts.map +1 -1
- package/dist/commands/shared-output.js +21 -2
- package/dist/commands/shared-output.js.map +1 -1
- package/dist/commands/show.d.ts.map +1 -1
- package/dist/commands/show.js +12 -9
- package/dist/commands/show.js.map +1 -1
- package/dist/commands/validate.d.ts +19 -0
- package/dist/commands/validate.d.ts.map +1 -1
- package/dist/commands/validate.js +243 -64
- package/dist/commands/validate.js.map +1 -1
- package/dist/commands/workflow/instructions.d.ts +7 -1
- package/dist/commands/workflow/instructions.d.ts.map +1 -1
- package/dist/commands/workflow/instructions.js +299 -81
- package/dist/commands/workflow/instructions.js.map +1 -1
- package/dist/commands/workflow/new-change.d.ts.map +1 -1
- package/dist/commands/workflow/new-change.js +26 -17
- package/dist/commands/workflow/new-change.js.map +1 -1
- package/dist/commands/workflow/prompt-escape.d.ts +25 -0
- package/dist/commands/workflow/prompt-escape.d.ts.map +1 -0
- package/dist/commands/workflow/prompt-escape.js +62 -0
- package/dist/commands/workflow/prompt-escape.js.map +1 -0
- package/dist/commands/workflow/schemas.d.ts.map +1 -1
- package/dist/commands/workflow/schemas.js +34 -16
- package/dist/commands/workflow/schemas.js.map +1 -1
- package/dist/commands/workflow/shared.d.ts +46 -10
- package/dist/commands/workflow/shared.d.ts.map +1 -1
- package/dist/commands/workflow/shared.js +66 -30
- package/dist/commands/workflow/shared.js.map +1 -1
- package/dist/commands/workflow/status.d.ts +5 -2
- package/dist/commands/workflow/status.d.ts.map +1 -1
- package/dist/commands/workflow/status.js +62 -28
- package/dist/commands/workflow/status.js.map +1 -1
- package/dist/core/archive.d.ts +38 -0
- package/dist/core/archive.d.ts.map +1 -1
- package/dist/core/archive.js +492 -75
- package/dist/core/archive.js.map +1 -1
- package/dist/core/artifact-graph/index.d.ts +2 -2
- package/dist/core/artifact-graph/index.d.ts.map +1 -1
- package/dist/core/artifact-graph/index.js +2 -2
- package/dist/core/artifact-graph/index.js.map +1 -1
- package/dist/core/artifact-graph/instruction-loader.d.ts +8 -0
- package/dist/core/artifact-graph/instruction-loader.d.ts.map +1 -1
- package/dist/core/artifact-graph/instruction-loader.js +58 -36
- package/dist/core/artifact-graph/instruction-loader.js.map +1 -1
- package/dist/core/artifact-graph/resolver.d.ts +39 -12
- package/dist/core/artifact-graph/resolver.d.ts.map +1 -1
- package/dist/core/artifact-graph/resolver.js +82 -36
- package/dist/core/artifact-graph/resolver.js.map +1 -1
- package/dist/core/artifact-graph/schema.d.ts +24 -0
- package/dist/core/artifact-graph/schema.d.ts.map +1 -1
- package/dist/core/artifact-graph/schema.js +32 -1
- package/dist/core/artifact-graph/schema.js.map +1 -1
- package/dist/core/artifact-graph/stub-detection.d.ts +10 -2
- package/dist/core/artifact-graph/stub-detection.d.ts.map +1 -1
- package/dist/core/artifact-graph/stub-detection.js +18 -11
- package/dist/core/artifact-graph/stub-detection.js.map +1 -1
- package/dist/core/artifact-graph/types.d.ts +2 -2
- package/dist/core/artifact-graph/types.d.ts.map +1 -1
- package/dist/core/artifact-graph/types.js +10 -1
- package/dist/core/artifact-graph/types.js.map +1 -1
- package/dist/core/change-metadata/schema.d.ts.map +1 -1
- package/dist/core/change-metadata/schema.js +18 -4
- package/dist/core/change-metadata/schema.js.map +1 -1
- package/dist/core/change-presenter.d.ts.map +1 -1
- package/dist/core/change-presenter.js +13 -8
- package/dist/core/change-presenter.js.map +1 -1
- package/dist/core/change-status-policy.d.ts.map +1 -1
- package/dist/core/change-status-policy.js +3 -1
- package/dist/core/change-status-policy.js.map +1 -1
- package/dist/core/codex-metrics.d.ts +1 -1
- package/dist/core/codex-metrics.js +1 -1
- package/dist/core/config-schema.d.ts +8 -0
- package/dist/core/config-schema.d.ts.map +1 -1
- package/dist/core/config-schema.js +10 -0
- package/dist/core/config-schema.js.map +1 -1
- package/dist/core/dashboard-activity.d.ts +4 -4
- package/dist/core/dashboard-activity.js +4 -4
- package/dist/core/dashboard-data.d.ts +11 -5
- package/dist/core/dashboard-data.d.ts.map +1 -1
- package/dist/core/dashboard-data.js +54 -28
- package/dist/core/dashboard-data.js.map +1 -1
- package/dist/core/dashboard-hub.d.ts +3 -3
- package/dist/core/dashboard-hub.d.ts.map +1 -1
- package/dist/core/dashboard-hub.js +16 -4
- package/dist/core/dashboard-hub.js.map +1 -1
- package/dist/core/dashboard-routes.d.ts +2 -1
- package/dist/core/dashboard-routes.d.ts.map +1 -1
- package/dist/core/dashboard-routes.js +102 -33
- package/dist/core/dashboard-routes.js.map +1 -1
- package/dist/core/global-config.d.ts +71 -2
- package/dist/core/global-config.d.ts.map +1 -1
- package/dist/core/global-config.js +149 -4
- package/dist/core/global-config.js.map +1 -1
- package/dist/core/id.d.ts +9 -0
- package/dist/core/id.d.ts.map +1 -1
- package/dist/core/id.js +37 -0
- package/dist/core/id.js.map +1 -1
- package/dist/core/init.d.ts +9 -2
- package/dist/core/init.d.ts.map +1 -1
- package/dist/core/init.js +116 -33
- package/dist/core/init.js.map +1 -1
- package/dist/core/list.d.ts.map +1 -1
- package/dist/core/list.js +69 -45
- package/dist/core/list.js.map +1 -1
- package/dist/core/local-server.d.ts +9 -2
- package/dist/core/local-server.d.ts.map +1 -1
- package/dist/core/local-server.js +24 -4
- package/dist/core/local-server.js.map +1 -1
- package/dist/core/markdown-render.d.ts.map +1 -1
- package/dist/core/markdown-render.js +7 -2
- package/dist/core/markdown-render.js.map +1 -1
- package/dist/core/migrate.d.ts +24 -2
- package/dist/core/migrate.d.ts.map +1 -1
- package/dist/core/migrate.js +335 -59
- package/dist/core/migrate.js.map +1 -1
- package/dist/core/parsers/change-parser.d.ts +20 -1
- package/dist/core/parsers/change-parser.d.ts.map +1 -1
- package/dist/core/parsers/change-parser.js +76 -73
- package/dist/core/parsers/change-parser.js.map +1 -1
- package/dist/core/parsers/markdown-parser.d.ts +24 -0
- package/dist/core/parsers/markdown-parser.d.ts.map +1 -1
- package/dist/core/parsers/markdown-parser.js +65 -10
- package/dist/core/parsers/markdown-parser.js.map +1 -1
- package/dist/core/parsers/requirement-blocks.d.ts +127 -6
- package/dist/core/parsers/requirement-blocks.d.ts.map +1 -1
- package/dist/core/parsers/requirement-blocks.js +349 -56
- package/dist/core/parsers/requirement-blocks.js.map +1 -1
- package/dist/core/parsers/requirement-text.d.ts +25 -1
- package/dist/core/parsers/requirement-text.d.ts.map +1 -1
- package/dist/core/parsers/requirement-text.js +62 -6
- package/dist/core/parsers/requirement-text.js.map +1 -1
- package/dist/core/parsers/spec-structure.d.ts.map +1 -1
- package/dist/core/parsers/spec-structure.js +36 -24
- package/dist/core/parsers/spec-structure.js.map +1 -1
- package/dist/core/project-config.d.ts +9 -2
- package/dist/core/project-config.d.ts.map +1 -1
- package/dist/core/project-config.js +30 -7
- package/dist/core/project-config.js.map +1 -1
- package/dist/core/project-layout.d.ts +26 -0
- package/dist/core/project-layout.d.ts.map +1 -1
- package/dist/core/project-layout.js +51 -1
- package/dist/core/project-layout.js.map +1 -1
- package/dist/core/schema-names.d.ts +17 -0
- package/dist/core/schema-names.d.ts.map +1 -1
- package/dist/core/schema-names.js +24 -0
- package/dist/core/schema-names.js.map +1 -1
- package/dist/core/shared/index.d.ts +1 -1
- package/dist/core/shared/index.d.ts.map +1 -1
- package/dist/core/shared/index.js +1 -1
- package/dist/core/shared/index.js.map +1 -1
- package/dist/core/shared/rules-generation.d.ts +12 -0
- package/dist/core/shared/rules-generation.d.ts.map +1 -1
- package/dist/core/shared/rules-generation.js +26 -2
- package/dist/core/shared/rules-generation.js.map +1 -1
- package/dist/core/shared/skill-generation.d.ts +7 -0
- package/dist/core/shared/skill-generation.d.ts.map +1 -1
- package/dist/core/shared/skill-generation.js +19 -0
- package/dist/core/shared/skill-generation.js.map +1 -1
- package/dist/core/shared/tool-detection.d.ts +10 -1
- package/dist/core/shared/tool-detection.d.ts.map +1 -1
- package/dist/core/shared/tool-detection.js +37 -6
- package/dist/core/shared/tool-detection.js.map +1 -1
- package/dist/core/spec-presenter.d.ts.map +1 -1
- package/dist/core/spec-presenter.js +23 -1
- package/dist/core/spec-presenter.js.map +1 -1
- package/dist/core/specs-apply.d.ts +98 -1
- package/dist/core/specs-apply.d.ts.map +1 -1
- package/dist/core/specs-apply.js +426 -63
- package/dist/core/specs-apply.js.map +1 -1
- package/dist/core/templates/fragments/change-diff.d.ts +37 -0
- package/dist/core/templates/fragments/change-diff.d.ts.map +1 -0
- package/dist/core/templates/fragments/change-diff.js +37 -0
- package/dist/core/templates/fragments/change-diff.js.map +1 -0
- package/dist/core/templates/fragments/sync-fail.d.ts +8 -0
- package/dist/core/templates/fragments/sync-fail.d.ts.map +1 -0
- package/dist/core/templates/fragments/sync-fail.js +8 -0
- package/dist/core/templates/fragments/sync-fail.js.map +1 -0
- package/dist/core/templates/fragments/validate.d.ts +14 -1
- package/dist/core/templates/fragments/validate.d.ts.map +1 -1
- package/dist/core/templates/fragments/validate.js +14 -1
- package/dist/core/templates/fragments/validate.js.map +1 -1
- package/dist/core/templates/fragments/verify.d.ts +2 -2
- package/dist/core/templates/fragments/verify.d.ts.map +1 -1
- package/dist/core/templates/fragments/verify.js +8 -5
- package/dist/core/templates/fragments/verify.js.map +1 -1
- package/dist/core/templates/workflows/apply.d.ts +1 -1
- package/dist/core/templates/workflows/apply.d.ts.map +1 -1
- package/dist/core/templates/workflows/apply.js +29 -10
- package/dist/core/templates/workflows/apply.js.map +1 -1
- package/dist/core/templates/workflows/archive.d.ts.map +1 -1
- package/dist/core/templates/workflows/archive.js +27 -9
- package/dist/core/templates/workflows/archive.js.map +1 -1
- package/dist/core/templates/workflows/decision.d.ts.map +1 -1
- package/dist/core/templates/workflows/decision.js +10 -4
- package/dist/core/templates/workflows/decision.js.map +1 -1
- package/dist/core/templates/workflows/explore.d.ts +2 -2
- package/dist/core/templates/workflows/explore.d.ts.map +1 -1
- package/dist/core/templates/workflows/explore.js +7 -3
- package/dist/core/templates/workflows/explore.js.map +1 -1
- package/dist/core/templates/workflows/grill.d.ts +2 -2
- package/dist/core/templates/workflows/grill.d.ts.map +1 -1
- package/dist/core/templates/workflows/grill.js +5 -4
- package/dist/core/templates/workflows/grill.js.map +1 -1
- package/dist/core/templates/workflows/issue.d.ts.map +1 -1
- package/dist/core/templates/workflows/issue.js +9 -3
- package/dist/core/templates/workflows/issue.js.map +1 -1
- package/dist/core/templates/workflows/propose.d.ts.map +1 -1
- package/dist/core/templates/workflows/propose.js +4 -1
- package/dist/core/templates/workflows/propose.js.map +1 -1
- package/dist/core/templates/workflows/sync.d.ts.map +1 -1
- package/dist/core/templates/workflows/sync.js +25 -11
- package/dist/core/templates/workflows/sync.js.map +1 -1
- package/dist/core/templates/workflows/update.d.ts.map +1 -1
- package/dist/core/templates/workflows/update.js +17 -10
- package/dist/core/templates/workflows/update.js.map +1 -1
- package/dist/core/update.d.ts +5 -0
- package/dist/core/update.d.ts.map +1 -1
- package/dist/core/update.js +66 -29
- package/dist/core/update.js.map +1 -1
- package/dist/core/validation/constants.d.ts +7 -1
- package/dist/core/validation/constants.d.ts.map +1 -1
- package/dist/core/validation/constants.js +16 -2
- package/dist/core/validation/constants.js.map +1 -1
- package/dist/core/validation/purpose-placeholder.d.ts.map +1 -1
- package/dist/core/validation/purpose-placeholder.js +35 -11
- package/dist/core/validation/purpose-placeholder.js.map +1 -1
- package/dist/core/validation/section-validator.d.ts +7 -0
- package/dist/core/validation/section-validator.d.ts.map +1 -1
- package/dist/core/validation/section-validator.js +22 -2
- package/dist/core/validation/section-validator.js.map +1 -1
- package/dist/core/validation/sister-changes.d.ts +93 -0
- package/dist/core/validation/sister-changes.d.ts.map +1 -0
- package/dist/core/validation/sister-changes.js +180 -0
- package/dist/core/validation/sister-changes.js.map +1 -0
- package/dist/core/validation/task-markers.d.ts +9 -0
- package/dist/core/validation/task-markers.d.ts.map +1 -0
- package/dist/core/validation/task-markers.js +71 -0
- package/dist/core/validation/task-markers.js.map +1 -0
- package/dist/core/validation/types.d.ts +58 -0
- package/dist/core/validation/types.d.ts.map +1 -1
- package/dist/core/validation/types.js +22 -0
- package/dist/core/validation/types.js.map +1 -1
- package/dist/core/validation/validator.d.ts +79 -2
- package/dist/core/validation/validator.d.ts.map +1 -1
- package/dist/core/validation/validator.js +565 -84
- package/dist/core/validation/validator.js.map +1 -1
- package/dist/utils/change-metadata.d.ts +62 -5
- package/dist/utils/change-metadata.d.ts.map +1 -1
- package/dist/utils/change-metadata.js +193 -31
- package/dist/utils/change-metadata.js.map +1 -1
- package/dist/utils/change-utils.d.ts +21 -0
- package/dist/utils/change-utils.d.ts.map +1 -1
- package/dist/utils/change-utils.js +168 -53
- package/dist/utils/change-utils.js.map +1 -1
- package/dist/utils/command-line.d.ts +11 -0
- package/dist/utils/command-line.d.ts.map +1 -0
- package/dist/utils/command-line.js +43 -0
- package/dist/utils/command-line.js.map +1 -0
- package/dist/utils/display-width.d.ts +10 -0
- package/dist/utils/display-width.d.ts.map +1 -0
- package/dist/utils/display-width.js +15 -0
- package/dist/utils/display-width.js.map +1 -0
- package/dist/utils/file-system.d.ts +16 -0
- package/dist/utils/file-system.d.ts.map +1 -1
- package/dist/utils/file-system.js +49 -2
- package/dist/utils/file-system.js.map +1 -1
- package/dist/utils/frontmatter.d.ts.map +1 -1
- package/dist/utils/frontmatter.js +11 -5
- package/dist/utils/frontmatter.js.map +1 -1
- package/dist/utils/interactive.d.ts.map +1 -1
- package/dist/utils/interactive.js +3 -1
- package/dist/utils/interactive.js.map +1 -1
- package/dist/utils/item-discovery.d.ts +3 -2
- package/dist/utils/item-discovery.d.ts.map +1 -1
- package/dist/utils/item-discovery.js +34 -16
- package/dist/utils/item-discovery.js.map +1 -1
- package/dist/utils/link.d.ts +0 -1
- package/dist/utils/link.d.ts.map +1 -1
- package/dist/utils/link.js +0 -1
- package/dist/utils/link.js.map +1 -1
- package/dist/utils/match.d.ts.map +1 -1
- package/dist/utils/match.js +10 -1
- package/dist/utils/match.js.map +1 -1
- package/dist/utils/option-flags.d.ts +9 -0
- package/dist/utils/option-flags.d.ts.map +1 -0
- package/dist/utils/option-flags.js +12 -0
- package/dist/utils/option-flags.js.map +1 -0
- package/dist/utils/sentence.d.ts +9 -0
- package/dist/utils/sentence.d.ts.map +1 -0
- package/dist/utils/sentence.js +12 -0
- package/dist/utils/sentence.js.map +1 -0
- package/dist/utils/spec-files.d.ts +84 -1
- package/dist/utils/spec-files.d.ts.map +1 -1
- package/dist/utils/spec-files.js +192 -3
- package/dist/utils/spec-files.js.map +1 -1
- package/dist/utils/task-progress.d.ts.map +1 -1
- package/dist/utils/task-progress.js +32 -9
- package/dist/utils/task-progress.js.map +1 -1
- package/dist/utils/timestamp.d.ts +27 -0
- package/dist/utils/timestamp.d.ts.map +1 -1
- package/dist/utils/timestamp.js +37 -0
- package/dist/utils/timestamp.js.map +1 -1
- package/package.json +4 -1
- package/schemas/decision/templates/decision.md +2 -2
- package/schemas/issue/schema.yaml +12 -6
- package/schemas/issue/templates/task.md +1 -1
- package/schemas/sdd/schema.yaml +21 -10
- package/schemas/sdd/templates/proposal.md +1 -1
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { SYNC_FAIL_WITHOUT_CODE_BUG } from '../fragments/sync-fail.js';
|
|
1
2
|
const ARCHIVE_BODY = `**Finishing a change: sync, then archive — in that order.** Do not run \`tospec archive\` speculatively "to see what happens"; each step below must actually hold first.
|
|
2
3
|
|
|
3
4
|
**Step 1 — run the sync, don't ask about it**
|
|
@@ -7,7 +8,7 @@ Archive merges the change's delta specs into \`tospec/specs/\` permanently, so i
|
|
|
7
8
|
Take these in order; the first that matches wins.
|
|
8
9
|
|
|
9
10
|
1. **The user's request unambiguously names sync as what to skip** ("archive without sync", "skip the sync") — honor that: skip the sync and archive **without** \`--require-sync\` (Step 2, not-synced branch). A request that merely contains the word "archive" ("just archive this") does not count — that is also the ordinary verb for the whole workflow, so matching on it alone skips a sync nobody asked to skip.
|
|
10
|
-
2. **No delta specs at all** (e.g. a purely cosmetic issue fix with no behavior change) — there is no spec-vs-code drift to find. Skip straight to Step 2 and archive directly. Under a schema that requires deltas (sdd), such a change also needs \`skip_specs: true\` in its \`.tospec.yaml\` or validation will refuse it — set that once, and only when the change
|
|
11
|
+
2. **No delta specs at all** (e.g. a purely cosmetic issue fix with no behavior change) — there is no spec-vs-code drift to find. Skip straight to Step 2 and archive directly. Under a schema that requires deltas (sdd), such a change also needs \`skip_specs: true\` in its \`.tospec.yaml\` or validation will refuse it — set that once, and only when the user explicitly says this change needs no delta spec, never on your own judgment. Never write a delta spec just to get past the gate.
|
|
11
12
|
3. **Otherwise the change produced delta specs** (a non-empty \`specs/<capability>/spec.md\` under the change dir), so behavior was added or changed and drift is possible. Run the \`tospec-sync\` workflow now, without asking — declining would mean knowingly publishing a spec that may not describe the code, so there is no decision here to put to the user.
|
|
12
13
|
|
|
13
14
|
Running it unannounced is safe because of how \`tospec-sync\` is ordered: it judges every Requirement before writing anything, so a defect surfaces while the working tree is still untouched.
|
|
@@ -19,12 +20,12 @@ Running it unannounced is safe because of how \`tospec-sync\` is ordered: it jud
|
|
|
19
20
|
|
|
20
21
|
> "Sync found <N> Requirement(s) the code doesn't satisfy: <names>. Fix them now, or leave it for later?"
|
|
21
22
|
|
|
22
|
-
- **Fix now** →
|
|
23
|
+
- **Fix now** → stop here as well, and ask the user to run \`tospec-apply\` to fix the named Requirement(s), then run \`tospec-archive\` again. Archive neither edits source nor runs \`tospec-apply\` itself: a fix runs the project's tests and edits code, which archive's tools do not cover. The rerun starts at Step 1, so its sync judges the fixed code afresh and rewrites \`sync-report.md\`; the gate reads that report, so this run's FAIL keeps refusing until then.
|
|
23
24
|
- **Later** → stop. Do not archive; the change stays active with its spec files unmodified.
|
|
24
25
|
|
|
25
|
-
|
|
26
|
+
Either way this run ends here, and its spec files stay unmodified. The one-question rule is per archive run.
|
|
26
27
|
|
|
27
|
-
- **\`Conclusion: FAIL\` with no CODE-BUG** —
|
|
28
|
+
- **\`Conclusion: FAIL\` with no CODE-BUG** — ${SYNC_FAIL_WITHOUT_CODE_BUG} Do not archive on a FAIL report, and do not reach for \`--require-sync\`'s absence to route around it.
|
|
28
29
|
|
|
29
30
|
**Step 2 — archive**
|
|
30
31
|
|
|
@@ -42,23 +43,40 @@ Only omit \`--require-sync\` on this branch; passing it without a sync having ru
|
|
|
42
43
|
|
|
43
44
|
Either way, the CLI then: re-validates the delta specs (blocking), checks tasks/task completion and that every required artifact was written (each blocking unless overridden — see \`--yes\` below), does a two-phase atomic merge into \`tospec/specs/\` (dry-run + re-validate every target first, writes only if all pass; in \`--json\` mode the merge needs no confirmation, and \`--skip-specs\` is the only way to decline it), and moves the change directory — including \`sync-report.md\` when present — into \`tospec/changes/archive/\` under a \`yyyyMMdd_HHmmss-<name>\` timestamp the CLI generates itself.
|
|
44
45
|
|
|
45
|
-
**Reading the result**: the \`--json\` output is \`{archive
|
|
46
|
+
**Reading the result**: the \`--json\` output is \`{archive}\`, plus \`status\` when there is anything to report — a successful archive with no warning carries no \`status\` at all. Success → \`archive\` holds \`{change, archivedAs, path, specsUpdated, totals}\`. Failure → \`archive\` is \`null\` and the \`status\` entry with \`severity: "error"\` tells you which ending you got (validation's warnings, and with \`--yes\` those for the gates it overrode, come before it, so it is not always \`status[0]\`):
|
|
46
47
|
- \`archive_validation_failed\` — fix the artifacts \`tospec validate\` names, re-validate, rerun
|
|
47
48
|
- \`archive_artifacts_incomplete\` — a required artifact was never written or is still the unfilled template (the message names it); write it rather than overriding, because archiving is what makes the omission permanent
|
|
48
49
|
- \`archive_tasks_incomplete\` / \`archive_tasks_missing\` — finish the tasks; rerun with \`--yes\` only if the user explicitly accepts archiving unfinished work
|
|
49
50
|
- \`sync_report_missing\` / \`sync_report_failed\` — the sync gate refused
|
|
50
|
-
- \`archive_spec_update_failed\` — the merge's own preconditions failed (an ADDED whose name the main spec already has with different content, a MODIFIED or RENAMED whose target it lacks)
|
|
51
|
+
- \`archive_spec_update_failed\` — the merge's own preconditions failed; nothing was written. Either the delta is at fault (an ADDED whose name the main spec already has with different content, a MODIFIED or RENAMED whose target it lacks, a MODIFIED, REMOVED or RENAMED on a capability with no main spec), or the main spec is: it is structurally invalid, or removing its last requirement would delete content outside its requirements (a \`## Notes\` section, notes inside a block). \`fix\` names which file to edit. \`tospec validate\` reports the delta's findings beforehand as warnings with \`code: "archive_would_refuse"\` (counted in \`summary.totals.archiveRefusals\`), which is why warnings are fixed, not skipped. One that carries \`blockedBy\` is not the delta's fault: tell the user to archive the changes it lists first, and do not edit the delta
|
|
51
52
|
- \`archive_spec_validation_failed\` / \`archive_spec_merge_empty\` — the rebuilt main spec would not validate, or the delta files sit where the merge cannot read them; nothing was written
|
|
53
|
+
- \`archive_partially_applied\` — the specs were already merged into \`tospec/specs/\` (or the change already moved), then a later step failed; the message says what is done and what failed. **Never rerun archive** — the merge refuses requirements it already added. Show the user the message and \`fix\`, which lists the manual steps left, and let them finish or approve them
|
|
54
|
+
- \`archive_change_not_found\` / \`archive_change_name_invalid\` / \`archive_target_exists\` — the change named does not exist, is not a valid change id, or its archive directory already exists; \`archive_error\` — an unexpected failure, reported by its message
|
|
52
55
|
|
|
53
|
-
Each status entry carries \`{code, message
|
|
56
|
+
Each status entry carries \`{severity, code, message}\`, and \`fix\` when there is a remedy to follow — follow it. The last four codes above carry none: report the message to the user.
|
|
54
57
|
|
|
55
58
|
**\`--yes\` is a blanket override, not a per-gate one.** It downgrades every overridable gate at once — incomplete tasks, missing tasks, incomplete artifacts, and the \`--no-validate\` confirmation — to a warning in the success document's \`status\`; there is no flag that overrides one gate and keeps the rest. So never pass it pre-emptively: run without it, read which gate refused, and add \`--yes\` only after the user has accepted that specific override — then read the result's \`status\` warnings to confirm nothing else was waived along with it. Merging specs never needs it.
|
|
56
59
|
|
|
57
60
|
A successful archive can also carry \`status\` warnings for things that happened but did not block: an overridden gate, or a delta whose \`## Purpose\` was ignored because the capability already has a main spec. Read them — nothing else reports these.
|
|
58
61
|
|
|
62
|
+
\`archive_sister_change_stale\` names another in-progress change whose delta rewrites a requirement this archive just changed. Relay it to the user: that change must rewrite its block against the updated main spec before it is archived, or its archive overwrites this change's edit. Do not edit the other change from here.
|
|
63
|
+
|
|
64
|
+
**Step 3 — settle the status of the change's decisions**
|
|
65
|
+
|
|
66
|
+
An ADR linked to the change is usually still \`proposed\`: explore and grill record it that way, and nothing moves it on by itself. \`tospec-propose\` and \`tospec-explore\` read only \`accepted\` ADRs, so a decision left \`proposed\` after its change ships is never read again.
|
|
67
|
+
|
|
68
|
+
1. Before Step 2's \`tospec archive\` (it moves the change directory), read the linked filenames from \`changeMetadata.decisions\` in \`tospec status --change "<name>" --json\`. None listed → skip this step.
|
|
69
|
+
2. Once the archive has succeeded, run \`tospec decision list --status proposed --json\` and keep the linked files that appear in it. None → skip the rest.
|
|
70
|
+
3. Ask the user **once**, listing those ADRs by filename and title, which of them the shipped change has made \`accepted\`. Never mark one on your own judgment.
|
|
71
|
+
4. For each one the user confirms:
|
|
72
|
+
\`\`\`bash
|
|
73
|
+
tospec decision status "<file>" accepted --json
|
|
74
|
+
\`\`\`
|
|
75
|
+
It rewrites the Status in the ADR file and the row in \`tospec/decisions/index.md\` together; never edit either by hand. Leave the others \`proposed\`.
|
|
76
|
+
|
|
59
77
|
**Guardrails**
|
|
60
78
|
- Run the sync when the change has spec deltas; do not ask permission for it. Honor an explicit request to skip, and skip it outright when there are no delta specs
|
|
61
|
-
- A CODE-BUG is the only outcome that may interrupt — MATCH and SPEC-UPDATED continue silently. Never edit source from here; a fix goes through \`tospec-apply
|
|
79
|
+
- A CODE-BUG is the only outcome that may interrupt — MATCH and SPEC-UPDATED continue silently. Never edit source from here; a fix goes through \`tospec-apply\`, which the user runs before rerunning archive
|
|
62
80
|
- Only pass \`--require-sync\` when \`tospec-sync\` actually produced a passing \`sync-report.md\` this run
|
|
63
81
|
- **\`tospec archive\` owns the archive directory** — it generates the \`yyyyMMdd_HHmmss-<name>\` name and moves the change there. Let the command do it: the timestamp comes from internals you cannot reproduce, so a hand-built name risks a collision or a wrong sort order
|
|
64
82
|
- If \`tospec archive\` reports a validation failure or asks for confirmation on incomplete tasks, resolve the underlying issue (or explicitly confirm with the user) — do not route around it with manual file operations
|
|
@@ -66,7 +84,7 @@ A successful archive can also carry \`status\` warnings for things that happened
|
|
|
66
84
|
|
|
67
85
|
**Output**
|
|
68
86
|
|
|
69
|
-
Report the archived name and path from \`tospec archive\`'s output, whether a sync ran and what it concluded, and **anything the sync found that no Requirement asked for** — that is reported here, never written into a spec, and never a reason to block. Confirm \`tospec/specs/\` now reflects the merged change.`;
|
|
87
|
+
Report the archived name and path from \`tospec archive\`'s output, whether a sync ran and what it concluded, which linked ADRs were marked \`accepted\` and which stay \`proposed\`, and **anything the sync found that no Requirement asked for** — that is reported here, never written into a spec, and never a reason to block. Confirm \`tospec/specs/\` now reflects the merged change.`;
|
|
70
88
|
export function getTospecArchiveSkillTemplate() {
|
|
71
89
|
return {
|
|
72
90
|
name: 'tospec-archive',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"archive.js","sourceRoot":"","sources":["../../../../src/core/templates/workflows/archive.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"archive.js","sourceRoot":"","sources":["../../../../src/core/templates/workflows/archive.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,0BAA0B,EAAE,MAAM,2BAA2B,CAAC;AAEvE,MAAM,YAAY,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;gDA0B2B,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+XA2DqT,CAAC;AAEhY,MAAM,UAAU,6BAA6B;IAC3C,OAAO;QACL,IAAI,EAAE,gBAAgB;QACtB,WAAW,EAAE,+LAA+L;QAC5M,YAAY,EAAE;;;;EAIhB,YAAY,EAAE;QACZ,OAAO,EAAE,KAAK;QACd,aAAa,EAAE,sBAAsB;QACrC,QAAQ,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE;QAC9B,YAAY,EAAE,CAAC,gBAAgB,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,iBAAiB,CAAC;KAC7F,CAAC;AACJ,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"decision.d.ts","sourceRoot":"","sources":["../../../../src/core/templates/workflows/decision.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"decision.d.ts","sourceRoot":"","sources":["../../../../src/core/templates/workflows/decision.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAuDjD,wBAAgB,8BAA8B,IAAI,aAAa,CAe9D"}
|
|
@@ -15,6 +15,12 @@ const DECISION_BODY = `Capture a decision that has already been made or is ready
|
|
|
15
15
|
\`\`\`
|
|
16
16
|
Derive a kebab-case \`<topic>\` from the subject. The CLI produces both files: it writes \`tospec/decisions/<yyyyMMdd_HHmmss>-<topic>.md\` from its template (Status/Date/title pre-filled) and appends a row to \`tospec/decisions/index.md\` (seeding that ledger on first use). **The CLI owns the dated filename and the index — never create/rename decision files or hand-edit \`index.md\` yourself.** Use \`--status accepted\` if already agreed, or \`--status superseded\` (and name the successor) when replacing an older decision; pass \`--date\` only to backfill a past decision.
|
|
17
17
|
|
|
18
|
+
**Linking to an existing change.** When the decision belongs to a change that already exists (it came out of grilling or exploring that change, or an issue diagnosis settled the fix), add \`--change "<name>"\`:
|
|
19
|
+
\`\`\`bash
|
|
20
|
+
tospec decision new "<topic>" --title "<title>" --summary "<one-line summary>" --status proposed --change "<name>"
|
|
21
|
+
\`\`\`
|
|
22
|
+
The CLI then also appends the new filename to that change's \`.tospec.yaml\` \`decisions:\` list, which is what status, instructions and archive read. It refuses an unknown or archived change before writing anything. To link an ADR that **already exists**, add its bare \`<yyyyMMdd_HHmmss>-<topic>.md\` filename to the change's \`decisions:\` list by hand, then run \`tospec validate "<name>"\`: it warns about a value that is not a decision filename or names no file.
|
|
23
|
+
|
|
18
24
|
4. **Fill the sections**
|
|
19
25
|
Open the created file. Six sections are required — they are the structure the schema validates against:
|
|
20
26
|
- **Status** — proposed / accepted / superseded (+ Date); if superseded, name the decision that replaces it.
|
|
@@ -26,7 +32,7 @@ const DECISION_BODY = `Capture a decision that has already been made or is ready
|
|
|
26
32
|
|
|
27
33
|
The template carries two more that are optional:
|
|
28
34
|
- **Decision Process** — the key questions you asked and the user's answers that shaped this decision. Format each pair as a \`**Q:** question\` line followed by the answer in the next paragraph, one pair per block. Summarize each Q&A; don't paste a full transcript. Omit the section entirely if there was no interactive discussion.
|
|
29
|
-
- **Related Changes** — leave it empty. Nothing writes it: \`tospec new change --decisions\`
|
|
35
|
+
- **Related Changes** — leave it empty. Nothing writes it: \`tospec new change --decisions\` and \`tospec decision new --change\` record the link on the change's side only, so this list is filled in by hand if anyone wants it.
|
|
30
36
|
|
|
31
37
|
5. **Verify**
|
|
32
38
|
\`\`\`bash
|
|
@@ -36,14 +42,14 @@ const DECISION_BODY = `Capture a decision that has already been made or is ready
|
|
|
36
42
|
|
|
37
43
|
**Output**
|
|
38
44
|
|
|
39
|
-
Summarize the decision, its status, and the follow-up work. If it supersedes an older decision, state which one and flip that older
|
|
45
|
+
Summarize the decision, its status, and the follow-up work. If it supersedes an older decision, state which one and flip that older record with \`tospec decision status "<older-file>" superseded\`, which rewrites its file and its ledger row together. Report the created filename explicitly — when a change later implements this decision, that filename is what \`tospec new change --decisions\` records to link the change back here (the file's optional \`## Related Changes\` section can list those changes in return).
|
|
40
46
|
|
|
41
|
-
Then point at the next step. ${nextStepLabelRule('the decision you just recorded', '\`(update)\`, \`(propose)\`/\`(issue)\`')} If the decision came out of grilling or exploring an **existing** change, offer **(update)** via \`tospec-update\` to fold it into that change's artifacts; if no change exists yet, offer **(propose)** / **(issue)** via \`tospec-propose\`/\`tospec-issue\` and carry the filename into \`--decisions\`.
|
|
47
|
+
Then point at the next step. ${nextStepLabelRule('the decision you just recorded', '\`(update)\`, \`(propose)\`/\`(issue)\`')} If the decision came out of grilling or exploring an **existing** change, it was created with \`--change\` (step 3), so the link is already in place; offer **(update)** via \`tospec-update\` to fold it into that change's artifacts; if no change exists yet, offer **(propose)** / **(issue)** via \`tospec-propose\`/\`tospec-issue\` and carry the filename into \`--decisions\`.
|
|
42
48
|
|
|
43
49
|
**Guardrails**
|
|
44
50
|
- The decision file, its date-prefixed filename, and the ledger row are all CLI-generated — pass \`--summary\`, and never create/rename decision files or hand-edit \`index.md\` yourself; only edit the decision file's section contents
|
|
45
51
|
- Don't record a decision whose rationale or alternatives you can't state — clarify with the user first
|
|
46
|
-
- \`superseded\` must name its successor; the superseded record's Status must be updated too
|
|
52
|
+
- \`superseded\` must name its successor; the superseded record's Status must be updated too, with \`tospec decision status\`. If a Status was edited by hand anyway, \`tospec decision list --reindex\` carries it into \`index.md\``;
|
|
47
53
|
export function getTospecDecisionSkillTemplate() {
|
|
48
54
|
return {
|
|
49
55
|
name: 'tospec-decision',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"decision.js","sourceRoot":"","sources":["../../../../src/core/templates/workflows/decision.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAE9D,MAAM,aAAa,GAAG
|
|
1
|
+
{"version":3,"file":"decision.js","sourceRoot":"","sources":["../../../../src/core/templates/workflows/decision.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAE9D,MAAM,aAAa,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+BA6CS,iBAAiB,CAAC,gCAAgC,EAAE,yCAAyC,CAAC;;;;;sOAKyG,CAAC;AAEvO,MAAM,UAAU,8BAA8B;IAC5C,OAAO;QACL,IAAI,EAAE,iBAAiB;QACvB,WAAW,EACT,6NAA6N;QAC/N,YAAY,EAAE;;;;EAIhB,aAAa,EAAE;QACb,OAAO,EAAE,KAAK;QACd,aAAa,EAAE,sBAAsB;QACrC,QAAQ,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE;QAC9B,YAAY,EAAE,CAAC,gBAAgB,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,iBAAiB,CAAC;KAC7F,CAAC;AACJ,CAAC"}
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* Explore Workflow Template
|
|
3
3
|
*
|
|
4
4
|
* Pre-change requirement convergence: interview a fuzzy idea or problem until
|
|
5
|
-
* it is concrete enough to hand to propose/issue. Read-only
|
|
6
|
-
* by asking the user for the next step. Its sibling `tospec-grill` pressure-tests
|
|
5
|
+
* it is concrete enough to hand to propose/issue. Read-only apart from the ADR
|
|
6
|
+
* step 5 records, and obliged to end by asking the user for the next step. Its sibling `tospec-grill` pressure-tests
|
|
7
7
|
* something already on the table — explore deliberately avoids leading with the
|
|
8
8
|
* word "grill" so the two don't compete for the same trigger.
|
|
9
9
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"explore.d.ts","sourceRoot":"","sources":["../../../../src/core/templates/workflows/explore.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AA4DjD,wBAAgB,uBAAuB,IAAI,aAAa,
|
|
1
|
+
{"version":3,"file":"explore.d.ts","sourceRoot":"","sources":["../../../../src/core/templates/workflows/explore.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AA4DjD,wBAAgB,uBAAuB,IAAI,aAAa,CAkBvD"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { INTERVIEW_MECHANICS } from '../fragments/interview.js';
|
|
2
2
|
import { nextStepLabelRule } from '../fragments/next-step.js';
|
|
3
|
-
const EXPLORE_BODY = `**Explore is for thinking, not implementing.** Read files, search code, and run read-only \`tospec\` commands; write no code and no artifact files. When the requirement converges, record any material decisions via \`tospec-decision\` first, then hand off to \`tospec-propose\` or \`tospec-issue\` — those write the files.
|
|
3
|
+
const EXPLORE_BODY = `**Explore is for thinking, not implementing.** Read files, search code, and run read-only \`tospec\` commands; write no code and no artifact files. The one write is the ADR step 5 records under \`tospec/decisions/\`, and that directory is the only place this skill may edit without a permission prompt. When the requirement converges, record any material decisions via \`tospec-decision\` first, then hand off to \`tospec-propose\` or \`tospec-issue\` — those write the files.
|
|
4
4
|
|
|
5
5
|
This is a structured interview, not a freeform chat: keep asking until you and the user share the same understanding of every branch that shapes the requirement.
|
|
6
6
|
|
|
@@ -14,7 +14,7 @@ ${INTERVIEW_MECHANICS}
|
|
|
14
14
|
\`\`\`bash
|
|
15
15
|
tospec list --json
|
|
16
16
|
\`\`\`
|
|
17
|
-
Read \`tospec/specs/\` for the capabilities this touches and \`tospec/config.yaml\` for project context. Do this BEFORE asking anything — questions you can answer yourself by reading the codebase are questions you should never ask the user.
|
|
17
|
+
Read \`tospec/specs/\` for the capabilities this touches and \`tospec/config.yaml\` for project context. Read \`tospec/decisions/index.md\` too if it exists — its rows are what was already decided — and open only the \`accepted\` ADRs that bear on this topic. If the direction taking shape conflicts with one, say so and suggest recording the new decision with \`tospec-decision\` to supersede it; never override it silently. Do this BEFORE asking anything — questions you can answer yourself by reading the codebase are questions you should never ask the user.
|
|
18
18
|
|
|
19
19
|
2. **Work the question priority order**
|
|
20
20
|
|
|
@@ -67,7 +67,11 @@ ${EXPLORE_BODY}`,
|
|
|
67
67
|
license: 'MIT',
|
|
68
68
|
compatibility: 'Requires tospec CLI.',
|
|
69
69
|
metadata: { author: 'tospec' },
|
|
70
|
-
|
|
70
|
+
// Edit scoped to the decisions dir covers the step 5 ADR (the sub-step's
|
|
71
|
+
// `decision new` runs under Bash(tospec:*), filling the file needs Edit) and
|
|
72
|
+
// nothing else: a source edit still prompts. No `Write(...)` rule: Claude
|
|
73
|
+
// Code checks file writes against Edit rules only and ignores a Write one.
|
|
74
|
+
allowedTools: ['Bash(tospec:*)', 'Read', 'Edit(tospec/decisions/**)', 'Grep', 'Glob', 'AskUserQuestion'],
|
|
71
75
|
};
|
|
72
76
|
}
|
|
73
77
|
//# sourceMappingURL=explore.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"explore.js","sourceRoot":"","sources":["../../../../src/core/templates/workflows/explore.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAE9D,MAAM,YAAY,GAAG;;;;;;EAMnB,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2GAoCsF,iBAAiB,CAAC,iCAAiC,EAAE,wCAAwC,CAAC;;;;;;;;;;;;yHAYhF,CAAC;AAE1H,MAAM,UAAU,uBAAuB;IACrC,OAAO;QACL,IAAI,EAAE,gBAAgB;QACtB,WAAW,EAAE,qRAAqR;QAClS,YAAY,EAAE;;;;EAIhB,YAAY,EAAE;QACZ,OAAO,EAAE,KAAK;QACd,aAAa,EAAE,sBAAsB;QACrC,QAAQ,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE;QAC9B,YAAY,EAAE,CAAC,gBAAgB,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"explore.js","sourceRoot":"","sources":["../../../../src/core/templates/workflows/explore.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAE9D,MAAM,YAAY,GAAG;;;;;;EAMnB,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2GAoCsF,iBAAiB,CAAC,iCAAiC,EAAE,wCAAwC,CAAC;;;;;;;;;;;;yHAYhF,CAAC;AAE1H,MAAM,UAAU,uBAAuB;IACrC,OAAO;QACL,IAAI,EAAE,gBAAgB;QACtB,WAAW,EAAE,qRAAqR;QAClS,YAAY,EAAE;;;;EAIhB,YAAY,EAAE;QACZ,OAAO,EAAE,KAAK;QACd,aAAa,EAAE,sBAAsB;QACrC,QAAQ,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE;QAC9B,yEAAyE;QACzE,6EAA6E;QAC7E,0EAA0E;QAC1E,2EAA2E;QAC3E,YAAY,EAAE,CAAC,gBAAgB,EAAE,MAAM,EAAE,2BAA2B,EAAE,MAAM,EAAE,MAAM,EAAE,iBAAiB,CAAC;KACzG,CAAC;AACJ,CAAC"}
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
*
|
|
4
4
|
* On-demand deep-dive interrogation of any artifact (plan / decision / idea)
|
|
5
5
|
* using a Known/Unknown four-quadrant frame. Explicit-invocation only,
|
|
6
|
-
* read-only, and — unlike explore — under no
|
|
7
|
-
* anything.
|
|
6
|
+
* read-only apart from the ADR it records, and — unlike explore — under no
|
|
7
|
+
* obligation to hand off or persist anything.
|
|
8
8
|
*/
|
|
9
9
|
import type { SkillTemplate } from '../types.js';
|
|
10
10
|
export declare function getGrillSkillTemplate(): SkillTemplate;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"grill.d.ts","sourceRoot":"","sources":["../../../../src/core/templates/workflows/grill.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAiDjD,wBAAgB,qBAAqB,IAAI,aAAa,
|
|
1
|
+
{"version":3,"file":"grill.d.ts","sourceRoot":"","sources":["../../../../src/core/templates/workflows/grill.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAiDjD,wBAAgB,qBAAqB,IAAI,aAAa,CAerD"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { INTERVIEW_MECHANICS } from '../fragments/interview.js';
|
|
2
2
|
import { nextStepLabelRule } from '../fragments/next-step.js';
|
|
3
|
-
const GRILL_BODY = `**Grill is read-only pressure-testing, not building.** Read files, search code, and run read-only \`tospec\` commands; write no code, source edits, or artifact files.
|
|
3
|
+
const GRILL_BODY = `**Grill is read-only pressure-testing, not building.** Read files, search code, and run read-only \`tospec\` commands; write no code, source edits, or artifact files. When the interrogation lands something worth persisting, grill delegates to the skill that owns that write (\`tospec-decision\` for a settled decision, \`tospec-update\` for a change's artifacts). The ADR is the one write that happens inside grill, run as a sub-step, and \`tospec/decisions/\` is the only place this skill may edit without a permission prompt.
|
|
4
4
|
|
|
5
5
|
This is a relentless interrogation of whatever is on the table — a plan, a decision, an idea, a design. Stress-test it until every assumption is named and every open question is either answered or explicitly parked.
|
|
6
6
|
|
|
@@ -36,9 +36,9 @@ You're done only when you can fully restate the shared understanding — the cla
|
|
|
36
36
|
|
|
37
37
|
A grill that shifts the picture leaves work behind. Once the user confirms the restatement:
|
|
38
38
|
|
|
39
|
-
1. **Record any decision the grill produced — don't ask first.** A choice between real alternatives with lasting architecture/design impact belongs in an ADR before anything else: record it via \`tospec-decision\` with \`--status proposed
|
|
39
|
+
1. **Record any decision the grill produced — don't ask first.** A choice between real alternatives with lasting architecture/design impact belongs in an ADR before anything else: record it via \`tospec-decision\` with \`--status proposed\`, and, when the target was an existing written proposal, with \`--change "<name>"\` too, so the ADR is linked to that change as it is created. Don't offer this as an option — the confirmation you just got is the consent, and \`proposed\` is a draft status the user can still reject. Record nothing when nothing material moved; a confirmed assumption is not a decision. If you can't state the rationale and the alternatives weighed, don't invent them — ask the user, per \`tospec-decision\`'s own rule. Run it as a sub-step and skip \`tospec-decision\`'s own next-step handoff; step 2 covers it. Report the created filename.
|
|
40
40
|
2. **Then offer the next step,** routed by target kind. ${nextStepLabelRule('what this grill actually surfaced', '\`(update)\`, \`(propose)\`/\`(issue)\`, \`(grill)\`')}
|
|
41
|
-
- **Target was an existing written proposal** → **(update)** via \`tospec-update\` to fold the outcome into that change's artifacts. Name the change so update doesn't have to re-ask, and carry any recorded decision filename with it.
|
|
41
|
+
- **Target was an existing written proposal** → **(update)** via \`tospec-update\` to fold the outcome into that change's artifacts. Name the change so update doesn't have to re-ask, and carry any recorded decision filename with it; \`--change\` already listed it in the change's \`decisions:\`, so update folds its content into the artifacts and links nothing itself.
|
|
42
42
|
- **Target was a raw idea or an explore** → nothing is written yet; offer **(propose)** (or **(issue)** when something is broken) via \`tospec-propose\`/\`tospec-issue\`, or **(grill)** if it's still fuzzy.
|
|
43
43
|
|
|
44
44
|
**Guardrails**
|
|
@@ -56,7 +56,8 @@ ${GRILL_BODY}`,
|
|
|
56
56
|
license: 'MIT',
|
|
57
57
|
compatibility: 'Requires tospec CLI.',
|
|
58
58
|
metadata: { author: 'tospec' },
|
|
59
|
-
|
|
59
|
+
// Scoped as explore's is, for the same sub-step: see explore.ts.
|
|
60
|
+
allowedTools: ['Bash(tospec:*)', 'Read', 'Edit(tospec/decisions/**)', 'Grep', 'Glob', 'AskUserQuestion'],
|
|
60
61
|
};
|
|
61
62
|
}
|
|
62
63
|
//# sourceMappingURL=grill.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"grill.js","sourceRoot":"","sources":["../../../../src/core/templates/workflows/grill.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAE9D,MAAM,UAAU,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;EA0BjB,mBAAmB;;;;;;;;;;;0DAWqC,iBAAiB,CAAC,mCAAmC,EAAE,sDAAsD,CAAC;;;;;;oHAMpD,CAAC;AAErH,MAAM,UAAU,qBAAqB;IACnC,OAAO;QACL,IAAI,EAAE,cAAc;QACpB,WAAW,EAAE,mVAAmV;QAChW,YAAY,EAAE;;;;EAIhB,UAAU,EAAE;QACV,OAAO,EAAE,KAAK;QACd,aAAa,EAAE,sBAAsB;QACrC,QAAQ,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE;QAC9B,YAAY,EAAE,CAAC,gBAAgB,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"grill.js","sourceRoot":"","sources":["../../../../src/core/templates/workflows/grill.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAE9D,MAAM,UAAU,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;EA0BjB,mBAAmB;;;;;;;;;;;0DAWqC,iBAAiB,CAAC,mCAAmC,EAAE,sDAAsD,CAAC;;;;;;oHAMpD,CAAC;AAErH,MAAM,UAAU,qBAAqB;IACnC,OAAO;QACL,IAAI,EAAE,cAAc;QACpB,WAAW,EAAE,mVAAmV;QAChW,YAAY,EAAE;;;;EAIhB,UAAU,EAAE;QACV,OAAO,EAAE,KAAK;QACd,aAAa,EAAE,sBAAsB;QACrC,QAAQ,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE;QAC9B,iEAAiE;QACjE,YAAY,EAAE,CAAC,gBAAgB,EAAE,MAAM,EAAE,2BAA2B,EAAE,MAAM,EAAE,MAAM,EAAE,iBAAiB,CAAC;KACzG,CAAC;AACJ,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"issue.d.ts","sourceRoot":"","sources":["../../../../src/core/templates/workflows/issue.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"issue.d.ts","sourceRoot":"","sources":["../../../../src/core/templates/workflows/issue.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAyEjD,wBAAgB,2BAA2B,IAAI,aAAa,CAc3D"}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { VALIDATE_VERDICT_RULE } from '../fragments/validate.js';
|
|
2
2
|
const ISSUE_BODY = `Diagnose before you propose a fix. Jumping to a hypothesis before you can reproduce the bug on command is the exact failure this workflow prevents.
|
|
3
3
|
|
|
4
|
+
**Planning boundary**: The request that triggered this workflow authorizes diagnosis only, even if it asks to fix something. Diagnosis includes the feedback loop's failing test (step 3) and temporary \`[DEBUG-xxxx]\` logging (step 5). Do not edit project code beyond those, and do not start implementation in the same response: present the ticket and \`task.md\`, then wait for a new user request before starting \`tospec-apply\`.
|
|
5
|
+
|
|
6
|
+
**Redact before you paste.** This workflow has you paste commands and their output into \`task.md\`, which is committed and kept in the archive for good. Redact every secret first — tokens, passwords, API keys, cookies, auth headers, connection strings: write \`<REDACTED>\` in its place. Build the feedback loop to read credentials from environment variables, so the secret stays in the environment rather than in what you paste. Quote only the lines that carry the signal (the error, the failing assertion, the relevant stack frames), not whole dumps — but do not redact those lines themselves: a scrubbed error message diagnoses nothing. A step that needs the user's login (an interactive auth, a session in their browser) is theirs to run: ask them to run it and report the result, and do not capture its output. If the redacted output is not enough to diagnose the bug, say so and ask the user.
|
|
7
|
+
|
|
4
8
|
**Steps**
|
|
5
9
|
|
|
6
10
|
1. **Create the change**
|
|
@@ -21,13 +25,13 @@ const ISSUE_BODY = `Diagnose before you propose a fix. Jumping to a hypothesis b
|
|
|
21
25
|
- **Red-capable** — actually drives the bug's code path and catches the user's exact symptom, not "runs without erroring"
|
|
22
26
|
- **Deterministic** — same verdict every run (flaky bugs: raise the reproduction rate until it's debuggable)
|
|
23
27
|
- **Fast** — seconds, not minutes
|
|
24
|
-
- **Already run at least once** — you have pasted its invocation and output before moving on
|
|
28
|
+
- **Already run at least once** — you have pasted its invocation and output (redacted) before moving on
|
|
25
29
|
|
|
26
30
|
Do not skip this to go read code and form a theory. No red-capable command, no hypotheses.
|
|
27
31
|
|
|
28
32
|
4. **Rank falsifiable hypotheses**
|
|
29
33
|
|
|
30
|
-
List as many as the evidence genuinely supports — when the feedback loop already points at one cause, one or two is fine. Each hypothesis must predict something checkable: "if X is the cause, changing Y makes the bug disappear." A hypothesis you can't falsify is a vibe — sharpen it or drop it. Show the ranked list to the user before testing; they often have context that instantly re-ranks it ("we just touched that module").
|
|
34
|
+
List as many as the evidence genuinely supports — when the feedback loop already points at one cause, one or two is fine. Each hypothesis must predict something checkable: "if X is the cause, changing Y makes the bug disappear." A hypothesis you can't falsify is a vibe — sharpen it or drop it. Show the ranked list to the user before testing; they often have context that instantly re-ranks it ("we just touched that module"). Then continue verifying without waiting for a reply: if the user later supplies information that changes the order, re-rank and continue from the new top.
|
|
31
35
|
|
|
32
36
|
5. **Verify hypotheses one at a time**
|
|
33
37
|
|
|
@@ -43,7 +47,7 @@ const ISSUE_BODY = `Diagnose before you propose a fix. Jumping to a hypothesis b
|
|
|
43
47
|
|
|
44
48
|
7. **Delta specs — only if behavior changes**
|
|
45
49
|
|
|
46
|
-
\`specs\` is optional in the issue schema. Only produce it if the fix changes externally observable behavior (leave it unwritten and \`status\` reports it as \`optional\`, not \`blocked\`; \`skipped\` is reserved for an artifact declared away with \`skip_specs: true\`). If the bug is the spec itself being wrong, use MODIFIED to correct the Requirement instead of writing new tests against a wrong spec.
|
|
50
|
+
\`specs\` is optional in the issue schema. Only produce it if the fix changes externally observable behavior (leave it unwritten and \`status\` reports it as \`optional\`, not \`blocked\`; \`skipped\` is reserved for an artifact declared away with \`skip_specs: true\`). If the bug is the spec itself being wrong, use MODIFIED to correct the Requirement instead of writing new tests against a wrong spec. Before writing a delta spec, run \`tospec list --specs --json\` and reuse the existing capability whose area the behavior falls in; create a new one only when the area is genuinely different.
|
|
47
51
|
|
|
48
52
|
8. **Validate and auto-fix**
|
|
49
53
|
\`\`\`bash
|
|
@@ -56,10 +60,12 @@ const ISSUE_BODY = `Diagnose before you propose a fix. Jumping to a hypothesis b
|
|
|
56
60
|
Summarize the confirmed root cause, the fix plan, and prompt: "Run \`tospec-apply\` to fix it."
|
|
57
61
|
|
|
58
62
|
**Guardrails**
|
|
63
|
+
- The request that invoked this workflow authorizes diagnosis only. Any fix instruction in it does not carry forward: don't edit project code beyond the feedback loop's failing test and temporary \`[DEBUG-xxxx]\` logging, and don't start \`tospec-apply\` in the same response — stop after presenting the ticket and \`task.md\` and wait for a new request
|
|
59
64
|
- The ticket file and its timestamp are CLI-generated — never create, rename, or move ticket files; only edit the Summary in the existing stub
|
|
60
65
|
- No hypotheses before a red-capable feedback loop exists
|
|
61
66
|
- Ranked, falsifiable hypotheses — as many as the evidence supports, never an unverified guess
|
|
62
67
|
- Root cause must be verified, not assumed — state how you confirmed it
|
|
68
|
+
- Every secret in pasted commands and output becomes \`<REDACTED>\`; steps that need the user's login are theirs to run, uncaptured
|
|
63
69
|
- Every Test Plan item maps to a task, or the Test Plan says why it needs none
|
|
64
70
|
- Don't write \`specs\` unless the fix actually changes external behavior`;
|
|
65
71
|
export function getTospecIssueSkillTemplate() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"issue.js","sourceRoot":"","sources":["../../../../src/core/templates/workflows/issue.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAEjE,MAAM,UAAU,GAAG
|
|
1
|
+
{"version":3,"file":"issue.js","sourceRoot":"","sources":["../../../../src/core/templates/workflows/issue.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAEjE,MAAM,UAAU,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAsDd,qBAAqB;;;;;;;;;;;;;;0EAcgD,CAAC;AAE3E,MAAM,UAAU,2BAA2B;IACzC,OAAO;QACL,IAAI,EAAE,cAAc;QACpB,WAAW,EAAE,6NAA6N;QAC1O,YAAY,EAAE;;;;EAIhB,UAAU,EAAE;QACV,OAAO,EAAE,KAAK;QACd,aAAa,EAAE,sBAAsB;QACrC,QAAQ,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE;QAC9B,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,iBAAiB,CAAC;KACnF,CAAC;AACJ,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"propose.d.ts","sourceRoot":"","sources":["../../../../src/core/templates/workflows/propose.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"propose.d.ts","sourceRoot":"","sources":["../../../../src/core/templates/workflows/propose.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAiEjD,wBAAgB,6BAA6B,IAAI,aAAa,CAc7D"}
|
|
@@ -25,9 +25,12 @@ const PROPOSE_BODY = `Do NOT re-interview the user — synthesize what's already
|
|
|
25
25
|
\`\`\`bash
|
|
26
26
|
tospec instructions <artifact-id> --change "<name>" --json
|
|
27
27
|
\`\`\`
|
|
28
|
-
Read \`template\` and \`instruction\` from the response, re-read every file listed under \`dependencies\` from disk (even ones you already saw — the user may have edited them since), write \`resolvedOutputPath\`, then re-run \`status --json\` and continue until every \`applyRequires\` artifact is \`done\`.
|
|
28
|
+
Read \`template\` and \`instruction\` from the response, re-read every file listed under \`dependencies\` from disk (even ones you already saw — the user may have edited them since; skip an entry marked \`skipped: true\`, or \`optional: true\` and not \`done\` — it has no file to read), write \`resolvedOutputPath\`, then re-run \`status --json\` and continue until every \`applyRequires\` artifact is \`done\`.
|
|
29
29
|
|
|
30
30
|
**Inspect the relevant implementation before drafting.** "Synthesize the conversation" is not permission to skip the code. Read \`context\` and \`rules\` first, then inspect the implementation this change touches, its nearby tests, its configuration, and its documentation — everything outside \`tospec/\`. Keep the inspection read-only and proportional to the change, and reuse what you find across the later artifacts instead of rediscovering it per artifact.
|
|
31
|
+
- Read \`tospec/decisions/index.md\` if it exists — its rows are what was already decided — and open only the \`accepted\` ADRs that bear on this change. ADRs linked with \`--decisions\` are not the only ones that bind it. If the plan conflicts with an accepted ADR, say so and suggest recording the new decision with \`tospec-decision\` to supersede it; never override it silently.
|
|
32
|
+
- Before filling Capabilities, run \`tospec list --specs --json\`. When this change falls inside an existing capability's area, reuse that capability under Modified Capabilities; create a new one only when the area is genuinely different. A capability named after the change (\`add-login-endpoint\` beside an existing \`auth\`) is written as ADDED, passes validate, and archives into a second, overlapping main spec.
|
|
33
|
+
- A Modified Capability needs a main spec that \`tospec list --specs --json\` lists. When the capability exists only as an ADDED delta in another in-progress change (\`tospec list --json\` lists those changes), tell the user that change must be archived first: archive refuses a MODIFIED, REMOVED or RENAMED aimed at a capability with no main spec. Write the MODIFIED blocks against the main spec that archive produces, not against the other change's delta: archive (and \`tospec-sync\`) can rewrite the requirement, and a block copied from the delta would silently revert that rewrite.
|
|
31
34
|
- Ground scope, approach, and tasks in what you found. Distinguish observed behavior from your assumptions and from what this change proposes to add. If something you find conflicts with an existing spec, surface the conflict — don't silently decide which side is right.
|
|
32
35
|
- Do the discovery **now**. Never leave a generic "explore the codebase" or "understand the current design" task for \`tospec-apply\` — that defers the cheapest work to the most expensive moment. A follow-up investigation task is fine only when it names a specific unresolved question.
|
|
33
36
|
- If the code this plan targets can't be reached, state that limitation in the artifact rather than planning as if you had read it.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"propose.js","sourceRoot":"","sources":["../../../../src/core/templates/workflows/propose.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAEjE,MAAM,YAAY,GAAG
|
|
1
|
+
{"version":3,"file":"propose.js","sourceRoot":"","sources":["../../../../src/core/templates/workflows/propose.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAEjE,MAAM,YAAY,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KA8ChB,qBAAqB;;;;;;;;;;;;;;gIAcsG,CAAC;AAEjI,MAAM,UAAU,6BAA6B;IAC3C,OAAO;QACL,IAAI,EAAE,gBAAgB;QACtB,WAAW,EAAE,kRAAkR;QAC/R,YAAY,EAAE;;;;EAIhB,YAAY,EAAE;QACZ,OAAO,EAAE,KAAK;QACd,aAAa,EAAE,sBAAsB;QACrC,QAAQ,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE;QAC9B,YAAY,EAAE,CAAC,gBAAgB,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,iBAAiB,CAAC;KAC7F,CAAC;AACJ,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../../../src/core/templates/workflows/sync.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../../../src/core/templates/workflows/sync.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AA6FjD,wBAAgB,0BAA0B,IAAI,aAAa,CAc1D"}
|
|
@@ -1,26 +1,37 @@
|
|
|
1
1
|
import { VALIDATE_VERDICT_RULE } from '../fragments/validate.js';
|
|
2
|
+
import { CHANGE_DIFF, GIT_COMMAND_RULE } from '../fragments/change-diff.js';
|
|
3
|
+
import { SYNC_FAIL_WITHOUT_CODE_BUG } from '../fragments/sync-fail.js';
|
|
2
4
|
const SYNC_BODY = `Whether a spec still matches the source code is a semantic judgment no CLI can make — that's why this is agent work, not a \`tospec\` subcommand. The CLI's job is the part that IS machine-checkable: the synced spec must still pass full validation, and \`tospec archive --require-sync\` refuses unless \`sync-report.md\` reports PASS.
|
|
3
5
|
|
|
6
|
+
${GIT_COMMAND_RULE}
|
|
7
|
+
|
|
4
8
|
**Steps**
|
|
5
9
|
|
|
6
10
|
1. **List the Requirements this change touches**
|
|
7
11
|
|
|
8
|
-
For sdd: every Requirement in \`specs/<capability>/spec.md\` under the change directory. For issue: the Requirement(s) referenced in the ticket/\`task.md\`, plus any delta specs the change produced.
|
|
12
|
+
For sdd: every Requirement in \`specs/<capability>/spec.md\` under the change directory. For issue: the Requirement(s) referenced in the ticket/\`task.md\`, plus any delta specs the change produced. Note which delta section each one sits in — ADDED, MODIFIED, REMOVED, or RENAMED — or that it sits in none (a Requirement the ticket/\`task.md\` names that exists only in the main spec), because steps 2 and 4 treat each case by a different rule.
|
|
9
13
|
|
|
10
|
-
**No-delta case**: an issue fix with no behavior change has no delta specs at all. Don't invent Requirements to check —
|
|
14
|
+
**No-delta case**: an issue fix with no behavior change has no delta specs at all, and neither does a change whose \`.tospec.yaml\` sets \`skip_specs: true\`, under any schema: the user decided it needs no delta spec. Either way there is no spec-vs-code drift to find. Don't invent Requirements to check, and don't write a delta spec or remove \`skip_specs\` to give this workflow something to judge — the flag records the user's decision. Instead confirm the tracks file's described work (\`task.md\`'s fix, or \`tasks.md\` for sdd) matches what the code actually does, and note this as the no-delta case in the report (see format below).
|
|
11
15
|
|
|
12
16
|
2. **Judge each Requirement against the actual implementation — writing nothing**
|
|
13
17
|
|
|
14
18
|
Steps 2 and 3 are the judge phase: they produce verdicts only. **Do not edit a spec file yet, however obviously stale it looks.** Record each verdict and move on; step 4 does all the writing, once every Requirement has a verdict.
|
|
15
19
|
|
|
16
|
-
For each Requirement, locate the corresponding code (the files apply touched are a good starting point) and judge
|
|
20
|
+
For each Requirement, locate the corresponding code (the files apply touched are a good starting point) and judge it by the rule for its delta section:
|
|
21
|
+
|
|
22
|
+
- **ADDED / MODIFIED**: does the implemented behavior match what the Requirement's scenarios describe? **Can't find any corresponding implementation at all**: that's a CODE-BUG, same severity as a behavioral mismatch — the Requirement was agreed to and never built. Don't wave it through as MATCH.
|
|
23
|
+
- **REMOVED**: the change agreed to take this behavior *out*, but the delta carries only its name and Reason/Migration notes, not the behavior. Read its block in the main spec (\`tospec/specs/<capability>/spec.md\`, under the same name) first, and search the code for the behavior that block's body and scenarios describe — never for the name alone, or code worded differently from the name reads as already gone. If the main spec no longer has the block (another change, or an earlier archive run, already removed it), recover it from that file's history: \`git log -p -- tospec/specs/<capability>/spec.md\`, run from the project root — git prints nothing for a path it does not match, so empty output is not proof the history is empty. In a project that is not a git repository (git answers \`not a git repository\`) there is no history to read: recover the behavior from this change's own delta entry (its Reason and Migration notes) and from earlier deltas under \`tospec/changes/archive/\` (\`<stamp>-<other-change>/specs/<capability>/spec.md\`) that ADDED or MODIFIED a Requirement of that name — the newest stamp's block is the last behavior agreed — and name the source you used in the entry's Notes. Finding no implementation is the correct result — MATCH. It is a CODE-BUG only when the behavior is **still there**. Never treat a missing implementation here as "never built": that verdict sends \`tospec-apply\` to put back the behavior the change just removed.
|
|
17
24
|
|
|
18
|
-
|
|
25
|
+
**No block in either place** (and, outside git, no behavior in the delta or the archive either): there is nothing to search for, so the Requirement is unjudged, not MATCH: record its verdict as \`UNJUDGED\`. That entry alone keeps the conclusion from PASS (step 5). \`tospec validate\` warns about the same entry, so this is an artifact problem, usually a misspelled name, not a CODE-BUG.
|
|
26
|
+
- **RENAMED**: a FROM/TO pair carries no behavior of its own. Judge the Requirement under its **TO** name, against the behavior in the main spec (\`tospec/specs/<capability>/spec.md\`, where it still sits under the FROM name) — or against this delta's MODIFIED block for the TO name, when it has one. Read both sources before you judge; the delta alone says nothing about what the code must do.
|
|
27
|
+
- **No delta section** (referenced from the ticket/\`task.md\`, present only in the main spec): judge it by the ADDED / MODIFIED rule, against its block in \`tospec/specs/<capability>/spec.md\`.
|
|
19
28
|
|
|
20
29
|
3. **Sweep the other direction — behavior nobody asked for**
|
|
21
30
|
|
|
22
31
|
Step 2 walks Requirements to code, so it can only find what is *missing*. It cannot see the opposite: behavior in the diff that **maps to no Requirement** at all. Walk the change's diff once and flag anything the specs never asked for.
|
|
23
32
|
|
|
33
|
+
${CHANGE_DIFF} In \`sync-report.md\` that record is the \`Diff scope:\` line (step 5).
|
|
34
|
+
|
|
24
35
|
**Report it, never spec it.** "Code wins" settles how a Requirement is *worded*, not whether behavior *belongs* — it is not a licence to make unrequested work look agreed after the fact. Never add a Requirement to cover scope creep: tell the user what you found and let them decide to keep it, drop it, or plan it properly.
|
|
25
36
|
|
|
26
37
|
4. **Write the resolutions — code wins**
|
|
@@ -29,14 +40,14 @@ const SYNC_BODY = `Whether a spec still matches the source code is a semantic ju
|
|
|
29
40
|
|
|
30
41
|
- **Any CODE-BUG** (the code doesn't do what was agreed in ticket/design, or was never built): **stop before writing anything.** Do not touch the spec to paper over a bug, and do not write the SPEC-UPDATED entries you already judged — they keep until the defect is resolved. Report the mismatch and go to step 5 with \`Conclusion: FAIL\`.
|
|
31
42
|
|
|
32
|
-
**Resuming after the defect is fixed** (this
|
|
33
|
-
- **No CODE-BUG**: work the SPEC-UPDATED verdicts one at a time. For each,
|
|
43
|
+
**Resuming after the defect is fixed** (the user fixed it while this sync was still open and asked to carry on; a \`tospec-archive\` rerun after a fix starts a fresh sync instead): come back to *this step*, not to step 1. Re-judge only the Requirements that were CODE-BUG; every other verdict still stands. Once none of them is a defect any more, fall through to the bullet below and write **every** SPEC-UPDATED verdict — the ones held back here included, or their staleness ships into \`tospec/specs/\` on archive. Then rewrite \`sync-report.md\` (step 5) with the new conclusion; a report left at FAIL blocks the archive gate.
|
|
44
|
+
- **No CODE-BUG**: work the SPEC-UPDATED verdicts one at a time. For each, rewrite the Requirement **in place, in the section it already sits in** (ADDED or MODIFIED), pasting the complete, corrected Requirement block. Never move an ADDED Requirement to MODIFIED: MODIFIED targets a Requirement the main spec already has, so for a new Requirement — or a whole new capability — archive finds nothing to modify and fails with \`archive_spec_update_failed\`. A RENAMED Requirement whose behavior drifted gets a MODIFIED block under its TO name. A Requirement with no delta section has no place to rewrite in place: give it a new MODIFIED block in this change's \`specs/<capability>/spec.md\`, restating the complete corrected block — here MODIFIED is correct, because the main spec already has the target. Then:
|
|
34
45
|
\`\`\`bash
|
|
35
46
|
tospec validate "<name>" --json
|
|
36
47
|
\`\`\`
|
|
37
48
|
Must pass before writing the next one — one write, one validate, so a failure names the Requirement that caused it instead of leaving you to bisect a bulk edit. Record the validate result in that Requirement's report entry.
|
|
38
49
|
|
|
39
|
-
**If that validate fails**, the
|
|
50
|
+
**If that validate fails**, the Requirement block you just rewrote is malformed — an artifact problem, not a code defect. Fix that block and re-run \`tospec validate\` until it passes, then carry on with the remaining verdicts. Only if you cannot make it pass do you stop and report \`Conclusion: FAIL\`, naming the Requirement; that FAIL is not a CODE-BUG and archive handles it as an artifact fix, not a return to \`tospec-apply\`.
|
|
40
51
|
|
|
41
52
|
5. **Write the sync report**
|
|
42
53
|
|
|
@@ -46,14 +57,15 @@ const SYNC_BODY = `Whether a spec still matches the source code is a semantic ju
|
|
|
46
57
|
# Sync Report: <change-name>
|
|
47
58
|
## Summary
|
|
48
59
|
Conclusion: <PASS or FAIL>
|
|
60
|
+
Diff scope: git diff <base> | fallback (not a git repository): <files read>
|
|
49
61
|
## Requirements
|
|
50
62
|
### <Requirement name>
|
|
51
63
|
- Implementation: <module/function description, not a hard path>
|
|
52
|
-
- Verdict: MATCH | SPEC-UPDATED (updated to match code) | CODE-BUG (stops archiving)
|
|
64
|
+
- Verdict: MATCH | SPEC-UPDATED (updated to match code) | CODE-BUG (stops archiving) | UNJUDGED (REMOVED with no block to read)
|
|
53
65
|
- Notes: <the difference and how it was handled; SPEC-UPDATED must include the validate result>
|
|
54
66
|
\`\`\`
|
|
55
67
|
|
|
56
|
-
Write exactly one real \`Conclusion:\` line, carrying one literal — \`Conclusion: PASS\` or \`Conclusion: FAIL\` (FAIL may append a \`(reason)\` note). Both options left in one line, or two lines that disagree, parse as no verdict at all and shut the gate. It is **FAIL** if even one Requirement is CODE-BUG — a single unresolved defect blocks the whole change, not just that Requirement. It's **PASS** only when every Requirement resolved to MATCH or SPEC-UPDATED (with validate passing). For the no-delta case, still emit the Summary and a single Requirements entry describing the
|
|
68
|
+
Write exactly one real \`Conclusion:\` line, carrying one literal — \`Conclusion: PASS\` or \`Conclusion: FAIL\` (FAIL may append a \`(reason)\` note). Both options left in one line, or two lines that disagree, parse as no verdict at all and shut the gate. It is **FAIL** if even one Requirement is CODE-BUG — a single unresolved defect blocks the whole change, not just that Requirement. It's **PASS** only when every Requirement resolved to MATCH or SPEC-UPDATED (with validate passing), so an UNJUDGED entry alone makes it FAIL, though it is not a CODE-BUG. The \`Diff scope:\` line records what step 3 swept: the \`<base>\` it diffed against, or, in a project that is not a git repository, \`fallback (not a git repository)\` and the files the fallback scope covered. For the no-delta case, still emit the Summary and a single Requirements entry describing the tracks-file-vs-code comparison (\`task.md\` or \`tasks.md\`; module described, not a Requirement name).
|
|
57
69
|
|
|
58
70
|
6. **Final artifact validation**
|
|
59
71
|
\`\`\`bash
|
|
@@ -65,13 +77,15 @@ const SYNC_BODY = `Whether a spec still matches the source code is a semantic ju
|
|
|
65
77
|
|
|
66
78
|
Summarize how many Requirements matched, how many specs were updated, whether anything was flagged as a code defect, and anything found that no Requirement asked for.
|
|
67
79
|
|
|
68
|
-
Where that summary goes depends on who called you. **Run from \`tospec-archive\`** (the usual case): hand the summary straight back — archive continues on \`Conclusion: PASS\`, passing \`--require-sync\` for free, and on \`Conclusion: FAIL\` archive owns the single question about fixing the
|
|
80
|
+
Where that summary goes depends on who called you. **Run from \`tospec-archive\`** (the usual case): hand the summary straight back — archive continues on \`Conclusion: PASS\`, passing \`--require-sync\` for free, and on \`Conclusion: FAIL\` archive owns what comes next: the single question about fixing a CODE-BUG, or the artifact fix when there is none. Do not prompt for archiving yourself; you are already inside it. **Run standalone**: on \`Conclusion: PASS\` prompt "Run \`tospec-archive\` to finish up", and on \`Conclusion: FAIL\` with a CODE-BUG prompt to return to \`tospec-apply\` first. On \`Conclusion: FAIL\` with no CODE-BUG, name the artifact to fix instead of sending the user to \`tospec-apply\` — no code needs to change. Such a FAIL means ${SYNC_FAIL_WITHOUT_CODE_BUG}
|
|
69
81
|
|
|
70
82
|
**Guardrails**
|
|
71
83
|
- Code is the source of truth for behavior — spec updates always follow code, never the other way around
|
|
72
84
|
- Scope creep is reported, never specced — "code wins" settles a Requirement's wording, never whether unrequested behavior belongs
|
|
73
85
|
- Never edit source code from this workflow — a code-side mismatch is diagnosis, not a license to patch here
|
|
74
|
-
- Judge every Requirement before writing any spec update; inside the write phase, every
|
|
86
|
+
- Judge every Requirement before writing any spec update; inside the write phase, every rewritten Requirement must re-pass \`tospec validate\` before writing the next one
|
|
87
|
+
- A rewrite stays in the Requirement's own section — ADDED stays ADDED; moving it to MODIFIED fails the archive. Only a RENAMED Requirement, under its TO name, and a Requirement with no delta section get a new MODIFIED block
|
|
88
|
+
- A REMOVED Requirement is judged by the behavior its main-spec block describes, never by its name: no implementation of that behavior is MATCH, not CODE-BUG — only behavior that is still there is a defect, and with no block to read it is UNJUDGED, never MATCH
|
|
75
89
|
- \`sync-report.md\` is required output, in the exact format above — \`tospec archive --require-sync\` depends on both its existence and its \`Conclusion:\` line
|
|
76
90
|
- One comparison pass per Requirement — check it against the code once and record the verdict. \`sync-report.md\` is the deliverable, not another review target: don't re-audit the report after writing it, and don't re-check a Requirement already judged MATCH`;
|
|
77
91
|
export function getTospecSyncSkillTemplate() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sync.js","sourceRoot":"","sources":["../../../../src/core/templates/workflows/sync.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"sync.js","sourceRoot":"","sources":["../../../../src/core/templates/workflows/sync.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAC5E,OAAO,EAAE,0BAA0B,EAAE,MAAM,2BAA2B,CAAC;AAEvE,MAAM,SAAS,GAAG;;EAEhB,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;KA2Bb,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;yFAyCyE,qBAAqB;;;;;;0vBAM4oB,0BAA0B;;;;;;;;;;mQAUjhB,CAAC;AAEpQ,MAAM,UAAU,0BAA0B;IACxC,OAAO;QACL,IAAI,EAAE,aAAa;QACnB,WAAW,EAAE,mMAAmM;QAChN,YAAY,EAAE;;;;EAIhB,SAAS,EAAE;QACT,OAAO,EAAE,KAAK;QACd,aAAa,EAAE,sBAAsB;QACrC,QAAQ,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE;QAC9B,YAAY,EAAE,CAAC,gBAAgB,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;KAC1E,CAAC;AACJ,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../../../src/core/templates/workflows/update.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../../../src/core/templates/workflows/update.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AA8EjD,wBAAgB,4BAA4B,IAAI,aAAa,CAc5D"}
|
|
@@ -15,6 +15,7 @@ const UPDATE_BODY = `**Steps**
|
|
|
15
15
|
- \`artifacts\`: Array of artifacts with their status — "done", "stub" (the file exists but is still the unfilled template), "ready", "blocked", "optional" (the schema allows omitting it and nothing was written), "skipped" (declared away with \`skip_specs: true\`)
|
|
16
16
|
- \`isComplete\`: Boolean indicating if all required artifacts are complete
|
|
17
17
|
- \`planningHome\`, \`changeRoot\`, \`artifactPaths\`, and \`actionContext\`: path and scope context. Use these instead of assuming repo-local paths.
|
|
18
|
+
- \`changeMetadata.decisions\`: the ADR filenames linked to this change (from \`.tospec.yaml\`). A decision handed over from \`tospec-decision\` or \`tospec-grill\` is normally listed already, because it was created with \`tospec decision new --change\`. If a handed-over filename is missing, adding it to \`decisions:\` is a step-5 revision like any other: propose it, and after writing it, step 6's validate checks the name.
|
|
18
19
|
|
|
19
20
|
The artifact ids and paths come from the active schema — never assume them, and never branch on hardcoded artifact names. Custom schemas must work unchanged.
|
|
20
21
|
|
|
@@ -24,21 +25,27 @@ const UPDATE_BODY = `**Steps**
|
|
|
24
25
|
- If the user asked for a specific revision ("the design now uses X"), that is the starting edit.
|
|
25
26
|
- If they only said "update" / "make this coherent", treat it as a coherence review: read the existing artifacts once and check them against each other for contradictions, gaps, and duplication. This is a single read-through, not a recursive audit — don't re-review your own reconciliation after making it.
|
|
26
27
|
|
|
27
|
-
4. **Read and reconcile**
|
|
28
|
+
4. **Read and reconcile — draft only, write nothing**
|
|
29
|
+
|
|
30
|
+
This step produces drafts in the conversation. **Do not write or edit any file here**; every write happens in step 5, after the user confirms it.
|
|
28
31
|
- Read the artifact(s) the request touches and the change's other existing artifacts.
|
|
29
|
-
-
|
|
32
|
+
- Draft the requested edit. Then check every other existing artifact against it — in ANY direction: an edit to a later artifact may require revising an earlier one, not only the other way around. Build order is a useful reading order, not a constraint on which artifacts may be revised.
|
|
30
33
|
- Note everything that is now inconsistent, missing, or contradictory.
|
|
31
|
-
-
|
|
34
|
+
- Propose revisions only to files that already exist (\`existingOutputPaths\`). Creating an artifact that doesn't exist yet is \`tospec-propose\`/\`tospec-issue\`'s job — note what's missing and point the user there.
|
|
35
|
+
- One exception: a missing file under a glob artifact that is already \`done\` — e.g. a second capability's \`specs/<capability>/spec.md\` when the change already has one. Propose builds only \`ready\` artifacts and never returns to a \`done\` one, so no other workflow can create it. Draft the new file here, at a concrete path (the glob with each \`*\` filled in), and create it in step 5.
|
|
32
36
|
- If the change is already coherent, say so and make no edits.
|
|
33
37
|
|
|
34
|
-
5. **Confirm and
|
|
35
|
-
|
|
38
|
+
5. **Confirm and write, one artifact at a time**
|
|
39
|
+
|
|
40
|
+
This is the only step that writes files.
|
|
41
|
+
- Show each drafted revision and why. Write it only after the user confirms.
|
|
36
42
|
- If the user rejects a revision, leave that artifact unchanged.
|
|
37
43
|
- When a substantial rewrite is needed, get that artifact's rules and template first:
|
|
38
44
|
\`\`\`bash
|
|
39
45
|
tospec instructions <artifact-id> --change "<name>" --json
|
|
40
46
|
\`\`\`
|
|
41
47
|
Read \`rules\` and \`template\` from the response.
|
|
48
|
+
- When the confirmed revision is a **new file under a done glob artifact**, run that same \`tospec instructions\` call first, and write the file from its \`template\` and \`instruction\`. Create it exclusively: check that the concrete path does not exist immediately before writing, and never overwrite an existing file — a file already there is a revision, and needs its own confirmation.
|
|
42
49
|
|
|
43
50
|
6. **Validate what you wrote**
|
|
44
51
|
\`\`\`bash
|
|
@@ -55,16 +62,16 @@ const UPDATE_BODY = `**Steps**
|
|
|
55
62
|
**Output**
|
|
56
63
|
|
|
57
64
|
After each invocation, show:
|
|
58
|
-
- Which artifacts were revised (and which proposed revisions were rejected)
|
|
59
|
-
- Anything deferred to artifact creation (not-yet-created artifacts
|
|
65
|
+
- Which artifacts were revised, which new files were created under a done glob artifact (and which proposed revisions were rejected)
|
|
66
|
+
- Anything deferred to artifact creation (not-yet-created artifacts → \`tospec-propose\`/\`tospec-issue\`)
|
|
60
67
|
- Where the change stands and the recommended next command
|
|
61
68
|
|
|
62
69
|
**Guardrails**
|
|
63
70
|
- Planning artifacts only — leave implementation code untouched. If the revised plan implies code changes, stop and point to \`tospec-apply\`.
|
|
64
71
|
- Use the artifact ids and paths reported by \`tospec status\`; never branch on hardcoded artifact names.
|
|
65
|
-
- Edit only the concrete files in \`existingOutputPaths
|
|
66
|
-
- Stay behind the build frontier: revise what exists
|
|
67
|
-
- Confirm every edit with the user before writing.
|
|
72
|
+
- Edit only the concrete files in \`existingOutputPaths\`, or create a confirmed new concrete file under a done glob artifact without overwriting anything; never write to a glob \`resolvedOutputPath\`. The one other edit is adding a confirmed ADR filename to \`.tospec.yaml\`'s \`decisions:\` list.
|
|
73
|
+
- Stay behind the build frontier: revise what exists and add files to glob artifacts that are already done; leave artifacts not yet started to \`tospec-propose\`/\`tospec-issue\`.
|
|
74
|
+
- Confirm every edit with the user before writing. Steps 1-4 write nothing; all writes happen in step 5.
|
|
68
75
|
- If the request changes the change's *intent* rather than refining it, recommend starting fresh with \`tospec-propose\`/\`tospec-issue\` (the "Update vs. Start Fresh" heuristic).`;
|
|
69
76
|
export function getTospecUpdateSkillTemplate() {
|
|
70
77
|
return {
|