@entelligentsia/forgecli 0.6.6 → 0.7.6
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 +88 -0
- package/README.md +28 -1
- package/dist/bin/forge.js +20 -0
- package/dist/bin/forge.js.map +1 -1
- package/dist/extensions/forgecli/approve.d.ts +24 -0
- package/dist/extensions/forgecli/approve.js +202 -0
- package/dist/extensions/forgecli/approve.js.map +1 -0
- package/dist/extensions/forgecli/audience-gate.d.ts +4 -0
- package/dist/extensions/forgecli/audience-gate.js +8 -5
- package/dist/extensions/forgecli/audience-gate.js.map +1 -1
- package/dist/extensions/forgecli/collate.d.ts +24 -0
- package/dist/extensions/forgecli/collate.js +199 -0
- package/dist/extensions/forgecli/collate.js.map +1 -0
- package/dist/extensions/forgecli/commit.d.ts +24 -0
- package/dist/extensions/forgecli/commit.js +202 -0
- package/dist/extensions/forgecli/commit.js.map +1 -0
- package/dist/extensions/forgecli/fix-bug.d.ts +75 -0
- package/dist/extensions/forgecli/fix-bug.js +1133 -0
- package/dist/extensions/forgecli/fix-bug.js.map +1 -0
- package/dist/extensions/forgecli/forge-commands.js +7 -0
- package/dist/extensions/forgecli/forge-commands.js.map +1 -1
- package/dist/extensions/forgecli/forge-init.js +16 -8
- package/dist/extensions/forgecli/forge-init.js.map +1 -1
- package/dist/extensions/forgecli/forge-subagent.d.ts +29 -0
- package/dist/extensions/forgecli/forge-subagent.js +14 -1
- package/dist/extensions/forgecli/forge-subagent.js.map +1 -1
- package/dist/extensions/forgecli/hook-dispatcher.d.ts +53 -1
- package/dist/extensions/forgecli/hook-dispatcher.js +47 -1
- package/dist/extensions/forgecli/hook-dispatcher.js.map +1 -1
- package/dist/extensions/forgecli/hooks/post-init-hook.d.ts +15 -0
- package/dist/extensions/forgecli/hooks/post-init-hook.js +127 -0
- package/dist/extensions/forgecli/hooks/post-init-hook.js.map +1 -0
- package/dist/extensions/forgecli/hooks/post-sprint-hook.d.ts +37 -0
- package/dist/extensions/forgecli/hooks/post-sprint-hook.js +166 -0
- package/dist/extensions/forgecli/hooks/post-sprint-hook.js.map +1 -0
- package/dist/extensions/forgecli/index.js +47 -0
- package/dist/extensions/forgecli/index.js.map +1 -1
- package/dist/extensions/forgecli/review-code.d.ts +24 -0
- package/dist/extensions/forgecli/review-code.js +202 -0
- package/dist/extensions/forgecli/review-code.js.map +1 -0
- package/dist/extensions/forgecli/review-plan.d.ts +24 -0
- package/dist/extensions/forgecli/review-plan.js +203 -0
- package/dist/extensions/forgecli/review-plan.js.map +1 -0
- package/dist/extensions/forgecli/run-sprint.d.ts +18 -0
- package/dist/extensions/forgecli/run-sprint.js +33 -1
- package/dist/extensions/forgecli/run-sprint.js.map +1 -1
- package/dist/extensions/forgecli/run-task.d.ts +21 -2
- package/dist/extensions/forgecli/run-task.js +33 -9
- package/dist/extensions/forgecli/run-task.js.map +1 -1
- package/dist/extensions/forgecli/session-registry.d.ts +10 -0
- package/dist/extensions/forgecli/session-registry.js +9 -0
- package/dist/extensions/forgecli/session-registry.js.map +1 -1
- package/dist/extensions/forgecli/validate.d.ts +24 -0
- package/dist/extensions/forgecli/validate.js +202 -0
- package/dist/extensions/forgecli/validate.js.map +1 -0
- package/dist/extensions/forgecli/wf-engine/engine.d.ts +23 -0
- package/dist/extensions/forgecli/wf-engine/engine.js +384 -0
- package/dist/extensions/forgecli/wf-engine/engine.js.map +1 -0
- package/dist/extensions/forgecli/wf-engine/event-parser.d.ts +6 -0
- package/dist/extensions/forgecli/wf-engine/event-parser.js +29 -0
- package/dist/extensions/forgecli/wf-engine/event-parser.js.map +1 -0
- package/dist/extensions/forgecli/wf-engine/id-gen.d.ts +6 -0
- package/dist/extensions/forgecli/wf-engine/id-gen.js +17 -0
- package/dist/extensions/forgecli/wf-engine/id-gen.js.map +1 -0
- package/dist/extensions/forgecli/wf-engine/loader.d.ts +2 -0
- package/dist/extensions/forgecli/wf-engine/loader.js +100 -0
- package/dist/extensions/forgecli/wf-engine/loader.js.map +1 -0
- package/dist/extensions/forgecli/wf-engine/predicate.d.ts +7 -0
- package/dist/extensions/forgecli/wf-engine/predicate.js +36 -0
- package/dist/extensions/forgecli/wf-engine/predicate.js.map +1 -0
- package/dist/extensions/forgecli/wf-engine/prompt-compiler.d.ts +15 -0
- package/dist/extensions/forgecli/wf-engine/prompt-compiler.js +23 -0
- package/dist/extensions/forgecli/wf-engine/prompt-compiler.js.map +1 -0
- package/dist/extensions/forgecli/wf-engine/register.d.ts +9 -0
- package/dist/extensions/forgecli/wf-engine/register.js +59 -0
- package/dist/extensions/forgecli/wf-engine/register.js.map +1 -0
- package/dist/extensions/forgecli/wf-engine/remit-check.d.ts +6 -0
- package/dist/extensions/forgecli/wf-engine/remit-check.js +42 -0
- package/dist/extensions/forgecli/wf-engine/remit-check.js.map +1 -0
- package/dist/extensions/forgecli/wf-engine/state-store.d.ts +13 -0
- package/dist/extensions/forgecli/wf-engine/state-store.js +43 -0
- package/dist/extensions/forgecli/wf-engine/state-store.js.map +1 -0
- package/dist/extensions/forgecli/wf-engine/types.d.ts +66 -0
- package/dist/extensions/forgecli/wf-engine/types.js +2 -0
- package/dist/extensions/forgecli/wf-engine/types.js.map +1 -0
- package/dist/extensions/forgecli/wf-engine/worker.d.ts +11 -0
- package/dist/extensions/forgecli/wf-engine/worker.js +50 -0
- package/dist/extensions/forgecli/wf-engine/worker.js.map +1 -0
- package/dist/forge-payload/.base-pack/workflows/_fragments/context-injection.md +10 -4
- package/dist/forge-payload/.base-pack/workflows/fix_bug.md +12 -0
- package/dist/forge-payload/.schemas/bug.schema.json +4 -2
- package/dist/forge-payload/.schemas/event.schema.json +22 -3
- package/dist/forge-payload/commands/add-pipeline.md +342 -0
- package/dist/forge-payload/commands/add-task.md +269 -0
- package/dist/forge-payload/commands/ask.md +43 -0
- package/dist/forge-payload/commands/calibrate.md +356 -0
- package/dist/forge-payload/commands/config.md +202 -0
- package/dist/forge-payload/commands/enhance.md +38 -0
- package/dist/forge-payload/commands/health.md +225 -0
- package/dist/forge-payload/commands/init.md +165 -0
- package/dist/forge-payload/commands/materialize.md +119 -0
- package/dist/forge-payload/commands/migrate.md +160 -0
- package/dist/forge-payload/commands/quiz-agent.md +38 -0
- package/dist/forge-payload/commands/regenerate.md +673 -0
- package/dist/forge-payload/commands/remove.md +174 -0
- package/dist/forge-payload/commands/report-bug.md +191 -0
- package/dist/forge-payload/commands/store-query.md +73 -0
- package/dist/forge-payload/commands/store-repair.md +187 -0
- package/dist/forge-payload/commands/update-tools.md +56 -0
- package/dist/forge-payload/commands/update.md +1376 -0
- package/dist/forge-payload/tools/preflight-gate.cjs +2 -1
- package/dist/forge-payload/tools/read-verdict.cjs +41 -8
- package/dist/forge-payload/tools/store-cli.cjs +4 -3
- package/node_modules/argparse/CHANGELOG.md +216 -0
- package/node_modules/argparse/LICENSE +254 -0
- package/node_modules/argparse/README.md +84 -0
- package/node_modules/argparse/argparse.js +3707 -0
- package/node_modules/argparse/lib/sub.js +67 -0
- package/node_modules/argparse/lib/textwrap.js +440 -0
- package/node_modules/argparse/package.json +31 -0
- package/node_modules/cliui/CHANGELOG.md +121 -0
- package/node_modules/color-convert/CHANGELOG.md +54 -0
- package/node_modules/esprima/ChangeLog +235 -0
- package/node_modules/js-yaml/LICENSE +21 -0
- package/node_modules/js-yaml/README.md +247 -0
- package/node_modules/js-yaml/bin/js-yaml.js +126 -0
- package/node_modules/js-yaml/dist/js-yaml.js +3880 -0
- package/node_modules/js-yaml/dist/js-yaml.min.js +2 -0
- package/node_modules/js-yaml/dist/js-yaml.mjs +3856 -0
- package/node_modules/js-yaml/index.js +47 -0
- package/node_modules/js-yaml/lib/common.js +59 -0
- package/node_modules/js-yaml/lib/dumper.js +965 -0
- package/node_modules/js-yaml/lib/exception.js +55 -0
- package/node_modules/js-yaml/lib/loader.js +1733 -0
- package/node_modules/js-yaml/lib/schema/core.js +11 -0
- package/node_modules/js-yaml/lib/schema/default.js +22 -0
- package/node_modules/js-yaml/lib/schema/failsafe.js +17 -0
- package/node_modules/js-yaml/lib/schema/json.js +19 -0
- package/node_modules/js-yaml/lib/schema.js +121 -0
- package/node_modules/js-yaml/lib/snippet.js +101 -0
- package/node_modules/js-yaml/lib/type/binary.js +125 -0
- package/node_modules/js-yaml/lib/type/bool.js +35 -0
- package/node_modules/js-yaml/lib/type/float.js +97 -0
- package/node_modules/js-yaml/lib/type/int.js +156 -0
- package/node_modules/js-yaml/lib/type/map.js +8 -0
- package/node_modules/js-yaml/lib/type/merge.js +12 -0
- package/node_modules/js-yaml/lib/type/null.js +35 -0
- package/node_modules/js-yaml/lib/type/omap.js +44 -0
- package/node_modules/js-yaml/lib/type/pairs.js +53 -0
- package/node_modules/js-yaml/lib/type/seq.js +8 -0
- package/node_modules/js-yaml/lib/type/set.js +29 -0
- package/node_modules/js-yaml/lib/type/str.js +8 -0
- package/node_modules/js-yaml/lib/type/timestamp.js +88 -0
- package/node_modules/js-yaml/lib/type.js +66 -0
- package/node_modules/js-yaml/package.json +66 -0
- package/node_modules/mz/HISTORY.md +66 -0
- package/node_modules/proper-lockfile/CHANGELOG.md +108 -0
- package/node_modules/source-map/CHANGELOG.md +301 -0
- package/node_modules/thenify/History.md +11 -0
- package/node_modules/thenify-all/History.md +11 -0
- package/node_modules/y18n/CHANGELOG.md +100 -0
- package/node_modules/yargs/CHANGELOG.md +88 -0
- package/node_modules/yargs-parser/CHANGELOG.md +263 -0
- package/package.json +6 -2
- package/workflows/lead-qualifier/prompts/digest.md +44 -0
- package/workflows/lead-qualifier/prompts/draft-outreach.md +44 -0
- package/workflows/lead-qualifier/prompts/enrich.md +52 -0
- package/workflows/lead-qualifier/prompts/intake.md +48 -0
- package/workflows/lead-qualifier/prompts/mark-cold.md +38 -0
- package/workflows/lead-qualifier/prompts/score.md +45 -0
- package/workflows/lead-qualifier/workflow.yaml +95 -0
- package/workflows/research-brief/prompts/brief-synthesize.md +43 -0
- package/workflows/research-brief/prompts/intake.md +51 -0
- package/workflows/research-brief/prompts/source-critique.md +38 -0
- package/workflows/research-brief/prompts/source-score.md +38 -0
- package/workflows/research-brief/prompts/source-summarize.md +54 -0
- package/workflows/research-brief/workflow.yaml +66 -0
- package/dist/extensions/forgecli/session-monitor-widget.d.ts +0 -37
- package/dist/extensions/forgecli/session-monitor-widget.js +0 -320
- package/dist/extensions/forgecli/session-monitor-widget.js.map +0 -1
- package/dist/extensions/forgecli/session-monitor.d.ts +0 -2
- package/dist/extensions/forgecli/session-monitor.js +0 -135
- package/dist/extensions/forgecli/session-monitor.js.map +0 -1
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// Match any ```json events ... ``` block; g flag so we can take the last one.
|
|
2
|
+
// LLMs often emit the block mid-response followed by explanatory prose, so we
|
|
3
|
+
// cannot anchor to $ — we take the last occurrence instead.
|
|
4
|
+
const FENCE_RE = /```json\s+events\s*\n([\s\S]*?)\n```/g;
|
|
5
|
+
export function parseEventsBlock(response) {
|
|
6
|
+
// Scan all matches; keep the last one (the actual output, not prompt examples).
|
|
7
|
+
let last = null;
|
|
8
|
+
let m;
|
|
9
|
+
const re = new RegExp(FENCE_RE.source, "g");
|
|
10
|
+
while ((m = re.exec(response)) !== null) {
|
|
11
|
+
last = m;
|
|
12
|
+
}
|
|
13
|
+
if (!last) {
|
|
14
|
+
return { events: [] };
|
|
15
|
+
}
|
|
16
|
+
const block = last[1];
|
|
17
|
+
let arr;
|
|
18
|
+
try {
|
|
19
|
+
arr = JSON.parse(block);
|
|
20
|
+
}
|
|
21
|
+
catch (err) {
|
|
22
|
+
throw new Error(`events block is not valid JSON: ${err.message}`);
|
|
23
|
+
}
|
|
24
|
+
if (!Array.isArray(arr)) {
|
|
25
|
+
throw new Error(`events block must be a JSON array, got ${typeof arr}`);
|
|
26
|
+
}
|
|
27
|
+
return { events: arr, rawBlock: block };
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=event-parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-parser.js","sourceRoot":"","sources":["../../../../src/extensions/forgecli/wf-engine/event-parser.ts"],"names":[],"mappings":"AAEA,8EAA8E;AAC9E,8EAA8E;AAC9E,4DAA4D;AAC5D,MAAM,QAAQ,GAAG,uCAAuC,CAAC;AAOzD,MAAM,UAAU,gBAAgB,CAAC,QAAgB;IAC/C,gFAAgF;IAChF,IAAI,IAAI,GAA2B,IAAI,CAAC;IACxC,IAAI,CAAyB,CAAC;IAC9B,MAAM,EAAE,GAAG,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC5C,OAAO,CAAC,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QACxC,IAAI,GAAG,CAAC,CAAC;IACX,CAAC;IACD,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;IACxB,CAAC;IACD,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IACtB,IAAI,GAAY,CAAC;IACjB,IAAI,CAAC;QACH,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAC1B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,mCAAoC,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;IAC/E,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,0CAA0C,OAAO,GAAG,EAAE,CAAC,CAAC;IAC1E,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,GAAc,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;AACrD,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export declare function makeInstanceId(workflowId: string, rand?: () => string): string;
|
|
2
|
+
export declare function makeNodeExecId(instanceId: string, nodeId: string, loop?: {
|
|
3
|
+
iter: number;
|
|
4
|
+
itemId: string;
|
|
5
|
+
}): string;
|
|
6
|
+
export declare function makeEventId(nodeExecId: string, seq: number, type: string): string;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import * as crypto from "node:crypto";
|
|
2
|
+
export function makeInstanceId(workflowId, rand) {
|
|
3
|
+
const iso = new Date().toISOString().replace(/[-:]/g, "").replace(/\.\d{3}Z$/, "Z");
|
|
4
|
+
const r = rand ? rand() : crypto.randomBytes(2).toString("hex");
|
|
5
|
+
return `wf_${workflowId}_${iso}_${r}`;
|
|
6
|
+
}
|
|
7
|
+
export function makeNodeExecId(instanceId, nodeId, loop) {
|
|
8
|
+
if (!loop)
|
|
9
|
+
return `${instanceId}__${nodeId}`;
|
|
10
|
+
const iterPad = String(loop.iter).padStart(2, "0");
|
|
11
|
+
return `${instanceId}__${nodeId}__iter${iterPad}__${loop.itemId}`;
|
|
12
|
+
}
|
|
13
|
+
export function makeEventId(nodeExecId, seq, type) {
|
|
14
|
+
const seqPad = String(seq).padStart(3, "0");
|
|
15
|
+
return `${nodeExecId}__${seqPad}__${type}`;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=id-gen.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"id-gen.js","sourceRoot":"","sources":["../../../../src/extensions/forgecli/wf-engine/id-gen.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AAEtC,MAAM,UAAU,cAAc,CAAC,UAAkB,EAAE,IAAmB;IACpE,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC;IACpF,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAChE,OAAO,MAAM,UAAU,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC;AACxC,CAAC;AAED,MAAM,UAAU,cAAc,CAC5B,UAAkB,EAClB,MAAc,EACd,IAAuC;IAEvC,IAAI,CAAC,IAAI;QAAE,OAAO,GAAG,UAAU,KAAK,MAAM,EAAE,CAAC;IAC7C,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IACnD,OAAO,GAAG,UAAU,KAAK,MAAM,SAAS,OAAO,KAAK,IAAI,CAAC,MAAM,EAAE,CAAC;AACpE,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,UAAkB,EAAE,GAAW,EAAE,IAAY;IACvE,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAC5C,OAAO,GAAG,UAAU,KAAK,MAAM,KAAK,IAAI,EAAE,CAAC;AAC7C,CAAC"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import * as yaml from "js-yaml";
|
|
4
|
+
export function loadWorkflow(workflowDir) {
|
|
5
|
+
const yamlPath = path.join(workflowDir, "workflow.yaml");
|
|
6
|
+
if (!fs.existsSync(yamlPath)) {
|
|
7
|
+
throw new Error(`workflow.yaml not found at ${yamlPath}`);
|
|
8
|
+
}
|
|
9
|
+
const raw = fs.readFileSync(yamlPath, "utf8");
|
|
10
|
+
const parsed = yaml.load(raw);
|
|
11
|
+
validateWorkflow(parsed, workflowDir);
|
|
12
|
+
return parsed;
|
|
13
|
+
}
|
|
14
|
+
function validateWorkflow(wf, workflowDir) {
|
|
15
|
+
if (!wf.id || typeof wf.id !== "string")
|
|
16
|
+
throw new Error("workflow.id required (string)");
|
|
17
|
+
if (!Array.isArray(wf.nodes) || wf.nodes.length === 0)
|
|
18
|
+
throw new Error("workflow.nodes required (non-empty array)");
|
|
19
|
+
if (!Array.isArray(wf.edges) || wf.edges.length === 0)
|
|
20
|
+
throw new Error("workflow.edges required (non-empty array)");
|
|
21
|
+
const nodeIds = new Set(wf.nodes.map(n => n.id));
|
|
22
|
+
for (const n of wf.nodes) {
|
|
23
|
+
if (!n.id)
|
|
24
|
+
throw new Error(`node missing id`);
|
|
25
|
+
if (!n.prompt)
|
|
26
|
+
throw new Error(`node ${n.id} missing prompt`);
|
|
27
|
+
const promptPath = path.join(workflowDir, n.prompt);
|
|
28
|
+
if (!fs.existsSync(promptPath))
|
|
29
|
+
throw new Error(`node ${n.id} prompt file not found: ${promptPath}`);
|
|
30
|
+
if (!n.expects?.success)
|
|
31
|
+
throw new Error(`node ${n.id} missing expects.success`);
|
|
32
|
+
if (!n.expects?.failure)
|
|
33
|
+
throw new Error(`node ${n.id} missing expects.failure`);
|
|
34
|
+
}
|
|
35
|
+
for (const e of wf.edges) {
|
|
36
|
+
if (!nodeIds.has(e.from))
|
|
37
|
+
throw new Error(`edge.from references unknown node: ${e.from}`);
|
|
38
|
+
if (e.to && !nodeIds.has(e.to))
|
|
39
|
+
throw new Error(`edge.to references unknown node: ${e.to}`);
|
|
40
|
+
if (e.next && !nodeIds.has(e.next))
|
|
41
|
+
throw new Error(`edge.next references unknown node: ${e.next}`);
|
|
42
|
+
if (!e.on || (e.on !== "success" && e.on !== "failure" && e.on !== "exhausted")) {
|
|
43
|
+
throw new Error(`edge.on must be 'success' | 'failure' | 'exhausted' (from ${e.from})`);
|
|
44
|
+
}
|
|
45
|
+
const hasOne = [e.to, e.halt, e.terminal, e.advance].filter(Boolean).length;
|
|
46
|
+
if (hasOne === 0)
|
|
47
|
+
throw new Error(`edge from ${e.from} has no continuation (to/halt/terminal/advance)`);
|
|
48
|
+
if (e.when && typeof e.when !== "string") {
|
|
49
|
+
throw new Error(`edge.when must be a string predicate (from ${e.from})`);
|
|
50
|
+
}
|
|
51
|
+
if (e.when && e.on !== "success") {
|
|
52
|
+
throw new Error(`edge.when only valid on success edges (from ${e.from})`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
// Group validation: collect groups, enforce single head, consistent loop.over
|
|
56
|
+
const groupMembers = new Map();
|
|
57
|
+
for (const n of wf.nodes) {
|
|
58
|
+
if (n.loop?.group) {
|
|
59
|
+
const arr = groupMembers.get(n.loop.group) ?? [];
|
|
60
|
+
arr.push(n.id);
|
|
61
|
+
groupMembers.set(n.loop.group, arr);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
for (const [group, members] of groupMembers) {
|
|
65
|
+
const heads = members.filter(id => wf.nodes.find(n => n.id === id).loop?.head === true);
|
|
66
|
+
if (heads.length !== 1) {
|
|
67
|
+
throw new Error(`loop group '${group}' must have exactly one head node, found ${heads.length}`);
|
|
68
|
+
}
|
|
69
|
+
const overs = new Set(members.map(id => wf.nodes.find(n => n.id === id).loop.over));
|
|
70
|
+
if (overs.size !== 1) {
|
|
71
|
+
throw new Error(`loop group '${group}' members must share the same loop.over (found: ${[...overs].join(", ")})`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
// Exhausted edges only valid from loop head (or non-grouped loop node)
|
|
75
|
+
for (const e of wf.edges) {
|
|
76
|
+
if (e.on === "exhausted") {
|
|
77
|
+
const fromNode = wf.nodes.find(n => n.id === e.from);
|
|
78
|
+
if (!fromNode.loop)
|
|
79
|
+
throw new Error(`edge.on='exhausted' requires from node to have a loop (from ${e.from})`);
|
|
80
|
+
if (fromNode.loop.group && fromNode.loop.head !== true) {
|
|
81
|
+
throw new Error(`edge.on='exhausted' must originate from group head (from ${e.from})`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
// Every node must have a success and failure edge; loop heads in groups must also have an exhausted edge
|
|
86
|
+
for (const n of wf.nodes) {
|
|
87
|
+
const hasSuccess = wf.edges.some(e => e.from === n.id && e.on === "success");
|
|
88
|
+
const hasFailure = wf.edges.some(e => e.from === n.id && e.on === "failure");
|
|
89
|
+
if (!hasSuccess)
|
|
90
|
+
throw new Error(`node ${n.id} missing success edge`);
|
|
91
|
+
if (!hasFailure)
|
|
92
|
+
throw new Error(`node ${n.id} missing failure edge`);
|
|
93
|
+
if (n.loop?.group && n.loop?.head) {
|
|
94
|
+
const hasExhausted = wf.edges.some(e => e.from === n.id && e.on === "exhausted");
|
|
95
|
+
if (!hasExhausted)
|
|
96
|
+
throw new Error(`group-head node ${n.id} missing exhausted edge`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../../../src/extensions/forgecli/wf-engine/loader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
const OP_RE = /^(\S+)\s+(==|!=|<=|>=|<|>)\s+(.+)$/;
|
|
2
|
+
export function evalPredicate(expr, ctx) {
|
|
3
|
+
const trimmed = expr.trim();
|
|
4
|
+
const m = trimmed.match(OP_RE);
|
|
5
|
+
if (!m)
|
|
6
|
+
throw new Error(`predicate: cannot parse '${expr}' — expected '<path> <op> <literal>'`);
|
|
7
|
+
const [, lhsPath, op, rhsLit] = m;
|
|
8
|
+
const lhs = resolvePath({ state: ctx.state, loop: ctx.loop }, lhsPath);
|
|
9
|
+
let rhs;
|
|
10
|
+
try {
|
|
11
|
+
rhs = JSON.parse(rhsLit);
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
throw new Error(`predicate: rhs '${rhsLit}' is not a valid JSON literal`);
|
|
15
|
+
}
|
|
16
|
+
switch (op) {
|
|
17
|
+
case "==": return lhs === rhs;
|
|
18
|
+
case "!=": return lhs !== rhs;
|
|
19
|
+
case "<": return lhs < rhs;
|
|
20
|
+
case "<=": return lhs <= rhs;
|
|
21
|
+
case ">": return lhs > rhs;
|
|
22
|
+
case ">=": return lhs >= rhs;
|
|
23
|
+
default: throw new Error(`predicate: unsupported op '${op}'`);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
function resolvePath(obj, dotted) {
|
|
27
|
+
const parts = dotted.split(".");
|
|
28
|
+
let cur = obj;
|
|
29
|
+
for (const p of parts) {
|
|
30
|
+
if (cur === null || typeof cur !== "object")
|
|
31
|
+
return undefined;
|
|
32
|
+
cur = cur[p];
|
|
33
|
+
}
|
|
34
|
+
return cur;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=predicate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"predicate.js","sourceRoot":"","sources":["../../../../src/extensions/forgecli/wf-engine/predicate.ts"],"names":[],"mappings":"AAKA,MAAM,KAAK,GAAG,oCAAoC,CAAC;AAEnD,MAAM,UAAU,aAAa,CAAC,IAAY,EAAE,GAAqB;IAC/D,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IAC5B,MAAM,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAC/B,IAAI,CAAC,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,4BAA4B,IAAI,sCAAsC,CAAC,CAAC;IAChG,MAAM,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC;IAElC,MAAM,GAAG,GAAG,WAAW,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,EAAE,OAAO,CAAC,CAAC;IACvE,IAAI,GAAY,CAAC;IACjB,IAAI,CAAC;QACH,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAC3B,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,mBAAmB,MAAM,+BAA+B,CAAC,CAAC;IAC5E,CAAC;IAED,QAAQ,EAAE,EAAE,CAAC;QACX,KAAK,IAAI,CAAC,CAAC,OAAO,GAAG,KAAK,GAAG,CAAC;QAC9B,KAAK,IAAI,CAAC,CAAC,OAAO,GAAG,KAAK,GAAG,CAAC;QAC9B,KAAK,GAAG,CAAC,CAAE,OAAQ,GAAc,GAAK,GAAc,CAAC;QACrD,KAAK,IAAI,CAAC,CAAC,OAAQ,GAAc,IAAK,GAAc,CAAC;QACrD,KAAK,GAAG,CAAC,CAAE,OAAQ,GAAc,GAAK,GAAc,CAAC;QACrD,KAAK,IAAI,CAAC,CAAC,OAAQ,GAAc,IAAK,GAAc,CAAC;QACrD,OAAO,CAAC,CAAG,MAAM,IAAI,KAAK,CAAC,8BAA8B,EAAE,GAAG,CAAC,CAAC;IAClE,CAAC;AACH,CAAC;AAED,SAAS,WAAW,CAAC,GAAY,EAAE,MAAc;IAC/C,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAChC,IAAI,GAAG,GAAY,GAAG,CAAC;IACvB,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,IAAI,GAAG,KAAK,IAAI,IAAI,OAAO,GAAG,KAAK,QAAQ;YAAE,OAAO,SAAS,CAAC;QAC9D,GAAG,GAAI,GAA+B,CAAC,CAAC,CAAC,CAAC;IAC5C,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface PromptContext {
|
|
2
|
+
wf: {
|
|
3
|
+
instanceId: string;
|
|
4
|
+
workingDir: string;
|
|
5
|
+
};
|
|
6
|
+
node: {
|
|
7
|
+
execId: string;
|
|
8
|
+
id: string;
|
|
9
|
+
};
|
|
10
|
+
state: unknown;
|
|
11
|
+
loop?: {
|
|
12
|
+
item: unknown;
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
export declare function compilePrompt(promptFile: string, ctx: PromptContext): string;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
export function compilePrompt(promptFile, ctx) {
|
|
3
|
+
let body = fs.readFileSync(promptFile, "utf8");
|
|
4
|
+
body = substitute(body, "{{wf.instanceId}}", ctx.wf.instanceId);
|
|
5
|
+
body = substitute(body, "{{wf.workingDir}}", ctx.wf.workingDir);
|
|
6
|
+
body = substitute(body, "{{node.execId}}", ctx.node.execId);
|
|
7
|
+
body = substitute(body, "{{node.id}}", ctx.node.id);
|
|
8
|
+
body = substitute(body, "{{state}}", JSON.stringify(ctx.state, null, 2));
|
|
9
|
+
if (ctx.loop) {
|
|
10
|
+
body = substitute(body, "{{loop.item}}", JSON.stringify(ctx.loop.item, null, 2));
|
|
11
|
+
// Also support {{loop.item.<key>}} for shallow object access
|
|
12
|
+
if (typeof ctx.loop.item === "object" && ctx.loop.item !== null) {
|
|
13
|
+
for (const [k, v] of Object.entries(ctx.loop.item)) {
|
|
14
|
+
body = substitute(body, `{{loop.item.${k}}}`, String(v));
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return body;
|
|
19
|
+
}
|
|
20
|
+
function substitute(s, token, value) {
|
|
21
|
+
return s.split(token).join(value);
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=prompt-compiler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompt-compiler.js","sourceRoot":"","sources":["../../../../src/extensions/forgecli/wf-engine/prompt-compiler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAS9B,MAAM,UAAU,aAAa,CAAC,UAAkB,EAAE,GAAkB;IAClE,IAAI,IAAI,GAAG,EAAE,CAAC,YAAY,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;IAC/C,IAAI,GAAG,UAAU,CAAC,IAAI,EAAE,mBAAmB,EAAI,GAAG,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC;IAClE,IAAI,GAAG,UAAU,CAAC,IAAI,EAAE,mBAAmB,EAAI,GAAG,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC;IAClE,IAAI,GAAG,UAAU,CAAC,IAAI,EAAE,iBAAiB,EAAM,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAChE,IAAI,GAAG,UAAU,CAAC,IAAI,EAAE,aAAa,EAAU,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC5D,IAAI,GAAG,UAAU,CAAC,IAAI,EAAE,WAAW,EAAY,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IACnF,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC;QACb,IAAI,GAAG,UAAU,CAAC,IAAI,EAAE,eAAe,EAAM,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QACrF,6DAA6D;QAC7D,IAAI,OAAO,GAAG,CAAC,IAAI,CAAC,IAAI,KAAK,QAAQ,IAAI,GAAG,CAAC,IAAI,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;YAChE,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;gBACnD,IAAI,GAAG,UAAU,CAAC,IAAI,EAAE,eAAe,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;YAC3D,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,UAAU,CAAC,CAAS,EAAE,KAAa,EAAE,KAAa;IACzD,OAAO,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AACpC,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ExtensionAPI } from "@entelligentsia/pi-coding-agent";
|
|
2
|
+
export interface RegisterRunWorkflowOptions {
|
|
3
|
+
cwd?: string;
|
|
4
|
+
/** Explicit single search dir. If set, overrides the CWD-first/bundled-fallback resolution. */
|
|
5
|
+
workflowsDir?: string;
|
|
6
|
+
/** Bundled workflows shipped with the package — used as fallback when CWD/workflows/<id> doesn't exist. */
|
|
7
|
+
bundledWorkflowsDir?: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function registerRunWorkflow(pi: ExtensionAPI, options?: RegisterRunWorkflowOptions): void;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import { runWorkflow } from "./engine.js";
|
|
4
|
+
import { getSessionRegistry } from "../session-registry.js";
|
|
5
|
+
export function registerRunWorkflow(pi, options = {}) {
|
|
6
|
+
pi.registerCommand("forge:run-workflow", {
|
|
7
|
+
description: "Run a generic workflow defined in workflows/<workflowId>/workflow.yaml. " +
|
|
8
|
+
"Resolution: CWD/workflows/<id> first, then bundled examples. " +
|
|
9
|
+
"Usage: /forge:run-workflow <workflowId> [entryPrompt...]",
|
|
10
|
+
async handler(args, ctx) {
|
|
11
|
+
const cwd = options.cwd ?? process.cwd();
|
|
12
|
+
const trimmed = args.trim();
|
|
13
|
+
if (!trimmed) {
|
|
14
|
+
ctx.ui.notify("× /forge:run-workflow — workflowId required. Usage: /forge:run-workflow <workflowId> [prompt]", "error");
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
const [workflowId, ...rest] = trimmed.split(/\s+/);
|
|
18
|
+
const entryPrompt = rest.join(" ");
|
|
19
|
+
// Resolve workflowsDir: explicit override > CWD/workflows (if it has the id) > bundled fallback
|
|
20
|
+
let workflowsDir;
|
|
21
|
+
if (options.workflowsDir) {
|
|
22
|
+
workflowsDir = options.workflowsDir;
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
const cwdCandidate = path.join(cwd, "workflows");
|
|
26
|
+
if (fs.existsSync(path.join(cwdCandidate, workflowId, "workflow.yaml"))) {
|
|
27
|
+
workflowsDir = cwdCandidate;
|
|
28
|
+
}
|
|
29
|
+
else if (options.bundledWorkflowsDir) {
|
|
30
|
+
workflowsDir = options.bundledWorkflowsDir;
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
workflowsDir = cwdCandidate; // last resort — will surface a clear not-found error
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
try {
|
|
37
|
+
const result = await runWorkflow({
|
|
38
|
+
workflowsDir,
|
|
39
|
+
workflowId,
|
|
40
|
+
cwd,
|
|
41
|
+
entryPrompt,
|
|
42
|
+
notify: (line) => ctx.ui.notify(line, "info"),
|
|
43
|
+
registry: getSessionRegistry(),
|
|
44
|
+
});
|
|
45
|
+
if (result.status === "completed") {
|
|
46
|
+
ctx.ui.notify(`✓ workflow complete: ${result.workingDir}`, "info");
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
ctx.ui.notify(`× workflow halted (${result.haltReason}): ${result.workingDir}`, "error");
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
const e = err;
|
|
54
|
+
ctx.ui.notify(`× /forge:run-workflow threw: ${e.message ?? "unknown"}`, "error");
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=register.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register.js","sourceRoot":"","sources":["../../../../src/extensions/forgecli/wf-engine/register.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAU5D,MAAM,UAAU,mBAAmB,CAAC,EAAgB,EAAE,UAAsC,EAAE;IAC5F,EAAE,CAAC,eAAe,CAAC,oBAAoB,EAAE;QACvC,WAAW,EACT,0EAA0E;YAC1E,+DAA+D;YAC/D,0DAA0D;QAC5D,KAAK,CAAC,OAAO,CAAC,IAAY,EAAE,GAA4B;YACtD,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;YAEzC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;YAC5B,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,+FAA+F,EAAE,OAAO,CAAC,CAAC;gBACxH,OAAO;YACT,CAAC;YACD,MAAM,CAAC,UAAU,EAAE,GAAG,IAAI,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YACnD,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAEnC,gGAAgG;YAChG,IAAI,YAAgC,CAAC;YACrC,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;gBACzB,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC;YACtC,CAAC;iBAAM,CAAC;gBACN,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;gBACjD,IAAI,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,UAAU,EAAE,eAAe,CAAC,CAAC,EAAE,CAAC;oBACxE,YAAY,GAAG,YAAY,CAAC;gBAC9B,CAAC;qBAAM,IAAI,OAAO,CAAC,mBAAmB,EAAE,CAAC;oBACvC,YAAY,GAAG,OAAO,CAAC,mBAAmB,CAAC;gBAC7C,CAAC;qBAAM,CAAC;oBACN,YAAY,GAAG,YAAY,CAAC,CAAG,qDAAqD;gBACtF,CAAC;YACH,CAAC;YAED,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC;oBAC/B,YAAY;oBACZ,UAAU;oBACV,GAAG;oBACH,WAAW;oBACX,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC;oBAC7C,QAAQ,EAAE,kBAAkB,EAAE;iBAC/B,CAAC,CAAC;gBACH,IAAI,MAAM,CAAC,MAAM,KAAK,WAAW,EAAE,CAAC;oBAClC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,wBAAwB,MAAM,CAAC,UAAU,EAAE,EAAE,MAAM,CAAC,CAAC;gBACrE,CAAC;qBAAM,CAAC;oBACN,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,sBAAsB,MAAM,CAAC,UAAU,MAAM,MAAM,CAAC,UAAU,EAAE,EAAE,OAAO,CAAC,CAAC;gBAC3F,CAAC;YACH,CAAC;YAAC,OAAO,GAAY,EAAE,CAAC;gBACtB,MAAM,CAAC,GAAG,GAA2B,CAAC;gBACtC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,gCAAgC,CAAC,CAAC,OAAO,IAAI,SAAS,EAAE,EAAE,OAAO,CAAC,CAAC;YACnF,CAAC;QACH,CAAC;KACF,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
export function checkRemit(emitted, node, loopItemId) {
|
|
2
|
+
const violations = [];
|
|
3
|
+
// Must have started + exactly one terminal
|
|
4
|
+
const startedCount = emitted.filter(e => e.type === "started").length;
|
|
5
|
+
if (startedCount !== 1)
|
|
6
|
+
violations.push(`expected exactly 1 'started' event, got ${startedCount}`);
|
|
7
|
+
const terminals = emitted.filter(e => e.type === "success" || e.type === "failure");
|
|
8
|
+
if (terminals.length !== 1)
|
|
9
|
+
violations.push(`expected exactly 1 terminal event (success/failure), got ${terminals.length}`);
|
|
10
|
+
if (terminals.length === 1) {
|
|
11
|
+
const term = terminals[0];
|
|
12
|
+
if (term.type === "success" && term.writes?.artifact) {
|
|
13
|
+
const pattern = node.expects.success.writes?.artifact?.pattern;
|
|
14
|
+
if (!pattern) {
|
|
15
|
+
violations.push(`node emitted artifact but expects.success.writes.artifact not declared`);
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
const resolved = pattern.replace(/\{loop\.item\.id\}/g, loopItemId ?? "");
|
|
19
|
+
if (term.writes.artifact.path !== resolved) {
|
|
20
|
+
violations.push(`artifact path '${term.writes.artifact.path}' does not match declared pattern '${resolved}'`);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
if (term.type === "success" && term.writes?.state) {
|
|
25
|
+
const allowed = node.expects.success.writes?.state ?? [];
|
|
26
|
+
for (const key of Object.keys(term.writes.state)) {
|
|
27
|
+
const matched = allowed.some(a => {
|
|
28
|
+
const resolved = a.replace(/\{loop\.item\.id\}/g, loopItemId ?? "");
|
|
29
|
+
return resolved === key;
|
|
30
|
+
});
|
|
31
|
+
if (!matched) {
|
|
32
|
+
violations.push(`state write '${key}' not in declared expects.success.writes.state`);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
if (term.type === "failure" && (!term.reason || typeof term.reason !== "string")) {
|
|
37
|
+
violations.push(`failure event missing 'reason' string`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return { ok: violations.length === 0, violations };
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=remit-check.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remit-check.js","sourceRoot":"","sources":["../../../../src/extensions/forgecli/wf-engine/remit-check.ts"],"names":[],"mappings":"AAOA,MAAM,UAAU,UAAU,CACxB,OAAgB,EAChB,IAAa,EACb,UAAmB;IAEnB,MAAM,UAAU,GAAa,EAAE,CAAC;IAEhC,2CAA2C;IAC3C,MAAM,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,MAAM,CAAC;IACtE,IAAI,YAAY,KAAK,CAAC;QAAE,UAAU,CAAC,IAAI,CAAC,2CAA2C,YAAY,EAAE,CAAC,CAAC;IAEnG,MAAM,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,SAAS,IAAI,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC;IACpF,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;QAAE,UAAU,CAAC,IAAI,CAAC,4DAA4D,SAAS,CAAC,MAAM,EAAE,CAAC,CAAC;IAE5H,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC3B,MAAM,IAAI,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;QAC1B,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,MAAM,EAAE,QAAQ,EAAE,CAAC;YACrD,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,QAAQ,EAAE,OAAO,CAAC;YAC/D,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,UAAU,CAAC,IAAI,CAAC,wEAAwE,CAAC,CAAC;YAC5F,CAAC;iBAAM,CAAC;gBACN,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,qBAAqB,EAAE,UAAU,IAAI,EAAE,CAAC,CAAC;gBAC1E,IAAI,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;oBAC3C,UAAU,CAAC,IAAI,CAAC,kBAAkB,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,sCAAsC,QAAQ,GAAG,CAAC,CAAC;gBAChH,CAAC;YACH,CAAC;QACH,CAAC;QAED,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC;YAClD,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,KAAK,IAAI,EAAE,CAAC;YACzD,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;gBACjD,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;oBAC/B,MAAM,QAAQ,GAAG,CAAC,CAAC,OAAO,CAAC,qBAAqB,EAAE,UAAU,IAAI,EAAE,CAAC,CAAC;oBACpE,OAAO,QAAQ,KAAK,GAAG,CAAC;gBAC1B,CAAC,CAAC,CAAC;gBACH,IAAI,CAAC,OAAO,EAAE,CAAC;oBACb,UAAU,CAAC,IAAI,CAAC,gBAAgB,GAAG,gDAAgD,CAAC,CAAC;gBACvF,CAAC;YACH,CAAC;QACH,CAAC;QAED,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,IAAI,OAAO,IAAI,CAAC,MAAM,KAAK,QAAQ,CAAC,EAAE,CAAC;YACjF,UAAU,CAAC,IAAI,CAAC,uCAAuC,CAAC,CAAC;QAC3D,CAAC;IACH,CAAC;IAED,OAAO,EAAE,EAAE,EAAE,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,UAAU,EAAE,CAAC;AACrD,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Event, RuntimeState } from "./types.js";
|
|
2
|
+
export declare class StateStore {
|
|
3
|
+
private readonly workingDir;
|
|
4
|
+
constructor(workingDir: string);
|
|
5
|
+
initialState(initial: RuntimeState): void;
|
|
6
|
+
readState(): RuntimeState;
|
|
7
|
+
writeState(s: RuntimeState): void;
|
|
8
|
+
appendEvents(events: Event[]): void;
|
|
9
|
+
writeArtifact(relPath: string, content: string): void;
|
|
10
|
+
writeNodeArchive(nodeExecId: string, files: Record<string, string>): void;
|
|
11
|
+
private statePath;
|
|
12
|
+
private eventLogPath;
|
|
13
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
export class StateStore {
|
|
4
|
+
workingDir;
|
|
5
|
+
constructor(workingDir) {
|
|
6
|
+
this.workingDir = workingDir;
|
|
7
|
+
}
|
|
8
|
+
initialState(initial) {
|
|
9
|
+
fs.mkdirSync(this.workingDir, { recursive: true });
|
|
10
|
+
fs.mkdirSync(path.join(this.workingDir, "nodes"), { recursive: true });
|
|
11
|
+
fs.mkdirSync(path.join(this.workingDir, "artifacts"), { recursive: true });
|
|
12
|
+
fs.writeFileSync(this.statePath(), JSON.stringify(initial, null, 2));
|
|
13
|
+
fs.writeFileSync(this.eventLogPath(), ""); // create empty file
|
|
14
|
+
}
|
|
15
|
+
readState() {
|
|
16
|
+
return JSON.parse(fs.readFileSync(this.statePath(), "utf8"));
|
|
17
|
+
}
|
|
18
|
+
writeState(s) {
|
|
19
|
+
// Atomic write: tmp + rename
|
|
20
|
+
const tmp = `${this.statePath()}.tmp`;
|
|
21
|
+
fs.writeFileSync(tmp, JSON.stringify(s, null, 2));
|
|
22
|
+
fs.renameSync(tmp, this.statePath());
|
|
23
|
+
}
|
|
24
|
+
appendEvents(events) {
|
|
25
|
+
const lines = events.map(e => JSON.stringify(e)).join("\n") + "\n";
|
|
26
|
+
fs.appendFileSync(this.eventLogPath(), lines);
|
|
27
|
+
}
|
|
28
|
+
writeArtifact(relPath, content) {
|
|
29
|
+
const abs = path.join(this.workingDir, relPath);
|
|
30
|
+
fs.mkdirSync(path.dirname(abs), { recursive: true });
|
|
31
|
+
fs.writeFileSync(abs, content);
|
|
32
|
+
}
|
|
33
|
+
writeNodeArchive(nodeExecId, files) {
|
|
34
|
+
const dir = path.join(this.workingDir, "nodes", nodeExecId);
|
|
35
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
36
|
+
for (const [name, content] of Object.entries(files)) {
|
|
37
|
+
fs.writeFileSync(path.join(dir, name), content);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
statePath() { return path.join(this.workingDir, "state.json"); }
|
|
41
|
+
eventLogPath() { return path.join(this.workingDir, "events.log.jsonl"); }
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=state-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state-store.js","sourceRoot":"","sources":["../../../../src/extensions/forgecli/wf-engine/state-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
export interface WorkflowDef {
|
|
2
|
+
id: string;
|
|
3
|
+
version: number;
|
|
4
|
+
description?: string;
|
|
5
|
+
nodes: NodeDef[];
|
|
6
|
+
edges: EdgeDef[];
|
|
7
|
+
}
|
|
8
|
+
export interface NodeDef {
|
|
9
|
+
id: string;
|
|
10
|
+
prompt: string;
|
|
11
|
+
loop?: LoopSpec;
|
|
12
|
+
expects: ExpectsSpec;
|
|
13
|
+
}
|
|
14
|
+
export interface LoopSpec {
|
|
15
|
+
over: string;
|
|
16
|
+
alias: string;
|
|
17
|
+
alsoEmitsItemId?: boolean;
|
|
18
|
+
group?: string;
|
|
19
|
+
head?: boolean;
|
|
20
|
+
}
|
|
21
|
+
export interface ExpectsSpec {
|
|
22
|
+
success: {
|
|
23
|
+
writes?: {
|
|
24
|
+
state?: string[];
|
|
25
|
+
artifact?: {
|
|
26
|
+
pattern: string;
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
failure: {};
|
|
31
|
+
}
|
|
32
|
+
export interface EdgeDef {
|
|
33
|
+
from: string;
|
|
34
|
+
on: "success" | "failure" | "exhausted";
|
|
35
|
+
to?: string;
|
|
36
|
+
halt?: string;
|
|
37
|
+
terminal?: "complete";
|
|
38
|
+
advance?: "loop-or-next";
|
|
39
|
+
next?: string;
|
|
40
|
+
when?: string;
|
|
41
|
+
}
|
|
42
|
+
export interface RuntimeState {
|
|
43
|
+
cursor: string;
|
|
44
|
+
loopCursor: Record<string, number>;
|
|
45
|
+
entryPrompt?: string;
|
|
46
|
+
[key: string]: unknown;
|
|
47
|
+
}
|
|
48
|
+
export interface Event {
|
|
49
|
+
eventId: string;
|
|
50
|
+
nodeExecId: string;
|
|
51
|
+
type: "started" | "progress" | "success" | "failure" | "workflow.started" | "workflow.completed" | "workflow.halted" | "node.dispatched" | "node.committed" | "node.remit-violation";
|
|
52
|
+
ts: string;
|
|
53
|
+
writes?: {
|
|
54
|
+
state?: Record<string, unknown>;
|
|
55
|
+
artifact?: {
|
|
56
|
+
path: string;
|
|
57
|
+
content: string;
|
|
58
|
+
};
|
|
59
|
+
};
|
|
60
|
+
summary?: string;
|
|
61
|
+
reason?: string;
|
|
62
|
+
details?: string;
|
|
63
|
+
workflowId?: string;
|
|
64
|
+
instanceId?: string;
|
|
65
|
+
violatedRule?: string;
|
|
66
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/extensions/forgecli/wf-engine/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type AgentSessionEvent } from "@entelligentsia/pi-coding-agent";
|
|
2
|
+
export interface WorkerResult {
|
|
3
|
+
responseText: string;
|
|
4
|
+
exitCode: 0 | 1;
|
|
5
|
+
errorMessage?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function dispatchLlmWorker(opts: {
|
|
8
|
+
compiledPrompt: string;
|
|
9
|
+
cwd: string;
|
|
10
|
+
onEvent?: (event: AgentSessionEvent) => void;
|
|
11
|
+
}): Promise<WorkerResult>;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { AuthStorage, createAgentSession, DefaultResourceLoader, getAgentDir, ModelRegistry, SessionManager, } from "@entelligentsia/pi-coding-agent";
|
|
2
|
+
export async function dispatchLlmWorker(opts) {
|
|
3
|
+
const loader = new DefaultResourceLoader({
|
|
4
|
+
cwd: opts.cwd,
|
|
5
|
+
agentDir: getAgentDir(),
|
|
6
|
+
systemPromptOverride: () => "You are a workflow node worker. Read the user message carefully. "
|
|
7
|
+
+ "At the end of your reply, emit a ```json events block per the protocol. "
|
|
8
|
+
+ "Outside that block, you may write reasoning prose if helpful — but the engine ignores it.",
|
|
9
|
+
noExtensions: true,
|
|
10
|
+
noSkills: true,
|
|
11
|
+
noPromptTemplates: true,
|
|
12
|
+
noContextFiles: true,
|
|
13
|
+
});
|
|
14
|
+
await loader.reload();
|
|
15
|
+
const authStorage = AuthStorage.create();
|
|
16
|
+
const modelRegistry = ModelRegistry.create(authStorage);
|
|
17
|
+
const { session } = await createAgentSession({
|
|
18
|
+
sessionManager: SessionManager.inMemory(),
|
|
19
|
+
authStorage,
|
|
20
|
+
modelRegistry,
|
|
21
|
+
resourceLoader: loader,
|
|
22
|
+
});
|
|
23
|
+
let responseText = "";
|
|
24
|
+
const unsub = session.subscribe((event) => {
|
|
25
|
+
if (opts.onEvent)
|
|
26
|
+
opts.onEvent(event);
|
|
27
|
+
if (event.type === "turn_end" && event.message) {
|
|
28
|
+
const msg = event.message;
|
|
29
|
+
if (msg.role === "assistant") {
|
|
30
|
+
for (const part of msg.content) {
|
|
31
|
+
if (part.type === "text")
|
|
32
|
+
responseText += part.text;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
try {
|
|
38
|
+
await session.prompt(opts.compiledPrompt);
|
|
39
|
+
unsub();
|
|
40
|
+
session.dispose();
|
|
41
|
+
return { responseText, exitCode: 0 };
|
|
42
|
+
}
|
|
43
|
+
catch (err) {
|
|
44
|
+
unsub();
|
|
45
|
+
session.dispose();
|
|
46
|
+
const e = err;
|
|
47
|
+
return { responseText, exitCode: 1, errorMessage: e.message ?? "worker threw" };
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=worker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker.js","sourceRoot":"","sources":["../../../../src/extensions/forgecli/wf-engine/worker.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EACX,kBAAkB,EAClB,qBAAqB,EACrB,WAAW,EACX,aAAa,EACb,cAAc,GAEf,MAAM,iCAAiC,CAAC;AASzC,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,IAIvC;IACC,MAAM,MAAM,GAAG,IAAI,qBAAqB,CAAC;QACvC,GAAG,EAAE,IAAI,CAAC,GAAG;QACb,QAAQ,EAAE,WAAW,EAAE;QACvB,oBAAoB,EAAE,GAAG,EAAE,CACzB,mEAAmE;cACjE,0EAA0E;cAC1E,2FAA2F;QAC/F,YAAY,EAAE,IAAI;QAClB,QAAQ,EAAE,IAAI;QACd,iBAAiB,EAAE,IAAI;QACvB,cAAc,EAAE,IAAI;KACrB,CAAC,CAAC;IACH,MAAM,MAAM,CAAC,MAAM,EAAE,CAAC;IAEtB,MAAM,WAAW,GAAK,WAAW,CAAC,MAAM,EAAE,CAAC;IAC3C,MAAM,aAAa,GAAG,aAAa,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;IAExD,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,kBAAkB,CAAC;QAC3C,cAAc,EAAE,cAAc,CAAC,QAAQ,EAAE;QACzC,WAAW;QACX,aAAa;QACb,cAAc,EAAE,MAAM;KACvB,CAAC,CAAC;IAEH,IAAI,YAAY,GAAG,EAAE,CAAC;IAEtB,MAAM,KAAK,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC,KAAwB,EAAE,EAAE;QAC3D,IAAI,IAAI,CAAC,OAAO;YAAE,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QACtC,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;YAC/C,MAAM,GAAG,GAAG,KAAK,CAAC,OAAkB,CAAC;YACrC,IAAI,GAAG,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;gBAC7B,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,OAAO,EAAE,CAAC;oBAC/B,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM;wBAAE,YAAY,IAAI,IAAI,CAAC,IAAI,CAAC;gBACtD,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC;QACH,MAAM,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAC1C,KAAK,EAAE,CAAC;QACR,OAAO,CAAC,OAAO,EAAE,CAAC;QAClB,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;IACvC,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,KAAK,EAAE,CAAC;QACR,OAAO,CAAC,OAAO,EAAE,CAAC;QAClB,MAAM,CAAC,GAAG,GAA2B,CAAC;QACtC,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,CAAC,EAAE,YAAY,EAAE,CAAC,CAAC,OAAO,IAAI,cAAc,EAAE,CAAC;IAClF,CAAC;AACH,CAAC"}
|