@rpamis/comet 0.3.9 → 0.4.0-beta.1
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/LICENSE +21 -21
- package/README.md +371 -222
- package/assets/manifest.json +33 -12
- package/assets/skills/comet/SKILL.md +87 -102
- package/assets/skills/comet/reference/auto-transition.md +1 -1
- package/assets/skills/comet/reference/comet-yaml-fields.md +11 -4
- package/assets/skills/comet/reference/context-recovery.md +12 -2
- package/assets/skills/comet/reference/debug-gate.md +17 -1
- package/assets/skills/comet/reference/decision-point.md +13 -2
- package/assets/skills/comet/reference/intent-frame.md +74 -0
- package/assets/skills/comet/reference/scripts.md +69 -0
- package/assets/skills/comet/reference/subagent-dispatch.md +79 -23
- package/assets/skills/comet/rules/comet-phase-guard.en.md +18 -10
- package/assets/skills/comet/rules/comet-phase-guard.md +17 -10
- package/assets/skills/comet/runtime/classic/checks.yaml +6 -0
- package/assets/skills/comet/runtime/classic/guardrails.yaml +13 -0
- package/assets/skills/comet/runtime/classic/skill.yaml +122 -0
- package/assets/skills/comet/scripts/comet-archive.mjs +3 -0
- package/assets/skills/comet/scripts/comet-env.mjs +15 -0
- package/assets/skills/comet/scripts/comet-guard.mjs +3 -0
- package/assets/skills/comet/scripts/comet-handoff.mjs +3 -0
- package/assets/skills/comet/scripts/comet-hook-guard.mjs +3 -0
- package/assets/skills/comet/scripts/comet-intent.mjs +3 -0
- package/assets/skills/comet/scripts/comet-runtime.mjs +12857 -0
- package/assets/skills/comet/scripts/comet-state.mjs +3 -0
- package/assets/skills/comet/scripts/comet-yaml-validate.mjs +3 -0
- package/assets/skills/comet-any/SKILL.md +118 -0
- package/assets/skills/comet-any/reference/authored-zone-example.md +100 -0
- package/assets/skills/comet-any/reference/authoring-protocol.json +91 -0
- package/assets/skills/comet-any/reference/authoring-subagents.md +102 -0
- package/assets/skills/comet-any/reference/bundle-authoring.md +166 -0
- package/assets/skills/comet-any/reference/eval-provider.md +83 -0
- package/assets/skills/comet-any/reference/subagents/pause-points-author.md +75 -0
- package/assets/skills/comet-any/reference/subagents/reference-author.md +77 -0
- package/assets/skills/comet-any/reference/subagents/script-author.md +81 -0
- package/assets/skills/comet-any/reference/subagents/skill-core-author.md +129 -0
- package/assets/skills/comet-any/reference/subagents/skill-reviewer.md +124 -0
- package/assets/skills/comet-any/reference/subagents/workflow-entry-author.md +100 -0
- package/assets/skills/comet-archive/SKILL.md +25 -15
- package/assets/skills/comet-build/SKILL.md +51 -40
- package/assets/skills/comet-design/SKILL.md +14 -18
- package/assets/skills/comet-hotfix/SKILL.md +33 -43
- package/assets/skills/comet-open/SKILL.md +10 -20
- package/assets/skills/comet-tweak/SKILL.md +71 -65
- package/assets/skills/comet-verify/SKILL.md +31 -35
- package/assets/skills-zh/comet/SKILL.md +87 -101
- package/assets/skills-zh/comet/reference/auto-transition.md +3 -3
- package/assets/skills-zh/comet/reference/comet-yaml-fields.md +8 -4
- package/assets/skills-zh/comet/reference/context-recovery.md +11 -1
- package/assets/skills-zh/comet/reference/debug-gate.md +17 -1
- package/assets/skills-zh/comet/reference/decision-point.md +13 -2
- package/assets/skills-zh/comet/reference/intent-frame.md +74 -0
- package/assets/skills-zh/comet/reference/scripts.md +69 -0
- package/assets/skills-zh/comet/reference/subagent-dispatch.md +67 -18
- package/assets/skills-zh/comet/runtime/classic/checks.yaml +6 -0
- package/assets/skills-zh/comet/runtime/classic/guardrails.yaml +13 -0
- package/assets/skills-zh/comet/runtime/classic/skill.yaml +122 -0
- package/assets/skills-zh/comet-any/SKILL.md +118 -0
- package/assets/skills-zh/comet-any/reference/authored-zone-example.md +100 -0
- package/assets/skills-zh/comet-any/reference/authoring-protocol.json +91 -0
- package/assets/skills-zh/comet-any/reference/authoring-subagents.md +107 -0
- package/assets/skills-zh/comet-any/reference/bundle-authoring.md +166 -0
- package/assets/skills-zh/comet-any/reference/eval-provider.md +66 -0
- package/assets/skills-zh/comet-any/reference/subagents/pause-points-author.md +79 -0
- package/assets/skills-zh/comet-any/reference/subagents/reference-author.md +81 -0
- package/assets/skills-zh/comet-any/reference/subagents/script-author.md +84 -0
- package/assets/skills-zh/comet-any/reference/subagents/skill-core-author.md +129 -0
- package/assets/skills-zh/comet-any/reference/subagents/skill-reviewer.md +124 -0
- package/assets/skills-zh/comet-any/reference/subagents/workflow-entry-author.md +98 -0
- package/assets/skills-zh/comet-archive/SKILL.md +25 -15
- package/assets/skills-zh/comet-build/SKILL.md +41 -43
- package/assets/skills-zh/comet-design/SKILL.md +14 -18
- package/assets/skills-zh/comet-hotfix/SKILL.md +37 -47
- package/assets/skills-zh/comet-open/SKILL.md +12 -22
- package/assets/skills-zh/comet-tweak/SKILL.md +70 -63
- package/assets/skills-zh/comet-verify/SKILL.md +28 -30
- package/bin/comet.js +1 -1
- package/dist/{cli → app/cli}/index.d.ts.map +1 -1
- package/dist/app/cli/index.js +430 -0
- package/dist/app/cli/index.js.map +1 -0
- package/dist/app/commands/bundle.d.ts +51 -0
- package/dist/app/commands/bundle.d.ts.map +1 -0
- package/dist/app/commands/bundle.js +387 -0
- package/dist/app/commands/bundle.js.map +1 -0
- package/dist/app/commands/creator.d.ts +14 -0
- package/dist/app/commands/creator.d.ts.map +1 -0
- package/dist/app/commands/creator.js +82 -0
- package/dist/app/commands/creator.js.map +1 -0
- package/dist/app/commands/dashboard.d.ts +16 -0
- package/dist/app/commands/dashboard.d.ts.map +1 -0
- package/dist/app/commands/dashboard.js +53 -0
- package/dist/app/commands/dashboard.js.map +1 -0
- package/dist/{commands → app/commands}/doctor.d.ts +1 -1
- package/dist/app/commands/doctor.d.ts.map +1 -0
- package/dist/{commands → app/commands}/doctor.js +110 -60
- package/dist/app/commands/doctor.js.map +1 -0
- package/dist/app/commands/eval.d.ts +17 -0
- package/dist/app/commands/eval.d.ts.map +1 -0
- package/dist/app/commands/eval.js +169 -0
- package/dist/app/commands/eval.js.map +1 -0
- package/dist/app/commands/i18n.d.ts +4 -0
- package/dist/app/commands/i18n.d.ts.map +1 -0
- package/dist/{commands → app/commands}/i18n.js +22 -2
- package/dist/app/commands/i18n.js.map +1 -0
- package/dist/{commands → app/commands}/init.d.ts +3 -1
- package/dist/app/commands/init.d.ts.map +1 -0
- package/dist/{commands → app/commands}/init.js +81 -31
- package/dist/app/commands/init.js.map +1 -0
- package/dist/app/commands/platform-select-prompt.d.ts +38 -0
- package/dist/app/commands/platform-select-prompt.d.ts.map +1 -0
- package/dist/app/commands/platform-select-prompt.js +141 -0
- package/dist/app/commands/platform-select-prompt.js.map +1 -0
- package/dist/app/commands/publish.d.ts +7 -0
- package/dist/app/commands/publish.d.ts.map +1 -0
- package/dist/app/commands/publish.js +14 -0
- package/dist/app/commands/publish.js.map +1 -0
- package/dist/app/commands/skill.d.ts +23 -0
- package/dist/app/commands/skill.d.ts.map +1 -0
- package/dist/app/commands/skill.js +208 -0
- package/dist/app/commands/skill.js.map +1 -0
- package/dist/app/commands/status.d.ts.map +1 -0
- package/dist/app/commands/status.js +159 -0
- package/dist/app/commands/status.js.map +1 -0
- package/dist/{commands → app/commands}/uninstall.d.ts +1 -1
- package/dist/app/commands/uninstall.d.ts.map +1 -0
- package/dist/{commands → app/commands}/uninstall.js +3 -3
- package/dist/app/commands/uninstall.js.map +1 -0
- package/dist/{commands → app/commands}/update.d.ts +4 -3
- package/dist/app/commands/update.d.ts.map +1 -0
- package/dist/{commands → app/commands}/update.js +33 -10
- package/dist/app/commands/update.js.map +1 -0
- package/dist/config/repository-layout.json +98 -0
- package/dist/domains/bundle/authoring.d.ts +82 -0
- package/dist/domains/bundle/authoring.d.ts.map +1 -0
- package/dist/domains/bundle/authoring.js +185 -0
- package/dist/domains/bundle/authoring.js.map +1 -0
- package/dist/domains/bundle/bundle-platform.d.ts +39 -0
- package/dist/domains/bundle/bundle-platform.d.ts.map +1 -0
- package/dist/domains/bundle/bundle-platform.js +287 -0
- package/dist/domains/bundle/bundle-platform.js.map +1 -0
- package/dist/domains/bundle/candidates.d.ts +29 -0
- package/dist/domains/bundle/candidates.d.ts.map +1 -0
- package/dist/domains/bundle/candidates.js +37 -0
- package/dist/domains/bundle/candidates.js.map +1 -0
- package/dist/domains/bundle/compatibility-benchmark.d.ts +12 -0
- package/dist/domains/bundle/compatibility-benchmark.d.ts.map +1 -0
- package/dist/domains/bundle/compatibility-benchmark.js +224 -0
- package/dist/domains/bundle/compatibility-benchmark.js.map +1 -0
- package/dist/domains/bundle/compiler.d.ts +5 -0
- package/dist/domains/bundle/compiler.d.ts.map +1 -0
- package/dist/domains/bundle/compiler.js +106 -0
- package/dist/domains/bundle/compiler.js.map +1 -0
- package/dist/domains/bundle/distribute.d.ts +33 -0
- package/dist/domains/bundle/distribute.d.ts.map +1 -0
- package/dist/domains/bundle/distribute.js +166 -0
- package/dist/domains/bundle/distribute.js.map +1 -0
- package/dist/domains/bundle/draft.d.ts +19 -0
- package/dist/domains/bundle/draft.d.ts.map +1 -0
- package/dist/domains/bundle/draft.js +82 -0
- package/dist/domains/bundle/draft.js.map +1 -0
- package/dist/domains/bundle/eval.d.ts +36 -0
- package/dist/domains/bundle/eval.d.ts.map +1 -0
- package/dist/domains/bundle/eval.js +501 -0
- package/dist/domains/bundle/eval.js.map +1 -0
- package/dist/domains/bundle/factory-compose.d.ts +12 -0
- package/dist/domains/bundle/factory-compose.d.ts.map +1 -0
- package/dist/domains/bundle/factory-compose.js +309 -0
- package/dist/domains/bundle/factory-compose.js.map +1 -0
- package/dist/domains/bundle/factory-guide.d.ts +37 -0
- package/dist/domains/bundle/factory-guide.d.ts.map +1 -0
- package/dist/domains/bundle/factory-guide.js +96 -0
- package/dist/domains/bundle/factory-guide.js.map +1 -0
- package/dist/domains/bundle/factory-plan.d.ts +48 -0
- package/dist/domains/bundle/factory-plan.d.ts.map +1 -0
- package/dist/domains/bundle/factory-plan.js +172 -0
- package/dist/domains/bundle/factory-plan.js.map +1 -0
- package/dist/domains/bundle/factory-proposal.d.ts +31 -0
- package/dist/domains/bundle/factory-proposal.d.ts.map +1 -0
- package/dist/domains/bundle/factory-proposal.js +225 -0
- package/dist/domains/bundle/factory-proposal.js.map +1 -0
- package/dist/domains/bundle/factory-resolve.d.ts +11 -0
- package/dist/domains/bundle/factory-resolve.d.ts.map +1 -0
- package/dist/domains/bundle/factory-resolve.js +121 -0
- package/dist/domains/bundle/factory-resolve.js.map +1 -0
- package/dist/domains/bundle/factory.d.ts +17 -0
- package/dist/domains/bundle/factory.d.ts.map +1 -0
- package/dist/domains/bundle/factory.js +511 -0
- package/dist/domains/bundle/factory.js.map +1 -0
- package/dist/domains/bundle/hash.d.ts +3 -0
- package/dist/domains/bundle/hash.d.ts.map +1 -0
- package/dist/domains/bundle/hash.js +72 -0
- package/dist/domains/bundle/hash.js.map +1 -0
- package/dist/domains/bundle/load.d.ts +4 -0
- package/dist/domains/bundle/load.d.ts.map +1 -0
- package/dist/domains/bundle/load.js +355 -0
- package/dist/domains/bundle/load.js.map +1 -0
- package/dist/domains/bundle/next-action.d.ts +37 -0
- package/dist/domains/bundle/next-action.d.ts.map +1 -0
- package/dist/domains/bundle/next-action.js +185 -0
- package/dist/domains/bundle/next-action.js.map +1 -0
- package/dist/domains/bundle/platform.d.ts +21 -0
- package/dist/domains/bundle/platform.d.ts.map +1 -0
- package/dist/domains/bundle/platform.js +170 -0
- package/dist/domains/bundle/platform.js.map +1 -0
- package/dist/domains/bundle/preferences.d.ts +11 -0
- package/dist/domains/bundle/preferences.d.ts.map +1 -0
- package/dist/domains/bundle/preferences.js +17 -0
- package/dist/domains/bundle/preferences.js.map +1 -0
- package/dist/domains/bundle/publish.d.ts +14 -0
- package/dist/domains/bundle/publish.d.ts.map +1 -0
- package/dist/domains/bundle/publish.js +159 -0
- package/dist/domains/bundle/publish.js.map +1 -0
- package/dist/domains/bundle/readiness-user-summary.d.ts +25 -0
- package/dist/domains/bundle/readiness-user-summary.d.ts.map +1 -0
- package/dist/domains/bundle/readiness-user-summary.js +186 -0
- package/dist/domains/bundle/readiness-user-summary.js.map +1 -0
- package/dist/domains/bundle/review-summary.d.ts +36 -0
- package/dist/domains/bundle/review-summary.d.ts.map +1 -0
- package/dist/domains/bundle/review-summary.js +348 -0
- package/dist/domains/bundle/review-summary.js.map +1 -0
- package/dist/domains/bundle/state.d.ts +7 -0
- package/dist/domains/bundle/state.d.ts.map +1 -0
- package/dist/domains/bundle/state.js +132 -0
- package/dist/domains/bundle/state.js.map +1 -0
- package/dist/domains/bundle/types.d.ts +347 -0
- package/dist/domains/bundle/types.d.ts.map +1 -0
- package/dist/domains/bundle/types.js.map +1 -0
- package/dist/domains/bundle/user-facing.d.ts +48 -0
- package/dist/domains/bundle/user-facing.d.ts.map +1 -0
- package/dist/domains/bundle/user-facing.js +73 -0
- package/dist/domains/bundle/user-facing.js.map +1 -0
- package/dist/domains/bundle/validate.d.ts +5 -0
- package/dist/domains/bundle/validate.d.ts.map +1 -0
- package/dist/domains/bundle/validate.js +292 -0
- package/dist/domains/bundle/validate.js.map +1 -0
- package/dist/domains/comet-classic/classic-archive-entry.d.ts +2 -0
- package/dist/domains/comet-classic/classic-archive-entry.d.ts.map +1 -0
- package/dist/domains/comet-classic/classic-archive-entry.js +4 -0
- package/dist/domains/comet-classic/classic-archive-entry.js.map +1 -0
- package/dist/domains/comet-classic/classic-archive.d.ts +3 -0
- package/dist/domains/comet-classic/classic-archive.d.ts.map +1 -0
- package/dist/domains/comet-classic/classic-archive.js +392 -0
- package/dist/domains/comet-classic/classic-archive.js.map +1 -0
- package/dist/domains/comet-classic/classic-cli.d.ts +15 -0
- package/dist/domains/comet-classic/classic-cli.d.ts.map +1 -0
- package/dist/domains/comet-classic/classic-cli.js +94 -0
- package/dist/domains/comet-classic/classic-cli.js.map +1 -0
- package/dist/domains/comet-classic/classic-diagnostics.d.ts +16 -0
- package/dist/domains/comet-classic/classic-diagnostics.d.ts.map +1 -0
- package/dist/domains/comet-classic/classic-diagnostics.js +57 -0
- package/dist/domains/comet-classic/classic-diagnostics.js.map +1 -0
- package/dist/domains/comet-classic/classic-evidence.d.ts +10 -0
- package/dist/domains/comet-classic/classic-evidence.d.ts.map +1 -0
- package/dist/domains/comet-classic/classic-evidence.js +114 -0
- package/dist/domains/comet-classic/classic-evidence.js.map +1 -0
- package/dist/domains/comet-classic/classic-guard-entry.d.ts +2 -0
- package/dist/domains/comet-classic/classic-guard-entry.d.ts.map +1 -0
- package/dist/domains/comet-classic/classic-guard-entry.js +4 -0
- package/dist/domains/comet-classic/classic-guard-entry.js.map +1 -0
- package/dist/domains/comet-classic/classic-guard.d.ts +3 -0
- package/dist/domains/comet-classic/classic-guard.d.ts.map +1 -0
- package/dist/domains/comet-classic/classic-guard.js +833 -0
- package/dist/domains/comet-classic/classic-guard.js.map +1 -0
- package/dist/domains/comet-classic/classic-handoff-entry.d.ts +2 -0
- package/dist/domains/comet-classic/classic-handoff-entry.d.ts.map +1 -0
- package/dist/domains/comet-classic/classic-handoff-entry.js +4 -0
- package/dist/domains/comet-classic/classic-handoff-entry.js.map +1 -0
- package/dist/domains/comet-classic/classic-handoff.d.ts +3 -0
- package/dist/domains/comet-classic/classic-handoff.d.ts.map +1 -0
- package/dist/domains/comet-classic/classic-handoff.js +478 -0
- package/dist/domains/comet-classic/classic-handoff.js.map +1 -0
- package/dist/domains/comet-classic/classic-hook-guard-entry.d.ts +2 -0
- package/dist/domains/comet-classic/classic-hook-guard-entry.d.ts.map +1 -0
- package/dist/domains/comet-classic/classic-hook-guard-entry.js +4 -0
- package/dist/domains/comet-classic/classic-hook-guard-entry.js.map +1 -0
- package/dist/domains/comet-classic/classic-hook-guard.d.ts +3 -0
- package/dist/domains/comet-classic/classic-hook-guard.d.ts.map +1 -0
- package/dist/domains/comet-classic/classic-hook-guard.js +302 -0
- package/dist/domains/comet-classic/classic-hook-guard.js.map +1 -0
- package/dist/domains/comet-classic/classic-intent-command.d.ts +3 -0
- package/dist/domains/comet-classic/classic-intent-command.d.ts.map +1 -0
- package/dist/domains/comet-classic/classic-intent-command.js +40 -0
- package/dist/domains/comet-classic/classic-intent-command.js.map +1 -0
- package/dist/domains/comet-classic/classic-intent-entry.d.ts +2 -0
- package/dist/domains/comet-classic/classic-intent-entry.d.ts.map +1 -0
- package/dist/domains/comet-classic/classic-intent-entry.js +4 -0
- package/dist/domains/comet-classic/classic-intent-entry.js.map +1 -0
- package/dist/domains/comet-classic/classic-intent.d.ts +79 -0
- package/dist/domains/comet-classic/classic-intent.d.ts.map +1 -0
- package/dist/domains/comet-classic/classic-intent.js +307 -0
- package/dist/domains/comet-classic/classic-intent.js.map +1 -0
- package/dist/domains/comet-classic/classic-migrate.d.ts +18 -0
- package/dist/domains/comet-classic/classic-migrate.d.ts.map +1 -0
- package/dist/domains/comet-classic/classic-migrate.js +184 -0
- package/dist/domains/comet-classic/classic-migrate.js.map +1 -0
- package/dist/domains/comet-classic/classic-paths.d.ts +8 -0
- package/dist/domains/comet-classic/classic-paths.d.ts.map +1 -0
- package/dist/domains/comet-classic/classic-paths.js +61 -0
- package/dist/domains/comet-classic/classic-paths.js.map +1 -0
- package/dist/domains/comet-classic/classic-resolver.d.ts +10 -0
- package/dist/domains/comet-classic/classic-resolver.d.ts.map +1 -0
- package/dist/domains/comet-classic/classic-resolver.js +89 -0
- package/dist/domains/comet-classic/classic-resolver.js.map +1 -0
- package/dist/domains/comet-classic/classic-runtime-evals.d.ts +9 -0
- package/dist/domains/comet-classic/classic-runtime-evals.d.ts.map +1 -0
- package/dist/domains/comet-classic/classic-runtime-evals.js +45 -0
- package/dist/domains/comet-classic/classic-runtime-evals.js.map +1 -0
- package/dist/domains/comet-classic/classic-runtime-run.d.ts +7 -0
- package/dist/domains/comet-classic/classic-runtime-run.d.ts.map +1 -0
- package/dist/domains/comet-classic/classic-runtime-run.js +105 -0
- package/dist/domains/comet-classic/classic-runtime-run.js.map +1 -0
- package/dist/domains/comet-classic/classic-script-entry.d.ts +3 -0
- package/dist/domains/comet-classic/classic-script-entry.d.ts.map +1 -0
- package/dist/domains/comet-classic/classic-script-entry.js +31 -0
- package/dist/domains/comet-classic/classic-script-entry.js.map +1 -0
- package/dist/domains/comet-classic/classic-state-command.d.ts +3 -0
- package/dist/domains/comet-classic/classic-state-command.d.ts.map +1 -0
- package/dist/domains/comet-classic/classic-state-command.js +984 -0
- package/dist/domains/comet-classic/classic-state-command.js.map +1 -0
- package/dist/domains/comet-classic/classic-state-entry.d.ts +2 -0
- package/dist/domains/comet-classic/classic-state-entry.d.ts.map +1 -0
- package/dist/domains/comet-classic/classic-state-entry.js +4 -0
- package/dist/domains/comet-classic/classic-state-entry.js.map +1 -0
- package/dist/domains/comet-classic/classic-state-events.d.ts +18 -0
- package/dist/domains/comet-classic/classic-state-events.d.ts.map +1 -0
- package/dist/domains/comet-classic/classic-state-events.js +15 -0
- package/dist/domains/comet-classic/classic-state-events.js.map +1 -0
- package/dist/domains/comet-classic/classic-state.d.ts +69 -0
- package/dist/domains/comet-classic/classic-state.d.ts.map +1 -0
- package/dist/domains/comet-classic/classic-state.js +238 -0
- package/dist/domains/comet-classic/classic-state.js.map +1 -0
- package/dist/domains/comet-classic/classic-store.d.ts +7 -0
- package/dist/domains/comet-classic/classic-store.d.ts.map +1 -0
- package/dist/domains/comet-classic/classic-store.js +127 -0
- package/dist/domains/comet-classic/classic-store.js.map +1 -0
- package/dist/domains/comet-classic/classic-transitions.d.ts +24 -0
- package/dist/domains/comet-classic/classic-transitions.d.ts.map +1 -0
- package/dist/domains/comet-classic/classic-transitions.js +124 -0
- package/dist/domains/comet-classic/classic-transitions.js.map +1 -0
- package/dist/domains/comet-classic/classic-validate-command.d.ts +3 -0
- package/dist/domains/comet-classic/classic-validate-command.d.ts.map +1 -0
- package/dist/domains/comet-classic/classic-validate-command.js +154 -0
- package/dist/domains/comet-classic/classic-validate-command.js.map +1 -0
- package/dist/domains/comet-classic/classic-validate-entry.d.ts +2 -0
- package/dist/domains/comet-classic/classic-validate-entry.d.ts.map +1 -0
- package/dist/domains/comet-classic/classic-validate-entry.js +4 -0
- package/dist/domains/comet-classic/classic-validate-entry.js.map +1 -0
- package/dist/domains/comet-classic/index.d.ts +20 -0
- package/dist/domains/comet-classic/index.d.ts.map +1 -0
- package/dist/domains/comet-classic/index.js +20 -0
- package/dist/domains/comet-classic/index.js.map +1 -0
- package/dist/domains/dashboard/collector.d.ts +12 -0
- package/dist/domains/dashboard/collector.d.ts.map +1 -0
- package/dist/domains/dashboard/collector.js +475 -0
- package/dist/domains/dashboard/collector.js.map +1 -0
- package/dist/domains/dashboard/git.d.ts +8 -0
- package/dist/domains/dashboard/git.d.ts.map +1 -0
- package/dist/domains/dashboard/git.js +69 -0
- package/dist/domains/dashboard/git.js.map +1 -0
- package/dist/domains/dashboard/next-action.d.ts +17 -0
- package/dist/domains/dashboard/next-action.d.ts.map +1 -0
- package/dist/domains/dashboard/next-action.js +83 -0
- package/dist/domains/dashboard/next-action.js.map +1 -0
- package/dist/domains/dashboard/open-browser.d.ts +9 -0
- package/dist/domains/dashboard/open-browser.d.ts.map +1 -0
- package/dist/domains/dashboard/open-browser.js +40 -0
- package/dist/domains/dashboard/open-browser.js.map +1 -0
- package/dist/domains/dashboard/risk.d.ts +24 -0
- package/dist/domains/dashboard/risk.d.ts.map +1 -0
- package/dist/domains/dashboard/risk.js +97 -0
- package/dist/domains/dashboard/risk.js.map +1 -0
- package/dist/domains/dashboard/server.d.ts +21 -0
- package/dist/domains/dashboard/server.d.ts.map +1 -0
- package/dist/domains/dashboard/server.js +149 -0
- package/dist/domains/dashboard/server.js.map +1 -0
- package/dist/domains/dashboard/task-parser.d.ts +13 -0
- package/dist/domains/dashboard/task-parser.d.ts.map +1 -0
- package/dist/domains/dashboard/task-parser.js +82 -0
- package/dist/domains/dashboard/task-parser.js.map +1 -0
- package/dist/domains/dashboard/types.d.ts +122 -0
- package/dist/domains/dashboard/types.d.ts.map +1 -0
- package/dist/domains/dashboard/types.js +10 -0
- package/dist/domains/dashboard/types.js.map +1 -0
- package/dist/domains/dashboard/verify-parser.d.ts +18 -0
- package/dist/domains/dashboard/verify-parser.d.ts.map +1 -0
- package/dist/domains/dashboard/verify-parser.js +94 -0
- package/dist/domains/dashboard/verify-parser.js.map +1 -0
- package/dist/domains/dashboard/web/assets/demo-DQyfozbi.js +1 -0
- package/dist/domains/dashboard/web/assets/index-BcO3_QlT.css +1 -0
- package/dist/domains/dashboard/web/assets/index-CjU3VXVu.js +22 -0
- package/dist/domains/dashboard/web/favicon.png +0 -0
- package/dist/domains/dashboard/web/index.html +16 -0
- package/dist/domains/dashboard/yaml.d.ts +13 -0
- package/dist/domains/dashboard/yaml.d.ts.map +1 -0
- package/dist/domains/dashboard/yaml.js +61 -0
- package/dist/domains/dashboard/yaml.js.map +1 -0
- package/dist/domains/engine/evals.d.ts +4 -0
- package/dist/domains/engine/evals.d.ts.map +1 -0
- package/dist/domains/engine/evals.js +25 -0
- package/dist/domains/engine/evals.js.map +1 -0
- package/dist/domains/engine/guardrails.d.ts +10 -0
- package/dist/domains/engine/guardrails.d.ts.map +1 -0
- package/dist/domains/engine/guardrails.js +25 -0
- package/dist/domains/engine/guardrails.js.map +1 -0
- package/dist/domains/engine/loop.d.ts +15 -0
- package/dist/domains/engine/loop.d.ts.map +1 -0
- package/dist/domains/engine/loop.js +126 -0
- package/dist/domains/engine/loop.js.map +1 -0
- package/dist/domains/engine/manual-run.d.ts +30 -0
- package/dist/domains/engine/manual-run.d.ts.map +1 -0
- package/dist/domains/engine/manual-run.js +184 -0
- package/dist/domains/engine/manual-run.js.map +1 -0
- package/dist/domains/engine/resolver.d.ts +20 -0
- package/dist/domains/engine/resolver.d.ts.map +1 -0
- package/dist/domains/engine/resolver.js +36 -0
- package/dist/domains/engine/resolver.js.map +1 -0
- package/dist/domains/engine/run-store.d.ts +13 -0
- package/dist/domains/engine/run-store.d.ts.map +1 -0
- package/dist/domains/engine/run-store.js +100 -0
- package/dist/domains/engine/run-store.js.map +1 -0
- package/dist/domains/engine/runtime-types.d.ts +11 -0
- package/dist/domains/engine/runtime-types.d.ts.map +1 -0
- package/dist/domains/engine/runtime-types.js +2 -0
- package/dist/domains/engine/runtime-types.js.map +1 -0
- package/dist/domains/engine/standalone-run.d.ts +13 -0
- package/dist/domains/engine/standalone-run.d.ts.map +1 -0
- package/dist/domains/engine/standalone-run.js +27 -0
- package/dist/domains/engine/standalone-run.js.map +1 -0
- package/dist/domains/engine/state.d.ts +10 -0
- package/dist/domains/engine/state.d.ts.map +1 -0
- package/dist/domains/engine/state.js +160 -0
- package/dist/domains/engine/state.js.map +1 -0
- package/dist/domains/engine/types.d.ts +51 -0
- package/dist/domains/engine/types.d.ts.map +1 -0
- package/dist/domains/engine/types.js +2 -0
- package/dist/domains/engine/types.js.map +1 -0
- package/dist/domains/eval/index.d.ts +7 -0
- package/dist/domains/eval/index.d.ts.map +1 -0
- package/dist/domains/eval/index.js +11 -0
- package/dist/domains/eval/index.js.map +1 -0
- package/dist/domains/eval/repository-benchmarks.d.ts +6 -0
- package/dist/domains/eval/repository-benchmarks.d.ts.map +1 -0
- package/dist/domains/eval/repository-benchmarks.js +10 -0
- package/dist/domains/eval/repository-benchmarks.js.map +1 -0
- package/dist/domains/factory/artifacts.d.ts +53 -0
- package/dist/domains/factory/artifacts.d.ts.map +1 -0
- package/dist/domains/factory/artifacts.js +8 -0
- package/dist/domains/factory/artifacts.js.map +1 -0
- package/dist/domains/factory/package.d.ts +7 -0
- package/dist/domains/factory/package.d.ts.map +1 -0
- package/dist/domains/factory/package.js +1511 -0
- package/dist/domains/factory/package.js.map +1 -0
- package/dist/domains/factory/types.d.ts +127 -0
- package/dist/domains/factory/types.d.ts.map +1 -0
- package/dist/domains/factory/types.js +2 -0
- package/dist/domains/factory/types.js.map +1 -0
- package/dist/{core → domains/integrations}/codegraph.d.ts +1 -1
- package/dist/domains/integrations/codegraph.d.ts.map +1 -0
- package/dist/{core → domains/integrations}/codegraph.js +1 -1
- package/dist/domains/integrations/codegraph.js.map +1 -0
- package/dist/domains/integrations/openspec.d.ts +18 -0
- package/dist/domains/integrations/openspec.d.ts.map +1 -0
- package/dist/{core → domains/integrations}/openspec.js +102 -25
- package/dist/domains/integrations/openspec.js.map +1 -0
- package/dist/{core → domains/integrations}/superpowers.d.ts +10 -2
- package/dist/domains/integrations/superpowers.d.ts.map +1 -0
- package/dist/{core → domains/integrations}/superpowers.js +59 -13
- package/dist/domains/integrations/superpowers.js.map +1 -0
- package/dist/domains/skill/discovery.d.ts +17 -0
- package/dist/domains/skill/discovery.d.ts.map +1 -0
- package/dist/domains/skill/discovery.js +80 -0
- package/dist/domains/skill/discovery.js.map +1 -0
- package/dist/domains/skill/find.d.ts +41 -0
- package/dist/domains/skill/find.d.ts.map +1 -0
- package/dist/domains/skill/find.js +251 -0
- package/dist/domains/skill/find.js.map +1 -0
- package/dist/domains/skill/install.d.ts +11 -0
- package/dist/domains/skill/install.d.ts.map +1 -0
- package/dist/domains/skill/install.js +82 -0
- package/dist/domains/skill/install.js.map +1 -0
- package/dist/domains/skill/inventory.d.ts +19 -0
- package/dist/domains/skill/inventory.d.ts.map +1 -0
- package/dist/domains/skill/inventory.js +64 -0
- package/dist/domains/skill/inventory.js.map +1 -0
- package/dist/domains/skill/languages.d.ts +19 -0
- package/dist/domains/skill/languages.d.ts.map +1 -0
- package/dist/domains/skill/languages.js +21 -0
- package/dist/domains/skill/languages.js.map +1 -0
- package/dist/domains/skill/load.d.ts +5 -0
- package/dist/domains/skill/load.d.ts.map +1 -0
- package/dist/domains/skill/load.js +313 -0
- package/dist/domains/skill/load.js.map +1 -0
- package/dist/domains/skill/platform-install.d.ts +87 -0
- package/dist/domains/skill/platform-install.d.ts.map +1 -0
- package/dist/{core/skills.js → domains/skill/platform-install.js} +243 -51
- package/dist/domains/skill/platform-install.js.map +1 -0
- package/dist/domains/skill/preferences.d.ts +42 -0
- package/dist/domains/skill/preferences.d.ts.map +1 -0
- package/dist/domains/skill/preferences.js +118 -0
- package/dist/domains/skill/preferences.js.map +1 -0
- package/dist/domains/skill/snapshot.d.ts +8 -0
- package/dist/domains/skill/snapshot.d.ts.map +1 -0
- package/dist/domains/skill/snapshot.js +184 -0
- package/dist/domains/skill/snapshot.js.map +1 -0
- package/dist/domains/skill/types.d.ts +85 -0
- package/dist/domains/skill/types.d.ts.map +1 -0
- package/dist/domains/skill/types.js +2 -0
- package/dist/{core → domains/skill}/types.js.map +1 -1
- package/dist/{core → domains/skill}/uninstall.d.ts +2 -18
- package/dist/domains/skill/uninstall.d.ts.map +1 -0
- package/dist/{core → domains/skill}/uninstall.js +15 -66
- package/dist/domains/skill/uninstall.js.map +1 -0
- package/dist/domains/skill/validate.d.ts +3 -0
- package/dist/domains/skill/validate.d.ts.map +1 -0
- package/dist/domains/skill/validate.js +81 -0
- package/dist/domains/skill/validate.js.map +1 -0
- package/dist/domains/workflow-contract/builtins.d.ts +8 -0
- package/dist/domains/workflow-contract/builtins.d.ts.map +1 -0
- package/dist/domains/workflow-contract/builtins.js +229 -0
- package/dist/domains/workflow-contract/builtins.js.map +1 -0
- package/dist/domains/workflow-contract/hash.d.ts +3 -0
- package/dist/domains/workflow-contract/hash.d.ts.map +1 -0
- package/dist/domains/workflow-contract/hash.js +16 -0
- package/dist/domains/workflow-contract/hash.js.map +1 -0
- package/dist/domains/workflow-contract/index.d.ts +6 -0
- package/dist/domains/workflow-contract/index.d.ts.map +1 -0
- package/dist/domains/workflow-contract/index.js +5 -0
- package/dist/domains/workflow-contract/index.js.map +1 -0
- package/dist/domains/workflow-contract/normalize.d.ts +3 -0
- package/dist/domains/workflow-contract/normalize.d.ts.map +1 -0
- package/dist/domains/workflow-contract/normalize.js +146 -0
- package/dist/domains/workflow-contract/normalize.js.map +1 -0
- package/dist/domains/workflow-contract/types.d.ts +128 -0
- package/dist/domains/workflow-contract/types.d.ts.map +1 -0
- package/dist/domains/workflow-contract/types.js +2 -0
- package/dist/domains/workflow-contract/types.js.map +1 -0
- package/dist/domains/workflow-contract/validation.d.ts +3 -0
- package/dist/domains/workflow-contract/validation.d.ts.map +1 -0
- package/dist/domains/workflow-contract/validation.js +180 -0
- package/dist/domains/workflow-contract/validation.js.map +1 -0
- package/dist/platform/fs/file-system.d.ts.map +1 -0
- package/dist/platform/fs/file-system.js.map +1 -0
- package/dist/platform/install/detect.d.ts.map +1 -0
- package/dist/{core → platform/install}/detect.js +4 -3
- package/dist/platform/install/detect.js.map +1 -0
- package/dist/platform/install/platforms.d.ts.map +1 -0
- package/dist/{core → platform/install}/platforms.js +41 -0
- package/dist/platform/install/platforms.js.map +1 -0
- package/dist/platform/install/types.d.ts +3 -0
- package/dist/platform/install/types.d.ts.map +1 -0
- package/dist/platform/install/types.js +2 -0
- package/dist/platform/install/types.js.map +1 -0
- package/dist/platform/paths/repository-layout.d.ts +22 -0
- package/dist/platform/paths/repository-layout.d.ts.map +1 -0
- package/dist/platform/paths/repository-layout.js +11 -0
- package/dist/platform/paths/repository-layout.js.map +1 -0
- package/dist/platform/process/command-error.d.ts.map +1 -0
- package/dist/platform/process/command-error.js.map +1 -0
- package/dist/platform/process/shell-quote.d.ts +22 -0
- package/dist/platform/process/shell-quote.d.ts.map +1 -0
- package/dist/platform/process/shell-quote.js +34 -0
- package/dist/platform/process/shell-quote.js.map +1 -0
- package/dist/platform/version/version.d.ts.map +1 -0
- package/dist/{core → platform/version}/version.js +16 -3
- package/dist/platform/version/version.js.map +1 -0
- package/package.json +39 -13
- package/assets/skills/comet/scripts/comet-archive.sh +0 -311
- package/assets/skills/comet/scripts/comet-env.sh +0 -110
- package/assets/skills/comet/scripts/comet-guard.sh +0 -778
- package/assets/skills/comet/scripts/comet-handoff.sh +0 -390
- package/assets/skills/comet/scripts/comet-hook-guard.sh +0 -336
- package/assets/skills/comet/scripts/comet-state.sh +0 -1338
- package/assets/skills/comet/scripts/comet-yaml-validate.sh +0 -225
- package/dist/cli/index.js +0 -84
- package/dist/cli/index.js.map +0 -1
- package/dist/commands/doctor.d.ts.map +0 -1
- package/dist/commands/doctor.js.map +0 -1
- package/dist/commands/i18n.d.ts +0 -4
- package/dist/commands/i18n.d.ts.map +0 -1
- package/dist/commands/i18n.js.map +0 -1
- package/dist/commands/init.d.ts.map +0 -1
- package/dist/commands/init.js.map +0 -1
- package/dist/commands/status.d.ts.map +0 -1
- package/dist/commands/status.js +0 -108
- package/dist/commands/status.js.map +0 -1
- package/dist/commands/uninstall.d.ts.map +0 -1
- package/dist/commands/uninstall.js.map +0 -1
- package/dist/commands/update.d.ts.map +0 -1
- package/dist/commands/update.js.map +0 -1
- package/dist/core/codegraph.d.ts.map +0 -1
- package/dist/core/codegraph.js.map +0 -1
- package/dist/core/command-error.d.ts.map +0 -1
- package/dist/core/command-error.js.map +0 -1
- package/dist/core/detect.d.ts.map +0 -1
- package/dist/core/detect.js.map +0 -1
- package/dist/core/openspec.d.ts +0 -11
- package/dist/core/openspec.d.ts.map +0 -1
- package/dist/core/openspec.js.map +0 -1
- package/dist/core/platforms.d.ts.map +0 -1
- package/dist/core/platforms.js.map +0 -1
- package/dist/core/skills.d.ts +0 -58
- package/dist/core/skills.d.ts.map +0 -1
- package/dist/core/skills.js.map +0 -1
- package/dist/core/superpowers.d.ts.map +0 -1
- package/dist/core/superpowers.js.map +0 -1
- package/dist/core/types.d.ts +0 -2
- package/dist/core/types.d.ts.map +0 -1
- package/dist/core/uninstall.d.ts.map +0 -1
- package/dist/core/uninstall.js.map +0 -1
- package/dist/core/version.d.ts.map +0 -1
- package/dist/core/version.js.map +0 -1
- package/dist/utils/file-system.d.ts.map +0 -1
- package/dist/utils/file-system.js.map +0 -1
- /package/dist/{cli → app/cli}/index.d.ts +0 -0
- /package/dist/{commands → app/commands}/status.d.ts +0 -0
- /package/dist/{core → domains/bundle}/types.js +0 -0
- /package/dist/{utils → platform/fs}/file-system.d.ts +0 -0
- /package/dist/{utils → platform/fs}/file-system.js +0 -0
- /package/dist/{core → platform/install}/detect.d.ts +0 -0
- /package/dist/{core → platform/install}/platforms.d.ts +0 -0
- /package/dist/{core → platform/process}/command-error.d.ts +0 -0
- /package/dist/{core → platform/process}/command-error.js +0 -0
- /package/dist/{core → platform/version}/version.d.ts +0 -0
- /package/scripts/{postinstall.js → install/postinstall.js} +0 -0
|
@@ -0,0 +1,984 @@
|
|
|
1
|
+
import { spawnSync } from 'child_process';
|
|
2
|
+
import { randomUUID } from 'crypto';
|
|
3
|
+
import { existsSync, promises as fs } from 'fs';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import { Document, parseDocument } from 'yaml';
|
|
6
|
+
import { collectClassicEvidence } from './classic-evidence.js';
|
|
7
|
+
import { openSpecChangeNameError, resolveClassicChangeDirectory } from './classic-paths.js';
|
|
8
|
+
import { resolveClassicStepId } from './classic-resolver.js';
|
|
9
|
+
import { transitionClassicRuntimeRun } from './classic-runtime-run.js';
|
|
10
|
+
import { appendClassicStateEvent } from './classic-state-events.js';
|
|
11
|
+
import { CLASSIC_WIRE_KEYS, RUN_WIRE_KEYS, parseClassicStateDocument, } from './classic-state.js';
|
|
12
|
+
import { readClassicState, writeClassicState } from './classic-store.js';
|
|
13
|
+
import { CLASSIC_TRANSITION_EVENTS, applyClassicTransition, } from './classic-transitions.js';
|
|
14
|
+
import { readRunState } from '../../domains/engine/state.js';
|
|
15
|
+
import { appendTrajectory, readTrajectory } from '../../domains/engine/run-store.js';
|
|
16
|
+
const GREEN = '\u001b[32m';
|
|
17
|
+
const RED = '\u001b[31m';
|
|
18
|
+
const YELLOW = '\u001b[33m';
|
|
19
|
+
const RESET = '\u001b[0m';
|
|
20
|
+
const PROFILES = ['full', 'hotfix', 'tweak'];
|
|
21
|
+
const PHASES = ['open', 'design', 'build', 'verify', 'archive'];
|
|
22
|
+
const ARTIFACT_LANGUAGES = ['en', 'zh-CN'];
|
|
23
|
+
const EVENTS = CLASSIC_TRANSITION_EVENTS;
|
|
24
|
+
const MACHINE_OWNED_FIELDS = new Set([
|
|
25
|
+
...RUN_WIRE_KEYS,
|
|
26
|
+
'classic_profile',
|
|
27
|
+
'classic_migration',
|
|
28
|
+
]);
|
|
29
|
+
const SETTABLE_FIELDS = new Set(CLASSIC_WIRE_KEYS.filter((field) => !MACHINE_OWNED_FIELDS.has(field)));
|
|
30
|
+
const FIELD_ENUMS = {
|
|
31
|
+
workflow: PROFILES,
|
|
32
|
+
phase: PHASES,
|
|
33
|
+
context_compression: ['off', 'beta'],
|
|
34
|
+
build_mode: ['subagent-driven-development', 'executing-plans', 'direct'],
|
|
35
|
+
build_pause: ['null', 'plan-ready'],
|
|
36
|
+
subagent_dispatch: ['null', 'confirmed'],
|
|
37
|
+
tdd_mode: ['tdd', 'direct'],
|
|
38
|
+
review_mode: ['off', 'standard', 'thorough'],
|
|
39
|
+
isolation: ['branch', 'worktree'],
|
|
40
|
+
verify_mode: ['light', 'full'],
|
|
41
|
+
auto_transition: ['true', 'false'],
|
|
42
|
+
verify_result: ['pending', 'pass', 'fail'],
|
|
43
|
+
branch_status: ['pending', 'handled'],
|
|
44
|
+
archived: ['true', 'false'],
|
|
45
|
+
direct_override: ['true', 'false'],
|
|
46
|
+
classic_profile: PROFILES,
|
|
47
|
+
classic_migration: ['1'],
|
|
48
|
+
};
|
|
49
|
+
const PATH_FIELDS = new Set(['design_doc', 'plan', 'verification_report', 'handoff_context']);
|
|
50
|
+
const CLASSIC_FIELD_WIRE_NAMES = {
|
|
51
|
+
archived: 'archived',
|
|
52
|
+
branchStatus: 'branch_status',
|
|
53
|
+
classicProfile: 'classic_profile',
|
|
54
|
+
designDoc: 'design_doc',
|
|
55
|
+
language: 'language',
|
|
56
|
+
phase: 'phase',
|
|
57
|
+
verificationReport: 'verification_report',
|
|
58
|
+
verifiedAt: 'verified_at',
|
|
59
|
+
verifyResult: 'verify_result',
|
|
60
|
+
workflow: 'workflow',
|
|
61
|
+
};
|
|
62
|
+
class CommandFailure extends Error {
|
|
63
|
+
exitCode;
|
|
64
|
+
constructor(message, exitCode = 1) {
|
|
65
|
+
super(message);
|
|
66
|
+
this.exitCode = exitCode;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
class CommandOutput {
|
|
70
|
+
stdout = [];
|
|
71
|
+
stderr = [];
|
|
72
|
+
result(exitCode = 0) {
|
|
73
|
+
return {
|
|
74
|
+
exitCode,
|
|
75
|
+
...(this.stdout.length > 0 ? { stdout: this.stdout.join('\n') + '\n' } : {}),
|
|
76
|
+
...(this.stderr.length > 0 ? { stderr: this.stderr.join('\n') } : {}),
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
function green(message) {
|
|
81
|
+
return `${GREEN}${message}${RESET}`;
|
|
82
|
+
}
|
|
83
|
+
function red(message) {
|
|
84
|
+
return `${RED}${message}${RESET}`;
|
|
85
|
+
}
|
|
86
|
+
function yellow(message) {
|
|
87
|
+
return `${YELLOW}${message}${RESET}`;
|
|
88
|
+
}
|
|
89
|
+
function fail(message) {
|
|
90
|
+
throw new CommandFailure(message);
|
|
91
|
+
}
|
|
92
|
+
function validateChangeName(name) {
|
|
93
|
+
const error = openSpecChangeNameError(name);
|
|
94
|
+
if (error)
|
|
95
|
+
fail(`ERROR: ${error}`);
|
|
96
|
+
}
|
|
97
|
+
function validateEnum(value, values) {
|
|
98
|
+
if (!values.includes(value)) {
|
|
99
|
+
fail(`ERROR: Invalid value: '${value}'\nValid values: ${values.join(' ')}`);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
function validateLanguage(value, source) {
|
|
103
|
+
if (ARTIFACT_LANGUAGES.includes(value)) {
|
|
104
|
+
return value;
|
|
105
|
+
}
|
|
106
|
+
fail(`ERROR: Invalid language from ${source}: '${value}'\nValid values: en, zh-CN`);
|
|
107
|
+
}
|
|
108
|
+
function validateRelativePath(value, field) {
|
|
109
|
+
if (!value || value === 'null')
|
|
110
|
+
return;
|
|
111
|
+
if (/^(?:[A-Za-z]:|[\\/]|~)/u.test(value)) {
|
|
112
|
+
fail(`ERROR: ${field} must be a relative path within the repo: '${value}'`);
|
|
113
|
+
}
|
|
114
|
+
if (value.split(/[\\/]/u).includes('..')) {
|
|
115
|
+
fail(`ERROR: ${field} cannot contain '..' (path traversal not allowed): '${value}'`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
async function exists(file) {
|
|
119
|
+
try {
|
|
120
|
+
await fs.access(file);
|
|
121
|
+
return true;
|
|
122
|
+
}
|
|
123
|
+
catch (error) {
|
|
124
|
+
if (error.code === 'ENOENT')
|
|
125
|
+
return false;
|
|
126
|
+
throw error;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
async function nonempty(file) {
|
|
130
|
+
try {
|
|
131
|
+
return (await fs.stat(file)).size > 0;
|
|
132
|
+
}
|
|
133
|
+
catch (error) {
|
|
134
|
+
if (error.code === 'ENOENT')
|
|
135
|
+
return false;
|
|
136
|
+
throw error;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
async function changeDirectory(name) {
|
|
140
|
+
return resolveClassicChangeDirectory(name);
|
|
141
|
+
}
|
|
142
|
+
async function readDocument(file) {
|
|
143
|
+
let source;
|
|
144
|
+
try {
|
|
145
|
+
source = await fs.readFile(file, 'utf8');
|
|
146
|
+
}
|
|
147
|
+
catch (error) {
|
|
148
|
+
if (error.code === 'ENOENT') {
|
|
149
|
+
fail(`ERROR: .comet.yaml not found at ${path.relative(process.cwd(), file).replaceAll('\\', '/')}`);
|
|
150
|
+
}
|
|
151
|
+
throw error;
|
|
152
|
+
}
|
|
153
|
+
const document = parseDocument(source, { uniqueKeys: false });
|
|
154
|
+
if (document.errors.length > 0)
|
|
155
|
+
fail(`ERROR: Invalid .comet.yaml: ${document.errors[0].message}`);
|
|
156
|
+
return document;
|
|
157
|
+
}
|
|
158
|
+
async function atomicWrite(file, content) {
|
|
159
|
+
await fs.mkdir(path.dirname(file), { recursive: true });
|
|
160
|
+
const temporary = `${file}.${randomUUID()}.tmp`;
|
|
161
|
+
try {
|
|
162
|
+
await fs.writeFile(temporary, content, 'utf8');
|
|
163
|
+
await fs.rename(temporary, file);
|
|
164
|
+
}
|
|
165
|
+
catch (error) {
|
|
166
|
+
await fs.rm(temporary, { force: true });
|
|
167
|
+
throw error;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
function scalar(value) {
|
|
171
|
+
if (value === null)
|
|
172
|
+
return 'null';
|
|
173
|
+
if (value === undefined)
|
|
174
|
+
return '';
|
|
175
|
+
if (typeof value === 'object')
|
|
176
|
+
return JSON.stringify(value);
|
|
177
|
+
return String(value);
|
|
178
|
+
}
|
|
179
|
+
function wireField(field) {
|
|
180
|
+
return CLASSIC_FIELD_WIRE_NAMES[field] ?? String(field);
|
|
181
|
+
}
|
|
182
|
+
function wireValue(value) {
|
|
183
|
+
return value === null ? 'null' : scalar(value);
|
|
184
|
+
}
|
|
185
|
+
function enumRecordValue(record, field, values, fallback) {
|
|
186
|
+
const value = record[field];
|
|
187
|
+
return typeof value === 'string' && values.includes(value)
|
|
188
|
+
? value
|
|
189
|
+
: fallback;
|
|
190
|
+
}
|
|
191
|
+
function nullableRecordString(record, field) {
|
|
192
|
+
const value = record[field];
|
|
193
|
+
if (value === null || value === undefined || value === '')
|
|
194
|
+
return null;
|
|
195
|
+
return typeof value === 'string' ? value : String(value);
|
|
196
|
+
}
|
|
197
|
+
function nullableRecordBoolean(record, field) {
|
|
198
|
+
const value = record[field];
|
|
199
|
+
if (value === null || value === undefined || value === '')
|
|
200
|
+
return null;
|
|
201
|
+
if (typeof value === 'boolean')
|
|
202
|
+
return value;
|
|
203
|
+
if (value === 'true')
|
|
204
|
+
return true;
|
|
205
|
+
if (value === 'false')
|
|
206
|
+
return false;
|
|
207
|
+
return null;
|
|
208
|
+
}
|
|
209
|
+
function sparseClassicState(record) {
|
|
210
|
+
const workflow = enumRecordValue(record, 'workflow', PROFILES, 'full');
|
|
211
|
+
return {
|
|
212
|
+
workflow,
|
|
213
|
+
language: enumRecordValue(record, 'language', ARTIFACT_LANGUAGES, null),
|
|
214
|
+
phase: enumRecordValue(record, 'phase', PHASES, 'open'),
|
|
215
|
+
contextCompression: enumRecordValue(record, 'context_compression', ['off', 'beta'], null),
|
|
216
|
+
buildMode: enumRecordValue(record, 'build_mode', ['subagent-driven-development', 'executing-plans', 'direct'], null),
|
|
217
|
+
buildPause: enumRecordValue(record, 'build_pause', ['plan-ready'], null),
|
|
218
|
+
subagentDispatch: enumRecordValue(record, 'subagent_dispatch', ['confirmed'], null),
|
|
219
|
+
tddMode: enumRecordValue(record, 'tdd_mode', ['tdd', 'direct'], null),
|
|
220
|
+
reviewMode: enumRecordValue(record, 'review_mode', ['off', 'standard', 'thorough'], null),
|
|
221
|
+
isolation: enumRecordValue(record, 'isolation', ['branch', 'worktree'], null),
|
|
222
|
+
verifyMode: enumRecordValue(record, 'verify_mode', ['light', 'full'], null),
|
|
223
|
+
autoTransition: nullableRecordBoolean(record, 'auto_transition'),
|
|
224
|
+
baseRef: nullableRecordString(record, 'base_ref'),
|
|
225
|
+
designDoc: nullableRecordString(record, 'design_doc'),
|
|
226
|
+
plan: nullableRecordString(record, 'plan'),
|
|
227
|
+
verifyResult: enumRecordValue(record, 'verify_result', ['pending', 'pass', 'fail'], 'pending'),
|
|
228
|
+
verificationReport: nullableRecordString(record, 'verification_report'),
|
|
229
|
+
branchStatus: enumRecordValue(record, 'branch_status', ['pending', 'handled'], null),
|
|
230
|
+
createdAt: nullableRecordString(record, 'created_at'),
|
|
231
|
+
verifiedAt: nullableRecordString(record, 'verified_at'),
|
|
232
|
+
archived: nullableRecordBoolean(record, 'archived') ?? false,
|
|
233
|
+
directOverride: nullableRecordBoolean(record, 'direct_override'),
|
|
234
|
+
buildCommand: nullableRecordString(record, 'build_command'),
|
|
235
|
+
verifyCommand: nullableRecordString(record, 'verify_command'),
|
|
236
|
+
handoffContext: nullableRecordString(record, 'handoff_context'),
|
|
237
|
+
handoffHash: nullableRecordString(record, 'handoff_hash'),
|
|
238
|
+
classicProfile: enumRecordValue(record, 'classic_profile', PROFILES, workflow),
|
|
239
|
+
classicMigration: typeof record.classic_migration === 'number' ? record.classic_migration : null,
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
async function projectConfigValue(field) {
|
|
243
|
+
const file = path.resolve('.comet', 'config.yaml');
|
|
244
|
+
if (!(await exists(file)))
|
|
245
|
+
return null;
|
|
246
|
+
const document = await readDocument(file);
|
|
247
|
+
const value = document.get(field);
|
|
248
|
+
return value === null || value === undefined ? null : scalar(value);
|
|
249
|
+
}
|
|
250
|
+
async function projectLanguageDefault() {
|
|
251
|
+
if (process.env.COMET_LANGUAGE)
|
|
252
|
+
return validateLanguage(process.env.COMET_LANGUAGE, 'COMET_LANGUAGE');
|
|
253
|
+
const value = await projectConfigValue('language');
|
|
254
|
+
if (value)
|
|
255
|
+
return validateLanguage(value, '.comet/config.yaml');
|
|
256
|
+
return 'en';
|
|
257
|
+
}
|
|
258
|
+
async function contextCompression() {
|
|
259
|
+
const value = process.env.COMET_CONTEXT_COMPRESSION ??
|
|
260
|
+
(await projectConfigValue('context_compression')) ??
|
|
261
|
+
'off';
|
|
262
|
+
if (!['off', 'beta'].includes(value)) {
|
|
263
|
+
fail(`ERROR: Invalid context_compression: '${value}'\nValid values: off, beta`);
|
|
264
|
+
}
|
|
265
|
+
return value;
|
|
266
|
+
}
|
|
267
|
+
async function autoTransition() {
|
|
268
|
+
const value = process.env.COMET_AUTO_TRANSITION ?? (await projectConfigValue('auto_transition')) ?? 'true';
|
|
269
|
+
if (!['true', 'false'].includes(value)) {
|
|
270
|
+
fail(`ERROR: Invalid auto_transition: '${value}'\nValid values: true, false`);
|
|
271
|
+
}
|
|
272
|
+
return value;
|
|
273
|
+
}
|
|
274
|
+
async function reviewModeDefault() {
|
|
275
|
+
const value = process.env.COMET_REVIEW_MODE ?? (await projectConfigValue('review_mode')) ?? 'standard';
|
|
276
|
+
if (!['null', 'off', 'standard', 'thorough'].includes(value)) {
|
|
277
|
+
fail(`ERROR: Invalid review_mode: '${value}'\nValid values: off, standard, thorough`);
|
|
278
|
+
}
|
|
279
|
+
return value === 'null' ? null : value;
|
|
280
|
+
}
|
|
281
|
+
function gitOutput(args) {
|
|
282
|
+
const result = spawnSync('git', args, { encoding: 'utf8' });
|
|
283
|
+
return result.status === 0 ? result.stdout.trim() : null;
|
|
284
|
+
}
|
|
285
|
+
async function stateFile(name) {
|
|
286
|
+
const change = await changeDirectory(name);
|
|
287
|
+
return {
|
|
288
|
+
...change,
|
|
289
|
+
file: path.join(change.directory, '.comet.yaml'),
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
async function readField(name, field) {
|
|
293
|
+
const { file } = await stateFile(name);
|
|
294
|
+
const document = await readDocument(file);
|
|
295
|
+
// Read via toJS so an explicit `field: null` round-trips as JS null (-> "null"),
|
|
296
|
+
// matching the shell `yaml_field` grep contract. A bare Document#get returns
|
|
297
|
+
// undefined for null-valued keys, erasing the distinction between "present but
|
|
298
|
+
// null" and "absent" that the frozen 0.3.8 behavior preserves.
|
|
299
|
+
const record = document.toJS();
|
|
300
|
+
const value = record[field];
|
|
301
|
+
if (field === 'language') {
|
|
302
|
+
if (value === null || value === undefined || value === '')
|
|
303
|
+
return projectLanguageDefault();
|
|
304
|
+
return validateLanguage(scalar(value), '.comet.yaml');
|
|
305
|
+
}
|
|
306
|
+
if (field === 'auto_transition' && (value === null || value === undefined || value === '')) {
|
|
307
|
+
return autoTransition();
|
|
308
|
+
}
|
|
309
|
+
return scalar(value);
|
|
310
|
+
}
|
|
311
|
+
function parsedValue(field, value) {
|
|
312
|
+
const document = parseDocument(`${field}: ${value}\n`);
|
|
313
|
+
if (document.errors.length > 0)
|
|
314
|
+
fail(`ERROR: Invalid value: '${value}'`);
|
|
315
|
+
return document.get(field);
|
|
316
|
+
}
|
|
317
|
+
function validateSetValue(field, value) {
|
|
318
|
+
if (field === 'language') {
|
|
319
|
+
validateLanguage(value, 'language');
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
const enumValues = FIELD_ENUMS[field];
|
|
323
|
+
if (enumValues)
|
|
324
|
+
validateEnum(value, enumValues);
|
|
325
|
+
if (PATH_FIELDS.has(field))
|
|
326
|
+
validateRelativePath(value, field);
|
|
327
|
+
if ((field === 'skill_hash' || field === 'handoff_hash') && !/^[a-f0-9]{64}$/u.test(value)) {
|
|
328
|
+
fail(`ERROR: ${field} must be a sha256 hex digest`);
|
|
329
|
+
}
|
|
330
|
+
if (field === 'iteration' && !/^[0-9]+$/u.test(value)) {
|
|
331
|
+
fail('ERROR: iteration must be a non-negative integer');
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
async function setField(output, name, field, value, options = {}) {
|
|
335
|
+
if (MACHINE_OWNED_FIELDS.has(field) && !options.machineOwned) {
|
|
336
|
+
fail(`ERROR: '${field}' is a machine-owned Run field and cannot be set directly`);
|
|
337
|
+
}
|
|
338
|
+
if (!SETTABLE_FIELDS.has(field) && !MACHINE_OWNED_FIELDS.has(field)) {
|
|
339
|
+
fail(`ERROR: Unknown field: '${field}'`);
|
|
340
|
+
}
|
|
341
|
+
if (field === 'phase' && !options.internal && process.env.COMET_FORCE_PHASE !== '1') {
|
|
342
|
+
fail("ERROR: Setting 'phase' directly is not allowed; it bypasses state machine evidence checks.\n" +
|
|
343
|
+
' Use: comet-state.mjs transition <change-name> <event>\n' +
|
|
344
|
+
' Repair-only escape hatch: COMET_FORCE_PHASE=1 comet-state.mjs set <change-name> phase <value>');
|
|
345
|
+
}
|
|
346
|
+
validateSetValue(field, value);
|
|
347
|
+
const { file, directory } = await stateFile(name);
|
|
348
|
+
const document = await readDocument(file);
|
|
349
|
+
document.set(field, parsedValue(field, value));
|
|
350
|
+
const run = await readRunState(directory);
|
|
351
|
+
const projection = parseClassicStateDocument(document.toJS(), run);
|
|
352
|
+
if (projection.run) {
|
|
353
|
+
if (!projection.classic)
|
|
354
|
+
fail('ERROR: migrated Run is missing its Classic projection');
|
|
355
|
+
const evidence = await collectClassicEvidence(directory, projection);
|
|
356
|
+
const currentStep = resolveClassicStepId(projection.classic, evidence);
|
|
357
|
+
const stepChanged = currentStep !== projection.run.currentStep;
|
|
358
|
+
const run = {
|
|
359
|
+
...projection.run,
|
|
360
|
+
currentStep,
|
|
361
|
+
iteration: projection.run.iteration + (stepChanged ? 1 : 0),
|
|
362
|
+
status: currentStep === 'completed' ? 'completed' : 'running',
|
|
363
|
+
};
|
|
364
|
+
await writeClassicState(directory, {
|
|
365
|
+
classic: projection.classic,
|
|
366
|
+
run,
|
|
367
|
+
unknownKeys: projection.unknownKeys,
|
|
368
|
+
});
|
|
369
|
+
if (stepChanged) {
|
|
370
|
+
const trajectory = await readTrajectory(directory, run.trajectoryRef);
|
|
371
|
+
await appendTrajectory(directory, run.trajectoryRef, {
|
|
372
|
+
sequence: trajectory.length + 1,
|
|
373
|
+
timestamp: new Date().toISOString(),
|
|
374
|
+
type: 'state_transitioned',
|
|
375
|
+
runId: run.runId,
|
|
376
|
+
data: {
|
|
377
|
+
kind: 'classic-config',
|
|
378
|
+
field,
|
|
379
|
+
fromStep: projection.run.currentStep,
|
|
380
|
+
toStep: currentStep,
|
|
381
|
+
},
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
else {
|
|
386
|
+
await atomicWrite(file, document.toString());
|
|
387
|
+
}
|
|
388
|
+
if (field === 'phase' && !options.internal) {
|
|
389
|
+
output.stderr.push(yellow("WARNING: Setting 'phase' directly bypasses state machine constraints."), yellow(' Consider using: comet-state.mjs transition <change-name> <event>'));
|
|
390
|
+
}
|
|
391
|
+
output.stderr.push(green(`[SET] ${field}=${value}`));
|
|
392
|
+
}
|
|
393
|
+
async function init(output, name, workflow) {
|
|
394
|
+
validateChangeName(name);
|
|
395
|
+
validateEnum(workflow, PROFILES);
|
|
396
|
+
const { file, label, directory } = await stateFile(name);
|
|
397
|
+
if (await exists(file))
|
|
398
|
+
fail(`ERROR: .comet.yaml already exists at ${label}/.comet.yaml`);
|
|
399
|
+
await fs.mkdir(directory, { recursive: true });
|
|
400
|
+
const preset = workflow !== 'full';
|
|
401
|
+
const reviewMode = preset ? 'off' : await reviewModeDefault();
|
|
402
|
+
const document = new Document({
|
|
403
|
+
workflow,
|
|
404
|
+
language: await projectLanguageDefault(),
|
|
405
|
+
phase: 'open',
|
|
406
|
+
context_compression: await contextCompression(),
|
|
407
|
+
build_mode: preset ? 'direct' : null,
|
|
408
|
+
build_pause: null,
|
|
409
|
+
subagent_dispatch: null,
|
|
410
|
+
tdd_mode: preset ? 'direct' : null,
|
|
411
|
+
review_mode: reviewMode,
|
|
412
|
+
isolation: preset ? 'branch' : null,
|
|
413
|
+
verify_mode: preset ? 'light' : null,
|
|
414
|
+
auto_transition: (await autoTransition()) === 'true',
|
|
415
|
+
base_ref: gitOutput(['rev-parse', '--verify', 'HEAD']),
|
|
416
|
+
design_doc: null,
|
|
417
|
+
plan: null,
|
|
418
|
+
verify_result: 'pending',
|
|
419
|
+
verification_report: null,
|
|
420
|
+
branch_status: 'pending',
|
|
421
|
+
created_at: new Date().toISOString().slice(0, 10),
|
|
422
|
+
verified_at: null,
|
|
423
|
+
archived: false,
|
|
424
|
+
});
|
|
425
|
+
await atomicWrite(file, document.toString());
|
|
426
|
+
output.stderr.push(green(`Initialized: ${label}/.comet.yaml (workflow=${workflow})`));
|
|
427
|
+
}
|
|
428
|
+
async function requirePhase(name, expected) {
|
|
429
|
+
const actual = await readField(name, 'phase');
|
|
430
|
+
if (actual !== expected) {
|
|
431
|
+
fail(`ERROR: Cannot transition '${name}': expected phase ${expected}, got ${actual}`);
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
async function requireBuildDecisions(name) {
|
|
435
|
+
const workflow = await readField(name, 'workflow');
|
|
436
|
+
const buildMode = await readField(name, 'build_mode');
|
|
437
|
+
const isolation = await readField(name, 'isolation');
|
|
438
|
+
const directOverride = await readField(name, 'direct_override');
|
|
439
|
+
const subagentDispatch = await readField(name, 'subagent_dispatch');
|
|
440
|
+
const tddMode = await readField(name, 'tdd_mode');
|
|
441
|
+
const reviewMode = await readField(name, 'review_mode');
|
|
442
|
+
if (!['branch', 'worktree'].includes(isolation)) {
|
|
443
|
+
fail(`ERROR: Cannot transition '${name}': isolation must be branch or worktree, got '${isolation || 'null'}'`);
|
|
444
|
+
}
|
|
445
|
+
if (!['subagent-driven-development', 'executing-plans', 'direct'].includes(buildMode)) {
|
|
446
|
+
fail(`ERROR: Cannot transition '${name}': build_mode must be selected before leaving build, got '${buildMode || 'null'}'`);
|
|
447
|
+
}
|
|
448
|
+
if (buildMode === 'direct' &&
|
|
449
|
+
!['hotfix', 'tweak'].includes(workflow) &&
|
|
450
|
+
directOverride !== 'true') {
|
|
451
|
+
fail(`ERROR: Cannot transition '${name}': build_mode=direct is only allowed for hotfix/tweak unless direct_override=true`);
|
|
452
|
+
}
|
|
453
|
+
if (buildMode === 'subagent-driven-development' && subagentDispatch !== 'confirmed') {
|
|
454
|
+
fail(`ERROR: Cannot transition '${name}': subagent_dispatch must be confirmed before using build_mode=subagent-driven-development`);
|
|
455
|
+
}
|
|
456
|
+
if (workflow === 'full' && (!tddMode || tddMode === 'null')) {
|
|
457
|
+
fail(`ERROR: Cannot transition '${name}': tdd_mode must be selected before leaving build (full workflow)`);
|
|
458
|
+
}
|
|
459
|
+
if (workflow === 'full' && !['off', 'standard', 'thorough'].includes(reviewMode)) {
|
|
460
|
+
fail(`ERROR: Cannot transition '${name}': review_mode must be selected before leaving build (full workflow); review_mode must be off, standard, or thorough, got '${reviewMode || 'null'}'`);
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
async function requireOpenArtifacts(name) {
|
|
464
|
+
const { directory } = await stateFile(name);
|
|
465
|
+
const workflow = await readField(name, 'workflow');
|
|
466
|
+
for (const artifact of ['proposal.md', 'tasks.md']) {
|
|
467
|
+
if (!(await nonempty(path.join(directory, artifact)))) {
|
|
468
|
+
fail(`ERROR: Cannot transition '${name}': ${artifact} must exist and be non-empty before leaving open`);
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
if (workflow === 'full' && !(await nonempty(path.join(directory, 'design.md')))) {
|
|
472
|
+
fail(`ERROR: Cannot transition '${name}': design.md must exist and be non-empty before leaving open`);
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
async function requireDesignEvidence(name) {
|
|
476
|
+
const designDoc = await readField(name, 'design_doc');
|
|
477
|
+
if (!designDoc || designDoc === 'null' || !(await nonempty(path.resolve(designDoc)))) {
|
|
478
|
+
fail(`ERROR: Cannot transition '${name}': design_doc must point to an existing Design Doc before leaving design`);
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
async function writeSparseTransitionEffects(directory, effects) {
|
|
482
|
+
const file = path.join(directory, '.comet.yaml');
|
|
483
|
+
const document = await readDocument(file);
|
|
484
|
+
for (const effect of effects) {
|
|
485
|
+
const field = wireField(effect.field);
|
|
486
|
+
document.set(field, parsedValue(field, wireValue(effect.to)));
|
|
487
|
+
}
|
|
488
|
+
await atomicWrite(file, document.toString());
|
|
489
|
+
}
|
|
490
|
+
async function applyTransitionEvent(output, name, event) {
|
|
491
|
+
const { directory } = await stateFile(name);
|
|
492
|
+
const projection = await readClassicState(directory);
|
|
493
|
+
let classic = projection.classic;
|
|
494
|
+
let sparse = false;
|
|
495
|
+
if (!classic) {
|
|
496
|
+
if (projection.run)
|
|
497
|
+
fail('ERROR: Classic state projection is missing');
|
|
498
|
+
const document = await readDocument(path.join(directory, '.comet.yaml'));
|
|
499
|
+
classic = sparseClassicState(document.toJS());
|
|
500
|
+
sparse = true;
|
|
501
|
+
}
|
|
502
|
+
const result = applyClassicTransition(classic, event);
|
|
503
|
+
if (projection.run) {
|
|
504
|
+
await transitionClassicRuntimeRun(directory, result.classic, projection.run, {
|
|
505
|
+
event,
|
|
506
|
+
source: 'comet-state',
|
|
507
|
+
});
|
|
508
|
+
}
|
|
509
|
+
else if (sparse) {
|
|
510
|
+
await writeSparseTransitionEffects(directory, result.effects);
|
|
511
|
+
}
|
|
512
|
+
else {
|
|
513
|
+
await writeClassicState(directory, {
|
|
514
|
+
classic: result.classic,
|
|
515
|
+
run: null,
|
|
516
|
+
unknownKeys: projection.unknownKeys,
|
|
517
|
+
});
|
|
518
|
+
}
|
|
519
|
+
await appendClassicStateEvent(directory, {
|
|
520
|
+
change: name,
|
|
521
|
+
event,
|
|
522
|
+
source: 'comet-state',
|
|
523
|
+
from: classic,
|
|
524
|
+
to: result.classic,
|
|
525
|
+
effects: result.effects,
|
|
526
|
+
});
|
|
527
|
+
for (const effect of result.effects) {
|
|
528
|
+
output.stderr.push(green(`[SET] ${wireField(effect.field)}=${wireValue(effect.to)}`));
|
|
529
|
+
}
|
|
530
|
+
output.stderr.push(green(`[TRANSITION] ${event}`));
|
|
531
|
+
}
|
|
532
|
+
async function transition(output, name, event) {
|
|
533
|
+
validateChangeName(name);
|
|
534
|
+
validateEnum(event, EVENTS);
|
|
535
|
+
if (event === 'open-complete') {
|
|
536
|
+
await requirePhase(name, 'open');
|
|
537
|
+
await requireOpenArtifacts(name);
|
|
538
|
+
}
|
|
539
|
+
else if (event === 'design-complete') {
|
|
540
|
+
await requirePhase(name, 'design');
|
|
541
|
+
await requireDesignEvidence(name);
|
|
542
|
+
}
|
|
543
|
+
else if (event === 'build-complete') {
|
|
544
|
+
await requirePhase(name, 'build');
|
|
545
|
+
await requireBuildDecisions(name);
|
|
546
|
+
}
|
|
547
|
+
else if (event === 'verify-pass') {
|
|
548
|
+
await requirePhase(name, 'verify');
|
|
549
|
+
const report = await readField(name, 'verification_report');
|
|
550
|
+
if (!report || !(await exists(path.resolve(report)))) {
|
|
551
|
+
fail(`ERROR: Cannot transition '${name}': verification_report must point to an existing report file`);
|
|
552
|
+
}
|
|
553
|
+
if ((await readField(name, 'branch_status')) !== 'handled') {
|
|
554
|
+
fail(`ERROR: Cannot transition '${name}': branch_status must be handled`);
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
else if (event === 'verify-fail') {
|
|
558
|
+
await requirePhase(name, 'verify');
|
|
559
|
+
}
|
|
560
|
+
else if (event === 'preset-escalate') {
|
|
561
|
+
// preset (hotfix/tweak) → full: rewind phase to design so the agent can
|
|
562
|
+
// supplement a Design Doc before continuing. Unlike verify-fail /
|
|
563
|
+
// archive-reopen, this event also lifts workflow to full. classic_profile
|
|
564
|
+
// MUST be synced alongside workflow, otherwise classic-resolver.ts throws
|
|
565
|
+
// on the (phase=design, profile!=full) invariant — profileFor() reads
|
|
566
|
+
// classicProfile first, which stays at the old preset value otherwise.
|
|
567
|
+
await requirePhase(name, 'build');
|
|
568
|
+
const workflow = await readField(name, 'workflow');
|
|
569
|
+
if (!['hotfix', 'tweak'].includes(workflow)) {
|
|
570
|
+
fail(`ERROR: Cannot transition '${name}': preset-escalate only applies to hotfix/tweak, got workflow='${workflow}'`);
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
else if (event === 'archive-reopen') {
|
|
574
|
+
await requirePhase(name, 'archive');
|
|
575
|
+
if ((await readField(name, 'archived')) === 'true') {
|
|
576
|
+
fail(`ERROR: Cannot transition '${name}': already archived`);
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
else {
|
|
580
|
+
await requirePhase(name, 'archive');
|
|
581
|
+
if ((await readField(name, 'verify_result')) !== 'pass') {
|
|
582
|
+
fail(`ERROR: Cannot transition '${name}': verify_result must be pass before archiving`);
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
await applyTransitionEvent(output, name, event);
|
|
586
|
+
}
|
|
587
|
+
async function next(output, name) {
|
|
588
|
+
validateChangeName(name);
|
|
589
|
+
const { file, label } = await stateFile(name);
|
|
590
|
+
if (!(await exists(file)))
|
|
591
|
+
fail(`ERROR: .comet.yaml not found at ${label}/.comet.yaml`);
|
|
592
|
+
const phase = await readField(name, 'phase');
|
|
593
|
+
const workflow = await readField(name, 'workflow');
|
|
594
|
+
const automatic = await readField(name, 'auto_transition');
|
|
595
|
+
if ((await readField(name, 'archived')) === 'true') {
|
|
596
|
+
output.stdout.push('NEXT: done');
|
|
597
|
+
return;
|
|
598
|
+
}
|
|
599
|
+
const skill = phase === 'open'
|
|
600
|
+
? 'comet-open'
|
|
601
|
+
: phase === 'design'
|
|
602
|
+
? 'comet-design'
|
|
603
|
+
: phase === 'verify'
|
|
604
|
+
? 'comet-verify'
|
|
605
|
+
: phase === 'archive'
|
|
606
|
+
? 'comet-archive'
|
|
607
|
+
: phase === 'build'
|
|
608
|
+
? workflow === 'hotfix'
|
|
609
|
+
? 'comet-hotfix'
|
|
610
|
+
: workflow === 'tweak'
|
|
611
|
+
? 'comet-tweak'
|
|
612
|
+
: 'comet-build'
|
|
613
|
+
: null;
|
|
614
|
+
if (!skill) {
|
|
615
|
+
fail(`ERROR: Cannot resolve next step for '${name}': unknown phase '${phase || 'null'}'`);
|
|
616
|
+
}
|
|
617
|
+
output.stdout.push(`NEXT: ${automatic === 'false' ? 'manual' : 'auto'}`, `SKILL: ${skill}`);
|
|
618
|
+
if (automatic === 'false') {
|
|
619
|
+
output.stdout.push(`HINT: phase is '${phase}'; run /${skill} manually to continue`);
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
async function taskCheckoff(output, taskFile, taskText) {
|
|
623
|
+
validateRelativePath(taskFile, 'task file');
|
|
624
|
+
if (!taskText)
|
|
625
|
+
fail('ERROR: Task text cannot be empty');
|
|
626
|
+
const file = path.resolve(taskFile);
|
|
627
|
+
if (!(await exists(file)))
|
|
628
|
+
fail(`ERROR: Task file not found: ${taskFile}`);
|
|
629
|
+
const lines = (await fs.readFile(file, 'utf8')).split(/\r?\n/u);
|
|
630
|
+
const matches = lines.filter((line) => [`- [ ] ${taskText}`, `- [x] ${taskText}`, `- [X] ${taskText}`].includes(line));
|
|
631
|
+
const checked = matches.filter((line) => /^- \[[xX]\] /u.test(line));
|
|
632
|
+
if (matches.length !== 1) {
|
|
633
|
+
fail(`ERROR: task text must appear exactly once in ${taskFile} (found ${matches.length}): ${taskText}`);
|
|
634
|
+
}
|
|
635
|
+
if (checked.length !== 1)
|
|
636
|
+
fail(`ERROR: task is not checked in ${taskFile}: ${taskText}`);
|
|
637
|
+
output.stdout.push('TASK_CHECKOFF: PASS', `FILE: ${taskFile}`, `TASK: ${taskText}`);
|
|
638
|
+
}
|
|
639
|
+
async function check(output, name, phase) {
|
|
640
|
+
validateChangeName(name);
|
|
641
|
+
validateEnum(phase, PHASES);
|
|
642
|
+
const { file, directory, label } = await stateFile(name);
|
|
643
|
+
output.stdout.push(`=== Entry Check: comet-${phase} ===`);
|
|
644
|
+
if (!(await exists(file)))
|
|
645
|
+
fail(`ERROR: .comet.yaml not found at ${label}/.comet.yaml`);
|
|
646
|
+
let blocked = false;
|
|
647
|
+
const pass = (message) => output.stdout.push(` ${green('[PASS]')} ${message}`);
|
|
648
|
+
const reject = (message) => {
|
|
649
|
+
output.stdout.push(` ${red('[FAIL]')} ${message}`);
|
|
650
|
+
blocked = true;
|
|
651
|
+
};
|
|
652
|
+
const expectField = async (field, expected) => {
|
|
653
|
+
const actual = await readField(name, field);
|
|
654
|
+
(actual === expected ? pass : reject)(`${field}=${actual} (expected: ${expected})`);
|
|
655
|
+
};
|
|
656
|
+
pass('.comet.yaml exists');
|
|
657
|
+
await expectField('phase', phase);
|
|
658
|
+
if (phase === 'design') {
|
|
659
|
+
await expectField('workflow', 'full');
|
|
660
|
+
const designDoc = await readField(name, 'design_doc');
|
|
661
|
+
(!designDoc || designDoc === 'null' ? pass : reject)(designDoc ? `design_doc=${designDoc} (expected: empty/null)` : 'design_doc is empty/null');
|
|
662
|
+
for (const artifact of ['proposal.md', 'design.md', 'tasks.md']) {
|
|
663
|
+
((await nonempty(path.join(directory, artifact))) ? pass : reject)(`${artifact} ${(await nonempty(path.join(directory, artifact))) ? 'non-empty' : 'missing or empty'}`);
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
else if (phase === 'build') {
|
|
667
|
+
const workflow = await readField(name, 'workflow');
|
|
668
|
+
const designDoc = await readField(name, 'design_doc');
|
|
669
|
+
if (workflow === 'full') {
|
|
670
|
+
(designDoc && designDoc !== 'null' && (await exists(path.resolve(designDoc)))
|
|
671
|
+
? pass
|
|
672
|
+
: reject)(`design_doc=${designDoc} (expected: non-null and file exists)`);
|
|
673
|
+
}
|
|
674
|
+
else {
|
|
675
|
+
pass(`workflow=${workflow} (design_doc not required)`);
|
|
676
|
+
}
|
|
677
|
+
for (const artifact of ['proposal.md', 'tasks.md']) {
|
|
678
|
+
((await nonempty(path.join(directory, artifact))) ? pass : reject)(`${artifact} ${(await nonempty(path.join(directory, artifact))) ? 'non-empty' : 'missing or empty'}`);
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
else if (phase === 'verify') {
|
|
682
|
+
const value = await readField(name, 'verify_result');
|
|
683
|
+
(['', 'null', 'pending'].includes(value) ? pass : reject)(`verify_result=${value} (expected: pending or null)`);
|
|
684
|
+
}
|
|
685
|
+
else if (phase === 'archive') {
|
|
686
|
+
await expectField('verify_result', 'pass');
|
|
687
|
+
const archived = await readField(name, 'archived');
|
|
688
|
+
(archived !== 'true' ? pass : reject)(`archived=${archived} (expected: not true)`);
|
|
689
|
+
}
|
|
690
|
+
output.stdout.push('');
|
|
691
|
+
if (blocked) {
|
|
692
|
+
output.stderr.push(red('BLOCKED — fix failing checks before proceeding'));
|
|
693
|
+
throw new CommandFailure('', 1);
|
|
694
|
+
}
|
|
695
|
+
output.stderr.push(green('ALL CHECKS PASSED — ready to proceed'));
|
|
696
|
+
}
|
|
697
|
+
function fieldStatus(field, value, file) {
|
|
698
|
+
if (!value || value === 'null')
|
|
699
|
+
return ` - ${field}: PENDING`;
|
|
700
|
+
if (file && !existsSync(path.resolve(file))) {
|
|
701
|
+
return ` - ${field}: BROKEN (path ${value} does not exist)`;
|
|
702
|
+
}
|
|
703
|
+
return ` - ${field}: DONE (${value})`;
|
|
704
|
+
}
|
|
705
|
+
async function recoverOpen(output, directory) {
|
|
706
|
+
output.stdout.push(' Artifacts:');
|
|
707
|
+
let complete = 0;
|
|
708
|
+
for (const artifact of ['proposal.md', 'design.md', 'tasks.md']) {
|
|
709
|
+
const done = await nonempty(path.join(directory, artifact));
|
|
710
|
+
if (done)
|
|
711
|
+
complete += 1;
|
|
712
|
+
output.stdout.push(` - ${artifact}: ${done ? 'DONE' : 'PENDING'}`);
|
|
713
|
+
}
|
|
714
|
+
output.stdout.push('', complete === 3
|
|
715
|
+
? 'Recovery action: All artifacts complete. Run /comet-open user confirmation, then guard to transition.'
|
|
716
|
+
: complete === 0
|
|
717
|
+
? 'Recovery action: No artifacts created yet. Start from /comet-open Step 1 (explore and clarify).'
|
|
718
|
+
: 'Recovery action: Some artifacts incomplete. Resume /comet-open from the first missing artifact.');
|
|
719
|
+
}
|
|
720
|
+
async function recoverDesign(output, name, directory) {
|
|
721
|
+
output.stdout.push(' Artifacts:');
|
|
722
|
+
for (const artifact of ['proposal.md', 'design.md', 'tasks.md']) {
|
|
723
|
+
output.stdout.push(` - ${artifact}: ${(await nonempty(path.join(directory, artifact))) ? 'DONE' : 'MISSING (unexpected in design phase)'}`);
|
|
724
|
+
}
|
|
725
|
+
const handoff = await readField(name, 'handoff_context');
|
|
726
|
+
const hash = await readField(name, 'handoff_hash');
|
|
727
|
+
const design = await readField(name, 'design_doc');
|
|
728
|
+
output.stdout.push('', ' Design progress:', fieldStatus('handoff_context', handoff, handoff), fieldStatus('handoff_hash', hash), fieldStatus('design_doc', design, design), '');
|
|
729
|
+
if (design && design !== 'null' && (await exists(path.resolve(design)))) {
|
|
730
|
+
output.stdout.push('Recovery action: Design Doc already created and linked. Run guard to transition to build.');
|
|
731
|
+
}
|
|
732
|
+
else if (handoff && handoff !== 'null' && (await exists(path.resolve(handoff)))) {
|
|
733
|
+
output.stdout.push('Recovery action: Handoff generated but Design Doc not yet created. Resume from brainstorming confirmation (Step 1c).');
|
|
734
|
+
}
|
|
735
|
+
else {
|
|
736
|
+
output.stdout.push('Recovery action: No handoff generated yet. Start from Step 1a (generate handoff package).');
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
async function recoverBuild(output, name, directory, workflow) {
|
|
740
|
+
const isolation = await readField(name, 'isolation');
|
|
741
|
+
const buildMode = await readField(name, 'build_mode');
|
|
742
|
+
const pause = await readField(name, 'build_pause');
|
|
743
|
+
const subagentDispatch = await readField(name, 'subagent_dispatch');
|
|
744
|
+
const tdd = await readField(name, 'tdd_mode');
|
|
745
|
+
const review = await readField(name, 'review_mode');
|
|
746
|
+
const plan = await readField(name, 'plan');
|
|
747
|
+
const decisions = [
|
|
748
|
+
' Build decisions:',
|
|
749
|
+
fieldStatus('isolation', isolation),
|
|
750
|
+
fieldStatus('build_mode', buildMode),
|
|
751
|
+
fieldStatus('build_pause', pause),
|
|
752
|
+
fieldStatus('tdd_mode', tdd),
|
|
753
|
+
fieldStatus('review_mode', review),
|
|
754
|
+
];
|
|
755
|
+
if (buildMode === 'subagent-driven-development' ||
|
|
756
|
+
(subagentDispatch && subagentDispatch !== 'null')) {
|
|
757
|
+
decisions.push(fieldStatus('subagent_dispatch', subagentDispatch));
|
|
758
|
+
}
|
|
759
|
+
output.stdout.push(...decisions, '', ' Plan:', fieldStatus('plan', plan, plan), '');
|
|
760
|
+
const tasks = path.join(directory, 'tasks.md');
|
|
761
|
+
if (!(await exists(tasks))) {
|
|
762
|
+
output.stdout.push(' Tasks: tasks.md MISSING', '', 'Recovery action: tasks.md missing. Verify change directory integrity.');
|
|
763
|
+
return;
|
|
764
|
+
}
|
|
765
|
+
const lines = (await fs.readFile(tasks, 'utf8')).split(/\r?\n/u);
|
|
766
|
+
const total = lines.filter((line) => /^\s*- \[[ xX]\] /u.test(line)).length;
|
|
767
|
+
const done = lines.filter((line) => /^\s*- \[[xX]\] /u.test(line)).length;
|
|
768
|
+
const pending = total - done;
|
|
769
|
+
let planTotal = 0;
|
|
770
|
+
let planDone = 0;
|
|
771
|
+
if (plan && plan !== 'null' && (await exists(path.resolve(plan)))) {
|
|
772
|
+
const planLines = (await fs.readFile(path.resolve(plan), 'utf8')).split(/\r?\n/u);
|
|
773
|
+
planTotal = planLines.filter((line) => /^\s*- \[[ xX]\] /u.test(line)).length;
|
|
774
|
+
planDone = planLines.filter((line) => /^\s*- \[[xX]\] /u.test(line)).length;
|
|
775
|
+
}
|
|
776
|
+
const planPending = planTotal - planDone;
|
|
777
|
+
output.stdout.push(` Tasks: ${done}/${total} done, ${pending} pending`);
|
|
778
|
+
if (planTotal > 0) {
|
|
779
|
+
output.stdout.push(` Plan tasks: ${planDone}/${planTotal} done, ${planPending} pending`);
|
|
780
|
+
}
|
|
781
|
+
output.stdout.push('');
|
|
782
|
+
const action = resolveBuildRecoveryAction(workflow, isolation, buildMode, pause, subagentDispatch, tdd, review, plan, pending, planPending);
|
|
783
|
+
output.stdout.push(action);
|
|
784
|
+
}
|
|
785
|
+
function isMissingStateValue(value) {
|
|
786
|
+
return !value || value === 'null';
|
|
787
|
+
}
|
|
788
|
+
function resolveBuildRecoveryAction(workflow, isolation, buildMode, pause, subagentDispatch, tdd, review, plan, pending, planPending) {
|
|
789
|
+
const planExists = plan && plan !== 'null';
|
|
790
|
+
const missingWorkflowChoices = workflow === 'full' && (isMissingStateValue(tdd) || isMissingStateValue(review));
|
|
791
|
+
if (pause === 'plan-ready' &&
|
|
792
|
+
planExists &&
|
|
793
|
+
(isMissingStateValue(isolation) || isMissingStateValue(buildMode) || missingWorkflowChoices)) {
|
|
794
|
+
return workflow === 'full'
|
|
795
|
+
? 'Recovery action: Plan-ready pause detected. Ask the user whether to continue, then choose isolation, build mode, TDD mode, and review mode without regenerating the plan.'
|
|
796
|
+
: 'Recovery action: Plan-ready pause detected. Ask the user whether to continue, then choose isolation and build mode without regenerating the plan.';
|
|
797
|
+
}
|
|
798
|
+
if (pause === 'plan-ready' && !planExists) {
|
|
799
|
+
return 'Recovery action: Plan-ready pause is recorded, but the plan file is missing. Restore the plan file or rerun writing-plans before choosing execution.';
|
|
800
|
+
}
|
|
801
|
+
if (pause === 'plan-ready') {
|
|
802
|
+
if (buildMode === 'subagent-driven-development' && (pending > 0 || planPending > 0)) {
|
|
803
|
+
return subagentDispatch === 'confirmed'
|
|
804
|
+
? 'Recovery action: Plan-ready pause is stale because build decisions are already selected. Clear build_pause to null, then inspect the first unchecked task (OpenSpec or plan additions) against recent git history/diff. If implemented, check it off; otherwise dispatch a real background subagent. Do not execute the pending task directly in the main window.'
|
|
805
|
+
: 'Recovery action: Plan-ready pause is stale and subagent dispatch is not confirmed. Confirm a real background subagent/Task/multi-agent dispatcher and set subagent_dispatch to confirmed, or set build_mode to executing-plans before continuing.';
|
|
806
|
+
}
|
|
807
|
+
if (pending > 0 || planPending > 0) {
|
|
808
|
+
return 'Recovery action: Plan-ready pause is stale because build decisions are already selected. Clear build_pause to null, then continue from the first unchecked task.';
|
|
809
|
+
}
|
|
810
|
+
return 'Recovery action: Plan-ready pause is stale and all tasks are done. Clear build_pause to null, then run guard to transition to verify.';
|
|
811
|
+
}
|
|
812
|
+
if (isMissingStateValue(isolation)) {
|
|
813
|
+
return "Recovery action: Isolation not selected. Use the current platform's user confirmation mechanism to ask user for branch/worktree choice.";
|
|
814
|
+
}
|
|
815
|
+
if (isMissingStateValue(buildMode)) {
|
|
816
|
+
return "Recovery action: Build mode not selected. Use the current platform's user confirmation mechanism to ask user for execution method.";
|
|
817
|
+
}
|
|
818
|
+
if (workflow === 'full' && isMissingStateValue(tdd)) {
|
|
819
|
+
return "Recovery action: TDD mode not selected. Use the current platform's user confirmation mechanism to ask user for tdd or direct.";
|
|
820
|
+
}
|
|
821
|
+
if (workflow === 'full' && isMissingStateValue(review)) {
|
|
822
|
+
return "Recovery action: Review mode not selected. Use the current platform's user confirmation mechanism to ask user for off, standard, or thorough.";
|
|
823
|
+
}
|
|
824
|
+
if (pending > 0) {
|
|
825
|
+
if (buildMode === 'subagent-driven-development') {
|
|
826
|
+
return subagentDispatch === 'confirmed'
|
|
827
|
+
? 'Recovery action: Read tasks.md and the Superpowers plan (which may include additions beyond OpenSpec), then inspect the first unchecked task against recent git history/diff. If implemented, check it off; otherwise dispatch a real background subagent. Do not execute the pending task directly in the main window.'
|
|
828
|
+
: 'Recovery action: Subagent dispatch is not confirmed. Confirm a real background subagent/Task/multi-agent dispatcher and set subagent_dispatch to confirmed, or set build_mode to executing-plans before continuing.';
|
|
829
|
+
}
|
|
830
|
+
return 'Recovery action: Read tasks.md and continue from first unchecked task.';
|
|
831
|
+
}
|
|
832
|
+
if (planPending > 0) {
|
|
833
|
+
if (buildMode === 'subagent-driven-development') {
|
|
834
|
+
return subagentDispatch === 'confirmed'
|
|
835
|
+
? 'Recovery action: Read the Superpowers plan, then inspect the first unchecked Superpowers plan task against recent git history/diff. If implemented, check it off; otherwise dispatch a real background subagent. Do not execute the pending task directly in the main window.'
|
|
836
|
+
: 'Recovery action: Subagent dispatch is not confirmed. Confirm a real background subagent/Task/multi-agent dispatcher and set subagent_dispatch to confirmed, or set build_mode to executing-plans before continuing.';
|
|
837
|
+
}
|
|
838
|
+
return 'Recovery action: Read the Superpowers plan and continue from the first unchecked plan task.';
|
|
839
|
+
}
|
|
840
|
+
return 'Recovery action: All tasks done. Run guard to transition to verify.';
|
|
841
|
+
}
|
|
842
|
+
async function recoverVerify(output, name) {
|
|
843
|
+
const result = await readField(name, 'verify_result');
|
|
844
|
+
const mode = await readField(name, 'verify_mode');
|
|
845
|
+
const report = await readField(name, 'verification_report');
|
|
846
|
+
const branch = await readField(name, 'branch_status');
|
|
847
|
+
output.stdout.push(' Verification:', fieldStatus('verify_result', result), fieldStatus('verify_mode', mode), fieldStatus('verification_report', report, report), fieldStatus('branch_status', branch), '', result === 'pass' && branch === 'handled'
|
|
848
|
+
? 'Recovery action: Verification complete. Run guard to transition to archive.'
|
|
849
|
+
: result === 'fail'
|
|
850
|
+
? 'Recovery action: Verification failed and rolled back to build. Resume from /comet-build.'
|
|
851
|
+
: 'Recovery action: Verification not yet started or in progress. Run scale assessment then verify.');
|
|
852
|
+
}
|
|
853
|
+
async function recoverArchive(output, name) {
|
|
854
|
+
output.stdout.push(' Archive:', fieldStatus('verify_result', await readField(name, 'verify_result')), fieldStatus('archived', await readField(name, 'archived')), '', 'Recovery action: Run /comet-archive to complete archiving.');
|
|
855
|
+
}
|
|
856
|
+
async function recover(output, name) {
|
|
857
|
+
validateChangeName(name);
|
|
858
|
+
const { file, directory, label } = await stateFile(name);
|
|
859
|
+
if (!(await exists(file)))
|
|
860
|
+
fail(`ERROR: .comet.yaml not found at ${label}/.comet.yaml`);
|
|
861
|
+
const phase = await readField(name, 'phase');
|
|
862
|
+
const workflow = await readField(name, 'workflow');
|
|
863
|
+
output.stdout.push(`=== Recovery Context: ${name} ===`, `Phase: ${phase}`, `Workflow: ${workflow}`, '', 'State fields:');
|
|
864
|
+
if (phase === 'open') {
|
|
865
|
+
await recoverOpen(output, directory);
|
|
866
|
+
}
|
|
867
|
+
else if (phase === 'design') {
|
|
868
|
+
await recoverDesign(output, name, directory);
|
|
869
|
+
}
|
|
870
|
+
else if (phase === 'build') {
|
|
871
|
+
await recoverBuild(output, name, directory, workflow);
|
|
872
|
+
}
|
|
873
|
+
else if (phase === 'verify') {
|
|
874
|
+
await recoverVerify(output, name);
|
|
875
|
+
}
|
|
876
|
+
else if (phase === 'archive') {
|
|
877
|
+
await recoverArchive(output, name);
|
|
878
|
+
}
|
|
879
|
+
else {
|
|
880
|
+
fail(`ERROR: Unknown phase: ${phase}`);
|
|
881
|
+
}
|
|
882
|
+
output.stdout.push('', '=== End Recovery Context ===');
|
|
883
|
+
}
|
|
884
|
+
async function scale(output, name) {
|
|
885
|
+
validateChangeName(name);
|
|
886
|
+
const { file, directory, label } = await stateFile(name);
|
|
887
|
+
if (!(await exists(file)))
|
|
888
|
+
fail(`ERROR: .comet.yaml not found at ${label}/.comet.yaml`);
|
|
889
|
+
const tasksFile = path.join(directory, 'tasks.md');
|
|
890
|
+
const taskCount = (await exists(tasksFile))
|
|
891
|
+
? (await fs.readFile(tasksFile, 'utf8')).split(/\r?\n/u).filter((line) => /^- \[/u.test(line))
|
|
892
|
+
.length
|
|
893
|
+
: 0;
|
|
894
|
+
const specs = path.join(directory, 'specs');
|
|
895
|
+
let deltaSpecs = 0;
|
|
896
|
+
if (await exists(specs)) {
|
|
897
|
+
for (const entry of await fs.readdir(specs)) {
|
|
898
|
+
if (await exists(path.join(specs, entry, 'spec.md')))
|
|
899
|
+
deltaSpecs += 1;
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
const plan = await readField(name, 'plan');
|
|
903
|
+
let baseRef = '';
|
|
904
|
+
if (plan && plan !== 'null' && (await exists(path.resolve(plan)))) {
|
|
905
|
+
const match = (await fs.readFile(path.resolve(plan), 'utf8')).match(/^base-ref:\s*(.+)$/mu);
|
|
906
|
+
baseRef = match?.[1].trim() ?? '';
|
|
907
|
+
}
|
|
908
|
+
if (!baseRef)
|
|
909
|
+
baseRef = await readField(name, 'base_ref');
|
|
910
|
+
const changed = gitOutput([
|
|
911
|
+
'diff',
|
|
912
|
+
'--name-only',
|
|
913
|
+
...(baseRef && baseRef !== 'null' ? [`${baseRef}...HEAD`] : ['HEAD']),
|
|
914
|
+
]);
|
|
915
|
+
const changedFiles = changed ? changed.split(/\r?\n/u).filter(Boolean).length : 0;
|
|
916
|
+
const result = taskCount > 3 || deltaSpecs > 1 || changedFiles > 8 ? 'full' : 'light';
|
|
917
|
+
await setField(new CommandOutput(), name, 'verify_mode', result);
|
|
918
|
+
output.stderr.push(`=== Scale Assessment: ${name} ===`, ` Tasks: ${taskCount} (threshold: 3)`, ` Delta specs: ${deltaSpecs} capabilities (threshold: 1)`, ` Changed files: ${changedFiles} (threshold: 8)`, ` → Result: ${result}`, green(`[SCALE] verify_mode=${result}`));
|
|
919
|
+
}
|
|
920
|
+
function required(args, count, usage) {
|
|
921
|
+
if (args.length < count)
|
|
922
|
+
fail(usage);
|
|
923
|
+
}
|
|
924
|
+
export const classicStateCommand = async (args) => {
|
|
925
|
+
const output = new CommandOutput();
|
|
926
|
+
try {
|
|
927
|
+
const [subcommand, ...rest] = args;
|
|
928
|
+
if (subcommand === 'init') {
|
|
929
|
+
required(rest, 2, 'Usage: comet-state.mjs init <change-name> <workflow>');
|
|
930
|
+
await init(output, rest[0], rest[1]);
|
|
931
|
+
}
|
|
932
|
+
else if (subcommand === 'get') {
|
|
933
|
+
required(rest, 2, 'Usage: comet-state.mjs get <change-name> <field>');
|
|
934
|
+
validateChangeName(rest[0]);
|
|
935
|
+
output.stdout.push(await readField(rest[0], rest[1]));
|
|
936
|
+
}
|
|
937
|
+
else if (subcommand === 'set') {
|
|
938
|
+
required(rest, 3, 'Usage: comet-state.mjs set <change-name> <field> <value>');
|
|
939
|
+
validateChangeName(rest[0]);
|
|
940
|
+
await setField(output, rest[0], rest[1], rest[2]);
|
|
941
|
+
}
|
|
942
|
+
else if (subcommand === 'transition') {
|
|
943
|
+
required(rest, 2, 'Usage: comet-state.mjs transition <change-name> <event>');
|
|
944
|
+
await transition(output, rest[0], rest[1]);
|
|
945
|
+
}
|
|
946
|
+
else if (subcommand === 'check') {
|
|
947
|
+
required(rest, 2, 'Usage: comet-state.mjs check <change-name> <phase> [--recover]');
|
|
948
|
+
if (rest[2] === '--recover')
|
|
949
|
+
await recover(output, rest[0]);
|
|
950
|
+
else
|
|
951
|
+
await check(output, rest[0], rest[1]);
|
|
952
|
+
}
|
|
953
|
+
else if (subcommand === 'scale') {
|
|
954
|
+
required(rest, 1, 'Usage: comet-state.mjs scale <change-name>');
|
|
955
|
+
await scale(output, rest[0]);
|
|
956
|
+
}
|
|
957
|
+
else if (subcommand === 'task-checkoff') {
|
|
958
|
+
required(rest, 2, 'Usage: comet-state.mjs task-checkoff <file> <task-text>');
|
|
959
|
+
await taskCheckoff(output, rest[0], rest[1]);
|
|
960
|
+
}
|
|
961
|
+
else if (subcommand === 'next') {
|
|
962
|
+
required(rest, 1, 'Usage: comet-state.mjs next <change-name>');
|
|
963
|
+
await next(output, rest[0]);
|
|
964
|
+
}
|
|
965
|
+
else {
|
|
966
|
+
fail(`Unknown subcommand: ${subcommand ?? ''}`);
|
|
967
|
+
}
|
|
968
|
+
return output.result();
|
|
969
|
+
}
|
|
970
|
+
catch (error) {
|
|
971
|
+
if (!(error instanceof CommandFailure))
|
|
972
|
+
throw error;
|
|
973
|
+
// The frozen 0.3.8 shell calls red() once per line and never embeds newlines
|
|
974
|
+
// inside a single color call. Mirror that contract by wrapping each line of
|
|
975
|
+
// the message in its own span so multi-line errors (e.g. validateEnum) render
|
|
976
|
+
// as separate colored lines rather than one span across a newline.
|
|
977
|
+
if (error.message) {
|
|
978
|
+
for (const line of error.message.split('\n'))
|
|
979
|
+
output.stderr.push(red(line));
|
|
980
|
+
}
|
|
981
|
+
return output.result(error.exitCode);
|
|
982
|
+
}
|
|
983
|
+
};
|
|
984
|
+
//# sourceMappingURL=classic-state-command.js.map
|