@niujiajie/freespec 0.0.0-stage → 1.15.0
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 +22 -0
- package/README.md +58 -2
- package/bin/freespec.js +5 -0
- package/dist/cli/index.d.ts +25 -0
- package/dist/cli/index.js +359 -0
- package/dist/commands/shared-output.d.ts +18 -0
- package/dist/commands/shared-output.js +61 -0
- package/dist/commands/workflow/default-schema.d.ts +2 -0
- package/dist/commands/workflow/default-schema.js +4 -0
- package/dist/commands/workflow/index.d.ts +13 -0
- package/dist/commands/workflow/index.js +10 -0
- package/dist/commands/workflow/instructions.d.ts +39 -0
- package/dist/commands/workflow/instructions.js +565 -0
- package/dist/commands/workflow/new-change.d.ts +19 -0
- package/dist/commands/workflow/new-change.js +135 -0
- package/dist/commands/workflow/shared.d.ts +94 -0
- package/dist/commands/workflow/shared.js +169 -0
- package/dist/commands/workflow/status.d.ts +18 -0
- package/dist/commands/workflow/status.js +201 -0
- package/dist/core/artifact-graph/graph.d.ts +72 -0
- package/dist/core/artifact-graph/graph.js +165 -0
- package/dist/core/artifact-graph/index.d.ts +9 -0
- package/dist/core/artifact-graph/index.js +14 -0
- package/dist/core/artifact-graph/instruction-loader.d.ts +208 -0
- package/dist/core/artifact-graph/instruction-loader.js +268 -0
- package/dist/core/artifact-graph/outputs.d.ts +19 -0
- package/dist/core/artifact-graph/outputs.js +351 -0
- package/dist/core/artifact-graph/resolver.d.ts +89 -0
- package/dist/core/artifact-graph/resolver.js +342 -0
- package/dist/core/artifact-graph/schema.d.ts +27 -0
- package/dist/core/artifact-graph/schema.js +160 -0
- package/dist/core/artifact-graph/state.d.ts +12 -0
- package/dist/core/artifact-graph/state.js +31 -0
- package/dist/core/artifact-graph/types.d.ts +40 -0
- package/dist/core/artifact-graph/types.js +59 -0
- package/dist/core/available-tools.d.ts +18 -0
- package/dist/core/available-tools.js +49 -0
- package/dist/core/change-layout.d.ts +17 -0
- package/dist/core/change-layout.js +30 -0
- package/dist/core/change-metadata/index.d.ts +2 -0
- package/dist/core/change-metadata/index.js +2 -0
- package/dist/core/change-metadata/schema.d.ts +23 -0
- package/dist/core/change-metadata/schema.js +46 -0
- package/dist/core/change-status-policy.d.ts +49 -0
- package/dist/core/change-status-policy.js +50 -0
- package/dist/core/command-generation/adapters/amazon-q.d.ts +17 -0
- package/dist/core/command-generation/adapters/amazon-q.js +32 -0
- package/dist/core/command-generation/adapters/antigravity.d.ts +13 -0
- package/dist/core/command-generation/adapters/antigravity.js +27 -0
- package/dist/core/command-generation/adapters/atomcode.d.ts +24 -0
- package/dist/core/command-generation/adapters/atomcode.js +46 -0
- package/dist/core/command-generation/adapters/auggie.d.ts +13 -0
- package/dist/core/command-generation/adapters/auggie.js +28 -0
- package/dist/core/command-generation/adapters/bob.d.ts +18 -0
- package/dist/core/command-generation/adapters/bob.js +33 -0
- package/dist/core/command-generation/adapters/claude.d.ts +13 -0
- package/dist/core/command-generation/adapters/claude.js +32 -0
- package/dist/core/command-generation/adapters/cline.d.ts +14 -0
- package/dist/core/command-generation/adapters/cline.js +27 -0
- package/dist/core/command-generation/adapters/codeassistant.d.ts +15 -0
- package/dist/core/command-generation/adapters/codeassistant.js +29 -0
- package/dist/core/command-generation/adapters/codebuddy.d.ts +13 -0
- package/dist/core/command-generation/adapters/codebuddy.js +29 -0
- package/dist/core/command-generation/adapters/codestudio.d.ts +13 -0
- package/dist/core/command-generation/adapters/codestudio.js +27 -0
- package/dist/core/command-generation/adapters/command-code.d.ts +19 -0
- package/dist/core/command-generation/adapters/command-code.js +34 -0
- package/dist/core/command-generation/adapters/continue.d.ts +13 -0
- package/dist/core/command-generation/adapters/continue.js +33 -0
- package/dist/core/command-generation/adapters/costrict.d.ts +13 -0
- package/dist/core/command-generation/adapters/costrict.js +28 -0
- package/dist/core/command-generation/adapters/crush.d.ts +13 -0
- package/dist/core/command-generation/adapters/crush.js +30 -0
- package/dist/core/command-generation/adapters/cursor.d.ts +14 -0
- package/dist/core/command-generation/adapters/cursor.js +31 -0
- package/dist/core/command-generation/adapters/devin.d.ts +19 -0
- package/dist/core/command-generation/adapters/devin.js +36 -0
- package/dist/core/command-generation/adapters/easycode.d.ts +17 -0
- package/dist/core/command-generation/adapters/easycode.js +28 -0
- package/dist/core/command-generation/adapters/factory.d.ts +13 -0
- package/dist/core/command-generation/adapters/factory.js +28 -0
- package/dist/core/command-generation/adapters/gemini.d.ts +13 -0
- package/dist/core/command-generation/adapters/gemini.js +27 -0
- package/dist/core/command-generation/adapters/gigacode.d.ts +17 -0
- package/dist/core/command-generation/adapters/gigacode.js +31 -0
- package/dist/core/command-generation/adapters/github-copilot.d.ts +13 -0
- package/dist/core/command-generation/adapters/github-copilot.js +27 -0
- package/dist/core/command-generation/adapters/iflow.d.ts +13 -0
- package/dist/core/command-generation/adapters/iflow.js +30 -0
- package/dist/core/command-generation/adapters/index.d.ts +40 -0
- package/dist/core/command-generation/adapters/index.js +40 -0
- package/dist/core/command-generation/adapters/junie.d.ts +13 -0
- package/dist/core/command-generation/adapters/junie.js +27 -0
- package/dist/core/command-generation/adapters/kilocode.d.ts +14 -0
- package/dist/core/command-generation/adapters/kilocode.js +23 -0
- package/dist/core/command-generation/adapters/kiro.d.ts +13 -0
- package/dist/core/command-generation/adapters/kiro.js +27 -0
- package/dist/core/command-generation/adapters/lingma.d.ts +13 -0
- package/dist/core/command-generation/adapters/lingma.js +30 -0
- package/dist/core/command-generation/adapters/oh-my-pi.d.ts +21 -0
- package/dist/core/command-generation/adapters/oh-my-pi.js +42 -0
- package/dist/core/command-generation/adapters/opencode.d.ts +14 -0
- package/dist/core/command-generation/adapters/opencode.js +38 -0
- package/dist/core/command-generation/adapters/pi.d.ts +18 -0
- package/dist/core/command-generation/adapters/pi.js +39 -0
- package/dist/core/command-generation/adapters/qoder.d.ts +13 -0
- package/dist/core/command-generation/adapters/qoder.js +30 -0
- package/dist/core/command-generation/adapters/qwen.d.ts +17 -0
- package/dist/core/command-generation/adapters/qwen.js +31 -0
- package/dist/core/command-generation/adapters/roocode.d.ts +14 -0
- package/dist/core/command-generation/adapters/roocode.js +27 -0
- package/dist/core/command-generation/adapters/trae.d.ts +13 -0
- package/dist/core/command-generation/adapters/trae.js +28 -0
- package/dist/core/command-generation/adapters/zcode.d.ts +16 -0
- package/dist/core/command-generation/adapters/zcode.js +33 -0
- package/dist/core/command-generation/generator.d.ts +29 -0
- package/dist/core/command-generation/generator.js +43 -0
- package/dist/core/command-generation/index.d.ts +22 -0
- package/dist/core/command-generation/index.js +24 -0
- package/dist/core/command-generation/invocation.d.ts +73 -0
- package/dist/core/command-generation/invocation.js +77 -0
- package/dist/core/command-generation/registry.d.ts +36 -0
- package/dist/core/command-generation/registry.js +114 -0
- package/dist/core/command-generation/toml.d.ts +19 -0
- package/dist/core/command-generation/toml.js +39 -0
- package/dist/core/command-generation/types.d.ts +63 -0
- package/dist/core/command-generation/types.js +8 -0
- package/dist/core/command-generation/yaml.d.ts +36 -0
- package/dist/core/command-generation/yaml.js +48 -0
- package/dist/core/command-surface.d.ts +15 -0
- package/dist/core/command-surface.js +33 -0
- package/dist/core/config-prompts.d.ts +9 -0
- package/dist/core/config-prompts.js +56 -0
- package/dist/core/config-schema.d.ts +98 -0
- package/dist/core/config-schema.js +308 -0
- package/dist/core/config.d.ts +50 -0
- package/dist/core/config.js +122 -0
- package/dist/core/file-state.d.ts +36 -0
- package/dist/core/file-state.js +144 -0
- package/dist/core/file-view.d.ts +13 -0
- package/dist/core/file-view.js +14 -0
- package/dist/core/global-config.d.ts +101 -0
- package/dist/core/global-config.js +182 -0
- package/dist/core/id.d.ts +17 -0
- package/dist/core/id.js +30 -0
- package/dist/core/index.d.ts +6 -0
- package/dist/core/index.js +7 -0
- package/dist/core/init.d.ts +57 -0
- package/dist/core/init.js +836 -0
- package/dist/core/list.d.ts +11 -0
- package/dist/core/list.js +197 -0
- package/dist/core/migration.d.ts +121 -0
- package/dist/core/migration.js +540 -0
- package/dist/core/onboarding-commands.d.ts +30 -0
- package/dist/core/onboarding-commands.js +38 -0
- package/dist/core/openspec-root.d.ts +47 -0
- package/dist/core/openspec-root.js +196 -0
- package/dist/core/planning-home.d.ts +16 -0
- package/dist/core/planning-home.js +67 -0
- package/dist/core/profile-sync-drift.d.ts +31 -0
- package/dist/core/profile-sync-drift.js +201 -0
- package/dist/core/profiles.d.ts +19 -0
- package/dist/core/profiles.js +33 -0
- package/dist/core/project-config.d.ts +132 -0
- package/dist/core/project-config.js +519 -0
- package/dist/core/references.d.ts +10 -0
- package/dist/core/references.js +46 -0
- package/dist/core/root-selection.d.ts +59 -0
- package/dist/core/root-selection.js +132 -0
- package/dist/core/shared/allowed-tools.d.ts +12 -0
- package/dist/core/shared/allowed-tools.js +12 -0
- package/dist/core/shared/ide-restart.d.ts +26 -0
- package/dist/core/shared/ide-restart.js +42 -0
- package/dist/core/shared/index.d.ts +11 -0
- package/dist/core/shared/index.js +11 -0
- package/dist/core/shared/skill-content-equivalence.d.ts +7 -0
- package/dist/core/shared/skill-content-equivalence.js +45 -0
- package/dist/core/shared/skill-files.d.ts +7 -0
- package/dist/core/shared/skill-files.js +43 -0
- package/dist/core/shared/skill-generation.d.ts +49 -0
- package/dist/core/shared/skill-generation.js +125 -0
- package/dist/core/shared/skill-paths.d.ts +13 -0
- package/dist/core/shared/skill-paths.js +23 -0
- package/dist/core/shared/tool-detection.d.ts +99 -0
- package/dist/core/shared/tool-detection.js +318 -0
- package/dist/core/shared-skill-target.d.ts +51 -0
- package/dist/core/shared-skill-target.js +239 -0
- package/dist/core/store/errors.d.ts +20 -0
- package/dist/core/store/errors.js +22 -0
- package/dist/core/store/index.d.ts +2 -0
- package/dist/core/store/index.js +2 -0
- package/dist/core/styles/palette.d.ts +7 -0
- package/dist/core/styles/palette.js +8 -0
- package/dist/core/templates/optional-workflow.d.ts +69 -0
- package/dist/core/templates/optional-workflow.js +140 -0
- package/dist/core/templates/types.d.ts +19 -0
- package/dist/core/templates/types.js +5 -0
- package/dist/core/templates/workflows/personal.d.ts +22 -0
- package/dist/core/templates/workflows/personal.js +225 -0
- package/dist/core/update-plan.d.ts +127 -0
- package/dist/core/update-plan.js +390 -0
- package/dist/core/update.d.ts +154 -0
- package/dist/core/update.js +723 -0
- package/dist/core/version-check.d.ts +188 -0
- package/dist/core/version-check.js +906 -0
- package/dist/core/zod-issues.d.ts +4 -0
- package/dist/core/zod-issues.js +10 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/prompts/searchable-multi-select.d.ts +35 -0
- package/dist/prompts/searchable-multi-select.js +188 -0
- package/dist/telemetry/config.d.ts +37 -0
- package/dist/telemetry/config.js +148 -0
- package/dist/telemetry/index.d.ts +39 -0
- package/dist/telemetry/index.js +217 -0
- package/dist/telemetry/opt-out.d.ts +17 -0
- package/dist/telemetry/opt-out.js +27 -0
- package/dist/ui/ascii-patterns.d.ts +16 -0
- package/dist/ui/ascii-patterns.js +133 -0
- package/dist/ui/welcome-screen.d.ts +18 -0
- package/dist/ui/welcome-screen.js +199 -0
- package/dist/utils/change-metadata.d.ts +116 -0
- package/dist/utils/change-metadata.js +324 -0
- package/dist/utils/change-utils.d.ts +79 -0
- package/dist/utils/change-utils.js +121 -0
- package/dist/utils/ci.d.ts +12 -0
- package/dist/utils/ci.js +16 -0
- package/dist/utils/command-references.d.ts +104 -0
- package/dist/utils/command-references.js +190 -0
- package/dist/utils/date.d.ts +8 -0
- package/dist/utils/date.js +13 -0
- package/dist/utils/executable-path.d.ts +5 -0
- package/dist/utils/executable-path.js +44 -0
- package/dist/utils/file-system.d.ts +58 -0
- package/dist/utils/file-system.js +432 -0
- package/dist/utils/index.d.ts +6 -0
- package/dist/utils/index.js +9 -0
- package/dist/utils/interactive.d.ts +85 -0
- package/dist/utils/interactive.js +174 -0
- package/dist/utils/item-discovery.d.ts +15 -0
- package/dist/utils/item-discovery.js +33 -0
- package/dist/utils/line-endings.d.ts +34 -0
- package/dist/utils/line-endings.js +46 -0
- package/dist/utils/match.d.ts +3 -0
- package/dist/utils/match.js +22 -0
- package/dist/utils/nested-change.d.ts +35 -0
- package/dist/utils/nested-change.js +185 -0
- package/dist/utils/shell-detection.d.ts +20 -0
- package/dist/utils/shell-detection.js +94 -0
- package/dist/utils/task-progress.d.ts +67 -0
- package/dist/utils/task-progress.js +184 -0
- package/package.json +74 -4
- package/schemas//351/273/230/350/256/244/schema.yaml +68 -0
- package/schemas//351/273/230/350/256/244/templates//344/273/273/345/212/241/346/270/205/345/215/225.md +25 -0
- package/schemas//351/273/230/350/256/244/templates//346/265/213/350/257/225/347/224/250/344/276/213.md +34 -0
- package/schemas//351/273/230/350/256/244/templates//350/256/276/350/256/241/346/226/207/346/241/243.md +172 -0
- package/schemas//351/273/230/350/256/244/templates//351/234/200/346/261/202/346/226/207/346/241/243.md +19 -0
- package/skill-files//344/273/273/345/212/241/references//346/212/244/346/240/217.md +43 -0
- package/skill-files//344/273/273/345/212/241/references//347/262/222/345/272/246.md +23 -0
- package/skill-files//344/273/273/345/212/241/references//347/272/246/346/235/237.md +8 -0
- package/skill-files//344/273/273/345/212/241/scripts/check-tasks.mjs +83 -0
- package/skill-files//345/206/231Java/references/Java/350/247/204/350/214/203.md +25 -0
- package/skill-files//345/206/231Java/references//345/215/261/351/231/251/345/206/231/346/263/225.md +27 -0
- package/skill-files//345/206/231Java/references//345/256/214/346/210/220/345/257/271/347/205/247.md +15 -0
- package/skill-files//345/206/231Java/references//346/212/244/346/240/217.md +35 -0
- package/skill-files//345/206/231Java/references//347/272/246/346/235/237.md +8 -0
- package/skill-files//345/206/231Java/references//350/270/251/345/235/221.md +17 -0
- package/skill-files//345/256/241Java/references//346/212/244/346/240/217.md +19 -0
- package/skill-files//345/256/241Java/references//347/244/272/344/276/213.md +23 -0
- package/skill-files//345/256/241Java/references//347/272/246/346/235/237.md +7 -0
- package/skill-files//345/256/241Java/references//350/247/204/345/210/231.md +23 -0
- package/skill-files//345/256/241Java/references//351/242/206/345/237/237/346/243/200/351/241/271.md +58 -0
- package/skill-files//345/256/241/346/226/207/346/241/243/references//346/212/244/346/240/217.md +18 -0
- package/skill-files//345/256/241/346/226/207/346/241/243/references//347/272/246/346/235/237.md +8 -0
- package/skill-files//345/256/241/346/226/207/346/241/243/references//347/273/264/345/272/246.md +17 -0
- package/skill-files//345/256/241/346/226/207/346/241/243/references//350/270/251/345/235/221.md +11 -0
- package/skill-files//346/226/260/345/273/272/references//344/272/244/346/216/245.md +11 -0
- package/skill-files//346/226/260/345/273/272/references//346/212/244/346/240/217.md +14 -0
- package/skill-files//346/226/260/345/273/272/references//347/272/246/346/235/237.md +7 -0
- package/skill-files//346/267/261/346/200/235/config/prompts.yaml +114 -0
- package/skill-files//346/267/261/346/200/235/references//344/270/211/346/226/271/346/240/270/345/257/271.md +72 -0
- package/skill-files//346/267/261/346/200/235/references//344/276/213/345/255/220.md +39 -0
- package/skill-files//346/267/261/346/200/235/references//346/200/216/344/271/210/346/203/263.md +61 -0
- package/skill-files//346/267/261/346/200/235/references//346/212/244/346/240/217.md +26 -0
- package/skill-files//346/267/261/346/200/235/references//347/202/271/351/200/211/346/217/220/351/227/256.md +66 -0
- package/skill-files//346/267/261/346/200/235/references//347/231/273/350/256/260.md +45 -0
- package/skill-files//346/267/261/346/200/235/references//347/272/246/346/235/237.md +9 -0
- package/skill-files//347/224/250/344/276/213/references//346/200/216/344/271/210/345/206/231.md +13 -0
- package/skill-files//347/224/250/344/276/213/references//346/212/244/346/240/217.md +42 -0
- package/skill-files//347/224/250/344/276/213/references//347/272/246/346/235/237.md +5 -0
- package/skill-files//347/224/250/344/276/213/scripts/check-cases.mjs +70 -0
- package/skill-files//350/256/276/350/256/241/references//345/207/206/345/244/207.md +25 -0
- package/skill-files//350/256/276/350/256/241/references//346/212/244/346/240/217.md +134 -0
- package/skill-files//350/256/276/350/256/241/references//346/226/207/351/243/216.md +17 -0
- package/skill-files//350/256/276/350/256/241/references//347/225/214/351/235/242.md +18 -0
- package/skill-files//350/256/276/350/256/241/references//347/261/273/345/236/213.md +19 -0
- package/skill-files//350/256/276/350/256/241/references//347/272/246/346/235/237.md +25 -0
- package/skill-files//350/256/276/350/256/241/scripts/_smoke.mjs +72 -0
- package/skill-files//350/256/276/350/256/241/scripts/check-design.mjs +331 -0
- package/skill-files//351/234/200/346/261/202/references//346/212/244/346/240/217.md +26 -0
- package/skill-files//351/234/200/346/261/202/references//346/226/207/351/243/216.md +23 -0
- package/skill-files//351/234/200/346/261/202/references//346/267/261/346/200/235/346/221/204/345/205/245.md +21 -0
- package/skill-files//351/234/200/346/261/202/references//347/272/246/346/235/237.md +8 -0
- package/skill-files//351/234/200/346/261/202/references//351/234/200/346/261/202/345/276/205/345/256/232.md +13 -0
- package/skill-files//351/234/200/346/261/202/scripts/check-requirements.mjs +60 -0
- package/skill-files//351/252/214/346/224/266/references//346/212/244/346/240/217.md +27 -0
- package/skill-files//351/252/214/346/224/266/references//346/240/270/345/257/271.md +17 -0
- package/skill-files//351/252/214/346/224/266/references//347/272/246/346/235/237.md +7 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 OpenSpec Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
package/README.md
CHANGED
|
@@ -1,3 +1,59 @@
|
|
|
1
|
-
#
|
|
1
|
+
# FreeSpec
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
AI 原生的规格驱动开发(spec-driven development)命令行工具([@niujiajie/freespec](https://gitee.com/niu_jiajie/openspec.git))。核心思路:先在 `freespec/` 目录下为每次变更写规格文档(需求、设计、任务清单、用例),再由 AI 编码工具按文档实现,文档与实现互相约束。
|
|
4
|
+
|
|
5
|
+
## 工作流
|
|
6
|
+
|
|
7
|
+
- 变更目录在 `freespec/<名称>变更/`,默认 schema 是 `默认`。
|
|
8
|
+
- `默认` schema(见 [schema.yaml](schemas/默认/schema.yaml))定义四份可选的中文文档,无先后依赖,可单独写:
|
|
9
|
+
- `需求文档.md` —— 给人看的需求说明;
|
|
10
|
+
- `设计文档.md` —— 按章写的设计说明,由 `scripts/check-design.mjs` 校验;
|
|
11
|
+
- `任务清单.md` —— 可勾选(`- [ ]` / `- [x]`)的执行清单;
|
|
12
|
+
- `测试用例.md` —— 输入、操作、期望三段式用例,不写具体语言的测试代码。
|
|
13
|
+
- 每份文档都有配套模板([schemas/默认/templates/](schemas/默认/templates/))和给 AI 的写作指令。
|
|
14
|
+
- `apply` 阶段:以已有文档为上下文实现代码,有用例时先落成失败的测试再写实现。
|
|
15
|
+
|
|
16
|
+
## 命令
|
|
17
|
+
|
|
18
|
+
终端里的全局 `freespec` 若是旧版本,请统一用本仓库编出来的命令:
|
|
19
|
+
|
|
20
|
+
```powershell
|
|
21
|
+
node bin/freespec.js init --tools cursor --profile core --no-animation
|
|
22
|
+
node bin/freespec.js new change 登录改造
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
已有项目在项目目录里执行 `node bin/freespec.js update` 更新指令文件。装完后重启 Cursor,入口是 `/freespec-新建` 等斜杠命令(技能见 [skill-files/](skill-files/):新建、需求、设计、任务、用例、写Java、审Java、审文档、深思、验收)。
|
|
26
|
+
|
|
27
|
+
| 命令 | 说明 |
|
|
28
|
+
| --- | --- |
|
|
29
|
+
| `init [path]` | 初始化项目,为指定 AI 工具生成指令文件和技能 |
|
|
30
|
+
| `update [path]` | 更新已生成文件,支持 `--dry-run` / `--json` |
|
|
31
|
+
| `new change <name>` | 新建变更目录,支持 `--schema`、`--json` |
|
|
32
|
+
| `list` | 列出 `freespec/` 下的变更目录,支持 `--sort` / `--json` |
|
|
33
|
+
| `status` | 查看变更产物完成度,支持 `--change`、`--all`、`--json` |
|
|
34
|
+
| `instructions [artifact]` | 输出某产物或 `apply` 的增强指令 |
|
|
35
|
+
|
|
36
|
+
## 支持的 AI 工具
|
|
37
|
+
|
|
38
|
+
`--tools` 可选 `all`、`none` 或逗号分隔列表,覆盖 50+ 工具(定义在 [config.ts](src/core/config.ts)),包括 Cursor、Claude Code、Codex、Gemini CLI、GitHub Copilot、Trae、Qwen Code、OpenCode 等,以及通用的 `.agents` 共享技能目录。
|
|
39
|
+
|
|
40
|
+
## 目录结构
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
bin/ CLI 入口(freespec.js)
|
|
44
|
+
src/cli/ Commander 命令定义
|
|
45
|
+
src/commands/ 命令实现(workflow:new-change、status、instructions)
|
|
46
|
+
src/core/ 核心逻辑(init、update、change-layout、profiles、config 等)
|
|
47
|
+
schemas/ 工作流 schema 与文档模板(默认 schema:默认)
|
|
48
|
+
skill-files/ 生成到各 AI 工具的技能源文件
|
|
49
|
+
scripts/ 构建与校验脚本
|
|
50
|
+
dist/ 构建产物(tsc 输出)
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## 开发
|
|
54
|
+
|
|
55
|
+
- Node.js >= 20.19,pnpm 包管理,ESM + TypeScript。
|
|
56
|
+
- `pnpm build`:清理 `dist/` 并用本地 tsc 编译([build.js](build.js))。
|
|
57
|
+
- `pnpm dev`:tsc watch;`pnpm dev:cli`:构建后直接跑本地 CLI。
|
|
58
|
+
- `pnpm lint`:ESLint 检查 `src/`。
|
|
59
|
+
- 命令实现全部按需 `import()` 懒加载(见 [cli/index.ts](src/cli/index.ts)),`--version`、`--help` 不加载其他命令的实现,启动零开销。
|
package/bin/freespec.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
declare const program: Command;
|
|
3
|
+
/**
|
|
4
|
+
* Get the full command path for nested commands.
|
|
5
|
+
* For example: 'change show' -> 'change:show'
|
|
6
|
+
*/
|
|
7
|
+
export declare function getCommandPath(command: Command): string;
|
|
8
|
+
/**
|
|
9
|
+
* True when the executing command asked for JSON output — used to suppress the
|
|
10
|
+
* first-run telemetry notice so stdout stays a single valid JSON document.
|
|
11
|
+
*
|
|
12
|
+
* `--json` reaches commands three ways, so a single parsed option is not enough:
|
|
13
|
+
* - declared on the leaf (`freespec status --json`) → `opts().json`
|
|
14
|
+
* - declared on a parent group and read via globals (`freespec workset --json list`)
|
|
15
|
+
* → `optsWithGlobals().json`
|
|
16
|
+
* - a residual arg on a permissive group that never declares the option
|
|
17
|
+
* (`freespec store --json`, which detects it from `command.args`) → `args`
|
|
18
|
+
*
|
|
19
|
+
* Suppressing is always safe: the disclosure is only deferred to the next
|
|
20
|
+
* non-JSON run, never lost, whereas printing it on a JSON run corrupts stdout.
|
|
21
|
+
*/
|
|
22
|
+
export declare function isJsonRun(command: Command): boolean;
|
|
23
|
+
export { program };
|
|
24
|
+
export declare function runCli(argv?: string[]): void;
|
|
25
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
import { Command, Option } from 'commander';
|
|
2
|
+
import { createRequire } from 'module';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import { fileURLToPath } from 'url';
|
|
5
|
+
import { existsSync, promises as fs } from 'fs';
|
|
6
|
+
import { AI_TOOLS, TOOL_ID_ALIASES } from '../core/config.js';
|
|
7
|
+
import { DEFAULT_SCHEMA } from '../commands/workflow/default-schema.js';
|
|
8
|
+
// Startup cost: every command's implementation, and the packages it uses,
|
|
9
|
+
// loads with `await import()` inside its action. This module and
|
|
10
|
+
// ./commands/ only define commands (names, options, help), so `--version`,
|
|
11
|
+
// `--help`, and each command load no other command's implementation.
|
|
12
|
+
async function failWithError(error, json) {
|
|
13
|
+
// The agent contract: every --json failure leaves exactly one JSON
|
|
14
|
+
// document on stdout (the command's null-shape plus a status array).
|
|
15
|
+
if (json?.enabled) {
|
|
16
|
+
const { asStatus } = await import('../commands/shared-output.js');
|
|
17
|
+
console.log(JSON.stringify({ ...(json.payload ?? {}), status: [asStatus(error, json.fallbackCode ?? 'command_error')] }, null, 2));
|
|
18
|
+
process.exitCode = 1;
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
const { default: ora } = await import('ora');
|
|
22
|
+
ora().fail(`Error: ${error.message}`);
|
|
23
|
+
// Resolution and store errors carry a pasteable fix - never drop it.
|
|
24
|
+
const fix = error.diagnostic?.fix;
|
|
25
|
+
if (fix) {
|
|
26
|
+
console.error(`Fix: ${fix}`);
|
|
27
|
+
}
|
|
28
|
+
process.exitCode = process.exitCode ?? 1;
|
|
29
|
+
}
|
|
30
|
+
const program = new Command();
|
|
31
|
+
const require = createRequire(import.meta.url);
|
|
32
|
+
const { version } = require('../../package.json');
|
|
33
|
+
/**
|
|
34
|
+
* Get the full command path for nested commands.
|
|
35
|
+
* For example: 'change show' -> 'change:show'
|
|
36
|
+
*/
|
|
37
|
+
export function getCommandPath(command) {
|
|
38
|
+
const names = [];
|
|
39
|
+
let current = command;
|
|
40
|
+
while (current) {
|
|
41
|
+
const name = current.name();
|
|
42
|
+
// Skip the root 'freespec' command
|
|
43
|
+
if (name && name !== 'freespec') {
|
|
44
|
+
names.unshift(name);
|
|
45
|
+
}
|
|
46
|
+
current = current.parent;
|
|
47
|
+
}
|
|
48
|
+
return names.join(':') || 'freespec';
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* True when the executing command asked for JSON output — used to suppress the
|
|
52
|
+
* first-run telemetry notice so stdout stays a single valid JSON document.
|
|
53
|
+
*
|
|
54
|
+
* `--json` reaches commands three ways, so a single parsed option is not enough:
|
|
55
|
+
* - declared on the leaf (`freespec status --json`) → `opts().json`
|
|
56
|
+
* - declared on a parent group and read via globals (`freespec workset --json list`)
|
|
57
|
+
* → `optsWithGlobals().json`
|
|
58
|
+
* - a residual arg on a permissive group that never declares the option
|
|
59
|
+
* (`freespec store --json`, which detects it from `command.args`) → `args`
|
|
60
|
+
*
|
|
61
|
+
* Suppressing is always safe: the disclosure is only deferred to the next
|
|
62
|
+
* non-JSON run, never lost, whereas printing it on a JSON run corrupts stdout.
|
|
63
|
+
*/
|
|
64
|
+
export function isJsonRun(command) {
|
|
65
|
+
return (command.optsWithGlobals().json === true ||
|
|
66
|
+
command.args.includes('--json'));
|
|
67
|
+
}
|
|
68
|
+
program
|
|
69
|
+
.name('freespec')
|
|
70
|
+
.description('AI-native system for spec-driven development')
|
|
71
|
+
.version(version);
|
|
72
|
+
// Global options
|
|
73
|
+
program.option('--no-color', 'Disable color output');
|
|
74
|
+
// Apply global flags and telemetry before any command runs
|
|
75
|
+
// Note: preAction receives (thisCommand, actionCommand) where:
|
|
76
|
+
// - thisCommand: the command where hook was added (root program)
|
|
77
|
+
// - actionCommand: the command actually being executed (subcommand)
|
|
78
|
+
program.hook('preAction', async (thisCommand, actionCommand) => {
|
|
79
|
+
const opts = thisCommand.opts();
|
|
80
|
+
if (opts.color === false) {
|
|
81
|
+
process.env.NO_COLOR = '1';
|
|
82
|
+
}
|
|
83
|
+
// Show first-run telemetry notice (if not seen). It's written to stderr, so it
|
|
84
|
+
// never pollutes stdout — but --json runs still defer it (see isJsonRun) so the
|
|
85
|
+
// very first invocation stays free of any incidental output on either stream.
|
|
86
|
+
const { maybeShowTelemetryNotice, trackCommand } = await import('../telemetry/index.js');
|
|
87
|
+
await maybeShowTelemetryNotice({ silent: isJsonRun(actionCommand) });
|
|
88
|
+
// Track command execution (use actionCommand to get the actual subcommand)
|
|
89
|
+
const commandPath = getCommandPath(actionCommand);
|
|
90
|
+
await trackCommand(commandPath, version);
|
|
91
|
+
});
|
|
92
|
+
// Shutdown telemetry after command completes
|
|
93
|
+
program.hook('postAction', async (_thisCommand, actionCommand) => {
|
|
94
|
+
const { shutdown } = await import('../telemetry/index.js');
|
|
95
|
+
await shutdown();
|
|
96
|
+
});
|
|
97
|
+
const availableToolIds = AI_TOOLS
|
|
98
|
+
.filter((tool) => tool.skillsDir || tool.globalSkillsDir)
|
|
99
|
+
.map((tool) => tool.value);
|
|
100
|
+
const toolAliasNote = Object.entries(TOOL_ID_ALIASES)
|
|
101
|
+
.map(([retired, current]) => `${retired} (now ${current})`)
|
|
102
|
+
.join(', ');
|
|
103
|
+
const toolsOptionDescription = `Configure AI tools non-interactively. Use "all", "none", or a comma-separated list of: ${availableToolIds.join(', ')}. Also accepted: ${toolAliasNote}`;
|
|
104
|
+
program
|
|
105
|
+
.command('init [path]')
|
|
106
|
+
.description('Initialize FreeSpec in your project')
|
|
107
|
+
.option('--tools <tools>', toolsOptionDescription)
|
|
108
|
+
.option('--language <language>', 'Write new FreeSpec artifacts in this language')
|
|
109
|
+
.option('--force', 'Auto-cleanup legacy files without prompting')
|
|
110
|
+
.option('--profile <profile>', 'Override global config profile (core or custom)')
|
|
111
|
+
.option('--no-animation', 'Show a static welcome screen instead of the animated one')
|
|
112
|
+
.action(async (targetPath = '.', options) => {
|
|
113
|
+
try {
|
|
114
|
+
// Validate that the path is a valid directory
|
|
115
|
+
const resolvedPath = path.resolve(targetPath);
|
|
116
|
+
try {
|
|
117
|
+
const stats = await fs.stat(resolvedPath);
|
|
118
|
+
if (!stats.isDirectory()) {
|
|
119
|
+
throw new Error(`Path "${targetPath}" is not a directory`);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
catch (error) {
|
|
123
|
+
if (error.code === 'ENOENT') {
|
|
124
|
+
// Directory doesn't exist, but we can create it
|
|
125
|
+
console.log(`Directory "${targetPath}" doesn't exist, it will be created.`);
|
|
126
|
+
}
|
|
127
|
+
else if (error.message && error.message.includes('not a directory')) {
|
|
128
|
+
throw error;
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
throw new Error(`Cannot access path "${targetPath}": ${error.message}`);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
const { InitCommand } = await import('../core/init.js');
|
|
135
|
+
const initCommand = new InitCommand({
|
|
136
|
+
tools: options?.tools,
|
|
137
|
+
language: options?.language,
|
|
138
|
+
force: options?.force,
|
|
139
|
+
profile: options?.profile,
|
|
140
|
+
animation: options?.animation,
|
|
141
|
+
});
|
|
142
|
+
await initCommand.execute(targetPath);
|
|
143
|
+
}
|
|
144
|
+
catch (error) {
|
|
145
|
+
await failWithError(error);
|
|
146
|
+
process.exit(1);
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
program
|
|
150
|
+
.command('update [path]')
|
|
151
|
+
.description('Update FreeSpec instruction files')
|
|
152
|
+
.option('--force', 'Force update even when tools are up to date')
|
|
153
|
+
.option('--dry-run', 'Report what the update would change without writing anything')
|
|
154
|
+
.option('--json', 'With --dry-run, print the planned changes as JSON')
|
|
155
|
+
.action(async (targetPath = '.', options) => {
|
|
156
|
+
try {
|
|
157
|
+
if (options?.json && !options?.dryRun) {
|
|
158
|
+
console.error('--json is only available with --dry-run.');
|
|
159
|
+
process.exitCode = 1;
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
// A dry run reports the plan and nothing else: no network check, no
|
|
163
|
+
// upgrade prompt, no output that would break --json.
|
|
164
|
+
if (options?.dryRun) {
|
|
165
|
+
const [{ UpdateCommand }, { formatUpdatePlan }] = await Promise.all([
|
|
166
|
+
import('../core/update.js'),
|
|
167
|
+
import('../core/update-plan.js'),
|
|
168
|
+
]);
|
|
169
|
+
const plan = await new UpdateCommand({
|
|
170
|
+
force: options?.force,
|
|
171
|
+
dryRun: true,
|
|
172
|
+
}).plan(targetPath);
|
|
173
|
+
console.log(options?.json ? JSON.stringify(plan, null, 2) : formatUpdatePlan(plan));
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
const [{ getInstallDir, isSourceCheckout, getAvailableCliUpdate, shouldOfferUpgrade, displayCliUpdateNote, offerCliUpgrade, rerunUpdateWithUpgradedCli, displayUpgradeCommand, }, { isInteractive }, { UpdateCommand },] = await Promise.all([
|
|
177
|
+
import('../core/version-check.js'),
|
|
178
|
+
import('../utils/interactive.js'),
|
|
179
|
+
import('../core/update.js'),
|
|
180
|
+
]);
|
|
181
|
+
const installDir = getInstallDir();
|
|
182
|
+
// Running from a clone: the version is whatever the branch says, so any
|
|
183
|
+
// upgrade advice would be noise. Decided before the request, so a
|
|
184
|
+
// contributor never waits on an answer that gets thrown away.
|
|
185
|
+
const latestVersion = isSourceCheckout(installDir) ? null : await getAvailableCliUpdate();
|
|
186
|
+
const announce = latestVersion !== null;
|
|
187
|
+
// Offer to upgrade first: this process generates files from its own
|
|
188
|
+
// templates, so upgrading afterwards would leave the old ones on disk.
|
|
189
|
+
// Both streams must be a terminal — with stdout redirected the question
|
|
190
|
+
// lands in the file and the user waits at a blank screen forever.
|
|
191
|
+
const canOffer = announce &&
|
|
192
|
+
shouldOfferUpgrade({
|
|
193
|
+
installDir,
|
|
194
|
+
projectPath: targetPath,
|
|
195
|
+
interactive: isInteractive(),
|
|
196
|
+
stdoutIsTty: Boolean(process.stdout.isTTY),
|
|
197
|
+
});
|
|
198
|
+
let declined = false;
|
|
199
|
+
if (latestVersion && canOffer) {
|
|
200
|
+
displayCliUpdateNote(latestVersion, targetPath, { withCommand: false });
|
|
201
|
+
const outcome = await offerCliUpgrade(latestVersion);
|
|
202
|
+
// Set the code and return rather than process.exit: exiting here would
|
|
203
|
+
// skip commander's postAction hook, killing the telemetry flush
|
|
204
|
+
// mid-request.
|
|
205
|
+
if (outcome === 'cancelled') {
|
|
206
|
+
// Ctrl-C means stop the command, not fall through to more prompts.
|
|
207
|
+
process.exitCode = 130;
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
if (outcome === 'upgraded') {
|
|
211
|
+
process.exitCode = await rerunUpdateWithUpgradedCli(targetPath, {
|
|
212
|
+
force: options?.force,
|
|
213
|
+
});
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
// Declined, failed, or upgraded-but-unreachable: fall through to the
|
|
217
|
+
// update, then leave the command on screen underneath it.
|
|
218
|
+
declined = true;
|
|
219
|
+
}
|
|
220
|
+
const updateCommand = new UpdateCommand({ force: options?.force });
|
|
221
|
+
await updateCommand.execute(targetPath);
|
|
222
|
+
if (declined) {
|
|
223
|
+
// The headline was printed before the prompt; only the manual route is
|
|
224
|
+
// still owed, and it belongs where the user is looking now.
|
|
225
|
+
displayUpgradeCommand(targetPath);
|
|
226
|
+
}
|
|
227
|
+
else if (latestVersion) {
|
|
228
|
+
displayCliUpdateNote(latestVersion, targetPath);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
catch (error) {
|
|
232
|
+
// The --json dry run follows the agent contract: exactly one JSON
|
|
233
|
+
// document on stdout, even on failure.
|
|
234
|
+
// failWithError sets the exit code. Returning instead of process.exit()
|
|
235
|
+
// lets piped stdout drain - an exit can cut the JSON document short where
|
|
236
|
+
// pipes are asynchronous (macOS, Windows) - and keeps commander's
|
|
237
|
+
// postAction telemetry flush, as the upgrade paths above already do.
|
|
238
|
+
await failWithError(error, {
|
|
239
|
+
enabled: options?.dryRun && options?.json,
|
|
240
|
+
payload: { changes: [], notes: [], failures: [] },
|
|
241
|
+
fallbackCode: 'update_error',
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
});
|
|
245
|
+
program
|
|
246
|
+
.command('list')
|
|
247
|
+
.description('List change directories under freespec/')
|
|
248
|
+
.option('--sort <order>', 'Sort order: "recent" (default) or "name"', 'recent')
|
|
249
|
+
.option('--json', 'Output as JSON (for programmatic use)')
|
|
250
|
+
.action(async (options) => {
|
|
251
|
+
try {
|
|
252
|
+
const [{ resolveRootForCommand, toRootOutput }, { ListCommand }] = await Promise.all([
|
|
253
|
+
import('../core/root-selection.js'),
|
|
254
|
+
import('../core/list.js'),
|
|
255
|
+
]);
|
|
256
|
+
const root = await resolveRootForCommand(options ?? {}, {
|
|
257
|
+
json: options?.json,
|
|
258
|
+
failurePayload: { changes: [], root: null },
|
|
259
|
+
allowImplicitRoot: existsSync(path.join(process.cwd(), 'freespec', 'project.md')),
|
|
260
|
+
});
|
|
261
|
+
if (!root) {
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
const listCommand = new ListCommand();
|
|
265
|
+
const sort = options?.sort === 'name' ? 'name' : 'recent';
|
|
266
|
+
await listCommand.execute(root.path, {
|
|
267
|
+
sort,
|
|
268
|
+
json: options?.json,
|
|
269
|
+
...(options?.json ? { root: toRootOutput(root) } : {}),
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
catch (error) {
|
|
273
|
+
await failWithError(error, {
|
|
274
|
+
enabled: options?.json,
|
|
275
|
+
payload: { changes: [], root: null },
|
|
276
|
+
fallbackCode: 'list_error',
|
|
277
|
+
});
|
|
278
|
+
process.exit(1);
|
|
279
|
+
}
|
|
280
|
+
});
|
|
281
|
+
// Status command
|
|
282
|
+
program
|
|
283
|
+
.command('status')
|
|
284
|
+
.description('Display artifact completion status for a change')
|
|
285
|
+
.option('--change <id>', 'Change name to show status for')
|
|
286
|
+
.option('--all', 'Show status for all active changes')
|
|
287
|
+
.option('--schema <name>', 'Schema override (auto-detected from config.yaml)')
|
|
288
|
+
.option('--json', 'Output as JSON')
|
|
289
|
+
.action(async (options) => {
|
|
290
|
+
try {
|
|
291
|
+
const { statusCommand } = await import('../commands/workflow/status.js');
|
|
292
|
+
await statusCommand(options);
|
|
293
|
+
}
|
|
294
|
+
catch (error) {
|
|
295
|
+
await failWithError(error, {
|
|
296
|
+
enabled: options.json,
|
|
297
|
+
// The batch null-shape; the single-change failure shape is
|
|
298
|
+
// pre-existing contract and stays payload-free.
|
|
299
|
+
payload: options.all
|
|
300
|
+
? (await import('../commands/workflow/status.js')).BATCH_STATUS_FAILURE_PAYLOAD
|
|
301
|
+
: undefined,
|
|
302
|
+
fallbackCode: 'change_error',
|
|
303
|
+
});
|
|
304
|
+
process.exit(1);
|
|
305
|
+
}
|
|
306
|
+
});
|
|
307
|
+
// Instructions command
|
|
308
|
+
program
|
|
309
|
+
.command('instructions [artifact]')
|
|
310
|
+
.description('Output enriched instructions for an artifact or for apply')
|
|
311
|
+
.option('--change <id>', 'Change name')
|
|
312
|
+
.option('--schema <name>', 'Schema override (auto-detected from config.yaml)')
|
|
313
|
+
.option('--json', 'Output as JSON')
|
|
314
|
+
.action(async (artifactId, options) => {
|
|
315
|
+
try {
|
|
316
|
+
const { applyInstructionsCommand, instructionsCommand } = await import('../commands/workflow/instructions.js');
|
|
317
|
+
if (artifactId === 'apply') {
|
|
318
|
+
await applyInstructionsCommand(options);
|
|
319
|
+
}
|
|
320
|
+
else {
|
|
321
|
+
await instructionsCommand(artifactId, options);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
catch (error) {
|
|
325
|
+
await failWithError(error, { enabled: options.json, fallbackCode: 'change_error' });
|
|
326
|
+
process.exit(1);
|
|
327
|
+
}
|
|
328
|
+
});
|
|
329
|
+
// New command group with change subcommand
|
|
330
|
+
const newCmd = program.command('new').description('Create new items');
|
|
331
|
+
newCmd
|
|
332
|
+
.command('change <name>')
|
|
333
|
+
.description('Create a new change directory')
|
|
334
|
+
.option('--description <text>', 'Description to add to README.md')
|
|
335
|
+
.option('--goal <text>', 'Optional goal metadata to store with the change')
|
|
336
|
+
.option('--schema <name>', `Workflow schema to use (default: ${DEFAULT_SCHEMA})`)
|
|
337
|
+
.option('--json', 'Output as JSON')
|
|
338
|
+
// Removed options kept registered (hidden) so users get a deliberate
|
|
339
|
+
// explanation instead of a generic unknown-option error.
|
|
340
|
+
.addOption(new Option('--initiative <id>', 'No longer supported').hideHelp())
|
|
341
|
+
.addOption(new Option('--areas <names>', 'No longer supported').hideHelp())
|
|
342
|
+
.action(async (name, options) => {
|
|
343
|
+
try {
|
|
344
|
+
const { newChangeCommand } = await import('../commands/workflow/new-change.js');
|
|
345
|
+
await newChangeCommand(name, options);
|
|
346
|
+
}
|
|
347
|
+
catch (error) {
|
|
348
|
+
await failWithError(error);
|
|
349
|
+
process.exit(1);
|
|
350
|
+
}
|
|
351
|
+
});
|
|
352
|
+
export { program };
|
|
353
|
+
export function runCli(argv = process.argv) {
|
|
354
|
+
program.parse(argv);
|
|
355
|
+
}
|
|
356
|
+
if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
|
|
357
|
+
runCli();
|
|
358
|
+
}
|
|
359
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared JSON/failure output plumbing for command groups whose errors
|
|
3
|
+
* carry the StoreDiagnostic envelope. One definition of the failure
|
|
4
|
+
* contract: exit code 1, Error:/Fix: lines in human mode, a status
|
|
5
|
+
* array in JSON mode.
|
|
6
|
+
*/
|
|
7
|
+
import { type StoreDiagnostic } from '../core/store/errors.js';
|
|
8
|
+
export declare function printJson(payload: unknown): void;
|
|
9
|
+
export declare function asErrorMessage(error: unknown): string;
|
|
10
|
+
/**
|
|
11
|
+
* @inquirer prompts reject with ExitPromptError on Ctrl-C; commands
|
|
12
|
+
* translate that to `Cancelled.` + exit 130 (third caller extracted
|
|
13
|
+
* this here in slice 7.1).
|
|
14
|
+
*/
|
|
15
|
+
export declare function isPromptCancellationError(error: unknown): boolean;
|
|
16
|
+
export declare function asStatus(error: unknown, fallbackCode: string): StoreDiagnostic;
|
|
17
|
+
export declare function emitFailure(json: boolean | undefined, payload: Record<string, unknown>, error: unknown, fallbackCode: string): void;
|
|
18
|
+
//# sourceMappingURL=shared-output.d.ts.map
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared JSON/failure output plumbing for command groups whose errors
|
|
3
|
+
* carry the StoreDiagnostic envelope. One definition of the failure
|
|
4
|
+
* contract: exit code 1, Error:/Fix: lines in human mode, a status
|
|
5
|
+
* array in JSON mode.
|
|
6
|
+
*/
|
|
7
|
+
import { StoreError } from '../core/store/errors.js';
|
|
8
|
+
export function printJson(payload) {
|
|
9
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
10
|
+
}
|
|
11
|
+
export function asErrorMessage(error) {
|
|
12
|
+
return error instanceof Error ? error.message : String(error);
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* @inquirer prompts reject with ExitPromptError on Ctrl-C; commands
|
|
16
|
+
* translate that to `Cancelled.` + exit 130 (third caller extracted
|
|
17
|
+
* this here in slice 7.1).
|
|
18
|
+
*/
|
|
19
|
+
export function isPromptCancellationError(error) {
|
|
20
|
+
return (error instanceof Error &&
|
|
21
|
+
(error.name === 'ExitPromptError' ||
|
|
22
|
+
error.message.includes('force closed the prompt with SIGINT')));
|
|
23
|
+
}
|
|
24
|
+
export function asStatus(error, fallbackCode) {
|
|
25
|
+
if (error instanceof StoreError) {
|
|
26
|
+
return error.diagnostic;
|
|
27
|
+
}
|
|
28
|
+
// RootSelectionError (and siblings) carry the same envelope without
|
|
29
|
+
// sharing a class hierarchy; duck-type the diagnostic once, here.
|
|
30
|
+
const diagnostic = error.diagnostic;
|
|
31
|
+
if (diagnostic && typeof diagnostic.code === 'string') {
|
|
32
|
+
return diagnostic;
|
|
33
|
+
}
|
|
34
|
+
return {
|
|
35
|
+
severity: 'error',
|
|
36
|
+
code: fallbackCode,
|
|
37
|
+
message: asErrorMessage(error),
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
export function emitFailure(json, payload, error, fallbackCode) {
|
|
41
|
+
// Ctrl-C in a prompt is the user's choice, not an error: every
|
|
42
|
+
// command group gets the Cancelled./130 convention through here.
|
|
43
|
+
if (!json && isPromptCancellationError(error)) {
|
|
44
|
+
console.error('Cancelled.');
|
|
45
|
+
process.exitCode = 130;
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
const status = asStatus(error, fallbackCode);
|
|
49
|
+
if (json) {
|
|
50
|
+
const prior = Array.isArray(payload.status) ? payload.status : [];
|
|
51
|
+
printJson({ ...payload, status: [...prior, status] });
|
|
52
|
+
process.exitCode = 1;
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
console.error(`Error: ${status.message}`);
|
|
56
|
+
if (status.fix) {
|
|
57
|
+
console.error(`Fix: ${status.fix}`);
|
|
58
|
+
}
|
|
59
|
+
process.exitCode = 1;
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=shared-output.js.map
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workflow CLI Commands
|
|
3
|
+
*
|
|
4
|
+
* Commands for the artifact-driven workflow: status, instructions, templates, schemas, new change.
|
|
5
|
+
*/
|
|
6
|
+
export { statusCommand, BATCH_STATUS_FAILURE_PAYLOAD } from './status.js';
|
|
7
|
+
export type { StatusOptions } from './status.js';
|
|
8
|
+
export { instructionsCommand, applyInstructionsCommand, } from './instructions.js';
|
|
9
|
+
export type { InstructionsOptions } from './instructions.js';
|
|
10
|
+
export { newChangeCommand } from './new-change.js';
|
|
11
|
+
export type { NewChangeOptions } from './new-change.js';
|
|
12
|
+
export { DEFAULT_SCHEMA } from './shared.js';
|
|
13
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workflow CLI Commands
|
|
3
|
+
*
|
|
4
|
+
* Commands for the artifact-driven workflow: status, instructions, templates, schemas, new change.
|
|
5
|
+
*/
|
|
6
|
+
export { statusCommand, BATCH_STATUS_FAILURE_PAYLOAD } from './status.js';
|
|
7
|
+
export { instructionsCommand, applyInstructionsCommand, } from './instructions.js';
|
|
8
|
+
export { newChangeCommand } from './new-change.js';
|
|
9
|
+
export { DEFAULT_SCHEMA } from './shared.js';
|
|
10
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Instructions Command
|
|
3
|
+
*
|
|
4
|
+
* Generates enriched instructions for creating artifacts or applying tasks.
|
|
5
|
+
* Includes both artifact instructions and apply instructions.
|
|
6
|
+
*/
|
|
7
|
+
import { type ArtifactInstructions } from '../../core/artifact-graph/index.js';
|
|
8
|
+
import { type PlanningHome } from '../../core/planning-home.js';
|
|
9
|
+
import { type ProjectConfig } from '../../core/project-config.js';
|
|
10
|
+
import { type ApplyInstructions } from './shared.js';
|
|
11
|
+
export interface InstructionsOptions {
|
|
12
|
+
change?: string;
|
|
13
|
+
schema?: string;
|
|
14
|
+
store?: string;
|
|
15
|
+
storePath?: string;
|
|
16
|
+
json?: boolean;
|
|
17
|
+
}
|
|
18
|
+
export interface ApplyInstructionsOptions {
|
|
19
|
+
change?: string;
|
|
20
|
+
schema?: string;
|
|
21
|
+
store?: string;
|
|
22
|
+
storePath?: string;
|
|
23
|
+
json?: boolean;
|
|
24
|
+
}
|
|
25
|
+
export declare function instructionsCommand(artifactId: string | undefined, options: InstructionsOptions): Promise<void>;
|
|
26
|
+
export declare function printInstructionsText(instructions: ArtifactInstructions, isBlocked: boolean): void;
|
|
27
|
+
export interface GenerateApplyInstructionsOptions {
|
|
28
|
+
planningHome?: PlanningHome;
|
|
29
|
+
projectConfig?: ProjectConfig | null;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Generates apply instructions for implementing tasks from a change.
|
|
33
|
+
* Schema-aware: reads apply phase configuration from schema to determine
|
|
34
|
+
* required artifacts, tracking file, and instruction.
|
|
35
|
+
*/
|
|
36
|
+
export declare function generateApplyInstructions(projectRoot: string, changeName: string, schemaName?: string, options?: GenerateApplyInstructionsOptions): Promise<ApplyInstructions>;
|
|
37
|
+
export declare function applyInstructionsCommand(options: ApplyInstructionsOptions): Promise<void>;
|
|
38
|
+
export declare function printApplyInstructionsText(instructions: ApplyInstructions): void;
|
|
39
|
+
//# sourceMappingURL=instructions.d.ts.map
|