@entelligentsia/forgecli 1.0.10 → 1.0.20
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 +191 -0
- package/dist/CHANGELOG-forge-plugin.md +211 -0
- package/dist/bin/forge.js +0 -0
- package/dist/extensions/forgecli/config-layer.js.map +1 -1
- package/dist/extensions/forgecli/context-governor-compaction.d.ts +83 -0
- package/dist/extensions/forgecli/context-governor-compaction.js +302 -0
- package/dist/extensions/forgecli/context-governor-compaction.js.map +1 -0
- package/dist/extensions/forgecli/context-governor.d.ts +173 -0
- package/dist/extensions/forgecli/context-governor.js +618 -0
- package/dist/extensions/forgecli/context-governor.js.map +1 -0
- package/dist/extensions/forgecli/dashboard/component.d.ts +105 -0
- package/dist/extensions/forgecli/dashboard/component.js +861 -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 +31 -0
- package/dist/extensions/forgecli/dashboard/register.js.map +1 -0
- package/dist/extensions/forgecli/dashboard/theme.d.ts +27 -0
- package/dist/extensions/forgecli/dashboard/theme.js +91 -0
- package/dist/extensions/forgecli/dashboard/theme.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 +126 -7
- package/dist/extensions/forgecli/fix-bug.js.map +1 -1
- package/dist/extensions/forgecli/forge-artifact-tool.js +2 -1
- package/dist/extensions/forgecli/forge-artifact-tool.js.map +1 -1
- 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.d.ts +20 -1
- package/dist/extensions/forgecli/forge-subagent.js +23 -7
- package/dist/extensions/forgecli/forge-subagent.js.map +1 -1
- package/dist/extensions/forgecli/forge-tools.js +3 -1
- package/dist/extensions/forgecli/forge-tools.js.map +1 -1
- package/dist/extensions/forgecli/hook-dispatcher.d.ts +3 -1
- package/dist/extensions/forgecli/hook-dispatcher.js +37 -3
- package/dist/extensions/forgecli/hook-dispatcher.js.map +1 -1
- package/dist/extensions/forgecli/index.js +38 -1
- package/dist/extensions/forgecli/index.js.map +1 -1
- package/dist/extensions/forgecli/lib/halt-advisor.d.ts +59 -0
- package/dist/extensions/forgecli/lib/halt-advisor.js +113 -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 +26 -0
- package/dist/extensions/forgecli/orchestrator-status-bar.js +213 -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.d.ts +3 -1
- package/dist/extensions/forgecli/run-sprint.js +34 -3
- package/dist/extensions/forgecli/run-sprint.js.map +1 -1
- package/dist/extensions/forgecli/run-task.d.ts +66 -1
- package/dist/extensions/forgecli/run-task.js +323 -12
- package/dist/extensions/forgecli/run-task.js.map +1 -1
- package/dist/extensions/forgecli/thread-switcher.d.ts +4 -1
- package/dist/extensions/forgecli/thread-switcher.js +118 -762
- 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 +15 -7
- package/dist/forge-payload/.base-pack/workflows/migrate_structural.md +12 -13
- package/dist/forge-payload/.base-pack/workflows/plan_task.md +12 -6
- package/dist/forge-payload/.base-pack/workflows/review_code.md +12 -11
- package/dist/forge-payload/.base-pack/workflows/review_plan.md +12 -11
- 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 +9 -9
- 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 +359 -18
- 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 +12 -11
- package/dist/forge-payload/meta/workflows/meta-review-plan.md +12 -11
- 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 +9 -9
- 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 +48 -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 +298 -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 +2 -2
- 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
|
@@ -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,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@entelligentsia/forgecli",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "Forge SDLC ported onto @earendil-works/pi-coding-agent
|
|
3
|
+
"version": "1.0.20",
|
|
4
|
+
"description": "Forge SDLC ported onto @earendil-works/pi-coding-agent — 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",
|
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"}
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import { type Static, Type } from "typebox";
|
|
2
|
-
export declare const PersonaSchema: Type.TObject<{
|
|
3
|
-
name: Type.TString;
|
|
4
|
-
filePath: Type.TString;
|
|
5
|
-
identity: Type.TString;
|
|
6
|
-
body: Type.TString;
|
|
7
|
-
capabilities: Type.TArray<Type.TString>;
|
|
8
|
-
frontmatter: Type.TRecord<"^.*$", Type.TUnknown>;
|
|
9
|
-
}>;
|
|
10
|
-
export type Persona = Static<typeof PersonaSchema>;
|
|
11
|
-
export declare const SkillSchema: Type.TObject<{
|
|
12
|
-
name: Type.TString;
|
|
13
|
-
filePath: Type.TString;
|
|
14
|
-
body: Type.TString;
|
|
15
|
-
capabilities: Type.TArray<Type.TString>;
|
|
16
|
-
frontmatter: Type.TRecord<"^.*$", Type.TUnknown>;
|
|
17
|
-
}>;
|
|
18
|
-
export type Skill = Static<typeof SkillSchema>;
|
|
19
|
-
export type PersonaSkillLoaderErrorCode = "missing_file" | "invalid_frontmatter" | "path_traversal" | "no_project_root" | "validation_failed";
|
|
20
|
-
export declare class PersonaSkillLoaderError extends Error {
|
|
21
|
-
readonly code: PersonaSkillLoaderErrorCode;
|
|
22
|
-
constructor(code: PersonaSkillLoaderErrorCode, message: string);
|
|
23
|
-
}
|
|
24
|
-
export interface LoaderOptions {
|
|
25
|
-
/** Override project root (the directory containing `.forge/`). */
|
|
26
|
-
projectRoot?: string;
|
|
27
|
-
/** cwd to start `.forge/config.json` discovery from. Defaults to `process.cwd()`. */
|
|
28
|
-
cwd?: string;
|
|
29
|
-
}
|
|
30
|
-
/**
|
|
31
|
-
* Load a Persona record from `<projectRoot>/.forge/personas/<name>.md`.
|
|
32
|
-
*
|
|
33
|
-
* `name` is the filename stem (e.g. `"engineer"` for `engineer.md`). It must
|
|
34
|
-
* not contain path separators or traversal segments — invalid names raise
|
|
35
|
-
* `PersonaSkillLoaderError` with `code: "path_traversal"`.
|
|
36
|
-
*/
|
|
37
|
-
export declare function loadPersona(name: string, opts?: LoaderOptions): Persona;
|
|
38
|
-
/**
|
|
39
|
-
* Load a Skill record from `<projectRoot>/.forge/skills/<name>.md`.
|
|
40
|
-
*
|
|
41
|
-
* `name` is the filename stem. The Forge convention names skill files
|
|
42
|
-
* `<noun>-skills.md` (e.g. `engineer-skills.md`); callers pass the full stem
|
|
43
|
-
* including the `-skills` suffix. The loader does not auto-append it.
|
|
44
|
-
*/
|
|
45
|
-
export declare function loadSkill(name: string, opts?: LoaderOptions): Skill;
|
|
@@ -1,227 +0,0 @@
|
|
|
1
|
-
// Central persona/skill loader — FORGE-S20-T02.
|
|
2
|
-
//
|
|
3
|
-
// Single canonical surface for reading persona and skill markdown files from
|
|
4
|
-
// the user's `.forge/personas/` and `.forge/skills/` directories. Future
|
|
5
|
-
// kickoff handlers (T04 /forge:enhance, T05 /forge:plan, T06 /forge:implement)
|
|
6
|
-
// load typed Persona/Skill records through this module instead of issuing
|
|
7
|
-
// ad-hoc fs.readFile calls. The smoke gate locks the invariant in place.
|
|
8
|
-
//
|
|
9
|
-
// Path resolution anchors at the **project root** containing `.forge/`, not
|
|
10
|
-
// at `forgeRoot` (which points at the bundled plugin source — `.forge/personas/`
|
|
11
|
-
// is a project-local generated directory).
|
|
12
|
-
//
|
|
13
|
-
// Iron Law 6 (no shell-string interpolation): all I/O is via fs synchronous
|
|
14
|
-
// APIs with absolute paths constructed by `path.join`/`path.resolve`. No
|
|
15
|
-
// external process invocation.
|
|
16
|
-
// Iron Law 7 (no silent continuation): every failure mode raises a typed
|
|
17
|
-
// `PersonaSkillLoaderError` with an explicit `code`.
|
|
18
|
-
import * as fs from "node:fs";
|
|
19
|
-
import * as path from "node:path";
|
|
20
|
-
import { Type } from "typebox";
|
|
21
|
-
import { Value } from "typebox/value";
|
|
22
|
-
import { discoverForgeConfig } from "../forge-root.js";
|
|
23
|
-
// ── TypeBox schemas ──────────────────────────────────────────────────────
|
|
24
|
-
export const PersonaSchema = Type.Object({
|
|
25
|
-
name: Type.String(),
|
|
26
|
-
filePath: Type.String(),
|
|
27
|
-
identity: Type.String(),
|
|
28
|
-
body: Type.String(),
|
|
29
|
-
capabilities: Type.Array(Type.String()),
|
|
30
|
-
frontmatter: Type.Record(Type.String(), Type.Unknown()),
|
|
31
|
-
});
|
|
32
|
-
export const SkillSchema = Type.Object({
|
|
33
|
-
name: Type.String(),
|
|
34
|
-
filePath: Type.String(),
|
|
35
|
-
body: Type.String(),
|
|
36
|
-
capabilities: Type.Array(Type.String()),
|
|
37
|
-
frontmatter: Type.Record(Type.String(), Type.Unknown()),
|
|
38
|
-
});
|
|
39
|
-
export class PersonaSkillLoaderError extends Error {
|
|
40
|
-
code;
|
|
41
|
-
constructor(code, message) {
|
|
42
|
-
super(message);
|
|
43
|
-
this.name = "PersonaSkillLoaderError";
|
|
44
|
-
this.code = code;
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
// ── Project-root discovery ───────────────────────────────────────────────
|
|
48
|
-
function resolveProjectRoot(opts) {
|
|
49
|
-
if (opts?.projectRoot)
|
|
50
|
-
return opts.projectRoot;
|
|
51
|
-
const cwd = opts?.cwd ?? process.cwd();
|
|
52
|
-
const cfg = discoverForgeConfig(cwd);
|
|
53
|
-
if (!cfg) {
|
|
54
|
-
throw new PersonaSkillLoaderError("no_project_root", `No .forge/config.json found walking up from ${cwd}. ` +
|
|
55
|
-
"Run /forge:init to scaffold the project, or pass `projectRoot` explicitly.");
|
|
56
|
-
}
|
|
57
|
-
// configPath = <projectDir>/.forge/config.json → projectDir = parent of .forge/
|
|
58
|
-
return path.dirname(path.dirname(cfg.configPath));
|
|
59
|
-
}
|
|
60
|
-
// ── Name validation (defence in depth) ───────────────────────────────────
|
|
61
|
-
function validateName(name, kind) {
|
|
62
|
-
if (typeof name !== "string" || name.length === 0) {
|
|
63
|
-
throw new PersonaSkillLoaderError("path_traversal", `${kind} name must be a non-empty string`);
|
|
64
|
-
}
|
|
65
|
-
if (name.includes("/") || name.includes("\\") || name.includes("\0")) {
|
|
66
|
-
throw new PersonaSkillLoaderError("path_traversal", `${kind} name contains path separators: ${JSON.stringify(name)}`);
|
|
67
|
-
}
|
|
68
|
-
const parts = name.split(/[/\\]/);
|
|
69
|
-
for (const p of parts) {
|
|
70
|
-
if (p === ".." || p === "." || p === "") {
|
|
71
|
-
throw new PersonaSkillLoaderError("path_traversal", `${kind} name contains traversal segment: ${JSON.stringify(name)}`);
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
// ── Realpath confinement check ───────────────────────────────────────────
|
|
76
|
-
function assertWithinDir(realFile, realDir, kind) {
|
|
77
|
-
const prefix = realDir.endsWith(path.sep) ? realDir : realDir + path.sep;
|
|
78
|
-
if (!realFile.startsWith(prefix)) {
|
|
79
|
-
throw new PersonaSkillLoaderError("path_traversal", `${kind} path escapes ${realDir}: resolved to ${realFile}`);
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
function parseFrontmatter(content) {
|
|
83
|
-
// Normalise CRLF for line-based parsing while preserving body intact below.
|
|
84
|
-
const lines = content.split(/\r?\n/);
|
|
85
|
-
if (lines.length === 0 || lines[0] !== "---") {
|
|
86
|
-
return { frontmatter: {}, body: content };
|
|
87
|
-
}
|
|
88
|
-
const fm = {};
|
|
89
|
-
let i = 1;
|
|
90
|
-
let closed = false;
|
|
91
|
-
for (; i < lines.length; i++) {
|
|
92
|
-
const line = lines[i];
|
|
93
|
-
if (line === "---") {
|
|
94
|
-
closed = true;
|
|
95
|
-
i++;
|
|
96
|
-
break;
|
|
97
|
-
}
|
|
98
|
-
// Allow blank lines inside frontmatter.
|
|
99
|
-
if (line.trim() === "")
|
|
100
|
-
continue;
|
|
101
|
-
const m = /^([A-Za-z0-9_.-]+):\s*(.*)$/.exec(line);
|
|
102
|
-
if (!m) {
|
|
103
|
-
throw new PersonaSkillLoaderError("invalid_frontmatter", `Malformed frontmatter line ${i + 1}: ${JSON.stringify(line)}`);
|
|
104
|
-
}
|
|
105
|
-
const value = m[2].trim();
|
|
106
|
-
// Strip matching surrounding quotes if present.
|
|
107
|
-
let parsed = value;
|
|
108
|
-
if ((value.startsWith('"') && value.endsWith('"') && value.length >= 2) ||
|
|
109
|
-
(value.startsWith("'") && value.endsWith("'") && value.length >= 2)) {
|
|
110
|
-
parsed = value.slice(1, -1);
|
|
111
|
-
}
|
|
112
|
-
fm[m[1]] = parsed;
|
|
113
|
-
}
|
|
114
|
-
if (!closed) {
|
|
115
|
-
throw new PersonaSkillLoaderError("invalid_frontmatter", "Frontmatter block opened with `---` but never closed");
|
|
116
|
-
}
|
|
117
|
-
const body = lines.slice(i).join("\n");
|
|
118
|
-
return { frontmatter: fm, body };
|
|
119
|
-
}
|
|
120
|
-
// ── Capability + identity extraction ─────────────────────────────────────
|
|
121
|
-
function extractCapabilities(body) {
|
|
122
|
-
const lines = body.split(/\r?\n/);
|
|
123
|
-
const heading = /^##\s+Capabilities\s*$/;
|
|
124
|
-
const nextSection = /^##\s+\S/;
|
|
125
|
-
const bullet = /^[-*]\s+(.+)$/;
|
|
126
|
-
const out = [];
|
|
127
|
-
let inSection = false;
|
|
128
|
-
for (const line of lines) {
|
|
129
|
-
if (!inSection) {
|
|
130
|
-
if (heading.test(line))
|
|
131
|
-
inSection = true;
|
|
132
|
-
continue;
|
|
133
|
-
}
|
|
134
|
-
if (nextSection.test(line))
|
|
135
|
-
break;
|
|
136
|
-
const m = bullet.exec(line);
|
|
137
|
-
if (m)
|
|
138
|
-
out.push(m[1].trim());
|
|
139
|
-
}
|
|
140
|
-
return out;
|
|
141
|
-
}
|
|
142
|
-
function extractIdentity(body) {
|
|
143
|
-
for (const line of body.split(/\r?\n/)) {
|
|
144
|
-
if (line.trim().length > 0)
|
|
145
|
-
return line.trim();
|
|
146
|
-
}
|
|
147
|
-
return "";
|
|
148
|
-
}
|
|
149
|
-
// ── Internal generic load ────────────────────────────────────────────────
|
|
150
|
-
function loadFile(kind, subdir, name, opts) {
|
|
151
|
-
validateName(name, kind);
|
|
152
|
-
const projectRoot = resolveProjectRoot(opts);
|
|
153
|
-
const baseDir = path.join(projectRoot, ".forge", subdir);
|
|
154
|
-
const candidate = path.join(baseDir, `${name}.md`);
|
|
155
|
-
// Realpath the *directory* first — it must exist for confinement check.
|
|
156
|
-
let realDir;
|
|
157
|
-
try {
|
|
158
|
-
realDir = fs.realpathSync(baseDir);
|
|
159
|
-
}
|
|
160
|
-
catch {
|
|
161
|
-
throw new PersonaSkillLoaderError("missing_file", `${kind} directory does not exist: ${baseDir}`);
|
|
162
|
-
}
|
|
163
|
-
let realFile;
|
|
164
|
-
try {
|
|
165
|
-
realFile = fs.realpathSync(candidate);
|
|
166
|
-
}
|
|
167
|
-
catch {
|
|
168
|
-
throw new PersonaSkillLoaderError("missing_file", `${kind} file not found: ${candidate}`);
|
|
169
|
-
}
|
|
170
|
-
assertWithinDir(realFile, realDir, kind);
|
|
171
|
-
let raw;
|
|
172
|
-
try {
|
|
173
|
-
raw = fs.readFileSync(realFile, "utf8");
|
|
174
|
-
}
|
|
175
|
-
catch (err) {
|
|
176
|
-
const e = err;
|
|
177
|
-
throw new PersonaSkillLoaderError("missing_file", `Failed to read ${kind} file ${realFile}: ${e.message ?? "unknown"}`);
|
|
178
|
-
}
|
|
179
|
-
return { filePath: realFile, doc: parseFrontmatter(raw) };
|
|
180
|
-
}
|
|
181
|
-
// ── Public API ───────────────────────────────────────────────────────────
|
|
182
|
-
/**
|
|
183
|
-
* Load a Persona record from `<projectRoot>/.forge/personas/<name>.md`.
|
|
184
|
-
*
|
|
185
|
-
* `name` is the filename stem (e.g. `"engineer"` for `engineer.md`). It must
|
|
186
|
-
* not contain path separators or traversal segments — invalid names raise
|
|
187
|
-
* `PersonaSkillLoaderError` with `code: "path_traversal"`.
|
|
188
|
-
*/
|
|
189
|
-
export function loadPersona(name, opts) {
|
|
190
|
-
const { filePath, doc } = loadFile("persona", "personas", name, opts);
|
|
191
|
-
const persona = {
|
|
192
|
-
name,
|
|
193
|
-
filePath,
|
|
194
|
-
identity: extractIdentity(doc.body),
|
|
195
|
-
body: doc.body,
|
|
196
|
-
capabilities: extractCapabilities(doc.body),
|
|
197
|
-
frontmatter: doc.frontmatter,
|
|
198
|
-
};
|
|
199
|
-
if (!Value.Check(PersonaSchema, persona)) {
|
|
200
|
-
const errs = [...Value.Errors(PersonaSchema, persona)].map((e) => e.message);
|
|
201
|
-
throw new PersonaSkillLoaderError("validation_failed", `Persona ${name} failed schema validation: ${errs.join("; ")}`);
|
|
202
|
-
}
|
|
203
|
-
return persona;
|
|
204
|
-
}
|
|
205
|
-
/**
|
|
206
|
-
* Load a Skill record from `<projectRoot>/.forge/skills/<name>.md`.
|
|
207
|
-
*
|
|
208
|
-
* `name` is the filename stem. The Forge convention names skill files
|
|
209
|
-
* `<noun>-skills.md` (e.g. `engineer-skills.md`); callers pass the full stem
|
|
210
|
-
* including the `-skills` suffix. The loader does not auto-append it.
|
|
211
|
-
*/
|
|
212
|
-
export function loadSkill(name, opts) {
|
|
213
|
-
const { filePath, doc } = loadFile("skill", "skills", name, opts);
|
|
214
|
-
const skill = {
|
|
215
|
-
name,
|
|
216
|
-
filePath,
|
|
217
|
-
body: doc.body,
|
|
218
|
-
capabilities: extractCapabilities(doc.body),
|
|
219
|
-
frontmatter: doc.frontmatter,
|
|
220
|
-
};
|
|
221
|
-
if (!Value.Check(SkillSchema, skill)) {
|
|
222
|
-
const errs = [...Value.Errors(SkillSchema, skill)].map((e) => e.message);
|
|
223
|
-
throw new PersonaSkillLoaderError("validation_failed", `Skill ${name} failed schema validation: ${errs.join("; ")}`);
|
|
224
|
-
}
|
|
225
|
-
return skill;
|
|
226
|
-
}
|
|
227
|
-
//# sourceMappingURL=persona-skill-loader.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"persona-skill-loader.js","sourceRoot":"","sources":["../../../../src/extensions/forgecli/loaders/persona-skill-loader.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
export type TemplateRenderErrorCode = "missing_template_file" | "missing_var" | "invalid_args";
|
|
2
|
-
export declare class TemplateRenderError extends Error {
|
|
3
|
-
readonly code: TemplateRenderErrorCode;
|
|
4
|
-
constructor(code: TemplateRenderErrorCode, message: string);
|
|
5
|
-
}
|
|
6
|
-
/**
|
|
7
|
-
* Render a template file by substituting `{NAME}` tokens with values from `vars`.
|
|
8
|
-
*
|
|
9
|
-
* @param templatePath Absolute or cwd-relative path to a UTF-8 template file.
|
|
10
|
-
* @param vars Map from identifier name to substitution value (string).
|
|
11
|
-
* @returns The rendered template as a string.
|
|
12
|
-
*
|
|
13
|
-
* @throws TemplateRenderError({ code: "missing_template_file" }) if the file
|
|
14
|
-
* does not exist or cannot be read.
|
|
15
|
-
* @throws TemplateRenderError({ code: "missing_var" }) if the template
|
|
16
|
-
* references a token whose name is not a key in `vars`.
|
|
17
|
-
* @throws TemplateRenderError({ code: "invalid_args" }) if `templatePath` is
|
|
18
|
-
* not a non-empty string or any value in `vars` is not a string.
|
|
19
|
-
*/
|
|
20
|
-
export declare function renderTemplate(templatePath: string, vars: Record<string, string>): string;
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
// Shared template-render helper — FORGE-S20-T03.
|
|
2
|
-
//
|
|
3
|
-
// Tiny, dependency-free `{NAME}` substitution helper used by kickoff-message
|
|
4
|
-
// composition in forge-cli command handlers (T05 /forge:plan, T06
|
|
5
|
-
// /forge:implement, and any future kickoff shim that needs argv-driven seed
|
|
6
|
-
// substitution).
|
|
7
|
-
//
|
|
8
|
-
// API:
|
|
9
|
-
// renderTemplate(templatePath: string, vars: Record<string, string>): string
|
|
10
|
-
//
|
|
11
|
-
// Substitution rule (frozen):
|
|
12
|
-
// - Token syntax: `{NAME}` where NAME matches /[A-Za-z_][A-Za-z0-9_]*/.
|
|
13
|
-
// Anything else — `{}`, `{ NAME }`, `{1NAME}`, `{lowercase-dashed}` — is
|
|
14
|
-
// a literal and passes through unchanged.
|
|
15
|
-
// - Missing var (token in template, key absent from `vars`): throws
|
|
16
|
-
// TemplateRenderError("missing_var", ...). Never silently renders "".
|
|
17
|
-
// (Iron Law 7: no silent continuation.)
|
|
18
|
-
// - Extra vars (key in `vars` not referenced in template): ignored.
|
|
19
|
-
// - Values are inserted literally — no HTML/regex escaping. Callers handle
|
|
20
|
-
// downstream sanitisation.
|
|
21
|
-
// - Missing template file: throws TemplateRenderError("missing_template_file", ...).
|
|
22
|
-
//
|
|
23
|
-
// Iron Law 6 (no shell-string interpolation): pure fs.readFileSync, no
|
|
24
|
-
// child_process. Iron Law 7 (no silent continuation): every failure mode
|
|
25
|
-
// raises a typed TemplateRenderError with an explicit code.
|
|
26
|
-
import * as fs from "node:fs";
|
|
27
|
-
export class TemplateRenderError extends Error {
|
|
28
|
-
code;
|
|
29
|
-
constructor(code, message) {
|
|
30
|
-
super(message);
|
|
31
|
-
this.name = "TemplateRenderError";
|
|
32
|
-
this.code = code;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
// ── Token grammar ────────────────────────────────────────────────────────
|
|
36
|
-
//
|
|
37
|
-
// Single regex, global, captures the bare identifier. Anchored on `{` and `}`
|
|
38
|
-
// with no whitespace tolerance — `{ NAME }` is a literal, by design.
|
|
39
|
-
const TOKEN_RE = /\{([A-Za-z_][A-Za-z0-9_]*)\}/g;
|
|
40
|
-
// ── Internal: substitute over an in-memory string ────────────────────────
|
|
41
|
-
function substitute(template, vars) {
|
|
42
|
-
return template.replace(TOKEN_RE, (_match, name) => {
|
|
43
|
-
if (!Object.hasOwn(vars, name)) {
|
|
44
|
-
throw new TemplateRenderError("missing_var", `template references {${name}} but no value was supplied in vars`);
|
|
45
|
-
}
|
|
46
|
-
const value = vars[name];
|
|
47
|
-
if (typeof value !== "string") {
|
|
48
|
-
throw new TemplateRenderError("invalid_args", `vars[${JSON.stringify(name)}] must be a string, got ${typeof value}`);
|
|
49
|
-
}
|
|
50
|
-
return value;
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
// ── Public API ───────────────────────────────────────────────────────────
|
|
54
|
-
/**
|
|
55
|
-
* Render a template file by substituting `{NAME}` tokens with values from `vars`.
|
|
56
|
-
*
|
|
57
|
-
* @param templatePath Absolute or cwd-relative path to a UTF-8 template file.
|
|
58
|
-
* @param vars Map from identifier name to substitution value (string).
|
|
59
|
-
* @returns The rendered template as a string.
|
|
60
|
-
*
|
|
61
|
-
* @throws TemplateRenderError({ code: "missing_template_file" }) if the file
|
|
62
|
-
* does not exist or cannot be read.
|
|
63
|
-
* @throws TemplateRenderError({ code: "missing_var" }) if the template
|
|
64
|
-
* references a token whose name is not a key in `vars`.
|
|
65
|
-
* @throws TemplateRenderError({ code: "invalid_args" }) if `templatePath` is
|
|
66
|
-
* not a non-empty string or any value in `vars` is not a string.
|
|
67
|
-
*/
|
|
68
|
-
export function renderTemplate(templatePath, vars) {
|
|
69
|
-
if (typeof templatePath !== "string" || templatePath.length === 0) {
|
|
70
|
-
throw new TemplateRenderError("invalid_args", "templatePath must be a non-empty string");
|
|
71
|
-
}
|
|
72
|
-
if (vars === null || typeof vars !== "object") {
|
|
73
|
-
throw new TemplateRenderError("invalid_args", "vars must be an object");
|
|
74
|
-
}
|
|
75
|
-
let raw;
|
|
76
|
-
try {
|
|
77
|
-
raw = fs.readFileSync(templatePath, "utf8");
|
|
78
|
-
}
|
|
79
|
-
catch (err) {
|
|
80
|
-
const e = err;
|
|
81
|
-
throw new TemplateRenderError("missing_template_file", `failed to read template at ${templatePath}: ${e.code ?? ""} ${e.message ?? "unknown error"}`.trim());
|
|
82
|
-
}
|
|
83
|
-
return substitute(raw, vars);
|
|
84
|
-
}
|
|
85
|
-
//# sourceMappingURL=template-render.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"template-render.js","sourceRoot":"","sources":["../../../../src/extensions/forgecli/loaders/template-render.ts"],"names":[],"mappings":"AAAA,iDAAiD;AACjD,EAAE;AACF,6EAA6E;AAC7E,kEAAkE;AAClE,4EAA4E;AAC5E,iBAAiB;AACjB,EAAE;AACF,OAAO;AACP,+EAA+E;AAC/E,EAAE;AACF,8BAA8B;AAC9B,0EAA0E;AAC1E,6EAA6E;AAC7E,8CAA8C;AAC9C,sEAAsE;AACtE,0EAA0E;AAC1E,4CAA4C;AAC5C,sEAAsE;AACtE,6EAA6E;AAC7E,+BAA+B;AAC/B,uFAAuF;AACvF,EAAE;AACF,uEAAuE;AACvE,yEAAyE;AACzE,4DAA4D;AAE5D,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAM9B,MAAM,OAAO,mBAAoB,SAAQ,KAAK;IAC7B,IAAI,CAA0B;IAC9C,YAAY,IAA6B,EAAE,OAAe;QACzD,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAC;QAClC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IAClB,CAAC;CACD;AAED,4EAA4E;AAC5E,EAAE;AACF,8EAA8E;AAC9E,qEAAqE;AACrE,MAAM,QAAQ,GAAG,+BAA+B,CAAC;AAEjD,4EAA4E;AAE5E,SAAS,UAAU,CAAC,QAAgB,EAAE,IAA4B;IACjE,OAAO,QAAQ,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,IAAY,EAAE,EAAE;QAC1D,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC;YAChC,MAAM,IAAI,mBAAmB,CAC5B,aAAa,EACb,wBAAwB,IAAI,qCAAqC,CACjE,CAAC;QACH,CAAC;QACD,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC;QACzB,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YAC/B,MAAM,IAAI,mBAAmB,CAC5B,cAAc,EACd,QAAQ,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,2BAA2B,OAAO,KAAK,EAAE,CACrE,CAAC;QACH,CAAC;QACD,OAAO,KAAK,CAAC;IACd,CAAC,CAAC,CAAC;AACJ,CAAC;AAED,4EAA4E;AAE5E;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,cAAc,CAAC,YAAoB,EAAE,IAA4B;IAChF,IAAI,OAAO,YAAY,KAAK,QAAQ,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACnE,MAAM,IAAI,mBAAmB,CAAC,cAAc,EAAE,yCAAyC,CAAC,CAAC;IAC1F,CAAC;IACD,IAAI,IAAI,KAAK,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC/C,MAAM,IAAI,mBAAmB,CAAC,cAAc,EAAE,wBAAwB,CAAC,CAAC;IACzE,CAAC;IAED,IAAI,GAAW,CAAC;IAChB,IAAI,CAAC;QACJ,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;IAC7C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACd,MAAM,CAAC,GAAG,GAA0C,CAAC;QACrD,MAAM,IAAI,mBAAmB,CAC5B,uBAAuB,EACvB,8BAA8B,YAAY,KAAK,CAAC,CAAC,IAAI,IAAI,EAAE,IAAI,CAAC,CAAC,OAAO,IAAI,eAAe,EAAE,CAAC,IAAI,EAAE,CACpG,CAAC;IACH,CAAC;IAED,OAAO,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;AAC9B,CAAC"}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import { type Static, Type } from "typebox";
|
|
2
|
-
export declare const AUDIENCE_VALUES: readonly ["orchestrator-only", "subagent", "any"];
|
|
3
|
-
export type AudienceValue = (typeof AUDIENCE_VALUES)[number];
|
|
4
|
-
export declare const WorkflowFrontmatterSchema: Type.TObject<{
|
|
5
|
-
audience: Type.TOptional<Type.TUnion<[Type.TLiteral<"orchestrator-only">, Type.TLiteral<"subagent">, Type.TLiteral<"any">]>>;
|
|
6
|
-
deps: Type.TOptional<Type.TObject<{
|
|
7
|
-
personas: Type.TOptional<Type.TArray<Type.TString>>;
|
|
8
|
-
}>>;
|
|
9
|
-
}>;
|
|
10
|
-
export type WorkflowFrontmatter = Static<typeof WorkflowFrontmatterSchema>;
|
|
11
|
-
export interface LoadedWorkflow {
|
|
12
|
-
filePath: string;
|
|
13
|
-
rawMarkdown: string;
|
|
14
|
-
frontmatter: WorkflowFrontmatter;
|
|
15
|
-
/** Resolved audience; defaults to "any" when the key is absent. */
|
|
16
|
-
audience: AudienceValue;
|
|
17
|
-
}
|
|
18
|
-
export type WorkflowLoaderErrorCode = "missing_file" | "invalid_frontmatter" | "validation_failed";
|
|
19
|
-
export declare class WorkflowLoaderError extends Error {
|
|
20
|
-
readonly code: WorkflowLoaderErrorCode;
|
|
21
|
-
constructor(code: WorkflowLoaderErrorCode, message: string);
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* Parse the YAML-like frontmatter of a workflow markdown file.
|
|
25
|
-
*
|
|
26
|
-
* Returns `{}` if the file does not start with `---`.
|
|
27
|
-
* Throws `WorkflowLoaderError("invalid_frontmatter", ...)` on malformed YAML.
|
|
28
|
-
*/
|
|
29
|
-
export declare function parseWorkflowFrontmatter(rawMarkdown: string): WorkflowFrontmatter;
|
|
30
|
-
/**
|
|
31
|
-
* Extract the audience value from a parsed WorkflowFrontmatter.
|
|
32
|
-
* Returns "any" when the key is absent or has an unrecognised value.
|
|
33
|
-
*/
|
|
34
|
-
export declare function extractAudience(frontmatter: WorkflowFrontmatter): AudienceValue;
|
|
35
|
-
/**
|
|
36
|
-
* Load and parse a materialized workflow markdown file.
|
|
37
|
-
*
|
|
38
|
-
* Throws `WorkflowLoaderError("missing_file", ...)` if the file is absent or unreadable.
|
|
39
|
-
* Throws `WorkflowLoaderError("invalid_frontmatter", ...)` if frontmatter is malformed.
|
|
40
|
-
*/
|
|
41
|
-
export declare function loadWorkflow(workflowPath: string): LoadedWorkflow;
|