agile-context-engineering 0.2.2 → 0.5.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.
Files changed (146) hide show
  1. package/.claude-plugin/plugin.json +10 -0
  2. package/CHANGELOG.md +82 -0
  3. package/README.md +27 -18
  4. package/agents/ace-product-owner.md +1 -1
  5. package/agents/ace-technical-application-architect.md +28 -0
  6. package/agents/ace-wiki-mapper.md +144 -29
  7. package/bin/install.js +67 -63
  8. package/hooks/ace-check-update.js +17 -9
  9. package/package.json +7 -5
  10. package/shared/lib/ace-core.js +308 -0
  11. package/shared/lib/ace-core.test.js +308 -0
  12. package/shared/lib/ace-github.js +753 -0
  13. package/shared/lib/ace-story.js +400 -0
  14. package/shared/lib/ace-story.test.js +250 -0
  15. package/{agile-context-engineering → shared}/utils/ui-formatting.md +299 -299
  16. package/skills/execute-story/SKILL.md +110 -0
  17. package/skills/execute-story/script.js +305 -0
  18. package/skills/execute-story/script.test.js +261 -0
  19. package/skills/execute-story/walkthrough-template.xml +255 -0
  20. package/{agile-context-engineering/workflows/execute-story.xml → skills/execute-story/workflow.xml} +83 -9
  21. package/skills/help/SKILL.md +69 -0
  22. package/skills/help/script.js +318 -0
  23. package/skills/help/script.test.js +183 -0
  24. package/{agile-context-engineering/workflows/help.xml → skills/help/workflow.xml} +8 -8
  25. package/skills/init-coding-standards/SKILL.md +72 -0
  26. package/{agile-context-engineering/templates/wiki/coding-standards.xml → skills/init-coding-standards/coding-standards-template.xml} +38 -0
  27. package/skills/init-coding-standards/script.js +59 -0
  28. package/skills/init-coding-standards/script.test.js +70 -0
  29. package/{agile-context-engineering/workflows/init-coding-standards.xml → skills/init-coding-standards/workflow.xml} +4 -9
  30. package/skills/map-cross-cutting/SKILL.md +89 -0
  31. package/skills/map-cross-cutting/workflow.xml +330 -0
  32. package/skills/map-guide/SKILL.md +89 -0
  33. package/skills/map-guide/workflow.xml +320 -0
  34. package/skills/map-pattern/SKILL.md +89 -0
  35. package/skills/map-pattern/workflow.xml +331 -0
  36. package/skills/map-story/SKILL.md +127 -0
  37. package/skills/map-story/templates/guide.xml +137 -0
  38. package/skills/map-story/templates/pattern.xml +159 -0
  39. package/skills/map-story/templates/system-cross-cutting.xml +197 -0
  40. package/skills/map-story/templates/walkthrough.xml +255 -0
  41. package/{agile-context-engineering/workflows/map-story.xml → skills/map-story/workflow.xml} +258 -9
  42. package/skills/map-subsystem/SKILL.md +111 -0
  43. package/skills/map-subsystem/script.js +60 -0
  44. package/skills/map-subsystem/script.test.js +68 -0
  45. package/skills/map-subsystem/templates/decizions.xml +115 -0
  46. package/skills/map-subsystem/templates/guide.xml +137 -0
  47. package/{agile-context-engineering/templates/wiki → skills/map-subsystem/templates}/module-discovery.xml +3 -3
  48. package/skills/map-subsystem/templates/pattern.xml +159 -0
  49. package/skills/map-subsystem/templates/system-cross-cutting.xml +197 -0
  50. package/skills/map-subsystem/templates/system.xml +381 -0
  51. package/skills/map-subsystem/templates/walkthrough.xml +255 -0
  52. package/{agile-context-engineering/workflows/map-subsystem.xml → skills/map-subsystem/workflow.xml} +17 -21
  53. package/skills/map-sys-doc/SKILL.md +90 -0
  54. package/skills/map-sys-doc/system.xml +381 -0
  55. package/skills/map-sys-doc/workflow.xml +336 -0
  56. package/skills/map-system/SKILL.md +85 -0
  57. package/skills/map-system/script.js +84 -0
  58. package/skills/map-system/script.test.js +73 -0
  59. package/skills/map-system/templates/wiki-readme.xml +297 -0
  60. package/{agile-context-engineering/workflows/map-system.xml → skills/map-system/workflow.xml} +11 -16
  61. package/skills/map-walkthrough/SKILL.md +92 -0
  62. package/skills/map-walkthrough/walkthrough.xml +255 -0
  63. package/skills/map-walkthrough/workflow.xml +457 -0
  64. package/skills/plan-backlog/SKILL.md +75 -0
  65. package/skills/plan-backlog/script.js +136 -0
  66. package/skills/plan-backlog/script.test.js +83 -0
  67. package/{agile-context-engineering/workflows/plan-backlog.xml → skills/plan-backlog/workflow.xml} +13 -21
  68. package/skills/plan-feature/SKILL.md +76 -0
  69. package/skills/plan-feature/script.js +148 -0
  70. package/skills/plan-feature/script.test.js +80 -0
  71. package/{agile-context-engineering/workflows/plan-feature.xml → skills/plan-feature/workflow.xml} +21 -29
  72. package/skills/plan-product-vision/SKILL.md +75 -0
  73. package/skills/plan-product-vision/script.js +60 -0
  74. package/skills/plan-product-vision/script.test.js +69 -0
  75. package/{agile-context-engineering/workflows/plan-product-vision.xml → skills/plan-product-vision/workflow.xml} +4 -9
  76. package/skills/plan-story/SKILL.md +116 -0
  77. package/skills/plan-story/script.js +326 -0
  78. package/skills/plan-story/script.test.js +240 -0
  79. package/skills/plan-story/story-template.xml +451 -0
  80. package/{agile-context-engineering/workflows/plan-story.xml → skills/plan-story/workflow.xml} +1285 -909
  81. package/skills/research-external-solution/SKILL.md +107 -0
  82. package/skills/research-external-solution/script.js +238 -0
  83. package/skills/research-external-solution/script.test.js +134 -0
  84. package/{agile-context-engineering/workflows/research-external-solution.xml → skills/research-external-solution/workflow.xml} +4 -6
  85. package/skills/research-integration-solution/SKILL.md +98 -0
  86. package/{agile-context-engineering/templates/product/story-integration-solution.xml → skills/research-integration-solution/integration-solution-template.xml} +1 -0
  87. package/skills/research-integration-solution/script.js +231 -0
  88. package/skills/research-integration-solution/script.test.js +134 -0
  89. package/{agile-context-engineering/workflows/research-integration-solution.xml → skills/research-integration-solution/workflow.xml} +4 -5
  90. package/skills/research-story-wiki/SKILL.md +92 -0
  91. package/skills/research-story-wiki/script.js +231 -0
  92. package/skills/research-story-wiki/script.test.js +138 -0
  93. package/{agile-context-engineering/templates/product/story-wiki.xml → skills/research-story-wiki/story-wiki-template.xml} +4 -0
  94. package/{agile-context-engineering/workflows/research-story-wiki.xml → skills/research-story-wiki/workflow.xml} +5 -6
  95. package/skills/research-technical-solution/SKILL.md +103 -0
  96. package/skills/research-technical-solution/script.js +231 -0
  97. package/skills/research-technical-solution/script.test.js +134 -0
  98. package/{agile-context-engineering/workflows/research-technical-solution.xml → skills/research-technical-solution/workflow.xml} +4 -5
  99. package/skills/review-story/SKILL.md +100 -0
  100. package/skills/review-story/script.js +257 -0
  101. package/skills/review-story/script.test.js +169 -0
  102. package/skills/review-story/story-template.xml +451 -0
  103. package/{agile-context-engineering/workflows/review-story.xml → skills/review-story/workflow.xml} +1 -3
  104. package/skills/update/SKILL.md +53 -0
  105. package/{agile-context-engineering/workflows/update.xml → skills/update/workflow.xml} +237 -207
  106. package/agile-context-engineering/src/ace-tools.js +0 -2881
  107. package/agile-context-engineering/src/ace-tools.test.js +0 -1089
  108. package/agile-context-engineering/templates/_command.md +0 -54
  109. package/agile-context-engineering/templates/_workflow.xml +0 -17
  110. package/agile-context-engineering/templates/config.json +0 -0
  111. package/agile-context-engineering/templates/product/integration-solution.xml +0 -0
  112. package/agile-context-engineering/templates/wiki/wiki-readme.xml +0 -276
  113. package/commands/ace/execute-story.md +0 -137
  114. package/commands/ace/help.md +0 -93
  115. package/commands/ace/init-coding-standards.md +0 -83
  116. package/commands/ace/map-story.md +0 -156
  117. package/commands/ace/map-subsystem.md +0 -138
  118. package/commands/ace/map-system.md +0 -92
  119. package/commands/ace/plan-backlog.md +0 -83
  120. package/commands/ace/plan-feature.md +0 -89
  121. package/commands/ace/plan-product-vision.md +0 -81
  122. package/commands/ace/plan-story.md +0 -145
  123. package/commands/ace/research-external-solution.md +0 -138
  124. package/commands/ace/research-integration-solution.md +0 -135
  125. package/commands/ace/research-story-wiki.md +0 -116
  126. package/commands/ace/research-technical-solution.md +0 -147
  127. package/commands/ace/review-story.md +0 -109
  128. package/commands/ace/update.md +0 -54
  129. /package/{agile-context-engineering → shared}/utils/questioning.xml +0 -0
  130. /package/{agile-context-engineering/templates/product/story.xml → skills/execute-story/story-template.xml} +0 -0
  131. /package/{agile-context-engineering/templates/wiki → skills/map-cross-cutting}/system-cross-cutting.xml +0 -0
  132. /package/{agile-context-engineering/templates/wiki → skills/map-guide}/guide.xml +0 -0
  133. /package/{agile-context-engineering/templates/wiki → skills/map-pattern}/pattern.xml +0 -0
  134. /package/{agile-context-engineering/templates/wiki → skills/map-story/templates}/decizions.xml +0 -0
  135. /package/{agile-context-engineering/templates/wiki → skills/map-story/templates}/system.xml +0 -0
  136. /package/{agile-context-engineering/templates/wiki → skills/map-story/templates}/tech-debt-index.xml +0 -0
  137. /package/{agile-context-engineering/templates/wiki → skills/map-subsystem/templates}/subsystem-architecture.xml +0 -0
  138. /package/{agile-context-engineering/templates/wiki → skills/map-subsystem/templates}/subsystem-structure.xml +0 -0
  139. /package/{agile-context-engineering/templates/wiki → skills/map-system/templates}/system-architecture.xml +0 -0
  140. /package/{agile-context-engineering/templates/wiki → skills/map-system/templates}/system-structure.xml +0 -0
  141. /package/{agile-context-engineering/templates/wiki → skills/map-system/templates}/testing-framework.xml +0 -0
  142. /package/{agile-context-engineering/templates/product/product-backlog.xml → skills/plan-backlog/product-backlog-template.xml} +0 -0
  143. /package/{agile-context-engineering/templates/product/feature.xml → skills/plan-feature/feature-template.xml} +0 -0
  144. /package/{agile-context-engineering/templates/product/product-vision.xml → skills/plan-product-vision/product-vision-template.xml} +0 -0
  145. /package/{agile-context-engineering/templates/product/external-solution.xml → skills/research-external-solution/external-solution-template.xml} +0 -0
  146. /package/{agile-context-engineering/templates/product/story-technical-solution.xml → skills/research-technical-solution/technical-solution-template.xml} +0 -0
