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,318 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * help skill script — Entry point for all ace-tools operations
5
+ * needed by the help skill.
6
+ *
7
+ * Subcommands:
8
+ * init Environment detection for help workflow
9
+ * ensure-settings Create .ace/settings.json with defaults if missing
10
+ * setup-github Detect gh CLI, repo, and list GitHub Projects
11
+ * write-github-settings Write GitHub Project settings (key=value args)
12
+ * sync-agent-teams Sync agent_teams from runtime settings to .ace/settings.json
13
+ * write-agent-teams <true|false> Enable/disable agent teams in ACE + runtime settings
14
+ * verify-path-exists <path> Check file/directory existence
15
+ *
16
+ * Usage: node script.js <subcommand> [args] [--raw]
17
+ */
18
+
19
+ const fs = require('fs');
20
+ const path = require('path');
21
+
22
+ const {
23
+ loadConfig, pathExists, resolveModel,
24
+ detectBrownfieldStatus, loadSettings, writeSettings,
25
+ output, error,
26
+ } = require('../../shared/lib/ace-core');
27
+
28
+ // ─── Runtime Config Dir ─────────────────────────────────────────────────────
29
+
30
+ /**
31
+ * Detect the runtime config directory name.
32
+ * In the plugin context, the script lives at:
33
+ * <base>/<config-dir>/skills/help/script.js
34
+ * Default to '.claude' since the plugin always runs in Claude Code.
35
+ */
36
+ function getRuntimeConfigDirName() {
37
+ try {
38
+ const skillDir = __dirname; // <base>/<config-dir>/skills/help
39
+ const skillsDir = path.dirname(skillDir); // <base>/<config-dir>/skills
40
+ const configDir = path.dirname(skillsDir); // <base>/<config-dir>
41
+ const dirName = path.basename(configDir);
42
+ if (dirName === '.opencode' || dirName === '.claude') {
43
+ return dirName;
44
+ }
45
+ } catch {}
46
+ return '.claude';
47
+ }
48
+
49
+ const RUNTIME_CONFIG_DIR = getRuntimeConfigDirName();
50
+
51
+ // ─── CLI Dispatch ────────────────────────────────────────────────────────────
52
+
53
+ const cwd = process.cwd();
54
+ const args = process.argv.slice(2);
55
+ const raw = args.includes('--raw');
56
+ const cmd = args[0];
57
+
58
+ switch (cmd) {
59
+ case 'init':
60
+ cmdInit(cwd, raw);
61
+ break;
62
+ case 'ensure-settings':
63
+ cmdEnsureSettings(cwd, raw);
64
+ break;
65
+ case 'setup-github':
66
+ cmdSetupGithubProject(cwd, raw);
67
+ break;
68
+ case 'write-github-settings':
69
+ cmdWriteGithubSettings(cwd, raw, args.slice(1).filter(a => a !== '--raw'));
70
+ break;
71
+ case 'sync-agent-teams':
72
+ cmdSyncAgentTeams(cwd, raw);
73
+ break;
74
+ case 'write-agent-teams':
75
+ cmdWriteAgentTeamsSetting(cwd, raw, args.slice(1).filter(a => a !== '--raw'));
76
+ break;
77
+ case 'verify-path-exists': {
78
+ const targetPath = args[1];
79
+ if (!targetPath) error('path required for verify-path-exists');
80
+ const exists = pathExists(cwd, targetPath);
81
+ output({ exists, path: targetPath }, raw, exists ? 'true' : 'false');
82
+ break;
83
+ }
84
+ default:
85
+ error(`Unknown command: ${cmd}\nAvailable: init, ensure-settings, setup-github, write-github-settings, sync-agent-teams, write-agent-teams, verify-path-exists`);
86
+ }
87
+
88
+ // ─── Init: Help ─────────────────────────────────────────────────────────────
89
+
90
+ /**
91
+ * Environment detection for the help workflow (project status dashboard).
92
+ * Detects: git, gh CLI, brownfield status, wiki state, product artifacts.
93
+ */
94
+ function cmdInit(cwd, raw) {
95
+ const config = loadConfig(cwd);
96
+ const brownfield = detectBrownfieldStatus(cwd);
97
+
98
+ const result = {
99
+ // Models (pre-resolved so workflows know which model to spawn each agent with)
100
+ product_owner_model: resolveModel(cwd, 'ace-product-owner'),
101
+ researcher_model: resolveModel(cwd, 'ace-project-researcher'),
102
+ synthesizer_model: resolveModel(cwd, 'ace-research-synthesizer'),
103
+
104
+ // Config
105
+ commit_docs: config.commit_docs,
106
+
107
+ // Existing state
108
+ has_product_vision: pathExists(cwd, '.docs/product/product-vision.md'),
109
+ has_system_architecture: pathExists(cwd, '.docs/wiki/system-wide/system-architecture.md'),
110
+ has_system_structure: pathExists(cwd, '.docs/wiki/system-wide/system-structure.md'),
111
+ has_coding_standards: pathExists(cwd, '.docs/wiki/system-wide/coding-standards.md'),
112
+ has_testing_framework: pathExists(cwd, '.docs/wiki/system-wide/testing-framework.md'),
113
+ project_exists: pathExists(cwd, '.docs/product/product-vision.md'),
114
+ has_codebase_map: pathExists(cwd, '.ace/codebase'),
115
+ planning_exists: pathExists(cwd, '.ace'),
116
+
117
+ // Brownfield detection
118
+ ...brownfield,
119
+ needs_codebase_map: brownfield.is_brownfield && !pathExists(cwd, '.ace/codebase'),
120
+
121
+ // Git state
122
+ has_git: pathExists(cwd, '.git'),
123
+
124
+ // GitHub CLI
125
+ has_gh_cli: (() => {
126
+ try {
127
+ const { execSync } = require('child_process');
128
+ execSync('gh --version', { stdio: 'pipe' });
129
+ return true;
130
+ } catch { return false; }
131
+ })(),
132
+ };
133
+
134
+ output(result, raw);
135
+ }
136
+
137
+ // ─── Ensure Settings ────────────────────────────────────────────────────────
138
+
139
+ function cmdEnsureSettings(cwd, raw) {
140
+ const settingsPath = path.join(cwd, '.ace', 'settings.json');
141
+ const alreadyExists = pathExists(cwd, '.ace/settings.json');
142
+
143
+ if (!alreadyExists) {
144
+ const SETTINGS_DEFAULTS = {
145
+ model_profile: 'balanced',
146
+ commit_docs: true,
147
+ agent_teams: false,
148
+ github_project: {
149
+ enabled: false,
150
+ gh_installed: false,
151
+ repo: '',
152
+ project_number: null,
153
+ owner: '',
154
+ },
155
+ };
156
+ const defaults = JSON.parse(JSON.stringify(SETTINGS_DEFAULTS));
157
+ writeSettings(cwd, defaults);
158
+ output({ created: true, path: settingsPath, settings: defaults }, raw);
159
+ } else {
160
+ const settings = loadSettings(cwd);
161
+ output({ created: false, path: settingsPath, settings }, raw);
162
+ }
163
+ }
164
+
165
+ // ─── Setup GitHub Project ───────────────────────────────────────────────────
166
+
167
+ function cmdSetupGithubProject(cwd, raw) {
168
+ const { execSync } = require('child_process');
169
+ const settings = loadSettings(cwd);
170
+
171
+ // Detect gh CLI
172
+ let ghInstalled = false;
173
+ try {
174
+ execSync('gh --version', { stdio: 'pipe' });
175
+ ghInstalled = true;
176
+ } catch {}
177
+
178
+ // Detect repo
179
+ let repo = '';
180
+ let owner = '';
181
+ if (ghInstalled) {
182
+ try {
183
+ repo = execSync('gh repo view --json nameWithOwner -q .nameWithOwner', {
184
+ cwd,
185
+ stdio: ['pipe', 'pipe', 'pipe'],
186
+ encoding: 'utf-8',
187
+ }).trim();
188
+ owner = repo.split('/')[0] || '';
189
+ } catch {}
190
+ }
191
+
192
+ // List projects
193
+ let projects = [];
194
+ if (ghInstalled && owner) {
195
+ try {
196
+ const projectsJson = execSync(`gh project list --owner ${owner} --limit 10 --format json`, {
197
+ cwd,
198
+ stdio: ['pipe', 'pipe', 'pipe'],
199
+ encoding: 'utf-8',
200
+ }).trim();
201
+ const parsed = JSON.parse(projectsJson);
202
+ projects = (parsed.projects || parsed || []).map(p => ({
203
+ number: p.number,
204
+ title: p.title,
205
+ }));
206
+ } catch {}
207
+ }
208
+
209
+ output({
210
+ gh_installed: ghInstalled,
211
+ repo,
212
+ owner,
213
+ projects,
214
+ current_settings: settings.github_project,
215
+ }, raw);
216
+ }
217
+
218
+ // ─── Write GitHub Settings ──────────────────────────────────────────────────
219
+
220
+ function cmdWriteGithubSettings(cwd, raw, extraArgs) {
221
+ const settings = loadSettings(cwd);
222
+
223
+ for (const arg of extraArgs) {
224
+ const eqIndex = arg.indexOf('=');
225
+ if (eqIndex === -1) continue;
226
+ const key = arg.substring(0, eqIndex);
227
+ const value = arg.substring(eqIndex + 1);
228
+
229
+ switch (key) {
230
+ case 'enabled':
231
+ settings.github_project.enabled = value === 'true';
232
+ break;
233
+ case 'gh_installed':
234
+ settings.github_project.gh_installed = value === 'true';
235
+ break;
236
+ case 'repo':
237
+ settings.github_project.repo = value;
238
+ break;
239
+ case 'project_number':
240
+ settings.github_project.project_number = value === 'null' ? null : parseInt(value, 10);
241
+ break;
242
+ case 'owner':
243
+ settings.github_project.owner = value;
244
+ break;
245
+ }
246
+ }
247
+
248
+ writeSettings(cwd, settings);
249
+ output({ written: true, settings }, raw);
250
+ }
251
+
252
+ // ─── Sync Agent Teams ───────────────────────────────────────────────────────
253
+
254
+ function cmdSyncAgentTeams(cwd, raw) {
255
+ // Source of truth: runtime settings.json env var (e.g. .claude/settings.json)
256
+ const claudeSettingsPath = path.join(cwd, RUNTIME_CONFIG_DIR, 'settings.json');
257
+ let claudeEnabled = false;
258
+ try {
259
+ const claudeRaw = fs.readFileSync(claudeSettingsPath, 'utf-8');
260
+ const claudeSettings = JSON.parse(claudeRaw);
261
+ const val = claudeSettings?.env?.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS;
262
+ claudeEnabled = val === '1' || val === 'true';
263
+ } catch {
264
+ // File doesn't exist or is invalid — treat as disabled
265
+ }
266
+
267
+ // Sync ACE settings to match Claude's source of truth
268
+ const settings = loadSettings(cwd);
269
+ const wasDifferent = settings.agent_teams !== claudeEnabled;
270
+ if (wasDifferent) {
271
+ settings.agent_teams = claudeEnabled;
272
+ writeSettings(cwd, settings);
273
+ }
274
+
275
+ output({ agent_teams: claudeEnabled, synced: wasDifferent }, raw);
276
+ }
277
+
278
+ // ─── Write Agent Teams Setting ──────────────────────────────────────────────
279
+
280
+ function cmdWriteAgentTeamsSetting(cwd, raw, extraArgs) {
281
+ const enabled = extraArgs[0] === 'true';
282
+ const settings = loadSettings(cwd);
283
+ settings.agent_teams = enabled;
284
+ writeSettings(cwd, settings);
285
+
286
+ // Also update the project's runtime settings.json (e.g. .claude/)
287
+ const claudeDir = path.join(cwd, RUNTIME_CONFIG_DIR);
288
+ const claudeSettingsPath = path.join(claudeDir, 'settings.json');
289
+
290
+ let claudeSettings = {};
291
+ try {
292
+ const existing = fs.readFileSync(claudeSettingsPath, 'utf-8');
293
+ claudeSettings = JSON.parse(existing);
294
+ } catch {
295
+ // File doesn't exist or is invalid — start fresh
296
+ }
297
+
298
+ if (!claudeSettings.env) {
299
+ claudeSettings.env = {};
300
+ }
301
+
302
+ if (enabled) {
303
+ claudeSettings.env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS = '1';
304
+ } else {
305
+ delete claudeSettings.env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS;
306
+ // Clean up empty env object
307
+ if (Object.keys(claudeSettings.env).length === 0) {
308
+ delete claudeSettings.env;
309
+ }
310
+ }
311
+
312
+ if (!fs.existsSync(claudeDir)) {
313
+ fs.mkdirSync(claudeDir, { recursive: true });
314
+ }
315
+ fs.writeFileSync(claudeSettingsPath, JSON.stringify(claudeSettings, null, 2) + '\n', 'utf-8');
316
+
317
+ output({ written: true, agent_teams: enabled, settings, claude_settings: claudeSettings }, raw);
318
+ }
@@ -0,0 +1,183 @@
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
+ /**
11
+ * Create a minimal ACE project structure in a temp directory.
12
+ */
13
+ function createTestProject() {
14
+ const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'ace-test-'));
15
+
16
+ // .ace/config.json
17
+ const aceDir = path.join(tmpDir, '.ace');
18
+ fs.mkdirSync(aceDir, { recursive: true });
19
+ fs.writeFileSync(path.join(aceDir, 'config.json'), JSON.stringify({
20
+ version: '0.1.0',
21
+ projectName: 'test-project',
22
+ model_profile: 'quality',
23
+ commit_docs: true,
24
+ github: { enabled: false },
25
+ }, null, 2));
26
+
27
+ // .ace/settings.json
28
+ fs.writeFileSync(path.join(aceDir, 'settings.json'), JSON.stringify({
29
+ model_profile: 'quality',
30
+ commit_docs: true,
31
+ agent_teams: false,
32
+ github_project: { enabled: false, gh_installed: false, repo: '', project_number: null, owner: '' },
33
+ }, null, 2));
34
+
35
+ return tmpDir;
36
+ }
37
+
38
+ function runScript(subcommand, args, cwd) {
39
+ return execSync(`node "${SCRIPT}" ${subcommand} ${args}`, {
40
+ cwd,
41
+ encoding: 'utf-8',
42
+ timeout: 10000,
43
+ });
44
+ }
45
+
46
+ function cleanup(tmpDir) {
47
+ fs.rmSync(tmpDir, { recursive: true, force: true });
48
+ }
49
+
50
+ // ─── Tests ───────────────────────────────────────────────────────────────────
51
+
52
+ describe('help script', () => {
53
+
54
+ describe('init', () => {
55
+ let tmpDir;
56
+
57
+ before(() => { tmpDir = createTestProject(); });
58
+ after(() => { cleanup(tmpDir); });
59
+
60
+ it('returns valid JSON with environment detection', () => {
61
+ const result = JSON.parse(runScript('init', '', tmpDir));
62
+
63
+ assert.strictEqual(typeof result.commit_docs, 'boolean');
64
+ assert.strictEqual(typeof result.has_git, 'boolean');
65
+ assert.strictEqual(typeof result.has_product_vision, 'boolean');
66
+ assert.strictEqual(typeof result.has_system_architecture, 'boolean');
67
+ assert.strictEqual(typeof result.has_system_structure, 'boolean');
68
+ assert.strictEqual(typeof result.has_coding_standards, 'boolean');
69
+ assert.strictEqual(typeof result.has_testing_framework, 'boolean');
70
+ assert.strictEqual(typeof result.is_brownfield, 'boolean');
71
+ assert.strictEqual(typeof result.is_greenfield, 'boolean');
72
+ assert.ok(result.product_owner_model, 'should have product_owner_model');
73
+ });
74
+
75
+ it('detects brownfield vs greenfield correctly', () => {
76
+ const result = JSON.parse(runScript('init', '', tmpDir));
77
+ assert.strictEqual(result.is_brownfield, !result.is_greenfield);
78
+ });
79
+ });
80
+
81
+ describe('ensure-settings', () => {
82
+ let tmpDir;
83
+
84
+ before(() => { tmpDir = createTestProject(); });
85
+ after(() => { cleanup(tmpDir); });
86
+
87
+ it('reports settings already exist when they do', () => {
88
+ const result = JSON.parse(runScript('ensure-settings', '', tmpDir));
89
+ assert.strictEqual(result.created, false);
90
+ assert.ok(result.settings);
91
+ });
92
+
93
+ it('creates settings when they do not exist', () => {
94
+ const freshDir = fs.mkdtempSync(path.join(os.tmpdir(), 'ace-test-'));
95
+ const aceDir = path.join(freshDir, '.ace');
96
+ fs.mkdirSync(aceDir, { recursive: true });
97
+ fs.writeFileSync(path.join(aceDir, 'config.json'), JSON.stringify({
98
+ version: '0.1.0',
99
+ projectName: 'test',
100
+ model_profile: 'balanced',
101
+ commit_docs: true,
102
+ github: { enabled: false },
103
+ }, null, 2));
104
+
105
+ const result = JSON.parse(runScript('ensure-settings', '', freshDir));
106
+ assert.strictEqual(result.created, true);
107
+ assert.ok(result.settings);
108
+ assert.strictEqual(result.settings.model_profile, 'balanced');
109
+
110
+ cleanup(freshDir);
111
+ });
112
+ });
113
+
114
+ describe('sync-agent-teams', () => {
115
+ let tmpDir;
116
+
117
+ before(() => { tmpDir = createTestProject(); });
118
+ after(() => { cleanup(tmpDir); });
119
+
120
+ it('returns agent_teams boolean', () => {
121
+ const result = JSON.parse(runScript('sync-agent-teams', '', tmpDir));
122
+ assert.strictEqual(typeof result.agent_teams, 'boolean');
123
+ assert.strictEqual(typeof result.synced, 'boolean');
124
+ });
125
+ });
126
+
127
+ describe('write-agent-teams', () => {
128
+ let tmpDir;
129
+
130
+ before(() => { tmpDir = createTestProject(); });
131
+ after(() => { cleanup(tmpDir); });
132
+
133
+ it('enables agent teams', () => {
134
+ const result = JSON.parse(runScript('write-agent-teams', 'true', tmpDir));
135
+ assert.strictEqual(result.written, true);
136
+ assert.strictEqual(result.agent_teams, true);
137
+
138
+ // Verify .ace/settings.json updated
139
+ const settings = JSON.parse(fs.readFileSync(path.join(tmpDir, '.ace', 'settings.json'), 'utf-8'));
140
+ assert.strictEqual(settings.agent_teams, true);
141
+ });
142
+
143
+ it('disables agent teams', () => {
144
+ const result = JSON.parse(runScript('write-agent-teams', 'false', tmpDir));
145
+ assert.strictEqual(result.written, true);
146
+ assert.strictEqual(result.agent_teams, false);
147
+
148
+ const settings = JSON.parse(fs.readFileSync(path.join(tmpDir, '.ace', 'settings.json'), 'utf-8'));
149
+ assert.strictEqual(settings.agent_teams, false);
150
+ });
151
+ });
152
+
153
+ describe('verify-path-exists', () => {
154
+ let tmpDir;
155
+
156
+ before(() => { tmpDir = createTestProject(); });
157
+ after(() => { cleanup(tmpDir); });
158
+
159
+ it('returns true for existing path', () => {
160
+ const result = runScript('verify-path-exists', '.ace/config.json --raw', tmpDir).trim();
161
+ assert.strictEqual(result, 'true');
162
+ });
163
+
164
+ it('returns false for non-existing path', () => {
165
+ const result = runScript('verify-path-exists', 'nonexistent/file.md --raw', tmpDir).trim();
166
+ assert.strictEqual(result, 'false');
167
+ });
168
+ });
169
+
170
+ describe('error handling', () => {
171
+ it('errors on unknown command', () => {
172
+ assert.throws(() => {
173
+ execSync(`node "${SCRIPT}" bogus`, { encoding: 'utf-8', stdio: 'pipe' });
174
+ });
175
+ });
176
+
177
+ it('errors on verify-path-exists without path', () => {
178
+ assert.throws(() => {
179
+ execSync(`node "${SCRIPT}" verify-path-exists`, { encoding: 'utf-8', stdio: 'pipe' });
180
+ });
181
+ });
182
+ });
183
+ });
@@ -22,7 +22,7 @@
22
22
 
