@entelligentsia/forgecli 0.20.0 → 0.21.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/CHANGELOG.md +70 -0
- package/dist/extensions/forgecli/fix-bug.d.ts +1 -1
- package/dist/extensions/forgecli/fix-bug.js +14 -6
- package/dist/extensions/forgecli/fix-bug.js.map +1 -1
- package/dist/extensions/forgecli/forge-init/phase4-register.js +19 -0
- package/dist/extensions/forgecli/forge-init/phase4-register.js.map +1 -1
- package/dist/extensions/forgecli/run-task.d.ts +2 -1
- package/dist/extensions/forgecli/run-task.js +48 -4
- package/dist/extensions/forgecli/run-task.js.map +1 -1
- package/dist/forge-payload/.base-pack/workflows/enhance.md +34 -4
- package/dist/forge-payload/.claude-plugin/plugin.json +1 -1
- package/dist/forge-payload/.schemas/enum-catalog.json +2 -2
- package/dist/forge-payload/.schemas/migrations.json +11 -0
- package/dist/forge-payload/commands/update.md +23 -1
- package/dist/forge-payload/integrity.json +4 -4
- package/dist/forge-payload/meta/workflows/meta-enhance.md +34 -4
- package/dist/forge-payload/schemas/_defs/phaseSummary.schema.json +18 -0
- package/dist/forge-payload/schemas/bug.schema.json +40 -0
- package/dist/forge-payload/schemas/collation-state.schema.json +16 -0
- package/dist/forge-payload/schemas/config.schema.json +215 -0
- package/dist/forge-payload/schemas/enum-catalog.json +71 -0
- package/dist/forge-payload/schemas/event-sidecar.schema.json +22 -0
- package/dist/forge-payload/schemas/event.schema.json +184 -0
- package/dist/forge-payload/schemas/feature.schema.json +22 -0
- package/dist/forge-payload/schemas/progress-entry.schema.json +16 -0
- package/dist/forge-payload/schemas/project-context.schema.json +167 -0
- package/dist/forge-payload/schemas/project-overlay.schema.json +25 -0
- package/dist/forge-payload/schemas/proposal.schema.json +40 -0
- package/dist/forge-payload/schemas/sprint.schema.json +27 -0
- package/dist/forge-payload/schemas/structure-manifest.json +2 -2
- package/dist/forge-payload/schemas/structure-versions.schema.json +57 -0
- package/dist/forge-payload/schemas/task.schema.json +43 -0
- package/dist/forge-payload/schemas/transitions/bug.json +31 -0
- package/dist/forge-payload/schemas/transitions/sprint.json +46 -0
- package/dist/forge-payload/schemas/transitions/task.json +109 -0
- package/dist/forge-payload/tools/manage-config.cjs +120 -2
- package/package.json +3 -3
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
// manage-config pipeline add <name> --description <text> --phases <json>
|
|
9
9
|
// manage-config pipeline get <name>
|
|
10
10
|
// manage-config pipeline remove <name>
|
|
11
|
+
// manage-config backfill [--forge-root <path>] [--dry-run]
|
|
11
12
|
// manage-config resolve-forge-root
|
|
12
13
|
// manage-config set <key.path> <json-value>
|
|
13
14
|
|
|
@@ -106,8 +107,13 @@ function validatePhases(phases) {
|
|
|
106
107
|
function parseArgs(argv) {
|
|
107
108
|
const result = {};
|
|
108
109
|
for (let i = 0; i < argv.length; i++) {
|
|
109
|
-
if (argv[i].startsWith('--')
|
|
110
|
-
|
|
110
|
+
if (argv[i].startsWith('--')) {
|
|
111
|
+
const key = argv[i].slice(2);
|
|
112
|
+
if (i + 1 < argv.length && !argv[i + 1].startsWith('--')) {
|
|
113
|
+
result[key] = argv[++i];
|
|
114
|
+
} else {
|
|
115
|
+
result[key] = 'true'; // boolean flag
|
|
116
|
+
}
|
|
111
117
|
}
|
|
112
118
|
}
|
|
113
119
|
return result;
|
|
@@ -129,6 +135,7 @@ if (!subcmd) {
|
|
|
129
135
|
' pipeline get <name> Print a pipeline in full',
|
|
130
136
|
' pipeline remove <name>',
|
|
131
137
|
' pipeline backfill-models Backfill model fields from role defaults',
|
|
138
|
+
' backfill [--forge-root <path>] [--dry-run] Backfill missing config fields from schema defaults',
|
|
132
139
|
' resolve-forge-root Resolve Forge plugin root path',
|
|
133
140
|
' set <key.path> <json-value> Set an arbitrary value',
|
|
134
141
|
].join('\n'));
|
|
@@ -279,6 +286,117 @@ if (subcmd === 'set') {
|
|
|
279
286
|
// FR-010: resolve-forge-root — resolve the Forge plugin root path using
|
|
280
287
|
// three-tier priority: (1) CLAUDE_PLUGIN_ROOT env var, (2) cache/marketplace
|
|
281
288
|
// scan by forgeRef, (3) paths.forgeRoot fallback.
|
|
289
|
+
if (subcmd === 'backfill') {
|
|
290
|
+
// backfill-schema: write defaults for missing config fields per the config schema.
|
|
291
|
+
// Reads $FORGE_ROOT/schemas/config.schema.json (or .schemas/ fallback).
|
|
292
|
+
// Writes schema-defined defaults for any missing required or optional path fields.
|
|
293
|
+
// Also writes the top-level `version` field from the bundled plugin version.
|
|
294
|
+
// Usage: manage-config backfill [--forge-root <path>] [--dry-run]
|
|
295
|
+
const flags = parseArgs(args);
|
|
296
|
+
const forgeRoot = flags['forge-root'] || process.env.FORGE_ROOT || path.resolve(__dirname, '..');
|
|
297
|
+
const dryRun = !!flags['dry-run'];
|
|
298
|
+
|
|
299
|
+
// Locate config schema
|
|
300
|
+
let schemaPath = path.join(forgeRoot, 'schemas', 'config.schema.json');
|
|
301
|
+
if (!fs.existsSync(schemaPath)) {
|
|
302
|
+
schemaPath = path.join(forgeRoot, '.schemas', 'config.schema.json');
|
|
303
|
+
}
|
|
304
|
+
if (!fs.existsSync(schemaPath)) {
|
|
305
|
+
console.error('× config.schema.json not found in schemas/ or .schemas/ under forge-root:', forgeRoot);
|
|
306
|
+
process.exit(1);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
let schema;
|
|
310
|
+
try { schema = JSON.parse(fs.readFileSync(schemaPath, 'utf8')); } catch (e) {
|
|
311
|
+
console.error(`× reading config schema: ${e.message}`); process.exit(1);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
if (!fs.existsSync(CONFIG_PATH)) {
|
|
315
|
+
console.error('× .forge/config.json not found. Run /forge:init first.');
|
|
316
|
+
process.exit(1);
|
|
317
|
+
}
|
|
318
|
+
const { config, raw } = readConfig();
|
|
319
|
+
|
|
320
|
+
const backfilled = [];
|
|
321
|
+
const still = [];
|
|
322
|
+
|
|
323
|
+
// 1. Top-level `version` — write bundled plugin version if absent
|
|
324
|
+
if (!config.version) {
|
|
325
|
+
const pluginJsonPath = path.join(forgeRoot, '.claude-plugin', 'plugin.json');
|
|
326
|
+
if (fs.existsSync(pluginJsonPath)) {
|
|
327
|
+
try {
|
|
328
|
+
const plugin = JSON.parse(fs.readFileSync(pluginJsonPath, 'utf8'));
|
|
329
|
+
if (plugin.version) {
|
|
330
|
+
config.version = plugin.version;
|
|
331
|
+
backfilled.push('version = ' + plugin.version);
|
|
332
|
+
}
|
|
333
|
+
} catch { /* skip */ }
|
|
334
|
+
}
|
|
335
|
+
if (!config.version) {
|
|
336
|
+
still.push('version (no plugin.json found)');
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
// 2. Walk schema properties, apply defaults for any missing nested fields
|
|
341
|
+
// Covers: paths.*, commands.*
|
|
342
|
+
const walkDefaults = (obj, schemaProps, prefix) => {
|
|
343
|
+
if (!schemaProps || typeof schemaProps !== 'object') return;
|
|
344
|
+
for (const [key, spec] of Object.entries(schemaProps)) {
|
|
345
|
+
const dotPath = prefix ? prefix + '.' + key : key;
|
|
346
|
+
if (spec.type === 'object' && spec.properties) {
|
|
347
|
+
// Nested object — ensure container exists, then recurse
|
|
348
|
+
if (obj[key] == null || typeof obj[key] !== 'object') obj[key] = {};
|
|
349
|
+
walkDefaults(obj[key], spec.properties, dotPath);
|
|
350
|
+
} else if (obj[key] === undefined && spec.default !== undefined) {
|
|
351
|
+
obj[key] = spec.default;
|
|
352
|
+
backfilled.push(dotPath + ' = ' + JSON.stringify(spec.default));
|
|
353
|
+
} else if (obj[key] === undefined && spec.default === undefined) {
|
|
354
|
+
// Track that it's still missing (informational only)
|
|
355
|
+
const isRequired = Array.isArray(schema.required) && schema.required.includes(key);
|
|
356
|
+
if (isRequired || (prefix === 'paths' && spec.description)) {
|
|
357
|
+
still.push(dotPath + ' (no default in schema)');
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
};
|
|
362
|
+
|
|
363
|
+
// Walk top-level properties
|
|
364
|
+
for (const [key, spec] of Object.entries(schema.properties || {})) {
|
|
365
|
+
if (key === 'version') continue; // handled above
|
|
366
|
+
if (spec.type === 'object' && spec.properties) {
|
|
367
|
+
if (config[key] == null || typeof config[key] !== 'object') config[key] = {};
|
|
368
|
+
walkDefaults(config[key], spec.properties, key);
|
|
369
|
+
} else if (config[key] === undefined && spec.default !== undefined) {
|
|
370
|
+
config[key] = spec.default;
|
|
371
|
+
backfilled.push(key + ' = ' + JSON.stringify(spec.default));
|
|
372
|
+
} else if (config[key] === undefined && spec.default === undefined) {
|
|
373
|
+
if (Array.isArray(schema.required) && schema.required.includes(key)) {
|
|
374
|
+
still.push(key + ' (required, no default)');
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
if (backfilled.length > 0) {
|
|
380
|
+
if (dryRun) {
|
|
381
|
+
console.log('Would backfill:');
|
|
382
|
+
for (const b of backfilled) console.log(' + ' + b);
|
|
383
|
+
} else {
|
|
384
|
+
writeConfig(config, detectIndent(raw));
|
|
385
|
+
console.log('〇 Backfilled ' + backfilled.length + ' field(s):');
|
|
386
|
+
for (const b of backfilled) console.log(' + ' + b);
|
|
387
|
+
}
|
|
388
|
+
} else {
|
|
389
|
+
console.log('〇 No missing fields to backfill.');
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
if (still.length > 0) {
|
|
393
|
+
console.log('△ Still missing (no schema default):');
|
|
394
|
+
for (const s of still) console.log(' - ' + s);
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
process.exit(0);
|
|
398
|
+
}
|
|
399
|
+
|
|
282
400
|
if (subcmd === 'resolve-forge-root') {
|
|
283
401
|
// Priority 1: CLAUDE_PLUGIN_ROOT env var (if set and directory exists)
|
|
284
402
|
const envRoot = process.env.CLAUDE_PLUGIN_ROOT;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@entelligentsia/forgecli",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Forge SDLC ported onto @earendil-works/pi-coding-agent
|
|
3
|
+
"version": "0.21.0",
|
|
4
|
+
"description": "Forge SDLC ported onto @earendil-works/pi-coding-agent \u2014 production launcher with three bin aliases (forge/forgecli/4ge). Bundles a curated fork of pi-coding-agent vendored under earendil-works names.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Entelligentsia",
|
|
7
7
|
"homepage": "https://github.com/Entelligentsia/forge-cli#readme",
|
|
@@ -105,4 +105,4 @@
|
|
|
105
105
|
"@earendil-works/pi-tui",
|
|
106
106
|
"js-yaml"
|
|
107
107
|
]
|
|
108
|
-
}
|
|
108
|
+
}
|