@@ -0,0 +1,83 @@
1
+ const { describe, it, before, after } = require('node:test');
2
+ const assert = require('node:assert');
3
+ const { execSync } = require('child_process');
4
+ const fs = require('fs');
5
+ const path = require('path');
6
+ const os = require('os');
7
+
8
+ const SCRIPT = path.join(__dirname, 'script.js');
9
+
10
+ function createTestProject() {
11
+ const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'ace-test-'));
12
+
13
+ const aceDir = path.join(tmpDir, '.ace');
14
+ fs.mkdirSync(aceDir, { recursive: true });
15
+ fs.writeFileSync(path.join(aceDir, 'config.json'), JSON.stringify({
16
+ version: '0.1.0',
17
+ projectName: 'test-project',
18
+ model_profile: 'quality',
19
+ commit_docs: true,
20
+ github: { enabled: false },
21
+ }, null, 2));
22
+
23
+ fs.writeFileSync(path.join(aceDir, 'settings.json'), JSON.stringify({
24
+ model_profile: 'quality',
25
+ commit_docs: true,
26
+ agent_teams: false,
27
+ github_project: { enabled: false, gh_installed: false, repo: '', project_number: null, owner: '' },
28
+ }, null, 2));
29
+
30
+ return tmpDir;
31
+ }
32
+
33
+ function runScript(subcommand, args, cwd) {
34
+ return execSync(`node "${SCRIPT}" ${subcommand} ${args}`, {
35
+ cwd,
36
+ encoding: 'utf-8',
37
+ timeout: 10000,
38
+ });
39
+ }
40
+
41
+ function cleanup(tmpDir) {
42
+ fs.rmSync(tmpDir, { recursive: true, force: true });
43
+ }
44
+
45
+ describe('plan-backlog script', () => {
46
+ it('errors on unknown command', () => {
47
+ assert.throws(() => {
48
+ execSync(`node "${SCRIPT}" bogus`, { encoding: 'utf-8', stdio: 'pipe' });
49
+ });
50
+ });
51
+
52
+ describe('init', () => {
53
+ let tmpDir;
54
+
55
+ before(() => { tmpDir = createTestProject(); });
56
+ after(() => { cleanup(tmpDir); });
57
+
58
+ it('init returns valid JSON', () => {
59
+ const result = JSON.parse(runScript('init', '', tmpDir));
60
+ assert.ok(typeof result === 'object');
61
+ assert.ok(result.product_owner_model, 'should have product_owner_model');
62
+ assert.ok(result.researcher_model, 'should have researcher_model');
63
+ assert.strictEqual(typeof result.commit_docs, 'boolean');
64
+ assert.strictEqual(typeof result.has_git, 'boolean');
65
+ assert.strictEqual(typeof result.is_brownfield, 'boolean');
66
+ assert.strictEqual(typeof result.has_product_vision, 'boolean');
67
+ assert.strictEqual(typeof result.has_product_backlog, 'boolean');
68
+ assert.strictEqual(typeof result.has_features_research, 'boolean');
69
+ assert.strictEqual(typeof result.has_architecture_research, 'boolean');
70
+ assert.strictEqual(typeof result.has_wiki_analysis, 'boolean');
71
+ assert.strictEqual(typeof result.has_wiki, 'boolean');
72
+ assert.strictEqual(typeof result.has_gh_cli, 'boolean');
73
+ assert.ok(result.github_project !== undefined, 'should have github_project');
74
+ });
75
+
76
+ it('returns brownfield detection fields', () => {
77
+ const result = JSON.parse(runScript('init', '', tmpDir));
78
+ assert.strictEqual(typeof result.is_brownfield, 'boolean');
79
+ assert.strictEqual(typeof result.is_greenfield, 'boolean');
80
+ assert.strictEqual(result.is_brownfield, !result.is_greenfield);
81
+ });
82
+ });
83
+ });
@@ -28,11 +28,9 @@
28
28
  <step name="setup" order="1">