23
23
  <substep order="1.1" name="environment-detection">
24
24
  ```bash
25
- INIT=$(node ~/.claude/agile-context-engineering/src/ace-tools.js init new-project)
25
+ INIT=$(node "${CLAUDE_SKILL_DIR}/script.js" init)
26
26
  ```
27
27
 
28
28
  <output-fields>
@@ -60,7 +60,7 @@
60
60
 
61
61
  <substep order="2.1" name="create-settings-file">
62
62
  ```bash
63
- SETTINGS=$(node ~/.claude/agile-context-engineering/src/ace-tools.js ensure-settings)
63
+ SETTINGS=$(node "${CLAUDE_SKILL_DIR}/script.js" ensure-settings)
64
64
  ```
65
65
 
66
66
  <output-fields>
@@ -96,7 +96,7 @@
96
96
 
97
97
  <substep order="3.1" name="github-detection">
98
98
  ```bash
99
- GH_STATUS=$(node ~/.claude/agile-context-engineering/src/ace-tools.js init setup-github)
99
+ GH_STATUS=$(node "${CLAUDE_SKILL_DIR}/script.js" setup-github)
100
100
  ```
101
101
 
102
102
  <output-fields>
@@ -218,7 +218,7 @@
218
218
 
219
219
  <substep order="3.7" name="write-github-settings">
