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
package/bin/install.js
CHANGED
|
@@ -39,8 +39,8 @@ const RUNTIMES = {
|
|
|
39
39
|
},
|
|
40
40
|
};
|
|
41
41
|
|
|
42
|
-
//
|
|
43
|
-
const
|
|
42
|
+
// Legacy folder name — only used for cleanup of pre-plugin installations
|
|
43
|
+
const ACE_LEGACY_DIR_NAME = 'agile-context-engineering';
|
|
44
44
|
|
|
45
45
|
function log(message, color = '') {
|
|
46
46
|
console.log(`${color}${message}${colors.reset}`);
|
|
@@ -184,7 +184,7 @@ function getBasePath(runtime, scope) {
|
|
|
184
184
|
}
|
|
185
185
|
|
|
186
186
|
// File extensions that contain path references needing runtime transformation
|
|
187
|
-
const TRANSFORMABLE_EXTENSIONS = new Set(['.md', '.xml']);
|
|
187
|
+
const TRANSFORMABLE_EXTENSIONS = new Set(['.md', '.xml', '.js']);
|
|
188
188
|
|
|
189
189
|
// Transform file content for a target runtime (replaces .claude/ paths with target runtime paths)
|
|
190
190
|
function transformForRuntime(content, runtime) {
|
|
@@ -225,77 +225,73 @@ function copyDir(src, dest, runtime) {
|
|
|
225
225
|
function installForRuntime(runtime, scope, packageDir) {
|
|
226
226
|
const config = RUNTIMES[runtime];
|
|
227
227
|
const basePath = getBasePath(runtime, scope);
|
|
228
|
-
const commandsPath = path.join(basePath, config.commandsDir);
|
|
229
228
|
const agentsPath = path.join(basePath, config.agentsDir);
|
|
230
|
-
const acePath = path.join(basePath, ACE_DIR_NAME);
|
|
231
229
|
|
|
232
|
-
// Source directories
|
|
233
|
-
const
|
|
230
|
+
// Source directories (plugin structure)
|
|
231
|
+
const srcSkills = path.join(packageDir, 'skills');
|
|
232
|
+
const srcShared = path.join(packageDir, 'shared');
|
|
233
|
+
const srcPlugin = path.join(packageDir, '.claude-plugin');
|
|
234
234
|
const srcAgents = path.join(packageDir, 'agents');
|
|
235
|
-
const srcTemplates = path.join(packageDir, 'agile-context-engineering', 'templates');
|
|
236
|
-
const srcUtils = path.join(packageDir, 'agile-context-engineering', 'utils');
|
|
237
|
-
const srcWorkflows = path.join(packageDir, 'agile-context-engineering', 'workflows');
|
|
238
|
-
const srcTools = path.join(packageDir, 'agile-context-engineering', 'src');
|
|
239
235
|
|
|
240
236
|
log(`\nInstalling ACE for ${config.name}...`, colors.cyan);
|
|
241
237
|
log(` Target: ${basePath}`, colors.dim);
|
|
242
238
|
|
|
243
|
-
// Clean previous ACE installation to remove stale files
|
|
244
|
-
const aceCommandsPath = path.join(
|
|
239
|
+
// Clean previous ACE installation to remove stale files
|
|
240
|
+
const aceCommandsPath = path.join(basePath, config.commandsDir, 'ace');
|
|
245
241
|
if (fs.existsSync(aceCommandsPath)) {
|
|
246
242
|
fs.rmSync(aceCommandsPath, { recursive: true });
|
|
247
243
|
}
|
|
248
244
|
if (fs.existsSync(agentsPath)) {
|
|
249
|
-
// Only remove ace-* agent files, preserve non-ACE agents
|
|
250
245
|
for (const f of fs.readdirSync(agentsPath)) {
|
|
251
246
|
if (f.startsWith('ace-')) {
|
|
252
247
|
fs.rmSync(path.join(agentsPath, f), { recursive: true });
|
|
253
248
|
}
|
|
254
249
|
}
|
|
255
250
|
}
|
|
256
|
-
|
|
257
|
-
|
|
251
|
+
// Clean old agile-context-engineering directory from pre-plugin installs
|
|
252
|
+
const legacyAcePath = path.join(basePath, ACE_LEGACY_DIR_NAME);
|
|
253
|
+
if (fs.existsSync(legacyAcePath)) {
|
|
254
|
+
fs.rmSync(legacyAcePath, { recursive: true });
|
|
255
|
+
}
|
|
256
|
+
// Clean skills/shared directories from previous plugin installs
|
|
257
|
+
const skillsPath = path.join(basePath, 'skills');
|
|
258
|
+
const sharedPath = path.join(basePath, 'shared');
|
|
259
|
+
const pluginPath = path.join(basePath, '.claude-plugin');
|
|
260
|
+
if (fs.existsSync(skillsPath)) {
|
|
261
|
+
fs.rmSync(skillsPath, { recursive: true });
|
|
262
|
+
}
|
|
263
|
+
if (fs.existsSync(sharedPath)) {
|
|
264
|
+
fs.rmSync(sharedPath, { recursive: true });
|
|
265
|
+
}
|
|
266
|
+
if (fs.existsSync(pluginPath)) {
|
|
267
|
+
fs.rmSync(pluginPath, { recursive: true });
|
|
258
268
|
}
|
|
259
269
|
|
|
260
270
|
// Create directories
|
|
261
|
-
fs.mkdirSync(commandsPath, { recursive: true });
|
|
262
271
|
fs.mkdirSync(agentsPath, { recursive: true });
|
|
263
|
-
fs.mkdirSync(acePath, { recursive: true });
|
|
264
|
-
|
|
265
|
-
// Copy commands (transform paths for target runtime)
|
|
266
|
-
if (fs.existsSync(srcCommands)) {
|
|
267
|
-
copyDir(srcCommands, commandsPath, runtime);
|
|
268
|
-
log(` ✓ Commands installed`, colors.green);
|
|
269
|
-
}
|
|
270
272
|
|
|
271
|
-
// Copy
|
|
272
|
-
if (fs.existsSync(
|
|
273
|
-
copyDir(
|
|
274
|
-
log(` ✓
|
|
273
|
+
// Copy skills (plugin skill directories)
|
|
274
|
+
if (fs.existsSync(srcSkills)) {
|
|
275
|
+
copyDir(srcSkills, skillsPath, runtime);
|
|
276
|
+
log(` ✓ Skills installed`, colors.green);
|
|
275
277
|
}
|
|
276
278
|
|
|
277
|
-
// Copy
|
|
278
|
-
if (fs.existsSync(
|
|
279
|
-
copyDir(
|
|
280
|
-
log(` ✓
|
|
279
|
+
// Copy shared libs (ace-core.js, ace-story.js, ace-github.js, utils)
|
|
280
|
+
if (fs.existsSync(srcShared)) {
|
|
281
|
+
copyDir(srcShared, sharedPath, runtime);
|
|
282
|
+
log(` ✓ Shared libs installed`, colors.green);
|
|
281
283
|
}
|
|
282
284
|
|
|
283
|
-
// Copy
|
|
284
|
-
if (fs.existsSync(
|
|
285
|
-
copyDir(
|
|
286
|
-
log(` ✓
|
|
285
|
+
// Copy plugin manifest
|
|
286
|
+
if (fs.existsSync(srcPlugin)) {
|
|
287
|
+
copyDir(srcPlugin, pluginPath, runtime);
|
|
288
|
+
log(` ✓ Plugin manifest installed`, colors.green);
|
|
287
289
|
}
|
|
288
290
|
|
|
289
|
-
// Copy
|
|
290
|
-
if (fs.existsSync(
|
|
291
|
-
copyDir(
|
|
292
|
-
log(` ✓
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
// Copy src (ace-tools) into agile-context-engineering/
|
|
296
|
-
if (fs.existsSync(srcTools)) {
|
|
297
|
-
copyDir(srcTools, path.join(acePath, 'src'), runtime);
|
|
298
|
-
log(` ✓ Tools installed`, colors.green);
|
|
291
|
+
// Copy agents (transform paths for target runtime)
|
|
292
|
+
if (fs.existsSync(srcAgents)) {
|
|
293
|
+
copyDir(srcAgents, agentsPath, runtime);
|
|
294
|
+
log(` ✓ Agents installed`, colors.green);
|
|
299
295
|
}
|
|
300
296
|
|
|
301
297
|
// Copy hooks
|
|
@@ -314,10 +310,19 @@ function installForRuntime(runtime, scope, packageDir) {
|
|
|
314
310
|
log(` ✓ Hooks installed`, colors.green);
|
|
315
311
|
}
|
|
316
312
|
|
|
317
|
-
// Write VERSION file for update checking
|
|
318
|
-
const versionFile = path.join(
|
|
313
|
+
// Write VERSION file for update checking (in shared/ alongside libs)
|
|
314
|
+
const versionFile = path.join(sharedPath, 'VERSION');
|
|
315
|
+
if (!fs.existsSync(sharedPath)) fs.mkdirSync(sharedPath, { recursive: true });
|
|
319
316
|
fs.writeFileSync(versionFile, VERSION, 'utf-8');
|
|
320
317
|
|
|
318
|
+
// Copy CHANGELOG.md
|
|
319
|
+
const changelogSrc = path.join(packageDir, 'CHANGELOG.md');
|
|
320
|
+
const changelogDest = path.join(sharedPath, 'CHANGELOG.md');
|
|
321
|
+
if (fs.existsSync(changelogSrc)) {
|
|
322
|
+
fs.copyFileSync(changelogSrc, changelogDest);
|
|
323
|
+
log(` ✓ CHANGELOG.md installed`, colors.green);
|
|
324
|
+
}
|
|
325
|
+
|
|
321
326
|
return basePath;
|
|
322
327
|
}
|
|
323
328
|
|
|
@@ -478,29 +483,28 @@ async function main() {
|
|
|
478
483
|
log(`\nInstalled structure:`, colors.cyan);
|
|
479
484
|
for (const { path: p } of installedPaths) {
|
|
480
485
|
log(` ${p}/`, colors.dim);
|
|
481
|
-
log(`
|
|
486
|
+
log(` skills/ Skill directories (SKILL.md + workflow + templates + script.js)`, colors.dim);
|
|
487
|
+
log(` shared/ Shared libraries (ace-core.js, ace-story.js, ace-github.js)`, colors.dim);
|
|
482
488
|
log(` agents/ Agent definitions`, colors.dim);
|
|
483
489
|
log(` hooks/ Statusline & update hooks`, colors.dim);
|
|
484
|
-
log(`
|
|
485
|
-
log(` templates/ Project & artifact templates`, colors.dim);
|
|
486
|
-
log(` utils/ Formatting & utility guides`, colors.dim);
|
|
487
|
-
log(` workflows/ Workflow definitions`, colors.dim);
|
|
490
|
+
log(` .claude-plugin/ Plugin manifest`, colors.dim);
|
|
488
491
|
}
|
|
489
492
|
|
|
490
|
-
log(`\nAvailable
|
|
491
|
-
log(` /ace:help
|
|
492
|
-
log(` /ace:plan-
|
|
493
|
-
log(` /ace:plan-
|
|
494
|
-
log(` /ace:plan-feature
|
|
495
|
-
log(` /ace:plan-story
|
|
496
|
-
log(` /ace:
|
|
497
|
-
log(` /ace:
|
|
498
|
-
log(` /ace:
|
|
493
|
+
log(`\nAvailable skills:`, colors.cyan);
|
|
494
|
+
log(` /ace:help Check project status and next steps`, colors.dim);
|
|
495
|
+
log(` /ace:plan-product-vision Create or update the product vision`, colors.dim);
|
|
496
|
+
log(` /ace:plan-backlog Plan the product backlog`, colors.dim);
|
|
497
|
+
log(` /ace:plan-feature Plan a feature with stories`, colors.dim);
|
|
498
|
+
log(` /ace:plan-story Plan a story specification`, colors.dim);
|
|
499
|
+
log(` /ace:execute-story Execute a planned story`, colors.dim);
|
|
500
|
+
log(` /ace:map-system Map system-wide architecture`, colors.dim);
|
|
501
|
+
log(` /ace:map-subsystem Map a subsystem's internals`, colors.dim);
|
|
502
|
+
log(` /ace:init-coding-standards Generate coding standards`, colors.dim);
|
|
499
503
|
|
|
500
504
|
log(`\nGet started:`, colors.cyan);
|
|
501
505
|
log(` 1. Navigate to your project directory`, colors.dim);
|
|
502
506
|
log(` 2. Run /ace:help to initialize ACE`, colors.dim);
|
|
503
|
-
log(` 3. Run /ace:plan-
|
|
507
|
+
log(` 3. Run /ace:plan-product-vision to define your product\n`, colors.dim);
|
|
504
508
|
}
|
|
505
509
|
|
|
506
510
|
main().catch((err) => {
|
|
@@ -13,8 +13,11 @@ const cacheDir = path.join(homeDir, '.claude', 'cache');
|
|
|
13
13
|
const cacheFile = path.join(cacheDir, 'ace-update-check.json');
|
|
14
14
|
|
|
15
15
|
// VERSION file locations (check project first, then global)
|
|
16
|
-
|
|
17
|
-
const
|
|
16
|
+
// New plugin structure: shared/VERSION; legacy: agile-context-engineering/VERSION
|
|
17
|
+
const projectVersionFile = path.join(cwd, '.claude', 'shared', 'VERSION');
|
|
18
|
+
const globalVersionFile = path.join(homeDir, '.claude', 'shared', 'VERSION');
|
|
19
|
+
const legacyProjectVersionFile = path.join(cwd, '.claude', 'agile-context-engineering', 'VERSION');
|
|
20
|
+
const legacyGlobalVersionFile = path.join(homeDir, '.claude', 'agile-context-engineering', 'VERSION');
|
|
18
21
|
|
|
19
22
|
// Ensure cache directory exists
|
|
20
23
|
if (!fs.existsSync(cacheDir)) {
|
|
@@ -27,16 +30,21 @@ const child = spawn(process.execPath, ['-e', `
|
|
|
27
30
|
const { execSync } = require('child_process');
|
|
28
31
|
|
|
29
32
|
const cacheFile = ${JSON.stringify(cacheFile)};
|
|
30
|
-
const
|
|
31
|
-
|
|
33
|
+
const versionFiles = [
|
|
34
|
+
${JSON.stringify(projectVersionFile)},
|
|
35
|
+
${JSON.stringify(globalVersionFile)},
|
|
36
|
+
${JSON.stringify(legacyProjectVersionFile)},
|
|
37
|
+
${JSON.stringify(legacyGlobalVersionFile)},
|
|
38
|
+
];
|
|
32
39
|
|
|
33
|
-
// Check
|
|
40
|
+
// Check new paths first, then legacy
|
|
34
41
|
let installed = '0.0.0';
|
|
35
42
|
try {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
43
|
+
for (const vf of versionFiles) {
|
|
44
|
+
if (fs.existsSync(vf)) {
|
|
45
|
+
installed = fs.readFileSync(vf, 'utf8').trim();
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
40
48
|
}
|
|
41
49
|
} catch (e) {}
|
|
42
50
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agile-context-engineering",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "ACE - Agile Context Engineering: A spec-driven development system for Claude Code and Crush (formerly OpenCode) with Agile workflows",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -9,13 +9,15 @@
|
|
|
9
9
|
},
|
|
10
10
|
"files": [
|
|
11
11
|
"bin",
|
|
12
|
-
"
|
|
12
|
+
"skills",
|
|
13
|
+
"shared",
|
|
13
14
|
"agents",
|
|
14
15
|
"hooks",
|
|
15
|
-
"
|
|
16
|
+
".claude-plugin",
|
|
17
|
+
"CHANGELOG.md"
|
|
16
18
|
],
|
|
17
19
|
"scripts": {
|
|
18
|
-
"test": "node --test
|
|
20
|
+
"test": "node --test shared/lib/*.test.js skills/*/script.test.js"
|
|
19
21
|
},
|
|
20
22
|
"keywords": [
|
|
21
23
|
"claude-code",
|
|
@@ -32,7 +34,7 @@
|
|
|
32
34
|
"license": "MIT",
|
|
33
35
|
"repository": {
|
|
34
36
|
"type": "git",
|
|
35
|
-
"url": "https://github.com/
|
|
37
|
+
"url": "https://github.com/Quantarcane/ACE"
|
|
36
38
|
},
|
|
37
39
|
"engines": {
|
|
38
40
|
"node": ">=16.7.0"
|
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ACE Core — Universal helpers shared across all ACE skills.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from ace-tools.js monolith. Contains: config loading, model resolution,
|
|
5
|
+
* path checks, environment detection, slug/timestamp generation, settings management,
|
|
6
|
+
* and process-level output/error helpers.
|
|
7
|
+
*
|
|
8
|
+
* Usage: const { loadConfig, resolveModel, output, error } = require('./ace-core');
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const fs = require('fs');
|
|
12
|
+
const path = require('path');
|
|
13
|
+
|
|
14
|
+
// ─── Model Profile Table ─────────────────────────────────────────────────────
|
|
15
|
+
|
|
16
|
+
const MODEL_PROFILES = {
|
|
17
|
+
'ace-product-owner': { quality: 'opus', balanced: 'sonnet', budget: 'sonnet' },
|
|
18
|
+
'ace-project-researcher': { quality: 'opus', balanced: 'sonnet', budget: 'haiku' },
|
|
19
|
+
'ace-research-synthesizer': { quality: 'sonnet', balanced: 'sonnet', budget: 'haiku' },
|
|
20
|
+
'ace-wiki-mapper': { quality: 'sonnet', balanced: 'sonnet', budget: 'haiku' },
|
|
21
|
+
'ace-code-integration-analyst': { quality: 'opus', balanced: 'opus', budget: 'sonnet' },
|
|
22
|
+
'ace-code-discovery-analyst': { quality: 'opus', balanced: 'opus', budget: 'sonnet' },
|
|
23
|
+
'ace-executor': { quality: 'opus', balanced: 'sonnet', budget: 'sonnet' },
|
|
24
|
+
'ace-code-reviewer': { quality: 'sonnet', balanced: 'sonnet', budget: 'haiku' },
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
// ─── Settings Defaults ───────────────────────────────────────────────────────
|
|
28
|
+
|
|
29
|
+
const SETTINGS_DEFAULTS = {
|
|
30
|
+
model_profile: 'balanced',
|
|
31
|
+
commit_docs: true,
|
|
32
|
+
agent_teams: false,
|
|
33
|
+
github_project: {
|
|
34
|
+
enabled: false,
|
|
35
|
+
gh_installed: false,
|
|
36
|
+
repo: '',
|
|
37
|
+
project_number: null,
|
|
38
|
+
owner: '',
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
// ─── Process Output ──────────────────────────────────────────────────────────
|
|
43
|
+
|
|
44
|
+
function output(result, raw, rawValue) {
|
|
45
|
+
if (raw && rawValue !== undefined) {
|
|
46
|
+
process.stdout.write(String(rawValue));
|
|
47
|
+
} else {
|
|
48
|
+
process.stdout.write(JSON.stringify(result, null, 2));
|
|
49
|
+
}
|
|
50
|
+
process.exit(0);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function error(message) {
|
|
54
|
+
process.stderr.write('Error: ' + message + '\n');
|
|
55
|
+
process.exit(1);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// ─── Config ──────────────────────────────────────────────────────────────────
|
|
59
|
+
|
|
60
|
+
function loadConfig(cwd) {
|
|
61
|
+
const configPath = path.join(cwd, '.ace', 'config.json');
|
|
62
|
+
const defaults = {
|
|
63
|
+
version: '0.1.0',
|
|
64
|
+
projectName: '',
|
|
65
|
+
description: '',
|
|
66
|
+
storage: 'local',
|
|
67
|
+
model_profile: 'quality',
|
|
68
|
+
commit_docs: true,
|
|
69
|
+
github: {
|
|
70
|
+
enabled: false,
|
|
71
|
+
repo: null,
|
|
72
|
+
labels: {
|
|
73
|
+
epic: 'ace:epic',
|
|
74
|
+
feature: 'ace:feature',
|
|
75
|
+
story: 'ace:story',
|
|
76
|
+
task: 'ace:task',
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
createdAt: '',
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
try {
|
|
83
|
+
const raw = fs.readFileSync(configPath, 'utf-8');
|
|
84
|
+
const parsed = JSON.parse(raw);
|
|
85
|
+
return {
|
|
86
|
+
version: parsed.version ?? defaults.version,
|
|
87
|
+
projectName: parsed.projectName ?? defaults.projectName,
|
|
88
|
+
description: parsed.description ?? defaults.description,
|
|
89
|
+
storage: parsed.storage ?? defaults.storage,
|
|
90
|
+
model_profile: parsed.model_profile ?? defaults.model_profile,
|
|
91
|
+
commit_docs: parsed.commit_docs ?? defaults.commit_docs,
|
|
92
|
+
github: {
|
|
93
|
+
enabled: parsed.github?.enabled ?? defaults.github.enabled,
|
|
94
|
+
repo: parsed.github?.repo ?? defaults.github.repo,
|
|
95
|
+
labels: {
|
|
96
|
+
epic: parsed.github?.labels?.epic ?? defaults.github.labels.epic,
|
|
97
|
+
feature: parsed.github?.labels?.feature ?? defaults.github.labels.feature,
|
|
98
|
+
story: parsed.github?.labels?.story ?? defaults.github.labels.story,
|
|
99
|
+
task: parsed.github?.labels?.task ?? defaults.github.labels.task,
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
createdAt: parsed.createdAt ?? defaults.createdAt,
|
|
103
|
+
};
|
|
104
|
+
} catch {
|
|
105
|
+
return defaults;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// ─── Path Helpers ────────────────────────────────────────────────────────────
|
|
110
|
+
|
|
111
|
+
function pathExists(cwd, targetPath) {
|
|
112
|
+
const fullPath = path.isAbsolute(targetPath) ? targetPath : path.join(cwd, targetPath);
|
|
113
|
+
try {
|
|
114
|
+
fs.statSync(fullPath);
|
|
115
|
+
return true;
|
|
116
|
+
} catch {
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function safeReadFile(filePath) {
|
|
122
|
+
try { return fs.readFileSync(filePath, 'utf-8'); }
|
|
123
|
+
catch { return null; }
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// ─── Slug & Timestamp ────────────────────────────────────────────────────────
|
|
127
|
+
|
|
128
|
+
function generateSlug(text) {
|
|
129
|
+
if (!text) return null;
|
|
130
|
+
return text.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '');
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function currentTimestamp(format) {
|
|
134
|
+
const now = new Date();
|
|
135
|
+
switch (format) {
|
|
136
|
+
case 'date':
|
|
137
|
+
return now.toISOString().split('T')[0];
|
|
138
|
+
case 'filename':
|
|
139
|
+
return now.toISOString().replace(/[:.]/g, '-').replace('T', '_').split('Z')[0];
|
|
140
|
+
case 'full':
|
|
141
|
+
default:
|
|
142
|
+
return now.toISOString();
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// ─── Model Resolution ────────────────────────────────────────────────────────
|
|
147
|
+
|
|
148
|
+
function resolveModel(cwd, agentType) {
|
|
149
|
+
const config = loadConfig(cwd);
|
|
150
|
+
const profile = config.model_profile || 'balanced';
|
|
151
|
+
const agentModels = MODEL_PROFILES[agentType];
|
|
152
|
+
if (!agentModels) return 'sonnet';
|
|
153
|
+
return agentModels[profile] || agentModels['balanced'] || 'sonnet';
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// ─── Code & Environment Detection ────────────────────────────────────────────
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Detect existing code files by walking up to maxDepth levels.
|
|
160
|
+
*/
|
|
161
|
+
function detectCodeFiles(cwd, maxDepth) {
|
|
162
|
+
const codeExtensions = new Set(['.cs', '.ts', '.js', '.py', '.go', '.rs', '.swift', '.java', '.tsx', '.jsx']);
|
|
163
|
+
const ignoreDirs = new Set(['node_modules', '.git', '.ace', '.gsd', 'dist', 'build', '__pycache__']);
|
|
164
|
+
const found = [];
|
|
165
|
+
|
|
166
|
+
function walk(dir, depth) {
|
|
167
|
+
if (depth > maxDepth || found.length >= 5) return;
|
|
168
|
+
let entries;
|
|
169
|
+
try {
|
|
170
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
171
|
+
} catch {
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
for (const entry of entries) {
|
|
175
|
+
if (found.length >= 5) return;
|
|
176
|
+
if (entry.isDirectory()) {
|
|
177
|
+
if (!ignoreDirs.has(entry.name)) {
|
|
178
|
+
walk(path.join(dir, entry.name), depth + 1);
|
|
179
|
+
}
|
|
180
|
+
} else if (entry.isFile()) {
|
|
181
|
+
const ext = path.extname(entry.name);
|
|
182
|
+
if (codeExtensions.has(ext)) {
|
|
183
|
+
found.push(path.join(dir, entry.name));
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
walk(cwd, 0);
|
|
190
|
+
return found;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Detect whether the project is brownfield (existing code/manifests) or greenfield.
|
|
195
|
+
*/
|
|
196
|
+
function detectBrownfieldStatus(cwd) {
|
|
197
|
+
const codeFiles = detectCodeFiles(cwd, 3);
|
|
198
|
+
const hasExistingCode = codeFiles.length > 0;
|
|
199
|
+
|
|
200
|
+
const packageFiles = [
|
|
201
|
+
'package.json', 'requirements.txt', 'pyproject.toml', 'Cargo.toml',
|
|
202
|
+
'go.mod', 'Package.swift', 'pom.xml', 'build.gradle',
|
|
203
|
+
];
|
|
204
|
+
|
|
205
|
+
const hasDotnetProject = (() => {
|
|
206
|
+
try {
|
|
207
|
+
const rootFiles = fs.readdirSync(cwd);
|
|
208
|
+
return rootFiles.some(f => f.endsWith('.sln') || f.endsWith('.csproj'));
|
|
209
|
+
} catch {
|
|
210
|
+
return false;
|
|
211
|
+
}
|
|
212
|
+
})();
|
|
213
|
+
|
|
214
|
+
const hasPackageFile = packageFiles.some(f => pathExists(cwd, f)) || hasDotnetProject;
|
|
215
|
+
const isBrownfield = hasExistingCode || hasPackageFile;
|
|
216
|
+
|
|
217
|
+
return {
|
|
218
|
+
has_existing_code: hasExistingCode,
|
|
219
|
+
has_package_file: hasPackageFile,
|
|
220
|
+
is_brownfield: isBrownfield,
|
|
221
|
+
is_greenfield: !isBrownfield,
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// ─── Settings ────────────────────────────────────────────────────────────────
|
|
226
|
+
|
|
227
|
+
function loadSettings(cwd) {
|
|
228
|
+
const settingsPath = path.join(cwd, '.ace', 'settings.json');
|
|
229
|
+
try {
|
|
230
|
+
const raw = fs.readFileSync(settingsPath, 'utf-8');
|
|
231
|
+
const parsed = JSON.parse(raw);
|
|
232
|
+
return {
|
|
233
|
+
model_profile: parsed.model_profile ?? SETTINGS_DEFAULTS.model_profile,
|
|
234
|
+
commit_docs: parsed.commit_docs ?? SETTINGS_DEFAULTS.commit_docs,
|
|
235
|
+
agent_teams: parsed.agent_teams ?? SETTINGS_DEFAULTS.agent_teams,
|
|
236
|
+
github_project: {
|
|
237
|
+
enabled: parsed.github_project?.enabled ?? SETTINGS_DEFAULTS.github_project.enabled,
|
|
238
|
+
gh_installed: parsed.github_project?.gh_installed ?? SETTINGS_DEFAULTS.github_project.gh_installed,
|
|
239
|
+
repo: parsed.github_project?.repo ?? SETTINGS_DEFAULTS.github_project.repo,
|
|
240
|
+
project_number: parsed.github_project?.project_number ?? SETTINGS_DEFAULTS.github_project.project_number,
|
|
241
|
+
owner: parsed.github_project?.owner ?? SETTINGS_DEFAULTS.github_project.owner,
|
|
242
|
+
},
|
|
243
|
+
};
|
|
244
|
+
} catch {
|
|
245
|
+
return JSON.parse(JSON.stringify(SETTINGS_DEFAULTS));
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
function writeSettings(cwd, settings) {
|
|
250
|
+
const aceDir = path.join(cwd, '.ace');
|
|
251
|
+
if (!fs.existsSync(aceDir)) {
|
|
252
|
+
fs.mkdirSync(aceDir, { recursive: true });
|
|
253
|
+
}
|
|
254
|
+
const settingsPath = path.join(aceDir, 'settings.json');
|
|
255
|
+
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n', 'utf-8');
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// ─── Shell Execution ─────────────────────────────────────────────────────────
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Parse key=value arguments into an object.
|
|
262
|
+
*/
|
|
263
|
+
function parseKeyValueArgs(args) {
|
|
264
|
+
const result = {};
|
|
265
|
+
for (const arg of args) {
|
|
266
|
+
const eqIndex = arg.indexOf('=');
|
|
267
|
+
if (eqIndex === -1) continue;
|
|
268
|
+
result[arg.substring(0, eqIndex)] = arg.substring(eqIndex + 1);
|
|
269
|
+
}
|
|
270
|
+
return result;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Run a shell command and return trimmed stdout. Returns null on failure.
|
|
275
|
+
*/
|
|
276
|
+
function execCommand(cmd, cwd) {
|
|
277
|
+
const { execSync } = require('child_process');
|
|
278
|
+
try {
|
|
279
|
+
return execSync(cmd, {
|
|
280
|
+
cwd,
|
|
281
|
+
shell: 'bash',
|
|
282
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
283
|
+
encoding: 'utf-8',
|
|
284
|
+
timeout: 30000,
|
|
285
|
+
}).trim();
|
|
286
|
+
} catch {
|
|
287
|
+
return null;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
module.exports = {
|
|
292
|
+
MODEL_PROFILES,
|
|
293
|
+
SETTINGS_DEFAULTS,
|
|
294
|
+
output,
|
|
295
|
+
error,
|
|
296
|
+
loadConfig,
|
|
297
|
+
pathExists,
|
|
298
|
+
safeReadFile,
|
|
299
|
+
generateSlug,
|
|
300
|
+
currentTimestamp,
|
|
301
|
+
resolveModel,
|
|
302
|
+
detectCodeFiles,
|
|
303
|
+
detectBrownfieldStatus,
|
|
304
|
+
loadSettings,
|
|
305
|
+
writeSettings,
|
|
306
|
+
parseKeyValueArgs,
|
|
307
|
+
execCommand,
|
|
308
|
+
};
|