29
29
  **MANDATORY FIRST STEP — Execute environment detection before any user interaction:**
30
30
 
31
- ```bash
32
- INIT=$(node ~/.claude/agile-context-engineering/src/ace-tools.js init plan-backlog)
33
- ```
31
+ INIT is available from the preprocessed Environment Context above — do NOT re-run init.
34
32
 
35
- Parse JSON for: `product_owner_model`, `researcher_model`, `commit_docs`,
33
+ Parse INIT JSON for: `product_owner_model`, `researcher_model`, `commit_docs`,
36
34
  `has_product_vision`, `has_product_backlog`,
37
35
  `has_features_research`, `has_architecture_research`, `has_wiki_analysis`,
38
36
  `is_brownfield`, `is_greenfield`,
@@ -41,10 +39,7 @@
41
39
  `has_system_structure`, `has_testing_framework`, `has_git`, `has_gh_cli`,
42
40
  `github_project` (object: `enabled`, `gh_installed`, `repo`, `project_number`, `owner`).
43
41
 
44
- Also resolve the product owner model for spawning the writing agent:
45
- ```bash
46
- PO_MODEL=$(node ~/.claude/agile-context-engineering/src/ace-tools.js resolve-model ace-product-owner --raw)
47
- ```
42
+ PO_MODEL is available from INIT.product_owner_model do NOT re-run resolve-model.
48
43
 
