agile-context-engineering 0.3.0 → 0.5.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/.claude-plugin/marketplace.json +18 -0
- package/.claude-plugin/plugin.json +10 -0
- package/CHANGELOG.md +7 -1
- package/LICENSE +51 -51
- package/README.md +330 -318
- package/agents/ace-code-discovery-analyst.md +245 -245
- package/agents/ace-code-integration-analyst.md +248 -248
- package/agents/ace-code-reviewer.md +375 -375
- package/agents/ace-product-owner.md +365 -361
- package/agents/ace-project-researcher.md +606 -606
- package/agents/ace-research-synthesizer.md +228 -228
- package/agents/ace-technical-application-architect.md +315 -315
- package/agents/ace-wiki-mapper.md +449 -445
- package/bin/install.js +605 -195
- package/hooks/ace-check-update.js +71 -62
- package/hooks/ace-statusline.js +107 -89
- package/hooks/hooks.json +14 -0
- package/package.json +7 -5
- package/shared/lib/ace-core.js +361 -0
- package/shared/lib/ace-core.test.js +308 -0
- package/shared/lib/ace-github.js +753 -0
- package/shared/lib/ace-story.js +400 -0
- package/shared/lib/ace-story.test.js +250 -0
- package/{agile-context-engineering → shared}/utils/questioning.xml +110 -110
- package/{agile-context-engineering → shared}/utils/ui-formatting.md +299 -299
- package/{commands/ace/execute-story.md → skills/execute-story/SKILL.md} +116 -138
- package/skills/execute-story/script.js +291 -0
- package/skills/execute-story/script.test.js +261 -0
- package/{agile-context-engineering/templates/product/story.xml → skills/execute-story/story-template.xml} +451 -451
- package/skills/execute-story/walkthrough-template.xml +255 -0
- package/{agile-context-engineering/workflows/execute-story.xml → skills/execute-story/workflow.xml} +1221 -1219
- package/skills/help/SKILL.md +71 -0
- package/skills/help/script.js +315 -0
- package/skills/help/script.test.js +183 -0
- package/{agile-context-engineering/workflows/help.xml → skills/help/workflow.xml} +544 -533
- package/{commands/ace/init-coding-standards.md → skills/init-coding-standards/SKILL.md} +91 -83
- package/{agile-context-engineering/templates/wiki/coding-standards.xml → skills/init-coding-standards/coding-standards-template.xml} +531 -531
- package/skills/init-coding-standards/script.js +50 -0
- package/skills/init-coding-standards/script.test.js +70 -0
- package/{agile-context-engineering/workflows/init-coding-standards.xml → skills/init-coding-standards/workflow.xml} +381 -386
- package/skills/map-cross-cutting/SKILL.md +126 -0
- package/{agile-context-engineering/templates/wiki → skills/map-cross-cutting}/system-cross-cutting.xml +197 -197
- package/skills/map-cross-cutting/workflow.xml +330 -0
- package/skills/map-guide/SKILL.md +126 -0
- package/{agile-context-engineering/templates/wiki → skills/map-guide}/guide.xml +137 -137
- package/skills/map-guide/workflow.xml +320 -0
- package/skills/map-pattern/SKILL.md +125 -0
- package/{agile-context-engineering/templates/wiki → skills/map-pattern}/pattern.xml +159 -159
- package/skills/map-pattern/workflow.xml +331 -0
- package/{commands/ace/map-story.md → skills/map-story/SKILL.md} +180 -165
- package/{agile-context-engineering/templates/wiki → skills/map-story/templates}/decizions.xml +115 -115
- package/skills/map-story/templates/guide.xml +137 -0
- package/skills/map-story/templates/pattern.xml +159 -0
- package/skills/map-story/templates/system-cross-cutting.xml +197 -0
- package/{agile-context-engineering/templates/wiki → skills/map-story/templates}/system.xml +381 -381
- package/{agile-context-engineering/templates/wiki → skills/map-story/templates}/tech-debt-index.xml +125 -125
- package/{agile-context-engineering/templates/wiki → skills/map-story/templates}/walkthrough.xml +255 -255
- package/{agile-context-engineering/workflows/map-story.xml → skills/map-story/workflow.xml} +1046 -1046
- package/{commands/ace/map-subsystem.md → skills/map-subsystem/SKILL.md} +155 -140
- package/skills/map-subsystem/script.js +51 -0
- package/skills/map-subsystem/script.test.js +68 -0
- package/skills/map-subsystem/templates/decizions.xml +115 -0
- package/skills/map-subsystem/templates/guide.xml +137 -0
- package/{agile-context-engineering/templates/wiki → skills/map-subsystem/templates}/module-discovery.xml +174 -174
- package/skills/map-subsystem/templates/pattern.xml +159 -0
- package/{agile-context-engineering/templates/wiki → skills/map-subsystem/templates}/subsystem-architecture.xml +343 -343
- package/{agile-context-engineering/templates/wiki → skills/map-subsystem/templates}/subsystem-structure.xml +234 -234
- package/skills/map-subsystem/templates/system-cross-cutting.xml +197 -0
- package/skills/map-subsystem/templates/system.xml +381 -0
- package/skills/map-subsystem/templates/walkthrough.xml +255 -0
- package/{agile-context-engineering/workflows/map-subsystem.xml → skills/map-subsystem/workflow.xml} +1173 -1178
- package/skills/map-sys-doc/SKILL.md +125 -0
- package/skills/map-sys-doc/system.xml +381 -0
- package/skills/map-sys-doc/workflow.xml +336 -0
- package/{commands/ace/map-system.md → skills/map-system/SKILL.md} +103 -92
- package/skills/map-system/script.js +75 -0
- package/skills/map-system/script.test.js +73 -0
- package/{agile-context-engineering/templates/wiki → skills/map-system/templates}/system-architecture.xml +254 -254
- package/{agile-context-engineering/templates/wiki → skills/map-system/templates}/system-structure.xml +177 -177
- package/{agile-context-engineering/templates/wiki → skills/map-system/templates}/testing-framework.xml +283 -283
- package/{agile-context-engineering/templates/wiki → skills/map-system/templates}/wiki-readme.xml +296 -296
- package/{agile-context-engineering/workflows/map-system.xml → skills/map-system/workflow.xml} +667 -672
- package/{commands/ace/map-walkthrough.md → skills/map-walkthrough/SKILL.md} +140 -127
- package/skills/map-walkthrough/walkthrough.xml +255 -0
- package/{agile-context-engineering/workflows/map-walkthrough.xml → skills/map-walkthrough/workflow.xml} +457 -457
- package/{commands/ace/plan-backlog.md → skills/plan-backlog/SKILL.md} +93 -83
- package/{agile-context-engineering/templates/product/product-backlog.xml → skills/plan-backlog/product-backlog-template.xml} +231 -231
- package/skills/plan-backlog/script.js +121 -0
- package/skills/plan-backlog/script.test.js +83 -0
- package/{agile-context-engineering/workflows/plan-backlog.xml → skills/plan-backlog/workflow.xml} +1348 -1356
- package/{commands/ace/plan-feature.md → skills/plan-feature/SKILL.md} +99 -89
- package/{agile-context-engineering/templates/product/feature.xml → skills/plan-feature/feature-template.xml} +361 -361
- package/skills/plan-feature/script.js +131 -0
- package/skills/plan-feature/script.test.js +80 -0
- package/{agile-context-engineering/workflows/plan-feature.xml → skills/plan-feature/workflow.xml} +1487 -1495
- package/{commands/ace/plan-product-vision.md → skills/plan-product-vision/SKILL.md} +91 -81
- package/{agile-context-engineering/templates/product/product-vision.xml → skills/plan-product-vision/product-vision-template.xml} +227 -227
- package/skills/plan-product-vision/script.js +51 -0
- package/skills/plan-product-vision/script.test.js +69 -0
- package/{agile-context-engineering/workflows/plan-product-vision.xml → skills/plan-product-vision/workflow.xml} +337 -342
- package/{commands/ace/plan-story.md → skills/plan-story/SKILL.md} +139 -159
- package/skills/plan-story/script.js +295 -0
- package/skills/plan-story/script.test.js +240 -0
- package/skills/plan-story/story-template.xml +458 -0
- package/{agile-context-engineering/workflows/plan-story.xml → skills/plan-story/workflow.xml} +1301 -944
- package/{commands/ace/research-external-solution.md → skills/research-external-solution/SKILL.md} +120 -138
- package/{agile-context-engineering/templates/product/external-solution.xml → skills/research-external-solution/external-solution-template.xml} +832 -832
- package/skills/research-external-solution/script.js +229 -0
- package/skills/research-external-solution/script.test.js +134 -0
- package/{agile-context-engineering/workflows/research-external-solution.xml → skills/research-external-solution/workflow.xml} +657 -659
- package/{commands/ace/research-integration-solution.md → skills/research-integration-solution/SKILL.md} +121 -135
- package/{agile-context-engineering/templates/product/story-integration-solution.xml → skills/research-integration-solution/integration-solution-template.xml} +1015 -1015
- package/skills/research-integration-solution/script.js +223 -0
- package/skills/research-integration-solution/script.test.js +134 -0
- package/{agile-context-engineering/workflows/research-integration-solution.xml → skills/research-integration-solution/workflow.xml} +711 -713
- package/{commands/ace/research-story-wiki.md → skills/research-story-wiki/SKILL.md} +101 -116
- package/skills/research-story-wiki/script.js +223 -0
- package/skills/research-story-wiki/script.test.js +138 -0
- package/{agile-context-engineering/templates/product/story-wiki.xml → skills/research-story-wiki/story-wiki-template.xml} +194 -194
- package/{agile-context-engineering/workflows/research-story-wiki.xml → skills/research-story-wiki/workflow.xml} +473 -475
- package/{commands/ace/research-technical-solution.md → skills/research-technical-solution/SKILL.md} +131 -147
- package/skills/research-technical-solution/script.js +223 -0
- package/skills/research-technical-solution/script.test.js +134 -0
- package/{agile-context-engineering/templates/product/story-technical-solution.xml → skills/research-technical-solution/technical-solution-template.xml} +1025 -1025
- package/{agile-context-engineering/workflows/research-technical-solution.xml → skills/research-technical-solution/workflow.xml} +761 -763
- package/{commands/ace/review-story.md → skills/review-story/SKILL.md} +99 -109
- package/skills/review-story/script.js +249 -0
- package/skills/review-story/script.test.js +169 -0
- package/skills/review-story/story-template.xml +451 -0
- package/{agile-context-engineering/workflows/review-story.xml → skills/review-story/workflow.xml} +279 -281
- package/{commands/ace/update.md → skills/update/SKILL.md} +65 -56
- package/{agile-context-engineering/workflows/update.xml → skills/update/workflow.xml} +33 -18
- package/agile-context-engineering/src/ace-tools.js +0 -2881
- package/agile-context-engineering/src/ace-tools.test.js +0 -1089
- package/agile-context-engineering/templates/_command.md +0 -54
- package/agile-context-engineering/templates/_workflow.xml +0 -17
- package/agile-context-engineering/templates/config.json +0 -0
- package/agile-context-engineering/templates/product/integration-solution.xml +0 -0
- package/commands/ace/help.md +0 -93
|
@@ -1,159 +1,139 @@
|
|
|
1
|
-
---
|
|
2
|
-
name:
|
|
3
|
-
description: Plan a story through deep questioning to create CRYSTAL-CLEAR acceptance criteria with ZERO assumptions, then dispatch wiki research, external analysis, integration analysis, and technical solution design
|
|
4
|
-
argument-hint: "story=<file-path|github-url> [external-codebase=<source-path|github-url>] [external-docs=<weblink|filepath>] [lib-docs=<weblinks-and-filepaths>]"
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
<
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
<
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
</param>
|
|
60
|
-
<param name="
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
# With library documentation references
|
|
141
|
-
/ace:plan-story \
|
|
142
|
-
story=.ace/artifacts/product/e1-charts/f2-rendering/s3-canvas/s3-canvas.md \
|
|
143
|
-
lib-docs="https://docs.some-lib.io/api src/vendor/some-lib/README.md"
|
|
144
|
-
|
|
145
|
-
# With just an issue number (uses configured repo)
|
|
146
|
-
/ace:plan-story story=#95
|
|
147
|
-
```
|
|
148
|
-
</example-usage>
|
|
149
|
-
|
|
150
|
-
<next-steps>
|
|
151
|
-
**After this command:**
|
|
152
|
-
- `/ace:execute-story story=...` — Execute the story implementation
|
|
153
|
-
- `/ace:plan-story story=...` — Plan the next story in the feature
|
|
154
|
-
- `/ace:verify-story story=...` — Verify a completed story
|
|
155
|
-
- `/ace:help` — Check project initialization status
|
|
156
|
-
</next-steps>
|
|
157
|
-
|
|
158
|
-
</command>
|
|
159
|
-
```
|
|
1
|
+
---
|
|
2
|
+
name: plan-story
|
|
3
|
+
description: Plan a story through deep questioning to create CRYSTAL-CLEAR acceptance criteria with ZERO assumptions, then dispatch wiki research, external analysis, integration analysis, and technical solution design. Use this whenever the user wants to plan a story, specify a story, create acceptance criteria, refine story requirements, or take a story stub and turn it into a full specification — whether from a feature stub, GitHub issue, inline text, or from scratch.
|
|
4
|
+
argument-hint: "[story=<file-path|github-url>] [text=<inline-description>] [external-codebase=<source-path|github-url>] [external-docs=<weblink|filepath>] [lib-docs=<weblinks-and-filepaths>]"
|
|
5
|
+
disable-model-invocation: true
|
|
6
|
+
allowed-tools: Read, Bash, Write, Edit, AskUserQuestion, Glob, Grep, Agent
|
|
7
|
+
model: opus
|
|
8
|
+
effort: high
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Environment Context (preprocessed)
|
|
12
|
+
|
|
13
|
+
!`node "${CLAUDE_SKILL_DIR}/script.js" init "$ARGUMENTS" 2>/dev/null`
|
|
14
|
+
|
|
15
|
+
## Supporting Resources (auto-loaded)
|
|
16
|
+
|
|
17
|
+
!`cat "${CLAUDE_SKILL_DIR}/workflow.xml"`
|
|
18
|
+
|
|
19
|
+
!`cat "${CLAUDE_SKILL_DIR}/story-template.xml"`
|
|
20
|
+
|
|
21
|
+
!`cat "${CLAUDE_SKILL_DIR}/../../shared/utils/questioning.xml"`
|
|
22
|
+
|
|
23
|
+
!`cat "${CLAUDE_SKILL_DIR}/../../shared/utils/ui-formatting.md"`
|
|
24
|
+
|
|
25
|
+
```xml
|
|
26
|
+
<command>
|
|
27
|
+
|
|
28
|
+
<execution-time>
|
|
29
|
+
<runs-after>
|
|
30
|
+
<trigger>After /ace:plan-feature — once a feature's story breakdown exists with stub story files</trigger>
|
|
31
|
+
<trigger>Anytime — to create or refine a story specification from a description or GitHub issue</trigger>
|
|
32
|
+
</runs-after>
|
|
33
|
+
<use-when>
|
|
34
|
+
<condition>A story stub exists (from plan-feature) and needs formal specification</condition>
|
|
35
|
+
<condition>A GitHub issue describes work that needs INVEST-compliant acceptance criteria</condition>
|
|
36
|
+
<condition>An existing story needs refinement — scope changed, AC gaps found</condition>
|
|
37
|
+
<condition>You want to create a complete story specification from any text description</condition>
|
|
38
|
+
<condition>You have a new story idea (text or no input) and need it placed in the backlog</condition>
|
|
39
|
+
</use-when>
|
|
40
|
+
</execution-time>
|
|
41
|
+
|
|
42
|
+
<input>
|
|
43
|
+
<flags>
|
|
44
|
+
</flags>
|
|
45
|
+
|
|
46
|
+
<parameters>
|
|
47
|
+
<required>
|
|
48
|
+
</required>
|
|
49
|
+
|
|
50
|
+
<optional>
|
|
51
|
+
<param name="story" type="file | github-url">
|
|
52
|
+
Story source — can be either:
|
|
53
|
+
- **File path**: Path to an existing markdown file containing the story seed
|
|
54
|
+
(typically a stub from plan-feature, or any markdown with a description)
|
|
55
|
+
- **GitHub URL or issue number**: GitHub story reference
|
|
56
|
+
When omitted, the workflow enters "new story" mode and guides the user
|
|
57
|
+
through backlog placement before proceeding to specification.
|
|
58
|
+
If provided but invalid, stop and prompt the user.
|
|
59
|
+
</param>
|
|
60
|
+
<param name="text" type="text">
|
|
61
|
+
Inline story description to seed the planning session.
|
|
62
|
+
Used when no story file exists yet — the text becomes the initial description
|
|
63
|
+
and the workflow asks where in the backlog this story belongs.
|
|
64
|
+
Ignored if `story` is provided.
|
|
65
|
+
</param>
|
|
66
|
+
<param name="external-codebase" type="filepath | github-url">
|
|
67
|
+
Path or GitHub repo to an external industry-standard system to analyze.
|
|
68
|
+
When provided, pass 3 (external analysis) runs automatically.
|
|
69
|
+
When NOT provided, the user is offered the option to provide it or skip.
|
|
70
|
+
</param>
|
|
71
|
+
<param name="external-docs" type="weblink | filepath">
|
|
72
|
+
Link or path to external system documentation.
|
|
73
|
+
Only used when external-codebase is also provided.
|
|
74
|
+
Provides supplementary context for external analysis.
|
|
75
|
+
</param>
|
|
76
|
+
<param name="lib-docs" type="weblinks and/or filepaths">
|
|
77
|
+
Space-separated string of weblinks and/or file paths to library or API documentation.
|
|
78
|
+
These are injected into the story's Relevant Wiki section as a
|
|
79
|
+
`### Library Documentation` subsection after pass 2 completes,
|
|
80
|
+
so that passes 4-5 (integration analysis, technical solution) can
|
|
81
|
+
reference them when designing the implementation.
|
|
82
|
+
Useful for third-party libraries, SDK docs, or API references
|
|
83
|
+
that inform how the story should be built.
|
|
84
|
+
</param>
|
|
85
|
+
</optional>
|
|
86
|
+
</parameters>
|
|
87
|
+
</input>
|
|
88
|
+
|
|
89
|
+
<execution-context>
|
|
90
|
+
<!-- All supporting files are auto-loaded in the Supporting Resources section above.
|
|
91
|
+
The model does NOT need to Read these files — they are already in context. -->
|
|
92
|
+
</execution-context>
|
|
93
|
+
|
|
94
|
+
<output>
|
|
95
|
+
<objective>
|
|
96
|
+
Take a story seed (stub file, GitHub issue, or any text description) and produce
|
|
97
|
+
a COMPLETE story specification through deep questioning that ensures:
|
|
98
|
+
- ZERO ASSUMPTIONS — every behavior is explicitly specified
|
|
99
|
+
- CRYSTAL-CLEAR acceptance criteria with exact triggers, preconditions, outcomes
|
|
100
|
+
- INVEST compliance — Independent, Negotiable, Valuable, Estimable, Small, Testable
|
|
101
|
+
- Gherkin scenarios cover happy paths, edge cases, AND error paths
|
|
102
|
+
|
|
103
|
+
After story requirements are defined (pass 1), dispatch research passes 2-5
|
|
104
|
+
as background agents:
|
|
105
|
+
- Pass 2: Wiki research (updates story file with Relevant Wiki section)
|
|
106
|
+
- Pass 3: External analysis (OPTIONAL — creates external-analysis.md)
|
|
107
|
+
- Pass 4: Integration analysis (creates integration-analysis.md)
|
|
108
|
+
- Pass 5: Technical solution (appends to story file)
|
|
109
|
+
|
|
110
|
+
Each research pass writes directly to disk. The orchestrator context window
|
|
111
|
+
contains ONLY story requirements — research outputs do NOT flow back.
|
|
112
|
+
</objective>
|
|
113
|
+
|
|
114
|
+
<artifacts>
|
|
115
|
+
.ace/artifacts/product/<id-epic_name>/<id-feature_name>/<id-story_name>/<id-story_name>.md
|
|
116
|
+
.ace/artifacts/product/<id-epic_name>/<id-feature_name>/<id-story_name>/external-analysis.md (OPTIONAL)
|
|
117
|
+
.ace/artifacts/product/<id-epic_name>/<id-feature_name>/<id-story_name>/integration-analysis.md
|
|
118
|
+
</artifacts>
|
|
119
|
+
</output>
|
|
120
|
+
|
|
121
|
+
<process>
|
|
122
|
+
For this command use the `ace-product-owner` agent
|
|
123
|
+
that's specialized in requirements gathering, deep questioning, and story specification.
|
|
124
|
+
|
|
125
|
+
Execute the plan-story workflow from
|
|
126
|
+
`workflow.xml` end-to-end.
|
|
127
|
+
Preserve all workflow gates (validation, approvals, commits).
|
|
128
|
+
|
|
129
|
+
**CRITICAL — Context Window Protection:**
|
|
130
|
+
Passes 2-5 run as background agents. Each agent writes output directly to files.
|
|
131
|
+
The orchestrator MUST NOT call TaskOutput on any background agent.
|
|
132
|
+
The orchestrator only needs to know when each pass finishes to start the next one.
|
|
133
|
+
|
|
134
|
+
**Pass execution order:**
|
|
135
|
+
Pass 2 + Pass 3 (if applicable) → wait → Pass 4 → wait → Pass 5 → wait → done
|
|
136
|
+
</process>
|
|
137
|
+
|
|
138
|
+
<example-usage>
|
|
139
|
+
```
|
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* plan-story skill script — Entry point for all ace-tools operations
|
|
5
|
+
* needed by the plan-story skill.
|
|
6
|
+
*
|
|
7
|
+
* Subcommands:
|
|
8
|
+
* init [story-param] Environment detection for plan-story workflow
|
|
9
|
+
* update-state story=X status=Y Update story status across files
|
|
10
|
+
* sync-github repo=X story_file=Y Sync story/feature to GitHub
|
|
11
|
+
* resolve-model <agent-type> Get model for agent based on profile
|
|
12
|
+
*
|
|
13
|
+
* Usage: node script.js <subcommand> [args] [--raw]
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
const fs = require('fs');
|
|
17
|
+
const path = require('path');
|
|
18
|
+
|
|
19
|
+
const {
|
|
20
|
+
loadConfig, pathExists, safeReadFile, generateSlug, resolveModel,
|
|
21
|
+
detectBrownfieldStatus, loadSettings, execCommand,
|
|
22
|
+
output, error, runSkillScript,
|
|
23
|
+
} = require('../../shared/lib/ace-core');
|
|
24
|
+
|
|
25
|
+
const {
|
|
26
|
+
classifyStoryParam, extractStoryMetadata, extractStoryRequirements,
|
|
27
|
+
extractIssueNumber, extractIssueNumberFromFile, computeStoryPaths,
|
|
28
|
+
updateState,
|
|
29
|
+
} = require('../../shared/lib/ace-story');
|
|
30
|
+
|
|
31
|
+
const { syncStory, resolveFields, createIssue } = require('../../shared/lib/ace-github');
|
|
32
|
+
|
|
33
|
+
// ─── CLI Dispatch ────────────────────────────────────────────────────────────
|
|
34
|
+
|
|
35
|
+
runSkillScript({
|
|
36
|
+
init: cmdInit,
|
|
37
|
+
'update-state': (cwd, raw, args) => updateState(cwd, raw, args),
|
|
38
|
+
'sync-github': (cwd, raw, args) => syncStory(cwd, raw, args),
|
|
39
|
+
'resolve-model': (cwd, raw, args, parsed) => {
|
|
40
|
+
const agentType = parsed._positional || args[0];
|
|
41
|
+
if (!agentType) error('resolve-model requires agent-type argument');
|
|
42
|
+
const model = resolveModel(cwd, agentType);
|
|
43
|
+
output({ model, agent: agentType }, raw, model);
|
|
44
|
+
},
|
|
45
|
+
'generate-slug': (cwd, raw, args, parsed) => {
|
|
46
|
+
const text = parsed._positional || args.join(' ');
|
|
47
|
+
if (!text) error('generate-slug requires text argument');
|
|
48
|
+
const slug = generateSlug(text);
|
|
49
|
+
output({ slug }, raw, slug);
|
|
50
|
+
},
|
|
51
|
+
'resolve-fields': (cwd, raw, args) => resolveFields(cwd, raw, args),
|
|
52
|
+
'create-issue': (cwd, raw, args) => createIssue(cwd, raw, args),
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
// ─── Init: Plan Story ────────────────────────────────────────────────────────
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Environment detection for the plan-story workflow.
|
|
59
|
+
*
|
|
60
|
+
* Detects: git, gh CLI, GitHub project, brownfield status, wiki state,
|
|
61
|
+
* product artifacts, and story source/content/metadata.
|
|
62
|
+
*
|
|
63
|
+
* Supports three input modes:
|
|
64
|
+
* - story param provided → loads existing file or fetches GitHub issue
|
|
65
|
+
* - text param provided (no story) → uses inline text as seed description
|
|
66
|
+
* - neither → new story mode, workflow handles placement
|
|
67
|
+
*
|
|
68
|
+
* initArgs: array of arguments — either a single positional path/URL,
|
|
69
|
+
* or key=value pairs (story=X text=Y)
|
|
70
|
+
*/
|
|
71
|
+
function cmdInit(cwd, raw, args, parsed) {
|
|
72
|
+
const config = loadConfig(cwd);
|
|
73
|
+
const brownfield = detectBrownfieldStatus(cwd);
|
|
74
|
+
|
|
75
|
+
// ── Environment detection ──
|
|
76
|
+
const has_git = pathExists(cwd, '.git');
|
|
77
|
+
const has_gh_cli = (() => {
|
|
78
|
+
try {
|
|
79
|
+
const { execSync } = require('child_process');
|
|
80
|
+
execSync('gh --version', { stdio: 'pipe' });
|
|
81
|
+
return true;
|
|
82
|
+
} catch { return false; }
|
|
83
|
+
})();
|
|
84
|
+
const github_project = loadSettings(cwd).github_project;
|
|
85
|
+
|
|
86
|
+
// Wiki detection
|
|
87
|
+
const wikiSystemDir = '.docs/wiki/system-wide';
|
|
88
|
+
const has_wiki_system_wide = pathExists(cwd, wikiSystemDir);
|
|
89
|
+
const wikiSubsystemsDir = '.docs/wiki/subsystems';
|
|
90
|
+
const has_wiki_subsystems = pathExists(cwd, wikiSubsystemsDir);
|
|
91
|
+
let wiki_subsystem_names = [];
|
|
92
|
+
if (has_wiki_subsystems) {
|
|
93
|
+
try {
|
|
94
|
+
const entries = fs.readdirSync(path.join(cwd, wikiSubsystemsDir), { withFileTypes: true });
|
|
95
|
+
wiki_subsystem_names = entries.filter(e => e.isDirectory()).map(e => e.name);
|
|
96
|
+
} catch {}
|
|
97
|
+
}
|
|
98
|
+
const has_wiki = has_wiki_system_wide || has_wiki_subsystems;
|
|
99
|
+
|
|
100
|
+
// ── Parse input from shared parsed args ──
|
|
101
|
+
const resolvedStoryParam = parsed.story || parsed._positional || null;
|
|
102
|
+
const textParam = parsed.text || null;
|
|
103
|
+
|
|
104
|
+
// ── Base result (shared across all modes) ──
|
|
105
|
+
const baseResult = {
|
|
106
|
+
product_owner_model: resolveModel(cwd, 'ace-product-owner'),
|
|
107
|
+
commit_docs: config.commit_docs,
|
|
108
|
+
has_git, has_gh_cli, github_project,
|
|
109
|
+
...brownfield,
|
|
110
|
+
has_wiki, has_wiki_system_wide, has_wiki_subsystems, wiki_subsystem_names,
|
|
111
|
+
has_product_vision: pathExists(cwd, '.docs/product/product-vision.md'),
|
|
112
|
+
has_product_backlog: pathExists(cwd, '.ace/artifacts/product/product-backlog.md'),
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
// ── Mode 1: No story param and no text → new story mode ──
|
|
116
|
+
if (!resolvedStoryParam && !textParam) {
|
|
117
|
+
output({
|
|
118
|
+
...baseResult,
|
|
119
|
+
story_source: 'new',
|
|
120
|
+
story_valid: true,
|
|
121
|
+
story_error: null,
|
|
122
|
+
story_content: null,
|
|
123
|
+
story: { id: null, title: null, status: null, size: null, issue_number: null },
|
|
124
|
+
feature: { id: null, title: null, issue_number: null },
|
|
125
|
+
epic: { id: null, title: null },
|
|
126
|
+
user_story: null, description: null, acceptance_criteria_count: 0,
|
|
127
|
+
paths: null,
|
|
128
|
+
has_external_analysis: false, has_integration_analysis: false,
|
|
129
|
+
has_feature_file: false, has_story_file: false,
|
|
130
|
+
}, raw);
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// ── Mode 2: Text param only → use text as seed description ──
|
|
135
|
+
if (!resolvedStoryParam && textParam) {
|
|
136
|
+
output({
|
|
137
|
+
...baseResult,
|
|
138
|
+
story_source: 'text',
|
|
139
|
+
story_valid: true,
|
|
140
|
+
story_error: null,
|
|
141
|
+
story_content: textParam,
|
|
142
|
+
story: { id: null, title: null, status: null, size: null, issue_number: null },
|
|
143
|
+
feature: { id: null, title: null, issue_number: null },
|
|
144
|
+
epic: { id: null, title: null },
|
|
145
|
+
user_story: null, description: textParam, acceptance_criteria_count: 0,
|
|
146
|
+
paths: null,
|
|
147
|
+
has_external_analysis: false, has_integration_analysis: false,
|
|
148
|
+
has_feature_file: false, has_story_file: false,
|
|
149
|
+
}, raw);
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// ── Mode 3: Story param provided → classify and load ──
|
|
154
|
+
const classified = classifyStoryParam(resolvedStoryParam);
|
|
155
|
+
|
|
156
|
+
// Invalid param
|
|
157
|
+
if (classified.type === null || classified.type === 'invalid') {
|
|
158
|
+
output({
|
|
159
|
+
...baseResult,
|
|
160
|
+
story_source: null,
|
|
161
|
+
story_valid: false,
|
|
162
|
+
story_error: classified.reason || 'No story parameter provided',
|
|
163
|
+
story_content: null,
|
|
164
|
+
story: { id: null, title: null, status: null, size: null, issue_number: null },
|
|
165
|
+
feature: { id: null, title: null, issue_number: null },
|
|
166
|
+
epic: { id: null, title: null },
|
|
167
|
+
user_story: null, description: null, acceptance_criteria_count: 0,
|
|
168
|
+
paths: null,
|
|
169
|
+
has_external_analysis: false, has_integration_analysis: false,
|
|
170
|
+
has_feature_file: false, has_story_file: false,
|
|
171
|
+
}, raw);
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// ── Load story content ──
|
|
176
|
+
let storyContent = null;
|
|
177
|
+
let storySource = classified.type === 'file' ? 'file' : 'github';
|
|
178
|
+
let storyError = null;
|
|
179
|
+
let storyFilePath = null;
|
|
180
|
+
|
|
181
|
+
if (classified.type === 'file') {
|
|
182
|
+
const resolvedPath = path.isAbsolute(classified.filePath)
|
|
183
|
+
? classified.filePath
|
|
184
|
+
: path.join(cwd, classified.filePath);
|
|
185
|
+
if (!pathExists(cwd, classified.filePath)) {
|
|
186
|
+
storyError = `Story file not found: ${classified.filePath}`;
|
|
187
|
+
} else {
|
|
188
|
+
storyContent = safeReadFile(resolvedPath);
|
|
189
|
+
storyFilePath = classified.filePath;
|
|
190
|
+
if (!storyContent) storyError = `Could not read story file: ${classified.filePath}`;
|
|
191
|
+
}
|
|
192
|
+
} else {
|
|
193
|
+
// github-url or issue-number
|
|
194
|
+
if (!has_gh_cli) {
|
|
195
|
+
storyError = 'GitHub CLI (gh) not installed. Cannot fetch GitHub issues.';
|
|
196
|
+
} else {
|
|
197
|
+
const repo = classified.repo || (github_project.repo || null);
|
|
198
|
+
if (!repo) {
|
|
199
|
+
storyError = 'No repository configured. Provide a full GitHub URL or configure github_project.repo in settings.';
|
|
200
|
+
} else {
|
|
201
|
+
const ghResult = execCommand(
|
|
202
|
+
`gh issue view ${classified.issueNumber} --repo ${repo} --json title,body,labels,state`,
|
|
203
|
+
cwd
|
|
204
|
+
);
|
|
205
|
+
if (!ghResult) {
|
|
206
|
+
storyError = `Could not fetch GitHub issue #${classified.issueNumber} from ${repo}.`;
|
|
207
|
+
} else {
|
|
208
|
+
try {
|
|
209
|
+
const issue = JSON.parse(ghResult);
|
|
210
|
+
storyContent = issue.body || '';
|
|
211
|
+
if (storyContent && !storyContent.match(/^#\s+/m)) {
|
|
212
|
+
storyContent = `# ${issue.title}\n\n${storyContent}`;
|
|
213
|
+
}
|
|
214
|
+
} catch {
|
|
215
|
+
storyError = `Failed to parse GitHub issue response for #${classified.issueNumber}.`;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// ── Extract metadata & requirements ──
|
|
223
|
+
const metadata = extractStoryMetadata(storyContent);
|
|
224
|
+
const requirements = extractStoryRequirements(storyContent);
|
|
225
|
+
|
|
226
|
+
// ── Compute paths ──
|
|
227
|
+
let paths = null;
|
|
228
|
+
let has_story_file = false;
|
|
229
|
+
|
|
230
|
+
if (storyFilePath) {
|
|
231
|
+
const resolvedPath = path.isAbsolute(storyFilePath)
|
|
232
|
+
? storyFilePath
|
|
233
|
+
: path.join(cwd, storyFilePath);
|
|
234
|
+
const storyDir = path.dirname(resolvedPath);
|
|
235
|
+
const relStoryDir = path.relative(cwd, storyDir).replace(/\\/g, '/');
|
|
236
|
+
const storySlug = path.basename(storyDir);
|
|
237
|
+
const featureDir = path.dirname(storyDir);
|
|
238
|
+
const relFeatureDir = path.relative(cwd, featureDir).replace(/\\/g, '/');
|
|
239
|
+
const featureSlug = path.basename(featureDir);
|
|
240
|
+
|
|
241
|
+
paths = {
|
|
242
|
+
epic_slug: null,
|
|
243
|
+
feature_slug: featureSlug,
|
|
244
|
+
story_slug: storySlug,
|
|
245
|
+
story_dir: relStoryDir,
|
|
246
|
+
story_file: storyFilePath.replace(/\\/g, '/'),
|
|
247
|
+
external_analysis_file: `${relStoryDir}/external-analysis.md`,
|
|
248
|
+
integration_analysis_file: `${relStoryDir}/integration-analysis.md`,
|
|
249
|
+
feature_dir: relFeatureDir,
|
|
250
|
+
feature_file: `${relFeatureDir}/${featureSlug}.md`,
|
|
251
|
+
};
|
|
252
|
+
has_story_file = true;
|
|
253
|
+
} else if (metadata.epic.id && metadata.feature.id && metadata.id) {
|
|
254
|
+
paths = computeStoryPaths(
|
|
255
|
+
metadata.epic.id, metadata.epic.title || '',
|
|
256
|
+
metadata.feature.id, metadata.feature.title || '',
|
|
257
|
+
metadata.id, metadata.title || ''
|
|
258
|
+
);
|
|
259
|
+
has_story_file = paths ? pathExists(cwd, paths.story_file) : false;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// ── Check artifact existence ──
|
|
263
|
+
const has_external_analysis = paths ? pathExists(cwd, paths.external_analysis_file) : false;
|
|
264
|
+
const has_integration_analysis = paths ? pathExists(cwd, paths.integration_analysis_file) : false;
|
|
265
|
+
const has_feature_file = paths ? pathExists(cwd, paths.feature_file) : false;
|
|
266
|
+
|
|
267
|
+
// ── Build result ──
|
|
268
|
+
output({
|
|
269
|
+
...baseResult,
|
|
270
|
+
story_source: storySource,
|
|
271
|
+
story_valid: storyContent !== null && storyError === null,
|
|
272
|
+
story_error: storyError,
|
|
273
|
+
story_content: storyContent,
|
|
274
|
+
story: {
|
|
275
|
+
id: metadata.id,
|
|
276
|
+
title: metadata.title,
|
|
277
|
+
status: metadata.status,
|
|
278
|
+
size: metadata.size,
|
|
279
|
+
issue_number: extractIssueNumber(metadata.link),
|
|
280
|
+
},
|
|
281
|
+
feature: {
|
|
282
|
+
...metadata.feature,
|
|
283
|
+
issue_number: paths ? extractIssueNumberFromFile(cwd, paths.feature_file) : null,
|
|
284
|
+
},
|
|
285
|
+
epic: metadata.epic,
|
|
286
|
+
user_story: requirements.user_story,
|
|
287
|
+
description: requirements.description,
|
|
288
|
+
acceptance_criteria_count: requirements.acceptance_criteria_count,
|
|
289
|
+
paths,
|
|
290
|
+
has_external_analysis,
|
|
291
|
+
has_integration_analysis,
|
|
292
|
+
has_feature_file,
|
|
293
|
+
has_story_file,
|
|
294
|
+
}, raw);
|
|
295
|
+
}
|