220
220
  ```bash
221
- node ~/.claude/agile-context-engineering/src/ace-tools.js write-github-settings enabled=true gh_installed=true repo={repo} project_number={number} owner={owner}
221
+ node "${CLAUDE_SKILL_DIR}/script.js" write-github-settings enabled=true gh_installed=true repo={repo} project_number={number} owner={owner}
222
222
  ```
223
223
 
224
224
  Display:
@@ -245,7 +245,7 @@
245
245
  **MANDATORY — Run this command before evaluating state:**
246
246
 
247
247
  ```bash
248
- AGENT_TEAMS=$(node ~/.claude/agile-context-engineering/src/ace-tools.js sync-agent-teams --raw)
248
+ AGENT_TEAMS=$(node "${CLAUDE_SKILL_DIR}/script.js" sync-agent-teams --raw)
249
249
  ```
250
250
 
251
251
  Parse the JSON output. The `agent_teams` field is the synced boolean state.
@@ -267,7 +267,7 @@
267
267
 
268
268
  <variant condition="user chose Disable">
269
269
  ```bash
270
- node ~/.claude/agile-context-engineering/src/ace-tools.js write-agent-teams false
270
+ node "${CLAUDE_SKILL_DIR}/script.js" write-agent-teams false
271
271
  ```
