@entelligentsia/forgecli 1.0.10 → 1.0.14
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 +49 -0
- package/dist/CHANGELOG-forge-plugin.md +150 -0
- package/dist/bin/forge.js +0 -0
- package/dist/extensions/forgecli/config-layer.d.ts +16 -0
- package/dist/extensions/forgecli/config-layer.js +5 -0
- package/dist/extensions/forgecli/config-layer.js.map +1 -1
- package/dist/extensions/forgecli/dashboard/component.d.ts +102 -0
- package/dist/extensions/forgecli/dashboard/component.js +882 -0
- package/dist/extensions/forgecli/dashboard/component.js.map +1 -0
- package/dist/extensions/forgecli/dashboard/register.d.ts +2 -0
- package/dist/extensions/forgecli/dashboard/register.js +45 -0
- package/dist/extensions/forgecli/dashboard/register.js.map +1 -0
- package/dist/extensions/forgecli/dashboard/view-model.d.ts +35 -0
- package/dist/extensions/forgecli/dashboard/view-model.js +54 -0
- package/dist/extensions/forgecli/dashboard/view-model.js.map +1 -0
- package/dist/extensions/forgecli/fix-bug.js +72 -7
- package/dist/extensions/forgecli/fix-bug.js.map +1 -1
- package/dist/extensions/forgecli/forge-cli-schema.json +4 -0
- package/dist/extensions/forgecli/forge-commands.js +1 -0
- package/dist/extensions/forgecli/forge-commands.js.map +1 -1
- package/dist/extensions/forgecli/forge-init/phase4-register.js +53 -0
- package/dist/extensions/forgecli/forge-init/phase4-register.js.map +1 -1
- package/dist/extensions/forgecli/forge-subagent.js +6 -4
- package/dist/extensions/forgecli/forge-subagent.js.map +1 -1
- package/dist/extensions/forgecli/index.js +5 -0
- package/dist/extensions/forgecli/index.js.map +1 -1
- package/dist/extensions/forgecli/lib/halt-advisor.d.ts +54 -0
- package/dist/extensions/forgecli/lib/halt-advisor.js +90 -0
- package/dist/extensions/forgecli/lib/halt-advisor.js.map +1 -0
- package/dist/extensions/forgecli/migration-engine.js +25 -12
- package/dist/extensions/forgecli/migration-engine.js.map +1 -1
- package/dist/extensions/forgecli/orchestrator-status-bar.d.ts +25 -0
- package/dist/extensions/forgecli/orchestrator-status-bar.js +183 -0
- package/dist/extensions/forgecli/orchestrator-status-bar.js.map +1 -0
- package/dist/extensions/forgecli/orchestrator-tree.d.ts +96 -0
- package/dist/extensions/forgecli/orchestrator-tree.js +390 -0
- package/dist/extensions/forgecli/orchestrator-tree.js.map +1 -0
- package/dist/extensions/forgecli/project-orientation.js +12 -8
- package/dist/extensions/forgecli/project-orientation.js.map +1 -1
- package/dist/extensions/forgecli/regenerate.d.ts +16 -0
- package/dist/extensions/forgecli/regenerate.js +110 -0
- package/dist/extensions/forgecli/regenerate.js.map +1 -1
- package/dist/extensions/forgecli/run-sprint.js +33 -3
- package/dist/extensions/forgecli/run-sprint.js.map +1 -1
- package/dist/extensions/forgecli/run-task.d.ts +32 -0
- package/dist/extensions/forgecli/run-task.js +185 -12
- package/dist/extensions/forgecli/run-task.js.map +1 -1
- package/dist/extensions/forgecli/thread-switcher.js +105 -764
- package/dist/extensions/forgecli/thread-switcher.js.map +1 -1
- package/dist/extensions/forgecli/viewport-events.js +32 -0
- package/dist/extensions/forgecli/viewport-events.js.map +1 -1
- package/dist/forge-payload/.base-pack/commands/fix-bug.md +1 -1
- package/dist/forge-payload/.base-pack/commands/run-sprint.md +1 -1
- package/dist/forge-payload/.base-pack/commands/run-task.md +1 -1
- package/dist/forge-payload/.base-pack/personas/architect.md +1 -1
- package/dist/forge-payload/.base-pack/personas/bug-fixer.md +1 -1
- package/dist/forge-payload/.base-pack/personas/collator.md +3 -3
- package/dist/forge-payload/.base-pack/personas/engineer.md +1 -1
- package/dist/forge-payload/.base-pack/personas/librarian.md +1 -1
- package/dist/forge-payload/.base-pack/personas/orchestrator.md +1 -1
- package/dist/forge-payload/.base-pack/personas/product-manager.md +1 -1
- package/dist/forge-payload/.base-pack/personas/qa-engineer.md +1 -1
- package/dist/forge-payload/.base-pack/personas/supervisor.md +1 -1
- package/dist/forge-payload/.base-pack/workflows/_fragments/event-emission-schema.md +1 -1
- package/dist/forge-payload/.base-pack/workflows/_fragments/friction-emit.md +1 -1
- package/dist/forge-payload/.base-pack/workflows/_fragments/iron-laws.md +1 -1
- package/dist/forge-payload/.base-pack/workflows/_fragments/progress-reporting.md +2 -2
- package/dist/forge-payload/.base-pack/workflows/_fragments/store-cli-verbs.md +11 -2
- package/dist/forge-payload/.base-pack/workflows/architect_approve.md +6 -7
- package/dist/forge-payload/.base-pack/workflows/architect_review_sprint_completion.md +2 -2
- package/dist/forge-payload/.base-pack/workflows/architect_sprint_intake.md +2 -2
- package/dist/forge-payload/.base-pack/workflows/architect_sprint_plan.md +5 -5
- package/dist/forge-payload/.base-pack/workflows/collator_agent.md +4 -6
- package/dist/forge-payload/.base-pack/workflows/commit_task.md +5 -6
- package/dist/forge-payload/.base-pack/workflows/enhance.md +5 -5
- package/dist/forge-payload/.base-pack/workflows/implement_plan.md +6 -7
- package/dist/forge-payload/.base-pack/workflows/migrate_structural.md +12 -13
- package/dist/forge-payload/.base-pack/workflows/plan_task.md +5 -6
- package/dist/forge-payload/.base-pack/workflows/review_code.md +8 -8
- package/dist/forge-payload/.base-pack/workflows/review_plan.md +8 -8
- package/dist/forge-payload/.base-pack/workflows/sprint_retrospective.md +3 -3
- package/dist/forge-payload/.base-pack/workflows/triage.md +12 -9
- package/dist/forge-payload/.base-pack/workflows/update_implementation.md +2 -2
- package/dist/forge-payload/.base-pack/workflows/update_plan.md +2 -2
- package/dist/forge-payload/.base-pack/workflows/validate_task.md +5 -6
- package/dist/forge-payload/.base-pack/workflows-js/wfl-fix-bug.js +490 -0
- package/dist/forge-payload/.base-pack/workflows-js/wfl-run-sprint.js +416 -0
- package/dist/forge-payload/.base-pack/workflows-js/wfl-run-task.js +608 -0
- package/dist/forge-payload/.claude-plugin/plugin.json +1 -1
- package/dist/forge-payload/.schemas/config.schema.json +2 -3
- package/dist/forge-payload/.schemas/enum-catalog.json +2 -2
- package/dist/forge-payload/.schemas/event.schema.json +16 -0
- package/dist/forge-payload/.schemas/migrations.json +236 -0
- package/dist/forge-payload/commands/health.md +29 -0
- package/dist/forge-payload/commands/rebuild.md +143 -15
- package/dist/forge-payload/commands/update.md +28 -27
- package/dist/forge-payload/hooks/preflight-session.cjs +99 -0
- package/dist/forge-payload/init/phases/phase-3-materialize.md +18 -5
- package/dist/forge-payload/integrity.json +7 -6
- package/dist/forge-payload/meta/fragments/tool-discipline.md +1 -1
- package/dist/forge-payload/meta/personas/meta-architect.md +1 -1
- package/dist/forge-payload/meta/personas/meta-bug-fixer.md +1 -1
- package/dist/forge-payload/meta/personas/meta-collator.md +7 -7
- package/dist/forge-payload/meta/personas/meta-engineer.md +1 -1
- package/dist/forge-payload/meta/personas/meta-orchestrator.md +1 -1
- package/dist/forge-payload/meta/personas/meta-supervisor.md +1 -1
- package/dist/forge-payload/meta/tool-specs/store-cli.spec.md +1 -1
- package/dist/forge-payload/meta/workflows/_fragments/event-emission-schema.md +1 -1
- package/dist/forge-payload/meta/workflows/_fragments/friction-emit.md +1 -1
- package/dist/forge-payload/meta/workflows/_fragments/iron-laws.md +1 -1
- package/dist/forge-payload/meta/workflows/_fragments/progress-reporting.md +2 -2
- package/dist/forge-payload/meta/workflows/_fragments/store-cli-verbs.md +11 -2
- package/dist/forge-payload/meta/workflows/meta-approve.md +6 -7
- package/dist/forge-payload/meta/workflows/meta-bug-triage.md +12 -9
- package/dist/forge-payload/meta/workflows/meta-collate.md +5 -7
- package/dist/forge-payload/meta/workflows/meta-commit.md +5 -6
- package/dist/forge-payload/meta/workflows/meta-enhance.md +5 -5
- package/dist/forge-payload/meta/workflows/meta-fix-bug.md +35 -11
- package/dist/forge-payload/meta/workflows/meta-implement.md +15 -7
- package/dist/forge-payload/meta/workflows/meta-migrate.md +13 -14
- package/dist/forge-payload/meta/workflows/meta-new-sprint.md +3 -3
- package/dist/forge-payload/meta/workflows/meta-orchestrate.md +138 -39
- package/dist/forge-payload/meta/workflows/meta-plan-sprint.md +6 -6
- package/dist/forge-payload/meta/workflows/meta-plan-task.md +12 -6
- package/dist/forge-payload/meta/workflows/meta-retro.md +4 -4
- package/dist/forge-payload/meta/workflows/meta-retrospective.md +4 -4
- package/dist/forge-payload/meta/workflows/meta-review-implementation.md +8 -8
- package/dist/forge-payload/meta/workflows/meta-review-plan.md +8 -8
- package/dist/forge-payload/meta/workflows/meta-review-sprint-completion.md +3 -3
- package/dist/forge-payload/meta/workflows/meta-sprint-intake.md +3 -3
- package/dist/forge-payload/meta/workflows/meta-sprint-plan.md +6 -6
- package/dist/forge-payload/meta/workflows/meta-update-implementation.md +2 -2
- package/dist/forge-payload/meta/workflows/meta-update-plan.md +2 -2
- package/dist/forge-payload/meta/workflows/meta-validate.md +5 -6
- package/dist/forge-payload/schemas/config.schema.json +2 -3
- package/dist/forge-payload/schemas/enum-catalog.json +2 -2
- package/dist/forge-payload/schemas/event.schema.json +16 -0
- package/dist/forge-payload/schemas/structure-manifest.json +75 -73
- package/dist/forge-payload/skills/refresh-kb-links/SKILL.md +14 -7
- package/dist/forge-payload/tools/banners.cjs +29 -10
- package/dist/forge-payload/tools/check-structure.cjs +88 -7
- package/dist/forge-payload/tools/collate.cjs +16 -2
- package/dist/forge-payload/tools/manage-config.cjs +5 -7
- package/dist/forge-payload/tools/parse-gates.cjs +73 -1
- package/dist/forge-payload/tools/postflight-gate.cjs +252 -0
- package/dist/forge-payload/tools/preflight-gate.cjs +47 -0
- package/dist/forge-payload/tools/substitute-placeholders.cjs +5 -4
- package/dist/forge-payload/tools/verify-phase.cjs +17 -0
- package/package.json +1 -1
- package/dist/bin/forgecli.d.ts +0 -2
- package/dist/bin/forgecli.js +0 -6
- package/dist/bin/forgecli.js.map +0 -1
- package/dist/extensions/forgecli/config-tui/index.d.ts +0 -5
- package/dist/extensions/forgecli/config-tui/index.js +0 -5
- package/dist/extensions/forgecli/config-tui/index.js.map +0 -1
- package/dist/extensions/forgecli/loaders/persona-skill-loader.d.ts +0 -45
- package/dist/extensions/forgecli/loaders/persona-skill-loader.js +0 -227
- package/dist/extensions/forgecli/loaders/persona-skill-loader.js.map +0 -1
- package/dist/extensions/forgecli/loaders/template-render.d.ts +0 -20
- package/dist/extensions/forgecli/loaders/template-render.js +0 -85
- package/dist/extensions/forgecli/loaders/template-render.js.map +0 -1
- package/dist/extensions/forgecli/loaders/workflow-loader.d.ts +0 -41
- package/dist/extensions/forgecli/loaders/workflow-loader.js +0 -164
- package/dist/extensions/forgecli/loaders/workflow-loader.js.map +0 -1
- package/dist/forge-payload/.base-pack/workflows/fix_bug.md +0 -446
- package/dist/forge-payload/.base-pack/workflows/orchestrate_task.md +0 -928
- package/dist/forge-payload/.base-pack/workflows/run_sprint.md +0 -225
|
@@ -132,9 +132,17 @@ function validateManifest(manifest, forgeRoot) {
|
|
|
132
132
|
fragments: path.join(basePackDir, 'workflows', '_fragments'),
|
|
133
133
|
templates: path.join(basePackDir, 'templates'),
|
|
134
134
|
commands: path.join(basePackDir, 'commands'),
|
|
135
|
+
'workflows-js': path.join(basePackDir, 'workflows-js'),
|
|
136
|
+
// tools: not base-pack-sourced — source is forgeRoot/tools/ (verbatim vendor).
|
|
137
|
+
// Uses recursive enumeration to include lib/*.cjs with the lib/ prefix.
|
|
138
|
+
tools: path.join(forgeRoot, 'tools'),
|
|
135
139
|
// schemas: not base-pack-sourced — source is forgeRoot/schemas/
|
|
136
140
|
};
|
|
137
141
|
|
|
142
|
+
// Namespaces that require recursive enumeration (files may include path prefixes
|
|
143
|
+
// like lib/*.cjs). The walker returns relative paths with forward slashes.
|
|
144
|
+
const recursiveNs = new Set(['tools']);
|
|
145
|
+
|
|
138
146
|
const manifestOnly = []; // Files in manifest but not in base-pack
|
|
139
147
|
const basePackOnly = []; // Files in base-pack but not in manifest
|
|
140
148
|
|
|
@@ -147,14 +155,31 @@ function validateManifest(manifest, forgeRoot) {
|
|
|
147
155
|
|
|
148
156
|
const manifestFiles = new Set(ns.files || []);
|
|
149
157
|
|
|
150
|
-
// Read base-pack source directory
|
|
158
|
+
// Read base-pack source directory (flat or recursive depending on namespace)
|
|
151
159
|
let basePackFiles = [];
|
|
152
160
|
try {
|
|
153
|
-
|
|
154
|
-
//
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
161
|
+
if (recursiveNs.has(nsKey)) {
|
|
162
|
+
// Recursive walk: enumerate all files, returning paths relative to sourceDir
|
|
163
|
+
// (with forward-slash separators). Excludes *.test.cjs files.
|
|
164
|
+
const walkDir = (dir, prefix) => {
|
|
165
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
166
|
+
for (const entry of entries) {
|
|
167
|
+
const relPath = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
168
|
+
if (entry.isDirectory()) {
|
|
169
|
+
walkDir(path.join(dir, entry.name), relPath);
|
|
170
|
+
} else if (entry.isFile() && !entry.name.endsWith('.test.cjs')) {
|
|
171
|
+
basePackFiles.push(relPath);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
walkDir(sourceDir, '');
|
|
176
|
+
} else {
|
|
177
|
+
basePackFiles = fs.readdirSync(sourceDir).filter(f => {
|
|
178
|
+
// Only include regular files, skip subdirectories (like _fragments under workflows)
|
|
179
|
+
const stat = fs.statSync(path.join(sourceDir, f));
|
|
180
|
+
return stat.isFile();
|
|
181
|
+
});
|
|
182
|
+
}
|
|
158
183
|
} catch {
|
|
159
184
|
// Directory doesn't exist — all manifest files are manifestOnly
|
|
160
185
|
for (const f of manifestFiles) {
|
|
@@ -183,9 +208,65 @@ function validateManifest(manifest, forgeRoot) {
|
|
|
183
208
|
return { manifestOnly, basePackOnly };
|
|
184
209
|
}
|
|
185
210
|
|
|
211
|
+
// Checks whether the vendored .forge/tools/ directory is present, and whether
|
|
212
|
+
// the version marker (.forge/tools/.forge-tools-version) matches the active
|
|
213
|
+
// plugin version from .forge/config.json (paths.forgeRef).
|
|
214
|
+
//
|
|
215
|
+
// Returns:
|
|
216
|
+
// { present, vendoredVersion, activeVersion, stale, reason }
|
|
217
|
+
//
|
|
218
|
+
// present — true if .forge/tools/ directory exists
|
|
219
|
+
// vendoredVersion — version string from .forge-tools-version (or null)
|
|
220
|
+
// activeVersion — version string from paths.forgeRef in config (or null)
|
|
221
|
+
// stale — true when: dir absent=false; marker absent=true; versions differ=true
|
|
222
|
+
// reason — 'ok' | 'missing' | 'marker-absent' | 'version-mismatch'
|
|
223
|
+
function checkToolsVersion(projectRoot) {
|
|
224
|
+
const toolsDir = path.join(projectRoot, '.forge', 'tools');
|
|
225
|
+
const markerFile = path.join(toolsDir, '.forge-tools-version');
|
|
226
|
+
const configFile = path.join(projectRoot, '.forge', 'config.json');
|
|
227
|
+
|
|
228
|
+
// Dir absent → not stale (just missing)
|
|
229
|
+
if (!fs.existsSync(toolsDir)) {
|
|
230
|
+
return { present: false, vendoredVersion: null, activeVersion: null, stale: false, reason: 'missing' };
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// Read active version from config
|
|
234
|
+
let activeVersion = null;
|
|
235
|
+
if (fs.existsSync(configFile)) {
|
|
236
|
+
try {
|
|
237
|
+
const cfg = JSON.parse(fs.readFileSync(configFile, 'utf8'));
|
|
238
|
+
activeVersion = (cfg && cfg.paths && cfg.paths.forgeRef) ? cfg.paths.forgeRef : null;
|
|
239
|
+
} catch {
|
|
240
|
+
// unparseable — leave activeVersion null
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// Marker absent → stale
|
|
245
|
+
if (!fs.existsSync(markerFile)) {
|
|
246
|
+
return { present: true, vendoredVersion: null, activeVersion, stale: true, reason: 'marker-absent' };
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// Read vendored version from marker
|
|
250
|
+
let vendoredVersion = null;
|
|
251
|
+
try {
|
|
252
|
+
const marker = JSON.parse(fs.readFileSync(markerFile, 'utf8'));
|
|
253
|
+
vendoredVersion = (marker && marker.version) ? marker.version : null;
|
|
254
|
+
} catch {
|
|
255
|
+
// unparseable marker → treat as marker-absent
|
|
256
|
+
return { present: true, vendoredVersion: null, activeVersion, stale: true, reason: 'marker-absent' };
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// Version mismatch → stale
|
|
260
|
+
if (activeVersion && vendoredVersion && vendoredVersion !== activeVersion) {
|
|
261
|
+
return { present: true, vendoredVersion, activeVersion, stale: true, reason: 'version-mismatch' };
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
return { present: true, vendoredVersion, activeVersion, stale: false, reason: 'ok' };
|
|
265
|
+
}
|
|
266
|
+
|
|
186
267
|
// ── Exports ────────────────────────────────────────────────────────────────────
|
|
187
268
|
|
|
188
|
-
module.exports = { checkNamespaces, validateManifest };
|
|
269
|
+
module.exports = { checkNamespaces, validateManifest, checkToolsVersion };
|
|
189
270
|
|
|
190
271
|
// ── CLI ────────────────────────────────────────────────────────────────────────
|
|
191
272
|
|
|
@@ -108,9 +108,23 @@ function resolveTaskDir(task, sprintDirPath, engPath) {
|
|
|
108
108
|
const normalizedTaskPath = task.path ? task.path.replace(/\\/g, '/').replace(/\/$/, '') : null;
|
|
109
109
|
const normalizedEngPath = engPath ? engPath.replace(/\\/g, '/').replace(/\/$/, '') : '';
|
|
110
110
|
|
|
111
|
-
// Case 1: path is under the engineering root — it IS
|
|
111
|
+
// Case 1: path is under the engineering root — it IS (or is a file inside)
|
|
112
|
+
// the task directory. Some store records carry task.path pointing at a file
|
|
113
|
+
// inside the task dir (e.g. .../FORGE-S22-T04/PLAN.md) rather than the dir
|
|
114
|
+
// itself; in that case basename(path) is the filename, not the dir. Only
|
|
115
|
+
// trust Case 1 when its candidate resolves to a real directory on disk —
|
|
116
|
+
// otherwise fall through to the filesystem scan, which resolves by taskId.
|
|
112
117
|
if (normalizedTaskPath && normalizedEngPath && normalizedTaskPath.startsWith(normalizedEngPath + '/')) {
|
|
113
|
-
|
|
118
|
+
const candidate = path.basename(normalizedTaskPath);
|
|
119
|
+
// Can't verify against disk — preserve legacy behaviour and trust the path.
|
|
120
|
+
if (!sprintDirPath) return resultOk(candidate);
|
|
121
|
+
const candidatePath = path.join(sprintDirPath, candidate);
|
|
122
|
+
// Trust Case 1 only when the candidate is a real directory. If it's a file
|
|
123
|
+
// (task.path pointed at a doc inside the dir) or absent, fall through to the
|
|
124
|
+
// filesystem scan below, which resolves the dir by taskId.
|
|
125
|
+
if (fs.existsSync(candidatePath) && fs.statSync(candidatePath).isDirectory()) {
|
|
126
|
+
return resultOk(candidate);
|
|
127
|
+
}
|
|
114
128
|
}
|
|
115
129
|
|
|
116
130
|
// Case 2 (and fallback for case 1 missing): filesystem scan
|
|
@@ -418,7 +418,7 @@ if (subcmd === 'resolve-forge-root') {
|
|
|
418
418
|
|
|
419
419
|
const { config } = readConfig();
|
|
420
420
|
const forgeRef = getByPath(config, 'paths.forgeRef');
|
|
421
|
-
|
|
421
|
+
// Note: paths.forgeRoot read removed in FORGE-S29-T03 (Priority 3 deprecated).
|
|
422
422
|
|
|
423
423
|
// Priority 2: Scan cache/marketplace directories by forgeRef
|
|
424
424
|
if (forgeRef && typeof forgeRef === 'string') {
|
|
@@ -442,14 +442,12 @@ if (subcmd === 'resolve-forge-root') {
|
|
|
442
442
|
}
|
|
443
443
|
}
|
|
444
444
|
|
|
445
|
-
// Priority 3
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
process.exit(0);
|
|
449
|
-
}
|
|
445
|
+
// Priority 3 (paths.forgeRoot fallback) removed — FORGE-S29-T03.
|
|
446
|
+
// paths.forgeRoot is deprecated and no longer used as a resolution fallback.
|
|
447
|
+
// Relying on it masks misconfigured projects and blocks the FORGE_ROOT retirement.
|
|
450
448
|
|
|
451
449
|
// No resolution possible
|
|
452
|
-
console.error('× Cannot resolve Forge plugin root: no CLAUDE_PLUGIN_ROOT env var
|
|
450
|
+
console.error('× Cannot resolve Forge plugin root: no CLAUDE_PLUGIN_ROOT env var and no forgeRef cache match. Run /forge:update to refresh.');
|
|
453
451
|
process.exit(1);
|
|
454
452
|
}
|
|
455
453
|
|
|
@@ -154,4 +154,76 @@ function parseAfter(rest, lineNo) {
|
|
|
154
154
|
return { phase: m[1], verdict };
|
|
155
155
|
}
|
|
156
156
|
|
|
157
|
-
|
|
157
|
+
// parseOutputs — same fence-scan logic as parseGates but for ```outputs phase=X blocks.
|
|
158
|
+
// Closed grammar: only `artifact` and `require` directives are allowed.
|
|
159
|
+
// Unknown directives throw (parity with parseGates).
|
|
160
|
+
const OUTPUTS_FENCE_OPEN = /^```outputs\s+phase=([A-Za-z0-9_-]+)\s*$/;
|
|
161
|
+
|
|
162
|
+
function parseOutputs(markdown) {
|
|
163
|
+
if (typeof markdown !== 'string' || markdown.length === 0) return {};
|
|
164
|
+
const lines = markdown.split('\n');
|
|
165
|
+
const result = {};
|
|
166
|
+
let currentPhase = null;
|
|
167
|
+
let inFence = false;
|
|
168
|
+
let fenceStartLine = -1;
|
|
169
|
+
let fenceBuffer = [];
|
|
170
|
+
for (let i = 0; i < lines.length; i++) {
|
|
171
|
+
const line = lines[i];
|
|
172
|
+
const lineNo = i + 1;
|
|
173
|
+
if (!inFence) {
|
|
174
|
+
const m = line.match(OUTPUTS_FENCE_OPEN);
|
|
175
|
+
if (m) {
|
|
176
|
+
currentPhase = m[1];
|
|
177
|
+
if (result[currentPhase]) {
|
|
178
|
+
throw new Error(
|
|
179
|
+
`parse-gates: line ${lineNo}: duplicate outputs block for phase "${currentPhase}"`,
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
inFence = true;
|
|
183
|
+
fenceStartLine = lineNo;
|
|
184
|
+
fenceBuffer = [];
|
|
185
|
+
}
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
// Inside an outputs fence
|
|
189
|
+
if (FENCE_CLOSE.test(line)) {
|
|
190
|
+
result[currentPhase] = parseOutputsBlock(fenceBuffer, fenceStartLine);
|
|
191
|
+
inFence = false;
|
|
192
|
+
currentPhase = null;
|
|
193
|
+
fenceBuffer = [];
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
fenceBuffer.push({ text: line, lineNo });
|
|
197
|
+
}
|
|
198
|
+
if (inFence) {
|
|
199
|
+
throw new Error(`parse-gates: unterminated \`\`\`outputs fence opened at line ${fenceStartLine}`);
|
|
200
|
+
}
|
|
201
|
+
return result;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
function parseOutputsBlock(bufferedLines, _fenceStartLine) {
|
|
205
|
+
const spec = { artifacts: [], require: [] };
|
|
206
|
+
for (const { text, lineNo } of bufferedLines) {
|
|
207
|
+
const trimmed = text.trim();
|
|
208
|
+
if (trimmed === '' || trimmed.startsWith('#')) continue;
|
|
209
|
+
const firstSpace = trimmed.search(/\s/);
|
|
210
|
+
if (firstSpace < 0) {
|
|
211
|
+
throw new Error(`parse-gates: line ${lineNo}: malformed directive "${trimmed}"`);
|
|
212
|
+
}
|
|
213
|
+
const directive = trimmed.slice(0, firstSpace);
|
|
214
|
+
const rest = trimmed.slice(firstSpace + 1).trim();
|
|
215
|
+
switch (directive) {
|
|
216
|
+
case 'artifact':
|
|
217
|
+
spec.artifacts.push(parseArtifact(rest, lineNo));
|
|
218
|
+
break;
|
|
219
|
+
case 'require':
|
|
220
|
+
spec.require.push(parsePredicate(rest, lineNo));
|
|
221
|
+
break;
|
|
222
|
+
default:
|
|
223
|
+
throw new Error(`parse-gates: line ${lineNo}: unknown directive "${directive}"`);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
return spec;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
module.exports = { parseGates, parseOutputs };
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// postflight-gate.cjs — evaluates a phase's declared outputs block against
|
|
4
|
+
// the filesystem / task state, post-subagent-return. Returns structured failure
|
|
5
|
+
// data so the orchestrator (run-task.ts) can halt before FSM advance when outputs
|
|
6
|
+
// are not satisfied.
|
|
7
|
+
//
|
|
8
|
+
// Pure function: only fs.existsSync / fs.statSync / fs.readFileSync. No writes,
|
|
9
|
+
// no network, no LLM, no process spawns.
|
|
10
|
+
//
|
|
11
|
+
// CLI shim: node postflight-gate.cjs --phase <name> --task <taskId>
|
|
12
|
+
// Exit codes: 0 (ok), 1 (guard failed), 2 (invalid args / parse error)
|
|
13
|
+
// Stdout on exit 1: single JSON line { phase, reasonCode, detail, remediation }
|
|
14
|
+
//
|
|
15
|
+
// New reasonCodes (FORGE-S26-T19):
|
|
16
|
+
// output-missing — artifact path does not exist
|
|
17
|
+
// output-stub — artifact exists but size < min= bytes
|
|
18
|
+
// require-failed — require predicate over state field failed
|
|
19
|
+
// tool-error — internal parse or store-read failure
|
|
20
|
+
|
|
21
|
+
const fs = require('node:fs');
|
|
22
|
+
const path = require('node:path');
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* postflight({ phase, outputs, state, substitutions })
|
|
26
|
+
*
|
|
27
|
+
* @param {string} phase - Phase name (e.g. 'implement')
|
|
28
|
+
* @param {object} outputs - Parsed outputs spec from parseOutputs() — { [phase]: { artifacts, require } }
|
|
29
|
+
* @param {object} [state] - Task/bug state for require predicates (e.g. { task: {...} })
|
|
30
|
+
* @param {object} [substitutions] - Template variable substitutions (e.g. { engineering, sprint, task })
|
|
31
|
+
* @returns {{ ok: boolean, missing: string[], reasonCode: string, detail: string, remediation: string }}
|
|
32
|
+
*/
|
|
33
|
+
function postflight({ phase, outputs, state = {}, substitutions = {} }) {
|
|
34
|
+
const spec = outputs && outputs[phase];
|
|
35
|
+
if (!spec) {
|
|
36
|
+
// No outputs block for this phase — pass through (no-op)
|
|
37
|
+
return { ok: true, missing: [], reasonCode: null, detail: '', remediation: '' };
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const missing = [];
|
|
41
|
+
|
|
42
|
+
for (const art of spec.artifacts || []) {
|
|
43
|
+
const resolved = applySubstitutions(art.path, substitutions);
|
|
44
|
+
let exists = false;
|
|
45
|
+
let size = 0;
|
|
46
|
+
try {
|
|
47
|
+
const st = fs.statSync(resolved);
|
|
48
|
+
exists = st.isFile();
|
|
49
|
+
size = st.size;
|
|
50
|
+
} catch (_) {
|
|
51
|
+
exists = false;
|
|
52
|
+
}
|
|
53
|
+
if (!exists) {
|
|
54
|
+
missing.push(`output-missing: artifact absent: ${resolved}`);
|
|
55
|
+
} else if (size < (art.minBytes || 0)) {
|
|
56
|
+
missing.push(
|
|
57
|
+
`output-stub: artifact too small: ${resolved} (${size} bytes, need >= ${art.minBytes})`,
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
for (const pred of spec.require || []) {
|
|
63
|
+
if (!evalPredicate(pred, state)) {
|
|
64
|
+
missing.push(
|
|
65
|
+
`require-failed: ${describePredicate(pred)} (got ${JSON.stringify(readField(pred.field, state))})`,
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (missing.length === 0) {
|
|
71
|
+
return { ok: true, missing: [], reasonCode: null, detail: '', remediation: '' };
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const { reasonCode, detail, remediation } = buildStructuredFailure(phase, missing);
|
|
75
|
+
return { ok: false, missing, reasonCode, detail, remediation };
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function applySubstitutions(template, subs) {
|
|
79
|
+
return template.replace(/\{(\w+)\}/g, (full, key) => {
|
|
80
|
+
if (Object.prototype.hasOwnProperty.call(subs, key)) return String(subs[key]);
|
|
81
|
+
return full;
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function readField(dottedPath, state) {
|
|
86
|
+
const parts = dottedPath.split('.');
|
|
87
|
+
let cur = state;
|
|
88
|
+
for (const p of parts) {
|
|
89
|
+
if (cur === null || cur === undefined) return undefined;
|
|
90
|
+
cur = cur[p];
|
|
91
|
+
}
|
|
92
|
+
return cur;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function evalPredicate(pred, state) {
|
|
96
|
+
const actual = readField(pred.field, state);
|
|
97
|
+
switch (pred.op) {
|
|
98
|
+
case '==':
|
|
99
|
+
return String(actual) === String(pred.value);
|
|
100
|
+
case '!=':
|
|
101
|
+
return String(actual) !== String(pred.value);
|
|
102
|
+
case 'in':
|
|
103
|
+
return (pred.value || []).map(String).includes(String(actual));
|
|
104
|
+
default:
|
|
105
|
+
throw new Error(`postflight-gate: unknown predicate op "${pred.op}"`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function describePredicate(pred) {
|
|
110
|
+
if (pred.op === 'in') return `${pred.field} in [${(pred.value || []).join(', ')}]`;
|
|
111
|
+
return `${pred.field} ${pred.op} ${pred.value}`;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function buildStructuredFailure(phase, missing) {
|
|
115
|
+
let reasonCode = 'tool-error';
|
|
116
|
+
const detailParts = [];
|
|
117
|
+
|
|
118
|
+
for (const m of missing) {
|
|
119
|
+
detailParts.push(m);
|
|
120
|
+
if (reasonCode === 'tool-error') {
|
|
121
|
+
if (/^output-missing/i.test(m)) {
|
|
122
|
+
reasonCode = 'output-missing';
|
|
123
|
+
} else if (/^output-stub/i.test(m)) {
|
|
124
|
+
reasonCode = 'output-stub';
|
|
125
|
+
} else if (/^require-failed/i.test(m)) {
|
|
126
|
+
reasonCode = 'require-failed';
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const detail = detailParts.join('; ');
|
|
132
|
+
|
|
133
|
+
const remediationMap = {
|
|
134
|
+
'output-missing': 'Re-run the phase that produces this artifact (e.g. /forge:implement), then retry.',
|
|
135
|
+
'output-stub': 'The artifact was produced but appears incomplete (stub). Ensure the phase wrote a complete file.',
|
|
136
|
+
'require-failed': 'Correct the task/bug state so it satisfies the postflight require predicate, then retry.',
|
|
137
|
+
'tool-error': 'Check the outputs block configuration and store records; run node .forge/tools/postflight-gate.cjs manually for diagnostics.',
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
return {
|
|
141
|
+
reasonCode,
|
|
142
|
+
detail,
|
|
143
|
+
remediation: remediationMap[reasonCode],
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
module.exports = { postflight };
|
|
148
|
+
|
|
149
|
+
// CLI shim — only runs when invoked directly
|
|
150
|
+
if (require.main === module) {
|
|
151
|
+
const args = parseArgs(process.argv.slice(2));
|
|
152
|
+
if (!args.phase || !args.task) {
|
|
153
|
+
process.stderr.write('Usage: postflight-gate.cjs --phase <phaseName> --task <taskId>\n');
|
|
154
|
+
process.exit(2);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const { parseOutputs } = require('./parse-gates.cjs');
|
|
158
|
+
|
|
159
|
+
// Resolve config
|
|
160
|
+
let engineeringRoot = 'engineering';
|
|
161
|
+
try {
|
|
162
|
+
const cfg = JSON.parse(fs.readFileSync(path.resolve(process.cwd(), '.forge/config.json'), 'utf8'));
|
|
163
|
+
if (cfg.paths && cfg.paths.engineering) engineeringRoot = cfg.paths.engineering;
|
|
164
|
+
} catch (_) { /* fall back to default */ }
|
|
165
|
+
|
|
166
|
+
// Load task record
|
|
167
|
+
let taskRecord = null;
|
|
168
|
+
try {
|
|
169
|
+
const store = require('./store.cjs');
|
|
170
|
+
taskRecord = store.getTask(args.task);
|
|
171
|
+
} catch (_) {
|
|
172
|
+
// store.cjs not available or task not found — continue with substitutions from args
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Build substitutions
|
|
176
|
+
const sprintId = taskRecord ? taskRecord.sprintId : undefined;
|
|
177
|
+
const substitutions = {
|
|
178
|
+
engineering: engineeringRoot,
|
|
179
|
+
sprint: sprintId,
|
|
180
|
+
task: args.task,
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
// Load workflow markdown (scan .forge/workflows/ for phase)
|
|
184
|
+
const workflowMd = loadWorkflowMarkdown(args.phase);
|
|
185
|
+
if (!workflowMd) {
|
|
186
|
+
process.stderr.write(`postflight-gate: no outputs block defined for phase "${args.phase}" — skipping\n`);
|
|
187
|
+
process.exit(0);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
let outputs;
|
|
191
|
+
try {
|
|
192
|
+
outputs = parseOutputs(workflowMd);
|
|
193
|
+
} catch (err) {
|
|
194
|
+
process.stderr.write(`postflight-gate: ${err.message}\n`);
|
|
195
|
+
process.exit(2);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
if (!outputs[args.phase]) {
|
|
199
|
+
process.stderr.write(`postflight-gate: no outputs block for phase "${args.phase}" — skipping\n`);
|
|
200
|
+
process.exit(0);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Build state from task record
|
|
204
|
+
const state = {};
|
|
205
|
+
if (taskRecord) state.task = taskRecord;
|
|
206
|
+
|
|
207
|
+
const result = postflight({ phase: args.phase, outputs, state, substitutions });
|
|
208
|
+
|
|
209
|
+
if (result.ok) process.exit(0);
|
|
210
|
+
|
|
211
|
+
process.stderr.write(`Postflight guard failed for phase "${args.phase}":\n`);
|
|
212
|
+
for (const m of result.missing) process.stderr.write(` - ${m}\n`);
|
|
213
|
+
|
|
214
|
+
// Emit structured JSON on stdout for orchestrators
|
|
215
|
+
process.stdout.write(JSON.stringify({
|
|
216
|
+
phase: args.phase,
|
|
217
|
+
reasonCode: result.reasonCode,
|
|
218
|
+
detail: result.detail,
|
|
219
|
+
remediation: result.remediation,
|
|
220
|
+
}) + '\n');
|
|
221
|
+
process.exit(1);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function parseArgs(argv) {
|
|
225
|
+
const out = {};
|
|
226
|
+
for (let i = 0; i < argv.length; i++) {
|
|
227
|
+
const a = argv[i];
|
|
228
|
+
if (a === '--phase') out.phase = argv[++i];
|
|
229
|
+
else if (a === '--task') out.task = argv[++i];
|
|
230
|
+
}
|
|
231
|
+
return out;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function loadWorkflowMarkdown(phaseName) {
|
|
235
|
+
const workflowsDir = path.resolve(process.cwd(), '.forge/workflows');
|
|
236
|
+
let entries;
|
|
237
|
+
try {
|
|
238
|
+
entries = fs.readdirSync(workflowsDir).filter((f) => f.endsWith('.md'));
|
|
239
|
+
} catch (_) {
|
|
240
|
+
return null;
|
|
241
|
+
}
|
|
242
|
+
const fencePattern = new RegExp('^```outputs\\s+phase=' + escapeRegex(phaseName) + '\\s*$', 'm');
|
|
243
|
+
for (const entry of entries) {
|
|
244
|
+
const md = fs.readFileSync(path.join(workflowsDir, entry), 'utf8');
|
|
245
|
+
if (fencePattern.test(md)) return md;
|
|
246
|
+
}
|
|
247
|
+
return null;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
function escapeRegex(s) {
|
|
251
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
252
|
+
}
|
|
@@ -349,9 +349,56 @@ if (require.main === module) {
|
|
|
349
349
|
if (result.ok) process.exit(0);
|
|
350
350
|
process.stderr.write(`Gate failed for phase "${args.phase}":\n`);
|
|
351
351
|
for (const m of result.missing) process.stderr.write(` - ${m}\n`);
|
|
352
|
+
// Emit structured JSON on stdout for orchestrators to parse and render.
|
|
353
|
+
// Shape: { phase, reasonCode, detail, remediation }
|
|
354
|
+
const structured = buildStructuredFailure(args.phase, result.missing);
|
|
355
|
+
process.stdout.write(JSON.stringify(structured) + '\n');
|
|
352
356
|
process.exit(1);
|
|
353
357
|
}
|
|
354
358
|
|
|
359
|
+
// Build a structured gate-failure object for orchestrators.
|
|
360
|
+
// Maps the human-readable `missing[]` strings to a typed { phase, reasonCode, detail, remediation }.
|
|
361
|
+
// reasonCode is derived from the dominant failure pattern:
|
|
362
|
+
// artifact-missing — artifact missing / too small
|
|
363
|
+
// predecessor-verdict-missing — after-clause verdict absent or wrong
|
|
364
|
+
// illegal-status — require/forbid predicate fired
|
|
365
|
+
// tool-error — internal error / unrecognised pattern
|
|
366
|
+
// When multiple failures exist, reasonCode reflects the first recognised pattern;
|
|
367
|
+
// detail combines all messages; only a single JSON object is ever emitted.
|
|
368
|
+
function buildStructuredFailure(phase, missing) {
|
|
369
|
+
let reasonCode = 'tool-error';
|
|
370
|
+
const detailParts = [];
|
|
371
|
+
|
|
372
|
+
for (const m of missing) {
|
|
373
|
+
detailParts.push(m);
|
|
374
|
+
if (reasonCode === 'tool-error') {
|
|
375
|
+
if (/^artifact (missing|too small)/i.test(m)) {
|
|
376
|
+
reasonCode = 'artifact-missing';
|
|
377
|
+
} else if (/^predecessor verdict (missing|unreadable)/i.test(m) || /verdict is "/i.test(m)) {
|
|
378
|
+
reasonCode = 'predecessor-verdict-missing';
|
|
379
|
+
} else if (/^(require failed|forbid triggered)/i.test(m)) {
|
|
380
|
+
reasonCode = 'illegal-status';
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
const detail = detailParts.join('; ');
|
|
386
|
+
|
|
387
|
+
const remediationMap = {
|
|
388
|
+
'artifact-missing': `Re-run the phase that produces this artifact (e.g. /forge:plan or /forge:implement), then retry.`,
|
|
389
|
+
'predecessor-verdict-missing': `Ensure the predecessor review phase completed and recorded a verdict via set-summary, then retry.`,
|
|
390
|
+
'illegal-status': `Correct the task/bug status (use store-cli update-status) so it satisfies the gate predicate, then retry.`,
|
|
391
|
+
'tool-error': `Check the gate configuration and store records for this task; run node .forge/tools/preflight-gate.cjs manually for diagnostics.`,
|
|
392
|
+
};
|
|
393
|
+
|
|
394
|
+
return {
|
|
395
|
+
phase,
|
|
396
|
+
reasonCode,
|
|
397
|
+
detail,
|
|
398
|
+
remediation: remediationMap[reasonCode],
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
|
|
355
402
|
function parseArgs(argv) {
|
|
356
403
|
const out = {};
|
|
357
404
|
for (let i = 0; i < argv.length; i++) {
|
|
@@ -120,10 +120,11 @@ const RUNTIME_PASSTHROUGH_KEYS = new Set([
|
|
|
120
120
|
* project prefix via getCommandsSubdir() — see walkBasePack.
|
|
121
121
|
*/
|
|
122
122
|
const SUBDIR_OUTPUT_MAP = {
|
|
123
|
-
personas:
|
|
124
|
-
skills:
|
|
125
|
-
workflows:
|
|
126
|
-
templates:
|
|
123
|
+
personas: path.join('.forge', 'personas'),
|
|
124
|
+
skills: path.join('.forge', 'skills'),
|
|
125
|
+
workflows: path.join('.forge', 'workflows'),
|
|
126
|
+
templates: path.join('.forge', 'templates'),
|
|
127
|
+
'workflows-js': path.join('.claude', 'workflows'),
|
|
127
128
|
};
|
|
128
129
|
|
|
129
130
|
/**
|
|
@@ -194,6 +194,14 @@ function verifyPhase2(cwd, kbPath) {
|
|
|
194
194
|
|
|
195
195
|
const PHASE3_DIRS = ['workflows', 'personas', 'skills', 'templates'];
|
|
196
196
|
|
|
197
|
+
// JS workflow files that substitute-placeholders.cjs emits from
|
|
198
|
+
// base-pack/workflows-js/ into .claude/workflows/ (FORGE-S28-T01).
|
|
199
|
+
// These are checked in addition to the .forge/ directory checks.
|
|
200
|
+
const PHASE3_JS_FILES = [
|
|
201
|
+
path.join('.claude', 'workflows', 'wfl-run-task.js'),
|
|
202
|
+
path.join('.claude', 'workflows', 'wfl-run-sprint.js'),
|
|
203
|
+
];
|
|
204
|
+
|
|
197
205
|
function verifyPhase3(cwd) {
|
|
198
206
|
const missing = [];
|
|
199
207
|
const checked = [];
|
|
@@ -213,6 +221,15 @@ function verifyPhase3(cwd) {
|
|
|
213
221
|
}
|
|
214
222
|
}
|
|
215
223
|
|
|
224
|
+
// Assert generated JS workflow files are present (FORGE-S28-T01)
|
|
225
|
+
for (const relFile of PHASE3_JS_FILES) {
|
|
226
|
+
checked.push(relFile);
|
|
227
|
+
const absFile = path.join(cwd, relFile);
|
|
228
|
+
if (!fs.existsSync(absFile)) {
|
|
229
|
+
missing.push(relFile);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
216
233
|
return {
|
|
217
234
|
phase: 3,
|
|
218
235
|
ok: missing.length === 0,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@entelligentsia/forgecli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.14",
|
|
4
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",
|
package/dist/bin/forgecli.d.ts
DELETED
package/dist/bin/forgecli.js
DELETED
package/dist/bin/forgecli.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"forgecli.js","sourceRoot":"","sources":["../../src/bin/forgecli.ts"],"names":[],"mappings":";AACA,2EAA2E;AAE3E,OAAO,CAAC,GAAG,CAAC,mCAAmC,CAAC,CAAC;AACjD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC"}
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
export { createConfigTuiComponent, type ConfigTuiComponentOptions } from "./component.js";
|
|
2
|
-
export type { ConfigLayer } from "../config-writer.js";
|
|
3
|
-
export type { View, ConfigBuffer, AvailableModel, InitOptions, ConfigTuiState, ConfigTuiAction, PhaseOverride, ResolvedPersonaEntry, PersonaPickerEntry, PipelineOverrideSummary, TierAssignment, } from "./state/model.js";
|
|
4
|
-
export { CANONICAL_PHASES, initialState, reducer, getActiveView, listResolvedPersonas, listPersonaPickerEntries, uniqueProviders, listPipelineOverrideSummaries, getPhaseOverride, getTierAssignment, getAllTierAssignments, getTierForPersona, getPersonasInTier, writePersonaEntry, deletePersonaEntry, writePhaseOverride, clearPhaseOverride, writeTierAssignment, isConfigEmpty, personaSourceLabel, } from "./state.js";
|
|
5
|
-
export type { InputResult, Screen } from "./screens/types.js";
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
// Config-TUI public re-exports.
|
|
2
|
-
// Phase 3: theming + width safety + data-driven menus + auth error surfacing.
|
|
3
|
-
export { createConfigTuiComponent } from "./component.js";
|
|
4
|
-
export { CANONICAL_PHASES, initialState, reducer, getActiveView, listResolvedPersonas, listPersonaPickerEntries, uniqueProviders, listPipelineOverrideSummaries, getPhaseOverride, getTierAssignment, getAllTierAssignments, getTierForPersona, getPersonasInTier, writePersonaEntry, deletePersonaEntry, writePhaseOverride, clearPhaseOverride, writeTierAssignment, isConfigEmpty, personaSourceLabel, } from "./state.js";
|
|
5
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/extensions/forgecli/config-tui/index.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,8EAA8E;AAE9E,OAAO,EAAE,wBAAwB,EAAkC,MAAM,gBAAgB,CAAC;AAkB1F,OAAO,EACL,gBAAgB,EAChB,YAAY,EACZ,OAAO,EACP,aAAa,EACb,oBAAoB,EACpB,wBAAwB,EACxB,eAAe,EACf,6BAA6B,EAC7B,gBAAgB,EAChB,iBAAiB,EACjB,qBAAqB,EACrB,iBAAiB,EACjB,iBAAiB,EACjB,iBAAiB,EACjB,kBAAkB,EAClB,kBAAkB,EAClB,kBAAkB,EAClB,mBAAmB,EACnB,aAAa,EACb,kBAAkB,GACnB,MAAM,YAAY,CAAC"}
|