49
44
  Display stage banner:
50
45
 
@@ -145,7 +140,7 @@
145
140
  **Fetch all epics and features with full field data (single command):**
146
141
 
147
142
  ```bash
148
- GITHUB_ISSUES=$(node ~/.claude/agile-context-engineering/src/ace-tools.js github fetch-issues \
143
+ GITHUB_ISSUES=$(node "${CLAUDE_SKILL_DIR}/script.js" fetch-issues \
149
144
  repo={REPO} owner={OWNER} project={PROJECT_NUMBER})
150
145
  ```
151
146
 
@@ -549,10 +544,7 @@
549
544
  i Skipping architecture research — wiki architecture already captured in step 4.
550
545
  ```
551
546
 
552
- Resolve the researcher model:
553
- ```bash
554
- RESEARCHER_MODEL=$(node ~/.claude/agile-context-engineering/src/ace-tools.js resolve-model ace-project-researcher --raw)
555
- ```
547
+ RESEARCHER_MODEL is available from INIT.researcher_model — do NOT re-run resolve-model.
556
548
 
557
549
  **Features Researcher (always spawned):**
558
550
 
@@ -566,7 +558,7 @@
566
558
 
567
559
  Prompt:
568
560
  ```
569
- First, read ~/.claude/agents/ace-project-researcher.md for your role and instructions.
561
+ You are the ace-project-researcher agent. Follow your agent instructions.
570
562
 