272
272
  Display:
273
273
  ```
@@ -286,7 +286,7 @@
286
286
 
287
287
  <variant condition="user chose Enable Agent Teams">
288
288
  ```bash
289
- node ~/.claude/agile-context-engineering/src/ace-tools.js write-agent-teams true
289
+ node "${CLAUDE_SKILL_DIR}/script.js" write-agent-teams true
290
290
  ```
291
291
  Display:
292
292
  ```
@@ -455,7 +455,7 @@
455
455
 
456
456
  <substep order="9.1" name="check-backlog-exists">
457
457
  ```bash
458
- HAS_BACKLOG=$(node ~/.claude/agile-context-engineering/src/ace-tools.js verify-path-exists .ace/artifacts/product/product-backlog.md --raw)
458
+ HAS_BACKLOG=$(node "${CLAUDE_SKILL_DIR}/script.js" verify-path-exists .ace/artifacts/product/product-backlog.md --raw)
459
459
  ```
460
460
 
461
461
  <variant condition="HAS_BACKLOG is true">
@@ -0,0 +1,72 @@
1
+ ---
2
+ name: init-coding-standards
3
+ description: Generate a tailored coding-standards.md through codebase detection and user interview
4
+ argument-hint: "[optional: context='existing standards doc or notes to build on']"
5
+ disable-model-invocation: true
6
+ allowed-tools: Read, Bash, Glob, Grep, Write, Task, AskUserQuestion
7
+ model: sonnet
8
+ effort: high
9
+ ---
10
+
11
+ # Init Coding Standards
12
+
13
+ Generate a tailored coding-standards.md through codebase detection and user interview.
14
+
15
+ ## When to Use
16
+
17
+ - During `/ace:help` — as part of initial project setup
18
+ - After `/ace:map-system` — once codebase is mapped, add prescriptive standards
19
+ - Anytime — to create or refresh coding standards for a project
20
+ - Starting a new project and want to establish coding standards upfront (greenfield or brownfield)
21
+ - Onboarding AI agents to an existing codebase (prevents common AI mistakes)
22
+ - Current coding standards are outdated or missing
23
+ - Team has pain points with AI-generated code quality
24
+
25
+ ## Input
26
+
27
+ ### Optional
28
+
29
+ - **`context`** — Existing coding standards document, style guide, or notes to use as a starting point. Will be refined through the interview process.
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
+ - **Coding standards template**: Read [coding-standards-template.xml](coding-standards-template.xml) — output format for the coding standards
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 interviewing the user about coding philosophy and pain points.
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
+ .docs/wiki/system-wide/coding-standards.md
56
+ ```
57
+
58
+ ## Example Usage
59
+
60
+ ```
61
+ # Generate coding standards from codebase analysis + interview
62
+ /ace:init-coding-standards
63
+
64
+ # Generate with existing standards as seed
65
+ /ace:init-coding-standards context="path/to/existing-style-guide.md"
66
+ ```
67
+
68
+ ## Next Steps
69
+
70
+ - `/ace:map-system` — Map codebase structure and architecture
71
+ - `/ace:help` — Check project initialization status and next steps
72
+ - Review and edit `.docs/wiki/system-wide/coding-standards.md` anytime
@@ -60,6 +60,44 @@
60
60
  - **NEVER leave stub implementations** — No `throw NotImplemented`, no `pass`, no `...`
61
61
  - If code exists in the codebase, it must be complete and functional
62
62
 
63
+ ### Defensive Programming — Zero Tolerance for Permissive Code
64
+
65
+ **WE USE DEFENSIVE PROGRAMMING + FAIL-FAST. PERMISSIVE PROGRAMMING IS BANNED.**
66
+
67
+ Permissive programming ("be liberal in what you accept") has caused catastrophic bugs.
68
+ It hides errors, delays failures, and makes debugging impossible. Every parameter must
69
+ be validated. Every error must be surfaced. No exceptions.
70
+
71
+ **MANDATORY — Do This:**
72
+ - **Validate EVERY input at the boundary** — check types, ranges, formats, required
73
+ fields BEFORE processing
74
+ - **Fail fast and loud** — if something is wrong, return an error immediately with a
75
+ clear message explaining WHAT is wrong and WHY
76
+ - **Read the function you're calling** — check its constructor/signature to know EXACTLY
77
+ what parameters it requires before writing the caller
78
+ - **Required means required** — if a function needs a value, the caller MUST provide it.
79
+ No nullable wrappers. No default fallbacks that mask missing data
80
+ - **Return errors, not defaults** — if a value is missing or invalid, return an error
81
+ string/throw, do NOT return `""`, `0`, `null`, `[]`, or any placeholder
82
+ - **Validate on BOTH client and server** — server validates before processing/pushing,
83
+ client validates as a redundant safety net. Both layers reject garbage
84
+ - **Surface errors visibly** — errors must reach whoever can fix them (the LLM, the user,
85
+ the developer). Log them, display them, return them. Never swallow them
86
+
87
+ **ABSOLUTELY FORBIDDEN — Never Do This:**
88
+ - `string? param = null` when the value is actually required — use `string param` and validate
89
+ - `return ""` or `return null` or `return []` when an operation fails — return an error with context
90
+ - `.optional()` or `.nullable()` on schema fields that the consuming function REQUIRES
91
+ - Fallback defaults that hide missing data (e.g., `value ?? defaultValue` to mask a null
92
+ that should never be null)
93
+ - `try/catch` that swallows exceptions and returns empty objects
94
+ - Silently stripping, transforming, or cleaning invalid data to make it pass validation
95
+ - Writing a caller without reading the callee's actual parameter signature first
96
+ - Using Postel's Law ("be liberal in what you accept") as justification for accepting garbage
97
+
98
+ **The Principle:**
99
+ **Garbage in → ERROR out. Never garbage in → silence.**
100
+
63
101
  ### No Assumptions
64
102
  - **Use LSPs first when available** — Check diagnostics, go-to-definition, and find-references before guessing. The LSP knows the codebase better than a text search.
65
103
  - **NEVER assume** libraries, classes, models, methods, or APIs exist