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.
- package/.claude-plugin/plugin.json +10 -0
- package/CHANGELOG.md +82 -0
- package/README.md +27 -18
- package/agents/ace-product-owner.md +1 -1
- package/agents/ace-technical-application-architect.md +28 -0
- package/agents/ace-wiki-mapper.md +144 -29
- package/bin/install.js +67 -63
- package/hooks/ace-check-update.js +17 -9
- package/package.json +7 -5
- package/shared/lib/ace-core.js +308 -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/ui-formatting.md +299 -299
- package/skills/execute-story/SKILL.md +110 -0
- package/skills/execute-story/script.js +305 -0
- package/skills/execute-story/script.test.js +261 -0
- package/skills/execute-story/walkthrough-template.xml +255 -0
- package/{agile-context-engineering/workflows/execute-story.xml → skills/execute-story/workflow.xml} +83 -9
- package/skills/help/SKILL.md +69 -0
- package/skills/help/script.js +318 -0
- package/skills/help/script.test.js +183 -0
- package/{agile-context-engineering/workflows/help.xml → skills/help/workflow.xml} +8 -8
- package/skills/init-coding-standards/SKILL.md +72 -0
- package/{agile-context-engineering/templates/wiki/coding-standards.xml → skills/init-coding-standards/coding-standards-template.xml} +38 -0
- package/skills/init-coding-standards/script.js +59 -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} +4 -9
- package/skills/map-cross-cutting/SKILL.md +89 -0
- package/skills/map-cross-cutting/workflow.xml +330 -0
- package/skills/map-guide/SKILL.md +89 -0
- package/skills/map-guide/workflow.xml +320 -0
- package/skills/map-pattern/SKILL.md +89 -0
- package/skills/map-pattern/workflow.xml +331 -0
- package/skills/map-story/SKILL.md +127 -0
- 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/skills/map-story/templates/walkthrough.xml +255 -0
- package/{agile-context-engineering/workflows/map-story.xml → skills/map-story/workflow.xml} +258 -9
- package/skills/map-subsystem/SKILL.md +111 -0
- package/skills/map-subsystem/script.js +60 -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 +3 -3
- package/skills/map-subsystem/templates/pattern.xml +159 -0
- 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} +17 -21
- package/skills/map-sys-doc/SKILL.md +90 -0
- package/skills/map-sys-doc/system.xml +381 -0
- package/skills/map-sys-doc/workflow.xml +336 -0
- package/skills/map-system/SKILL.md +85 -0
- package/skills/map-system/script.js +84 -0
- package/skills/map-system/script.test.js +73 -0
- package/skills/map-system/templates/wiki-readme.xml +297 -0
- package/{agile-context-engineering/workflows/map-system.xml → skills/map-system/workflow.xml} +11 -16
- package/skills/map-walkthrough/SKILL.md +92 -0
- package/skills/map-walkthrough/walkthrough.xml +255 -0
- package/skills/map-walkthrough/workflow.xml +457 -0
- package/skills/plan-backlog/SKILL.md +75 -0
- package/skills/plan-backlog/script.js +136 -0
- package/skills/plan-backlog/script.test.js +83 -0
- package/{agile-context-engineering/workflows/plan-backlog.xml → skills/plan-backlog/workflow.xml} +13 -21
- package/skills/plan-feature/SKILL.md +76 -0
- package/skills/plan-feature/script.js +148 -0
- package/skills/plan-feature/script.test.js +80 -0
- package/{agile-context-engineering/workflows/plan-feature.xml → skills/plan-feature/workflow.xml} +21 -29
- package/skills/plan-product-vision/SKILL.md +75 -0
- package/skills/plan-product-vision/script.js +60 -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} +4 -9
- package/skills/plan-story/SKILL.md +116 -0
- package/skills/plan-story/script.js +326 -0
- package/skills/plan-story/script.test.js +240 -0
- package/skills/plan-story/story-template.xml +451 -0
- package/{agile-context-engineering/workflows/plan-story.xml → skills/plan-story/workflow.xml} +1285 -909
- package/skills/research-external-solution/SKILL.md +107 -0
- package/skills/research-external-solution/script.js +238 -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} +4 -6
- package/skills/research-integration-solution/SKILL.md +98 -0
- package/{agile-context-engineering/templates/product/story-integration-solution.xml → skills/research-integration-solution/integration-solution-template.xml} +1 -0
- package/skills/research-integration-solution/script.js +231 -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} +4 -5
- package/skills/research-story-wiki/SKILL.md +92 -0
- package/skills/research-story-wiki/script.js +231 -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} +4 -0
- package/{agile-context-engineering/workflows/research-story-wiki.xml → skills/research-story-wiki/workflow.xml} +5 -6
- package/skills/research-technical-solution/SKILL.md +103 -0
- package/skills/research-technical-solution/script.js +231 -0
- package/skills/research-technical-solution/script.test.js +134 -0
- package/{agile-context-engineering/workflows/research-technical-solution.xml → skills/research-technical-solution/workflow.xml} +4 -5
- package/skills/review-story/SKILL.md +100 -0
- package/skills/review-story/script.js +257 -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} +1 -3
- package/skills/update/SKILL.md +53 -0
- package/{agile-context-engineering/workflows/update.xml → skills/update/workflow.xml} +237 -207
- 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/agile-context-engineering/templates/wiki/wiki-readme.xml +0 -276
- package/commands/ace/execute-story.md +0 -137
- package/commands/ace/help.md +0 -93
- package/commands/ace/init-coding-standards.md +0 -83
- package/commands/ace/map-story.md +0 -156
- package/commands/ace/map-subsystem.md +0 -138
- package/commands/ace/map-system.md +0 -92
- package/commands/ace/plan-backlog.md +0 -83
- package/commands/ace/plan-feature.md +0 -89
- package/commands/ace/plan-product-vision.md +0 -81
- package/commands/ace/plan-story.md +0 -145
- package/commands/ace/research-external-solution.md +0 -138
- package/commands/ace/research-integration-solution.md +0 -135
- package/commands/ace/research-story-wiki.md +0 -116
- package/commands/ace/research-technical-solution.md +0 -147
- package/commands/ace/review-story.md +0 -109
- package/commands/ace/update.md +0 -54
- /package/{agile-context-engineering → shared}/utils/questioning.xml +0 -0
- /package/{agile-context-engineering/templates/product/story.xml → skills/execute-story/story-template.xml} +0 -0
- /package/{agile-context-engineering/templates/wiki → skills/map-cross-cutting}/system-cross-cutting.xml +0 -0
- /package/{agile-context-engineering/templates/wiki → skills/map-guide}/guide.xml +0 -0
- /package/{agile-context-engineering/templates/wiki → skills/map-pattern}/pattern.xml +0 -0
- /package/{agile-context-engineering/templates/wiki → skills/map-story/templates}/decizions.xml +0 -0
- /package/{agile-context-engineering/templates/wiki → skills/map-story/templates}/system.xml +0 -0
- /package/{agile-context-engineering/templates/wiki → skills/map-story/templates}/tech-debt-index.xml +0 -0
- /package/{agile-context-engineering/templates/wiki → skills/map-subsystem/templates}/subsystem-architecture.xml +0 -0
- /package/{agile-context-engineering/templates/wiki → skills/map-subsystem/templates}/subsystem-structure.xml +0 -0
- /package/{agile-context-engineering/templates/wiki → skills/map-system/templates}/system-architecture.xml +0 -0
- /package/{agile-context-engineering/templates/wiki → skills/map-system/templates}/system-structure.xml +0 -0
- /package/{agile-context-engineering/templates/wiki → skills/map-system/templates}/testing-framework.xml +0 -0
- /package/{agile-context-engineering/templates/product/product-backlog.xml → skills/plan-backlog/product-backlog-template.xml} +0 -0
- /package/{agile-context-engineering/templates/product/feature.xml → skills/plan-feature/feature-template.xml} +0 -0
- /package/{agile-context-engineering/templates/product/product-vision.xml → skills/plan-product-vision/product-vision-template.xml} +0 -0
- /package/{agile-context-engineering/templates/product/external-solution.xml → skills/research-external-solution/external-solution-template.xml} +0 -0
- /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
|
+
});
|
package/{agile-context-engineering/workflows/plan-backlog.xml → skills/plan-backlog/workflow.xml}
RENAMED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
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:**
|
|
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:
|
|
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
|
|
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
|
|
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
|
|
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
|
+
});
|