571
563
  <research_type>
572
564
  Project Research — Features dimension for [domain].
@@ -609,7 +601,7 @@
609
601
 
610
602
  Prompt:
611
603
  ```
612
- First, read ~/.claude/agents/ace-project-researcher.md for your role and instructions.
604
+ You are the ace-project-researcher agent. Follow your agent instructions.
613
605
 
614
606
  <research_type>
615
607
  Project Research — Architecture/Epic structure dimension for [domain].
@@ -948,7 +940,7 @@
948
940
  {paste the context brief here}
949
941
 
950
942
  **Instructions:**
951
- 1. Read the product backlog template: ~/.claude/agile-context-engineering/templates/product/product-backlog.xml
943
+ 1. Read the product backlog template: ${CLAUDE_SKILL_DIR}/product-backlog-template.xml
952
944
  2. Write `.ace/artifacts/product/product-backlog.md` following the template structure exactly
953
945
  3. Include the header paragraph explaining product direction
954
946
  4. Write the Epic Index table (ordered by strategic priority)
@@ -1020,7 +1012,7 @@
1020
1012
  prompt="You are an Agile Product Owner editing an existing product backlog.
1021
1013
 
1022
1014
  **Read the current backlog:** `.ace/artifacts/product/product-backlog.md`
1023
- **Read the template for reference:** `~/.claude/agile-context-engineering/templates/product/product-backlog.xml`
1015
+ **Read the template for reference:** `${CLAUDE_SKILL_DIR}/product-backlog-template.xml`
1024
1016
 
1025
1017
  **Changes to apply:**
1026
1018
  {paste the change brief here}
@@ -1085,7 +1077,7 @@
1085
1077
  - Keep Feature IDs globally sequential — if adding new features, use the next available F[N]
1086
1078
  - Update Epic status to reflect aggregate feature status
1087
1079
  - Size values must be Fibonacci×10 only: 10, 20, 30, 50, 80, 130
1088
- - Re-read the template for reference: ~/.claude/agile-context-engineering/templates/product/product-backlog.xml
1080
+ - Re-read the template for reference: ${CLAUDE_SKILL_DIR}/product-backlog-template.xml
1089
1081
 
1090
1082
  Use the Edit tool to modify in place. Return only a confirmation of what changed.",
1091
1083
  subagent_type="general-purpose",
@@ -1164,7 +1156,7 @@
1164
1156
  **Prerequisite — Resolve all field and type IDs (once, before creating any issues):**
1165
1157
 
1166
1158
  ```bash
1167
- GH_FIELDS=$(node ~/.claude/agile-context-engineering/src/ace-tools.js github resolve-fields repo={REPO} owner={OWNER} project={PROJECT_NUMBER})
1159
+ GH_FIELDS=$(node "${CLAUDE_SKILL_DIR}/script.js" resolve-fields repo={REPO} owner={OWNER} project={PROJECT_NUMBER})
1168
1160
  ```
1169
1161
 
1170
1162
  Parse the JSON response. Extract and cache:
@@ -1182,7 +1174,7 @@
1182
1174
  **For each unlinked Epic (in order):**
1183
1175
 
1184
1176
  ```bash
1185
- EPIC_RESULT=$(node ~/.claude/agile-context-engineering/src/ace-tools.js github create-issue \
1177
+ EPIC_RESULT=$(node "${CLAUDE_SKILL_DIR}/script.js" create-issue \
1186
1178
  type=Epic \
1187
1179
  "title={Epic Title}" \
1188
1180
  "body={Epic Description}" \
@@ -1206,7 +1198,7 @@
1206
1198
  **If "Create new only" or "Sync all" was selected, for each unlinked Feature (in order):**
1207
1199
 
1208
1200
  ```bash
1209
- FEATURE_RESULT=$(node ~/.claude/agile-context-engineering/src/ace-tools.js github create-issue \
1201
+ FEATURE_RESULT=$(node "${CLAUDE_SKILL_DIR}/script.js" create-issue \
1210
1202
  type=Feature \
1211
1203
  "title={Feature Title}" \
1212
1204
  "body={Feature Description}" \
@@ -0,0 +1,76 @@
1
+ ---
2
+ name: plan-feature
3
+ description: Plan a feature through backlog-aware questioning, story decomposition, and guided feature specification
4
+ argument-hint: "[feature-id] [optional: context='text or file with feature description prompt']"
5
+ disable-model-invocation: true
6
+ allowed-tools: Read, Bash, Write, Task, AskUserQuestion
7
+ model: opus
8
+ effort: high
9
+ ---
10
+
11
+ # Plan Feature
12
+
13
+ Plan a feature through backlog-aware questioning, story decomposition, and guided feature specification.
14
+
15
+ ## When to Use
16
+
17
+ - After `/ace:plan-backlog` — once the backlog exists, plan individual features
18
+ - Anytime — to create or refine a feature and its story breakdown
19
+ - Product backlog exists and you want to break a feature into stories
20
+ - Starting feature-level planning and need to decompose into stories
21
+ - Refining an existing feature with updated acceptance criteria or scope
22
+ - Adding a new feature to an existing epic
23
+
24
+ ## Input
25
+
26
+ ### Optional
27
+
28
+ - **`feature-id`** — Feature identifier from the product backlog (e.g., F3, #78). If provided, locates existing feature for planning or refinement. If omitted, presents the backlog for selection or allows creating a new feature.
29
+ - **`context`** — Feature description, acceptance criteria, user stories, or any context to seed the feature planning process. Will be absorbed and refined through questioning, not used as-is.
30
+
31
+ ## Environment Context (preprocessed)
32
+
33
+ !`node "${CLAUDE_SKILL_DIR}/script.js" init "$ARGUMENTS" 2>/dev/null`
34
+
35
+ ## Supporting Resources
36
+
37
+ Read ALL of these before starting the workflow:
38
+
39
+ - **Workflow**: Read [workflow.xml](workflow.xml) — complete orchestration process with all steps
40
+ - **Feature template**: Read [feature-template.xml](feature-template.xml) — output format for the feature specification
41
+ - **Questioning guide**: Read `${CLAUDE_SKILL_DIR}/../../shared/utils/questioning.xml` — deep questioning techniques
42
+ - **UI formatting**: Read `${CLAUDE_SKILL_DIR}/../../shared/utils/ui-formatting.md` — ACE output formatting rules
43
+
44
+ ## Process
45
+
46
+ Use the `ace-product-owner` agent for requirements gathering, deep questioning, and feature specification.
47
+
48
+ The Environment Context above contains the preprocessed INIT JSON — use it directly instead of running the init script manually. The workflow's step 1 setup can skip the init bash call since that data is already available.
49
+
50
+ Read all supporting resources listed above, then execute the workflow defined in [workflow.xml](workflow.xml) end-to-end. Preserve all workflow gates (validation, approvals, commits).
51
+
52
+ ## Artifacts
53
+
54
+ ```
55
+ .ace/artifacts/product/<id-epic_name>/<id-feature_name>/<id-feature_name>.md
56
+ .ace/artifacts/product/<id-epic_name>/<id-feature_name>/<id-story_name>/<id-story_name>.md
57
+ ```
58
+
59
+ ## Example Usage
60
+
61
+ ```
62
+ # Plan a feature by ID from the backlog
63
+ /ace:plan-feature F3
64
+
65
+ # Plan a feature with seed context
66
+ /ace:plan-feature context="OAuth2 login with Google and GitHub providers"
67
+
68
+ # Plan a feature by GitHub issue number
69
+ /ace:plan-feature #78
70
+ ```
71
+
72
+ ## Next Steps
73
+
74
+ - `/ace:plan-story story=...` — Plan a story from this feature
75
+ - `/ace:plan-feature feature-id` — Plan another feature
76
+ - `/ace:help` — Check project initialization status
@@ -0,0 +1,148 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * plan-feature skill script — Entry point for ace-tools operations
5
+ * needed by the plan-feature skill.
6
+ *
7
+ * Subcommands:
8
+ * init [args] Environment detection for plan-feature workflow
9
+ * resolve-fields [args] Resolve GitHub Project field IDs
10
+ * create-issue [args] Create a GitHub issue in a project
11
+ * update-issue [args] Update a GitHub issue
12
+ * generate-slug <text> Generate a URL-safe slug from text
13
+ * verify-path-exists <path> Check if a file/directory exists
14
+ *
15
+ * Usage: node script.js <subcommand> [args] [--raw]
16
+ */
17
+
18
+ const fs = require('fs');
19
+ const path = require('path');
20
+
21
+ const {
22
+ loadConfig, pathExists, generateSlug, resolveModel,
23
+ detectBrownfieldStatus, loadSettings, output, error,
24
+ } = require('../../shared/lib/ace-core');
25
+
26
+ const {
27
+ resolveFields, createIssue, updateIssue,
28
+ } = require('../../shared/lib/ace-github');
29
+
30
+ // ─── CLI Dispatch ────────────────────────────────────────────────────────────
31
+
32
+ const cwd = process.cwd();
33
+ const args = process.argv.slice(2);
34
+ const raw = args.includes('--raw');
35
+ const cmd = args[0];
36
+
37
+ switch (cmd) {
38
+ case 'init':
39
+ cmdInit(cwd, raw, args.slice(1).filter(a => a !== '--raw'));
40
+ break;
41
+ case 'resolve-fields':
42
+ resolveFields(cwd, raw, args.slice(1).filter(a => a !== '--raw'));
43
+ break;
44
+ case 'create-issue':
45
+ createIssue(cwd, raw, args.slice(1).filter(a => a !== '--raw'));
46
+ break;
47
+ case 'update-issue':
48
+ updateIssue(cwd, raw, args.slice(1).filter(a => a !== '--raw'));
49
+ break;
50
+ case 'generate-slug': {
51
+ const text = args.slice(1).filter(a => a !== '--raw').join(' ');
52
+ if (!text) error('generate-slug requires text argument');
53
+ const slug = generateSlug(text);
54
+ output({ slug }, raw, slug);
55
+ break;
56
+ }
57
+ case 'verify-path-exists': {
58
+ const targetPath = args.slice(1).filter(a => a !== '--raw').join(' ');
59
+ if (!targetPath) error('verify-path-exists requires path argument');
60
+ const exists = pathExists(cwd, targetPath);
61
+ output({ exists, path: targetPath }, raw, String(exists));
62
+ break;
63
+ }
64
+ default:
65
+ error(`Unknown command: ${cmd}\nAvailable: init, resolve-fields, create-issue, update-issue, generate-slug, verify-path-exists`);
66
+ }
67
+
68
+ // ─── Init: Plan Feature ─────────────────────────────────────────────────────
69
+
70
+ function cmdInit(cwd, raw) {
71
+ const config = loadConfig(cwd);
72
+ const brownfield = detectBrownfieldStatus(cwd);
73
+
74
+ // Wiki detection — system-wide
75
+ const wikiSystemDir = '.docs/wiki/system-wide';
76
+ const has_wiki_system_wide = pathExists(cwd, wikiSystemDir);
77
+ const has_system_architecture = pathExists(cwd, path.join(wikiSystemDir, 'system-architecture.md'));
78
+ const has_system_structure = pathExists(cwd, path.join(wikiSystemDir, 'system-structure.md'));
79
+ const has_testing_framework = pathExists(cwd, path.join(wikiSystemDir, 'testing-framework.md'));
80
+
81
+ // Wiki detection — subsystems
82
+ const wikiSubsystemsDir = '.docs/wiki/subsystems';
83
+ const has_wiki_subsystems = pathExists(cwd, wikiSubsystemsDir);
84
+
85
+ let wiki_subsystem_names = [];
86
+ if (has_wiki_subsystems) {
87
+ try {
88
+ const entries = fs.readdirSync(path.join(cwd, wikiSubsystemsDir), { withFileTypes: true });
89
+ wiki_subsystem_names = entries
90
+ .filter(e => e.isDirectory())
91
+ .map(e => e.name);
92
+ } catch {}
93
+ }
94
+
95
+ const has_wiki = has_wiki_system_wide || has_wiki_subsystems;
96
+
97
+ const result = {
98
+ // Models
99
+ product_owner_model: resolveModel(cwd, 'ace-product-owner'),
100
+ researcher_model: resolveModel(cwd, 'ace-project-researcher'),
101
+
102
+ // Config
103
+ commit_docs: config.commit_docs,
104
+
105
+ // Product artifacts
106
+ has_product_vision: pathExists(cwd, '.docs/product/product-vision.md'),
107
+ has_product_backlog: pathExists(cwd, '.ace/artifacts/product/product-backlog.md'),
108
+
109
+ // Wiki analysis cache (from previous runs)
110
+ has_wiki_analysis: pathExists(cwd, '.ace/artifacts/wiki/wiki-analysis.md'),
111
+
112
+ // Brownfield detection
113
+ ...brownfield,
114
+
115
+ // Wiki state — system-wide
116
+ has_wiki,
117
+ has_wiki_system_wide,
118
+ has_system_architecture,
119
+ has_system_structure,
120
+ has_testing_framework,
121
+
122
+ // Wiki state — subsystems
123
+ has_wiki_subsystems,
124
+ wiki_subsystem_names,
125
+
126
+ // Git state
127
+ has_git: pathExists(cwd, '.git'),
128
+
129
+ // GitHub CLI
130
+ has_gh_cli: (() => {
131
+ try {
132
+ const { execSync } = require('child_process');
133
+ execSync('gh --version', { stdio: 'pipe' });
134
+ return true;
135
+ } catch {
136
+ return false;
137
+ }
138
+ })(),
139
+
140
+ // GitHub Project settings (from settings.json)
141
+ github_project: (() => {
142
+ const settings = loadSettings(cwd);
143
+ return settings.github_project;
144
+ })(),
145
+ };
146
+
147
+ output(result, raw);
148
+ }
@@ -0,0 +1,80 @@
1
+ const { describe, it, before, after } = require('node:test');
2
+ const assert = require('node:assert');
3
+ const { execSync } = require('child_process');
4
+ const fs = require('fs');
5
+ const path = require('path');
6
+ const os = require('os');
7
+
8
+ const SCRIPT = path.join(__dirname, 'script.js');
9
+
10
+ function createTestProject() {
11
+ const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'ace-test-'));
12
+
13
+ const aceDir = path.join(tmpDir, '.ace');
14
+ fs.mkdirSync(aceDir, { recursive: true });
15
+ fs.writeFileSync(path.join(aceDir, 'config.json'), JSON.stringify({
16
+ version: '0.1.0',
17
+ projectName: 'test-project',
18
+ model_profile: 'quality',
19
+ commit_docs: true,
20
+ github: { enabled: false },
21
+ }, null, 2));
22
+
23
+ fs.writeFileSync(path.join(aceDir, 'settings.json'), JSON.stringify({
24
+ model_profile: 'quality',
25
+ commit_docs: true,
26
+ agent_teams: false,
27
+ github_project: { enabled: false, gh_installed: false, repo: '', project_number: null, owner: '' },
28
+ }, null, 2));
29
+
30
+ return tmpDir;
31
+ }
32
+
33
+ function runScript(subcommand, args, cwd) {
34
+ return execSync(`node "${SCRIPT}" ${subcommand} ${args}`, {
35
+ cwd,
36
+ encoding: 'utf-8',
37
+ timeout: 10000,
38
+ });
39
+ }
40
+
41
+ function cleanup(tmpDir) {
42
+ fs.rmSync(tmpDir, { recursive: true, force: true });
43
+ }
44
+
45
+ describe('plan-feature script', () => {
46
+ it('errors on unknown command', () => {
47
+ assert.throws(() => {
48
+ execSync(`node "${SCRIPT}" bogus`, { encoding: 'utf-8', stdio: 'pipe' });
49
+ });
50
+ });
51
+
52
+ describe('init', () => {
53
+ let tmpDir;
54
+
55
+ before(() => { tmpDir = createTestProject(); });
56
+ after(() => { cleanup(tmpDir); });
57
+
58
+ it('init returns valid JSON', () => {
59
+ const result = JSON.parse(runScript('init', '', tmpDir));
60
+ assert.ok(typeof result === 'object');
61
+ assert.ok(result.product_owner_model, 'should have product_owner_model');
62
+ assert.ok(result.researcher_model, 'should have researcher_model');
63
+ assert.strictEqual(typeof result.commit_docs, 'boolean');
64
+ assert.strictEqual(typeof result.has_git, 'boolean');
65
+ assert.strictEqual(typeof result.is_brownfield, 'boolean');
66
+ assert.strictEqual(typeof result.has_product_vision, 'boolean');
67
+ assert.strictEqual(typeof result.has_product_backlog, 'boolean');
68
+ assert.strictEqual(typeof result.has_wiki, 'boolean');
69
+ assert.strictEqual(typeof result.has_gh_cli, 'boolean');
70
+ assert.ok(result.github_project !== undefined, 'should have github_project');
71
+ });
72
+
73
+ it('returns brownfield detection fields', () => {
74
+ const result = JSON.parse(runScript('init', '', tmpDir));
75
+ assert.strictEqual(typeof result.is_brownfield, 'boolean');
76
+ assert.strictEqual(typeof result.is_greenfield, 'boolean');
77
+ assert.strictEqual(result.is_brownfield, !result.is_greenfield);
78
+ });
79
+ });
80
+ });