@gobing-ai/spur 0.3.98 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/config/config.global.yaml +17 -0
- package/config/decisions/task-pipeline.yaml +55 -0
- package/config/plugin-scripts.json +15 -0
- package/config/rules/boundary/sp-runtime-path.yaml +2 -0
- package/config/rules/quality/coverage-gate.yaml +5 -3
- package/config/rules/strict/runtime-boundaries.yaml +11 -0
- package/config/rules/structure/protected-files.yaml +3 -0
- package/config/templates/task/brainstorm.md +1 -1
- package/config/templates/task/feature-impl.md +1 -1
- package/config/templates/task/issue.md +1 -1
- package/config/templates/task/meta.md +1 -1
- package/config/templates/task/review.md +1 -1
- package/config/templates/task/standard.md +1 -1
- package/config/workflows/task-pipeline.yaml +178 -18
- package/package.json +9 -9
- package/plugins/sp/README.md +14 -1
- package/plugins/sp/agents/super-reviewer.md +25 -11
- package/plugins/sp/commands/dev-changelog.md +5 -4
- package/plugins/sp/commands/dev-review-session.md +12 -7
- package/plugins/sp/commands/dev-run.md +5 -2
- package/plugins/sp/commands/dev-runall.md +5 -2
- package/plugins/sp/hooks/agent-lifecycle.ts +155 -0
- package/plugins/sp/hooks/fleet-guest-stop.ts +180 -0
- package/plugins/sp/hooks/hooks.json +45 -1
- package/plugins/sp/hooks/pi/guard-extension.ts +21 -0
- package/plugins/sp/lib/history-anatomy.generated.mjs +5 -0
- package/plugins/sp/lib/idea-handoff.generated.mjs +68 -10
- package/plugins/sp/lib/inline-run.generated.d.mts +1 -0
- package/plugins/sp/lib/inline-run.generated.mjs +83 -20
- package/plugins/sp/lib/residual-scan.generated.d.mts +5 -0
- package/plugins/sp/lib/residual-scan.generated.mjs +45 -5
- package/plugins/sp/lib/transcript.ts +160 -0
- package/plugins/sp/plugin.json +1 -1
- package/plugins/sp/scripts/history-anatomy-cache.mjs +5 -0
- package/plugins/sp/scripts/inline-run-setup.mjs +21 -20
- package/plugins/sp/scripts/inline-run-setup.ts +25 -31
- package/plugins/sp/scripts/persist-out-check.mjs +164 -0
- package/plugins/sp/scripts/persist-out-check.ts +185 -0
- package/plugins/sp/scripts/residual-scan.mjs +52 -15
- package/plugins/sp/scripts/residual-scan.ts +11 -11
- package/plugins/sp/scripts/run-summary.mjs +286 -0
- package/plugins/sp/scripts/run-summary.ts +241 -0
- package/plugins/sp/scripts/session-timeline.mjs +234 -0
- package/plugins/sp/scripts/session-timeline.ts +152 -0
- package/plugins/sp/scripts/task-diffstat.mjs +17 -5
- package/plugins/sp/scripts/task-diffstat.ts +25 -4
- package/plugins/sp/skills/code-verification/SKILL.md +8 -0
- package/plugins/sp/skills/code-verification/references/verdict-schema.md +17 -1
- package/plugins/sp/skills/fleet-join/SKILL.md +63 -0
- package/plugins/sp/skills/session-review/SKILL.md +46 -24
- package/plugins/sp/skills/spur-cli/SKILL.md +1 -0
- package/plugins/sp/skills/spur-cli/references/agent.md +108 -6
- package/plugins/sp/skills/spur-cli/references/decision.md +97 -0
- package/plugins/sp/skills/spur-cli/references/tasks/verbs.md +22 -0
- package/plugins/sp/skills/spur-composer/SKILL.md +27 -1
- package/plugins/sp/skills/spur-dev/references/ac-style-guide.md +40 -7
- package/plugins/sp/skills/spur-dev/references/dev-operations.md +28 -16
- package/plugins/sp/skills/spur-dev/references/execution-batch.md +278 -42
- package/plugins/sp/skills/spur-dev/references/execution-workflow.md +17 -1
- package/plugins/sp/skills/spur-dev/references/flag-glossary.md +16 -4
- package/plugins/sp/skills/spur-dev/references/inline-pipeline-driver.md +139 -10
- package/plugins/sp/skills/spur-dev/references/planning-workflow.md +6 -0
- package/schemas/decision-catalog.schema.json +226 -0
- package/schemas/spur-config.schema.json +25 -0
- package/spur.js +8856 -2564
- package/web/_astro/BoardApp.Bzr4OXrW.js +324 -0
- package/web/_astro/{BoardApp.Dflq5a8x.js → BoardApp.VeoxxLBy.js} +1 -1
- package/web/_astro/{TaskDetail.CK7oXddP.js → TaskDetail.LAyR_Pvn.js} +1 -1
- package/web/_astro/{arc.BIqkDATc.js → arc.f4e0OYLg.js} +1 -1
- package/web/_astro/{architectureDiagram-3BPJPVTR.D0B3SvWv.js → architectureDiagram-3BPJPVTR.SSIvxi-Z.js} +1 -1
- package/web/_astro/{blockDiagram-GPEHLZMM.C2YyKQmL.js → blockDiagram-GPEHLZMM.DSXIHOFf.js} +1 -1
- package/web/_astro/{c4Diagram-AAUBKEIU.DmtTYrt_.js → c4Diagram-AAUBKEIU.DG9Ubu85.js} +1 -1
- package/web/_astro/channel.CUFdtWhm.js +1 -0
- package/web/_astro/{chunk-2J33WTMH.HsRXbh7l.js → chunk-2J33WTMH.C7QU88Qh.js} +1 -1
- package/web/_astro/{chunk-4BX2VUAB.obE_P-R3.js → chunk-4BX2VUAB.26Z94xBj.js} +1 -1
- package/web/_astro/{chunk-55IACEB6.CjWTF5mz.js → chunk-55IACEB6.DYRiBkqw.js} +1 -1
- package/web/_astro/{chunk-727SXJPM.DMo799Ax.js → chunk-727SXJPM.D5Vfv5pe.js} +1 -1
- package/web/_astro/{chunk-AQP2D5EJ.-cE6JOKZ.js → chunk-AQP2D5EJ.DXHV47bN.js} +1 -1
- package/web/_astro/{chunk-FMBD7UC4.D6Rw6HIk.js → chunk-FMBD7UC4.D1suAfOs.js} +1 -1
- package/web/_astro/{chunk-ND2GUHAM.d5rBD73Z.js → chunk-ND2GUHAM.D6BmdHEY.js} +1 -1
- package/web/_astro/{chunk-QZHKN3VN.r3ox40Q3.js → chunk-QZHKN3VN.rnPU-Ak-.js} +1 -1
- package/web/_astro/{classDiagram-4FO5ZUOK.CGGbvjjJ.js → classDiagram-4FO5ZUOK.CvEfXIo1.js} +1 -1
- package/web/_astro/{classDiagram-v2-Q7XG4LA2.CGGbvjjJ.js → classDiagram-v2-Q7XG4LA2.CvEfXIo1.js} +1 -1
- package/web/_astro/{cose-bilkent-S5V4N54A.CmKtPd4l.js → cose-bilkent-S5V4N54A.DkMisLSm.js} +1 -1
- package/web/_astro/{cynefin-OW5HDTMX.QNg5GXs8.js → cynefin-OW5HDTMX.C77Q-pF6.js} +1 -1
- package/web/_astro/{dagre-BM42HDAG.B1SabsjC.js → dagre-BM42HDAG.YaV8ce27.js} +1 -1
- package/web/_astro/{diagram-2AECGRRQ.RtDbNj89.js → diagram-2AECGRRQ.CUyGEKge.js} +1 -1
- package/web/_astro/{diagram-5GNKFQAL.IzZpuM-Y.js → diagram-5GNKFQAL.CRgd8dgj.js} +1 -1
- package/web/_astro/{diagram-KO2AKTUF.DPTF_fgv.js → diagram-KO2AKTUF.Bmzys9hq.js} +1 -1
- package/web/_astro/{diagram-LMA3HP47.CCyza39P.js → diagram-LMA3HP47.BvmJY4Lw.js} +1 -1
- package/web/_astro/{diagram-OG6HWLK6.BXAi8zcZ.js → diagram-OG6HWLK6.0hEhD30d.js} +1 -1
- package/web/_astro/{erDiagram-TEJ5UH35.DUDX7_MR.js → erDiagram-TEJ5UH35.Bjt8lrnm.js} +1 -1
- package/web/_astro/{flowDiagram-I6XJVG4X.C63QTh3N.js → flowDiagram-I6XJVG4X.CJZTjRDV.js} +1 -1
- package/web/_astro/{ganttDiagram-6RSMTGT7.CnlZJSwG.js → ganttDiagram-6RSMTGT7._VqoVafc.js} +1 -1
- package/web/_astro/{gitGraphDiagram-PVQCEYII.CTqIrOPC.js → gitGraphDiagram-PVQCEYII.CEDb7tVo.js} +1 -1
- package/web/_astro/index.Dg_3bOaJ.css +1 -0
- package/web/_astro/{infoDiagram-5YYISTIA.BYMiDFh9.js → infoDiagram-5YYISTIA.CgwifPpK.js} +1 -1
- package/web/_astro/{ishikawaDiagram-YF4QCWOH.CRiQmI-z.js → ishikawaDiagram-YF4QCWOH.B99wx2J1.js} +1 -1
- package/web/_astro/{journeyDiagram-JHISSGLW.YQgWBsEU.js → journeyDiagram-JHISSGLW.2hRwJbEo.js} +1 -1
- package/web/_astro/{kanban-definition-UN3LZRKU.1ECnrrK1.js → kanban-definition-UN3LZRKU.BahJkKNC.js} +1 -1
- package/web/_astro/{linear.DzVA71yT.js → linear.DguUUe6V.js} +1 -1
- package/web/_astro/{mermaid.core.BK7P2Sr_.js → mermaid.core.CvgfmqVr.js} +4 -4
- package/web/_astro/{mindmap-definition-RKZ34NQL.BvXyWZK7.js → mindmap-definition-RKZ34NQL.B3qEA3x9.js} +1 -1
- package/web/_astro/{pieDiagram-4H26LBE5.BiXk1TW3.js → pieDiagram-4H26LBE5.FlWA-_ru.js} +1 -1
- package/web/_astro/{quadrantDiagram-W4KKPZXB.krvBH8lh.js → quadrantDiagram-W4KKPZXB.9bVn35X7.js} +1 -1
- package/web/_astro/{requirementDiagram-4Y6WPE33.ih1gL25c.js → requirementDiagram-4Y6WPE33.ChykIhct.js} +1 -1
- package/web/_astro/{sankeyDiagram-5OEKKPKP.CpUxkv4u.js → sankeyDiagram-5OEKKPKP.Z2Y3hkYb.js} +1 -1
- package/web/_astro/{sequenceDiagram-3UESZ5HK.clAfeN7y.js → sequenceDiagram-3UESZ5HK.J7JsHWDt.js} +1 -1
- package/web/_astro/{stateDiagram-AJRCARHV.DpXWb8-m.js → stateDiagram-AJRCARHV.DAPbiCSS.js} +1 -1
- package/web/_astro/{stateDiagram-v2-BHNVJYJU.ClZb9GIH.js → stateDiagram-v2-BHNVJYJU.D2jvSi0q.js} +1 -1
- package/web/_astro/{timeline-definition-PNZ67QCA.BLcX5dh7.js → timeline-definition-PNZ67QCA.psW2ci29.js} +1 -1
- package/web/_astro/{vennDiagram-CIIHVFJN.oGgpKMpx.js → vennDiagram-CIIHVFJN.DlILYVmg.js} +1 -1
- package/web/_astro/{wardleyDiagram-YWT4CUSO.BPHtMtt-.js → wardleyDiagram-YWT4CUSO.xNWwLJnn.js} +1 -1
- package/web/_astro/{xychartDiagram-2RQKCTM6.BNZOPYSk.js → xychartDiagram-2RQKCTM6.EU_BuH7V.js} +1 -1
- package/web/board-runtime.json +1 -1
- package/web/index.html +2 -2
- package/web/_astro/BoardApp.CYbe-OTb.js +0 -322
- package/web/_astro/channel.JuKVyuhZ.js +0 -1
- package/web/_astro/index.CbNz17Sx.css +0 -1
|
@@ -407,7 +407,7 @@ END`;var MEASURE_COLS="messages, tool_calls, skill_calls, fresh_input_tokens, ca
|
|
|
407
407
|
''
|
|
408
408
|
)
|
|
409
409
|
ELSE ''
|
|
410
|
-
END`;var POST_WATERMARK_TABLES=[...KEYED_ROLLUP_TABLES,...GLOBAL_RANKED_ROLLUP_TABLES,"history_daily_stats","history_board_source_daily"];var HISTORY_IMPORT_SCHEMA_VERSION="0.5.
|
|
410
|
+
END`;var POST_WATERMARK_TABLES=[...KEYED_ROLLUP_TABLES,...GLOBAL_RANKED_ROLLUP_TABLES,"history_daily_stats","history_board_source_daily"];var HISTORY_IMPORT_SCHEMA_VERSION="0.5.16",HISTORY_IMPORT_SCHEMA_SQL=`
|
|
411
411
|
CREATE TABLE IF NOT EXISTS history_import_checkpoint (
|
|
412
412
|
source TEXT NOT NULL,
|
|
413
413
|
source_file TEXT NOT NULL,
|
|
@@ -514,7 +514,14 @@ CREATE TABLE IF NOT EXISTS history_skill_call (
|
|
|
514
514
|
started_at TEXT,
|
|
515
515
|
completed_at TEXT,
|
|
516
516
|
duration_ms REAL,
|
|
517
|
-
imported_at TEXT NOT NULL
|
|
517
|
+
imported_at TEXT NOT NULL,
|
|
518
|
+
-- Capability facts (E93 task 1028). Nullable on every row: legacy rows and rows
|
|
519
|
+
-- whose classification could not be established store NULL. Column order after
|
|
520
|
+
-- imported_at converges with the guarded standalone upgrade in the DAO.
|
|
521
|
+
capability_kind TEXT,
|
|
522
|
+
evidence_kind TEXT,
|
|
523
|
+
invocation_id TEXT,
|
|
524
|
+
origin_identity TEXT
|
|
518
525
|
);
|
|
519
526
|
CREATE INDEX IF NOT EXISTS idx_history_skill_call_session
|
|
520
527
|
ON history_skill_call(source, session_id, seq);
|
|
@@ -524,7 +531,13 @@ CREATE INDEX IF NOT EXISTS idx_history_skill_call_message_hash
|
|
|
524
531
|
ON history_skill_call(message_hash);
|
|
525
532
|
CREATE INDEX IF NOT EXISTS idx_history_skill_call_invocation_kind
|
|
526
533
|
ON history_skill_call(invocation_kind);
|
|
527
|
-
`.trim();init_zod();init_zod();import{createHash}from"node:crypto";function stableJson(value){if(Array.isArray(value))return`[${value.map((entry)=>entry===void 0?"null":stableJson(entry)).join(",")}]`;if(value!==null&&typeof value==="object"){let record2=value;return`{${Object.keys(record2).filter((key)=>record2[key]!==void 0).sort().map((key)=>`${JSON.stringify(key)}:${stableJson(record2[key])}`).join(",")}}`}return JSON.stringify(value)??"null"}function sha256(value){return createHash("sha256").update(stableJson(value)).digest("hex")}var MESSAGE_MAPPER_KEYS=["_codexUsageCarrier","session_id","seq","turn_index","role","record_type","disposition","ts","duration_ms","model","input_tokens","output_tokens","cache_read_tokens","cache_write_tokens","cost_usd","content_text","cwd","provenance","run_id","task_wbs","request_id"],TOOL_CALL_MAPPER_KEYS=["_messageSplitIndex","session_id","seq","tool_name","call_id","args_digest","args_raw","status","started_at","completed_at","duration_ms","result_bytes","error_text"],SKILL_CALL_MAPPER_KEYS=["_messageSplitIndex","session_id","seq","skill_name","invocation_kind","skill_path","args_raw","args_digest","call_id","status","started_at","completed_at","duration_ms"];function identityFieldMap(keys){let map2={};for(let key of keys)map2[key]=key;return map2}var HARNESS_SKILL_PACKAGES=new Set(["sp","rd3"]);function canonicalizeSkillName(raw){let name=raw.trim();if(name.startsWith("/")||name.startsWith("$"))name=name.slice(1);if(name.startsWith("skill:"))name=name.slice(6);let canonical=name.match(/^([a-z][a-z0-9]*):([a-z0-9-]+)$/);if(canonical!==null&&HARNESS_SKILL_PACKAGES.has(canonical[1]??""))return name;let dialect=name.match(/^([a-z][a-z0-9]*)-([a-z0-9-]+)$/);if(dialect!==null&&HARNESS_SKILL_PACKAGES.has(dialect[1]??""))return`${dialect[1]}:${dialect[2]}`;return name}function extractSkillCalls(raw,context,identity){switch(context?.source){case"claude":return detectClaudeSkillCalls(raw,identity);case"pi":return detectPiSkillCalls(raw,identity);case"omp":return detectOmpSkillCalls(raw,identity);case"codex":return detectCodexSkillCalls(raw,identity);case"agy":return detectAgySkillCalls(raw,identity);case"gemini":return detectGeminiSkillCalls(raw,identity);case"grok":return detectGrokSkillCalls(raw,identity);default:return[]}}function skillCallEntry(record2){return{targetTable:"history_skill_call",record:record2}}function skillRecord(identity,skillName,invocationKind,extra={}){return{_messageSplitIndex:identity.messageSplitIndex,session_id:identity.sessionId,seq:identity.seq,skill_name:canonicalizeSkillName(skillName),invocation_kind:invocationKind,skill_path:null,args_raw:null,args_digest:null,call_id:null,status:"ok",started_at:null,completed_at:null,duration_ms:null,...extra}}function skillNameFromPath(path){let normalized=path.replace(/\\/g,"/"),bySkillsSegment=normalized.match(/\/skills\/([^/]+)\/SKILL\.md$/i);if(bySkillsSegment!==null)return bySkillsSegment[1]??"";let stem=normalized.slice(0,normalized.length-9);return stem.split("/").pop()??stem}function detectClaudeSkillCalls(raw,identity){let contentBlocks=raw.content??o(raw.message).content;if(!Array.isArray(contentBlocks))return[];let rows=[];for(let block of contentBlocks){if(typeof block!=="object"||block===null)continue;let b=block;if(b.type!=="tool_use"||b.name!=="Skill")continue;let input=b.input??{},skill=s(input.skill);if(skill===void 0)continue;rows.push(skillRecord(identity,skill,s(o(b.caller).type)==="direct"?"user":"model",{args_raw:maybeArgsRaw("claude","Skill",input)??null,args_digest:argsDigest(input),call_id:s(b.id)??null}))}return rows}var PI_SKILL_WRAPPER=/<skill\s+name="([^"]+)"(?:\s+location="([^"]*)")?\s*>/g;function detectPiSkillCalls(raw,identity){let msg=raw.message;if(piRole(msg?.role??raw.role??raw.recordType??raw.type)!=="user")return[];let text=extractContentText(msg?.content??raw.content);if(text===void 0)return[];let rows=[];for(let match of text.matchAll(PI_SKILL_WRAPPER))rows.push(skillRecord(identity,match[1]??"","user",{skill_path:match[2]||null}));return rows}function detectOmpSkillCalls(raw,identity){let msg=raw.message;if(mapRole(msg?.role??raw.type??raw.role)!=="assistant")return[];let contentBlocks=msg?.content??raw.content;if(!Array.isArray(contentBlocks))return[];let rows=[];for(let block of contentBlocks){let call=normalizeOmpToolCall(block);if(call===null||call.name!=="Skill")continue;let input=call.input??call.arguments,skill=s(input?.skill);if(skill===void 0)continue;rows.push(skillRecord(identity,skill,"model",{args_raw:maybeArgsRaw("omp","Skill",input)??null,args_digest:argsDigest(input),call_id:s(call.id)??null}))}return rows}var CODEX_SKILL_BLOCK=/<skill>\s*<name>([^<]+)<\/name>\s*<path>([^<]+)<\/path>\s*<\/skill>/g;function detectCodexSkillCalls(raw,identity){let payload=raw.payload??raw,recordType=String(raw.type??""),payloadType=String(payload.type??""),role;if(recordType==="response_item")role=payloadType==="message"?mapRole(payload.role):payloadType==="agent_message"?"assistant":"meta";else if(recordType==="user"||recordType==="assistant")role=mapRole(recordType);else if(recordType==="message")role=mapRole(raw.role??payload.role);else return[];if(role!=="user")return[];let text=extractContentText(payload.content??raw.content)??s(payload.text,raw.text);if(text===void 0)return[];let rows=[];for(let match of text.matchAll(CODEX_SKILL_BLOCK))rows.push(skillRecord(identity,match[1]??"","user",{skill_path:match[2]??null}));return rows}function detectAgySkillCalls(raw,identity){if(String(raw.type??"")!=="PLANNER_RESPONSE"||!Array.isArray(raw.tool_calls))return[];let rows=[];for(let tc of raw.tool_calls){if(s(tc.name,tc.tool_name)!=="view_file")continue;let args=tc.args??tc.arguments??{};if(args.toolAction!=="Viewing skill file")continue;let path=s(args.AbsolutePath,args.absolute_path);if(path===void 0||!path.replace(/\\/g,"/").endsWith("/SKILL.md"))continue;let skillName=s(args.toolSummary)?.match(/SKILL\.md for (.+)$/)?.[1]??skillNameFromPath(path);rows.push(skillRecord(identity,skillName,"model",{skill_path:path,args_raw:maybeArgsRaw("agy","view_file",args)??null,args_digest:argsDigest(args)}))}return rows}var GEMINI_L0_PREFIX=/^\s*\/((?:sp|rd3)-[a-z0-9-]+)/;function detectGeminiSkillCalls(raw,identity){if(String(raw.type??"")!=="user")return[];let content=geminiContent(raw);if(content===null)return[];let match=content.match(GEMINI_L0_PREFIX);if(match===null)return[];return[skillRecord(identity,match[1]??"","user")]}function detectGrokSkillCalls(raw,identity){let n=normalizeGrokRecord(raw);if(n.recordType!=="tool_call"||n.toolName!=="read_file")return[];let meta3=n.body._meta??raw._meta??{};if(o(meta3["x.ai/tool"]).namespace!=="grok_build")return[];let targetFile=s(o(n.toolArgs).target_file);if(targetFile===void 0||!targetFile.replace(/\\/g,"/").endsWith("/SKILL.md"))return[];return[skillRecord(identity,skillNameFromPath(targetFile),"model",{skill_path:targetFile,args_raw:maybeArgsRaw("grok","read_file",n.toolArgs)??null,args_digest:argsDigest(n.toolArgs),started_at:n.ts??null})]}function argsDigest(args){let redacted=redactArgs(args);return sha256(redacted)}function redactArgs(args){if(typeof args==="string"){if(args.length>80)return"[REDACTED:long]";if(/[A-Za-z0-9+/]{40,}=*|[A-Za-z0-9_-]{20,}/.test(args))return"[REDACTED:secret]";return args}if(Array.isArray(args))return args.map(redactArgs);if(args!==null&&typeof args==="object"){let result={};for(let[key,value]of Object.entries(args))result[key]=redactArgs(value);return result}return args}var BASH_COMMAND_MAX_CHARS=8192,GENERIC_ARGS_MAX_CHARS=8192;function bashCommandOf(args){if(args===null||typeof args!=="object")return;let rec=args,command=rec.command??rec.CommandLine??rec.cmd??rec.script;if(typeof command==="string")return command;if(Array.isArray(command))return command.map(String).join(" ");return}var BULKY_PAYLOAD_KEYS=new Set(["content","codecontent","replacementcontent","targetcontent","filedata","buffer","blob","image","imagebase64"]);function normalizeKey(key){return key.toLowerCase().replace(/[^a-z0-9]/g,"")}function isShellTool(toolName){return/^(?:bash|shell|cmd|command|exec|execcommand|executecommand|runcommand|shellcommand|runshellcommand)$/.test(normalizeKey(toolName))}function sanitizeValue(value){if(typeof value==="string")return value.length>1000?`${value.slice(0,1000)}[truncated ${value.length} chars]`:value;if(Array.isArray(value))return value.map(sanitizeValue);if(value!==null&&typeof value==="object"){let out={};for(let[key,entry]of Object.entries(value))out[key]=typeof entry==="string"&&entry.length>120&&BULKY_PAYLOAD_KEYS.has(normalizeKey(key))?`[omitted ${entry.length} chars]`:sanitizeValue(entry);return out}return value}function serializeBounded(value){let serialized=JSON.stringify(sanitizeValue(value));if(serialized.length<=GENERIC_ARGS_MAX_CHARS)return serialized;let preview=serialized;for(;;){let wrapper=JSON.stringify({_truncated:!0,omittedChars:serialized.length-preview.length,preview});if(wrapper.length<=GENERIC_ARGS_MAX_CHARS)return wrapper;preview=preview.slice(0,preview.length-(wrapper.length-GENERIC_ARGS_MAX_CHARS))}}function maybeArgsRaw(_source,toolName,args){if(args===void 0||args===null)return;let value=args;if(typeof args==="string")try{value=JSON.parse(args)}catch{return args.length>BASH_COMMAND_MAX_CHARS?args.slice(0,BASH_COMMAND_MAX_CHARS):args}if(value!==null&&typeof value==="object"){let cmd=bashCommandOf(value);if(cmd!==void 0&&isShellTool(toolName))return cmd.length>BASH_COMMAND_MAX_CHARS?cmd.slice(0,BASH_COMMAND_MAX_CHARS):cmd;return serializeBounded(value)}return JSON.stringify(value)}function claudeSplit(raw,context){let entries=[],sessionId=s(raw.sessionId,raw.conversation_uuid)??"unknown",seq=typeof raw.seq==="number"?raw.seq:typeof raw.messageIndex==="number"?raw.messageIndex:0,ts=timestampOf(raw.ts,raw.timestamp,raw.createdAt),role=mapRole(raw.type??raw.role),recordType=String(raw.type??""),model=s(raw.model,o(raw.message).model),cwd=s(raw.cwd,raw.dir);if(raw.subtype==="turn_duration"&&typeof raw.durationMs==="number")return entries.push({targetTable:"history_message",record:{session_id:sessionId,seq,role:"system",record_type:"turn_duration",disposition:"meta",ts,duration_ms:raw.durationMs,content_text:null,provenance:"ambient"}}),entries;if(recordType==="attachment"||recordType.startsWith("file-history"))return entries.push({targetTable:"history_message",record:{session_id:sessionId,seq,role:"meta",record_type:recordType,disposition:"meta",ts,provenance:"ambient"}}),entries;let usage=typeof raw.usage==="object"&&raw.usage!==null?raw.usage:o(raw.message).usage,inputTokens=raw.inputTokens??usage?.input_tokens,outputTokens=raw.outputTokens??usage?.output_tokens,cacheRead=usage?.cacheReadTokens??usage?.cache_read_tokens??usage?.cache_read_input_tokens,cacheWrite=usage?.cacheWriteTokens??usage?.cache_write_tokens??usage?.cache_creation_input_tokens,costUsd=computeCost(inputTokens,outputTokens,model),contentBlocks=raw.content??o(raw.message).content,contentText=extractContentText(contentBlocks),messageSplitIndex=entries.length;if(entries.push({targetTable:"history_message",record:{session_id:sessionId,seq,turn_index:typeof raw.turnIndex==="number"?raw.turnIndex:void 0,role,record_type:recordType,disposition:"keep",ts,duration_ms:void 0,model:model??null,input_tokens:inputTokens??null,output_tokens:outputTokens??null,cache_read_tokens:cacheRead??null,cache_write_tokens:cacheWrite??null,cost_usd:costUsd??null,content_text:contentText??null,cwd:cwd??null,provenance:"ambient",request_id:s(raw.requestId)??null}}),Array.isArray(contentBlocks)&&role==="assistant")for(let block of contentBlocks){if(typeof block!=="object"||block===null)continue;let b=block;if(b.type==="tool_use")entries.push({targetTable:"history_tool_call",record:{_messageSplitIndex:messageSplitIndex,session_id:sessionId,seq,call_id:s(b.id),tool_name:String(b.name??""),args_digest:argsDigest(b.input),args_raw:maybeArgsRaw("claude",String(b.name??""),b.input),status:"ok",started_at:void 0,completed_at:void 0,duration_ms:void 0,result_bytes:void 0,error_text:void 0}})}for(let record2 of extractSkillCalls(raw,context,{sessionId,seq,messageSplitIndex}))entries.push(skillCallEntry(record2));return entries}function piSplit(raw,context){let msg=raw.message,recordType=String(raw.type??raw.recordType??""),sessionId=sessionIdFromContext(context,raw),seq=context?.sourceLine??(typeof raw.seq==="number"?raw.seq:0),ts=timestampOf(raw.timestamp,raw.createdAt,raw.ts);if(recordType==="title"||recordType==="title_change"||recordType==="service_tier_change"||recordType==="session_info"||recordType==="ttsr_injection"||recordType==="session_init"||recordType==="session"||recordType==="model_change"||recordType==="thinking_level_change"||recordType==="compaction"||recordType==="custom"||recordType==="custom_message"||recordType.startsWith("custom."))return[{targetTable:"history_message",record:{session_id:sessionId,seq,role:"meta",record_type:recordType,disposition:"meta",ts,provenance:"ambient"}}];let entries=[],role=piRole(msg?.role??raw.role??recordType),model=s(raw.model,o(msg).model),cwd=s(raw.cwd,raw.dir),usage=msg?.usage??raw.usage,inputTokens=usage?.input??usage?.input_tokens??void 0,outputTokens=usage?.output??usage?.output_tokens??void 0,cacheRead=usage?.cacheRead??usage?.cache_read_tokens??void 0,cacheWrite=usage?.cacheWrite??usage?.cache_write_tokens??void 0,costObj=msg?.cost??raw.cost,costUsd=typeof costObj?.total==="number"?costObj.total:computeCost(inputTokens,outputTokens,model),contentBlocks=msg?.content??raw.content,durationMs=typeof msg?.duration==="number"&&Number.isFinite(msg.duration)?msg.duration:void 0,messageSplitIndex=entries.length;if(entries.push({targetTable:"history_message",record:{session_id:sessionId,seq,role,record_type:recordType,disposition:"keep",ts,duration_ms:durationMs,model:model??null,input_tokens:inputTokens??null,output_tokens:outputTokens??null,cache_read_tokens:cacheRead??null,cache_write_tokens:cacheWrite??null,cost_usd:costUsd??null,content_text:extractContentText(contentBlocks)??s(raw.content,raw.text,msg?.content)??null,cwd:cwd??null,provenance:"ambient"}}),Array.isArray(contentBlocks)&&role==="assistant")for(let block of contentBlocks){let call=normalizeOmpToolCall(block);if(call===null)continue;entries.push({targetTable:"history_tool_call",record:{_messageSplitIndex:messageSplitIndex,session_id:sessionId,seq,tool_name:String(call.name??""),call_id:s(call.id),args_digest:argsDigest(call.input??call.arguments),args_raw:maybeArgsRaw("pi",String(call.name??""),call.input??call.arguments),status:"ok",started_at:void 0,completed_at:void 0,duration_ms:void 0,result_bytes:void 0,error_text:void 0}})}for(let record2 of extractSkillCalls(raw,context,{sessionId,seq,messageSplitIndex}))entries.push(skillCallEntry(record2));return entries}function piRole(type){let t=String(type??"").toLowerCase();if(t==="toolresult"||t==="tool_result"||t==="bashexecution"||t==="tool")return"user";let mapped=mapRole(t);if(mapped==="user"||mapped==="assistant"||mapped==="system")return mapped;return"unknown"}function ompSplit(raw,context){let msg=raw.message,recordType=String(raw.type??""),sessionId=sessionIdFromContext(context,raw),seq=context?.sourceLine??(typeof raw.seq==="number"?raw.seq:0),ts=timestampOf(raw.ts,raw.timestamp,raw.createdAt);if(recordType==="title"||recordType==="title_change"||recordType==="service_tier_change"||recordType==="ttsr_injection"||recordType==="session_init"||recordType==="session"||recordType==="model_change"||recordType==="thinking_level_change"||recordType==="compaction"||recordType==="custom"||recordType==="custom_message"||recordType.startsWith("custom."))return[{targetTable:"history_message",record:{session_id:sessionId,seq,role:"meta",record_type:recordType,disposition:"meta",ts,provenance:"ambient"}}];let entries=[],role=mapRole(msg?.role??raw.type??raw.role),model=s(raw.model,o(msg).model),cwd=s(raw.cwd,raw.dir),usage=msg?.usage??raw.usage,inputTokens=usage?.input??usage?.input_tokens??void 0,outputTokens=usage?.output??usage?.output_tokens??void 0,cacheRead=usage?.cacheRead??usage?.cache_read_tokens??void 0,cacheWrite=usage?.cacheWrite??usage?.cache_write_tokens??void 0,costObj=msg?.cost??raw.cost,costUsd=typeof costObj?.total==="number"?costObj.total:computeCost(inputTokens,outputTokens,model),contentBlocks=msg?.content??raw.content,durationMs=typeof msg?.duration==="number"&&Number.isFinite(msg.duration)?msg.duration:void 0,messageSplitIndex=entries.length;if(entries.push({targetTable:"history_message",record:{session_id:sessionId,seq,role,record_type:recordType,disposition:"keep",ts,duration_ms:durationMs,model:model??null,input_tokens:inputTokens??null,output_tokens:outputTokens??null,cache_read_tokens:cacheRead??null,cache_write_tokens:cacheWrite??null,cost_usd:costUsd??null,content_text:extractContentText(contentBlocks)??s(raw.content,raw.text,msg?.content)??null,cwd:cwd??null,provenance:"ambient"}}),Array.isArray(contentBlocks)&&role==="assistant")for(let block of contentBlocks){let call=normalizeOmpToolCall(block);if(call===null)continue;entries.push({targetTable:"history_tool_call",record:{_messageSplitIndex:messageSplitIndex,session_id:sessionId,seq,tool_name:String(call.name??""),call_id:s(call.id),args_digest:argsDigest(call.input??call.arguments),args_raw:maybeArgsRaw("omp",String(call.name??""),call.input??call.arguments),status:"ok",started_at:void 0,completed_at:void 0,duration_ms:void 0,result_bytes:void 0,error_text:void 0}})}for(let record2 of extractSkillCalls(raw,context,{sessionId,seq,messageSplitIndex}))entries.push(skillCallEntry(record2));return entries}function normalizeOmpToolCall(block){if(typeof block!=="object"||block===null)return null;let nested=o(block.toolCall);if(Object.keys(nested).length>0)return nested;if(block.type==="toolCall")return block;return null}function codexSplit(raw,context){let entries=[],payload=raw.payload??raw,seq=typeof raw.seq==="number"?raw.seq:0,ts=timestampOf(raw.timestamp,raw.ts,payload.ts),recordType=String(raw.type??""),payloadType=String(payload.type??""),isShortFormat=recordType===""&&raw.id!==void 0&&raw.timestamp!==void 0&&raw.instructions!==void 0,explicitSessionId=s(raw.session_id,o(raw.session_meta).id);if(explicitSessionId===void 0&&recordType==="session_meta")explicitSessionId=s(payload.id,o(raw.payload).id);if(explicitSessionId===void 0&&isShortFormat)explicitSessionId=s(raw.id);let pathSessionId=context?.sourceFile?sessionIdFromSourcePath("codex",context.sourceFile):void 0,sessionId=explicitSessionId??pathSessionId??"unknown";if(isShortFormat)return[{targetTable:"history_message",record:{session_id:sessionId,seq,role:"meta",record_type:"short_format",disposition:"meta",ts,provenance:"ambient"}}];let role,disposition,contentText,usage;if(recordType==="response_item")if(payloadType==="message")role=mapRole(payload.role),disposition="keep",contentText=extractContentText(payload.content)??s(payload.text)??null;else if(payloadType==="agent_message")role="assistant",disposition="keep",contentText=extractContentText(payload.content)??s(payload.text,payload.message)??null;else if(payloadType==="reasoning")role="assistant",disposition="keep",contentText=extractContentText(payload.summary)??s(payload.text)??null;else if(payloadType==="function_call"||payloadType==="custom_tool_call")role="tool",disposition="keep",contentText=null;else role="meta",disposition="meta",contentText=s(payload.text)??null;else if(recordType==="user"||recordType==="assistant")role=mapRole(recordType),disposition="keep",contentText=extractContentText(payload.content)??s(raw.content,payload.text)??null;else if(recordType==="message")role=mapRole(raw.role??payload.role),disposition="keep",contentText=extractContentText(payload.content??raw.content)??s(payload.text,raw.text)??null;else if(recordType==="event_msg")role="meta",disposition="meta",contentText=s(payload.message,payload.text)??null,usage=o(o(payload.info).last_token_usage);else role="meta",disposition="meta",contentText=s(payload.text,raw.instructions)??null;let model=s(raw.model,payload.model,o(o(raw.turn_context).payload).model),cwd=s(raw.cwd,raw.dir),tokenCount=payload.token_count,usageInput=usage?.input_tokens??tokenCount?.input??tokenCount?.input_tokens??void 0,usageOutput=usage?.output_tokens??tokenCount?.output??tokenCount?.output_tokens??void 0,cacheRead=usage?.cached_input_tokens??void 0,turnPayload=raw.turn_context?.payload,turnInputTokens=turnPayload?.input_tokens,turnOutputTokens=turnPayload?.output_tokens,finalInput=usageInput!==void 0?usageInput:turnInputTokens,finalOutput=usageOutput!==void 0?usageOutput:turnOutputTokens,costUsd=computeCost(finalInput,finalOutput,model),usageCarrier=finalInput!==void 0||finalOutput!==void 0?{input:finalInput??null,output:finalOutput??null,cacheRead:cacheRead??null}:void 0,stripUsage=role==="meta"&&usageCarrier!==void 0,messageSplitIndex=entries.length;entries.push({targetTable:"history_message",record:{session_id:sessionId,seq,role,record_type:recordType,disposition,ts,duration_ms:void 0,model:model??null,input_tokens:stripUsage?null:finalInput??null,output_tokens:stripUsage?null:finalOutput??null,cache_read_tokens:stripUsage?null:cacheRead??null,...usageCarrier!==void 0?{_codexUsageCarrier:usageCarrier}:{},cache_write_tokens:null,cost_usd:costUsd??null,content_text:contentText,cwd:cwd??null,provenance:"ambient"}});let toolItems=[];if((recordType==="response_item"||recordType==="function_call"||recordType==="custom_tool_call")&&(payloadType==="function_call"||payloadType==="custom_tool_call"))toolItems.push(payload);else if(payload.response_item)toolItems.push(payload.response_item);else if(Array.isArray(payload.response_items))toolItems.push(...payload.response_items);for(let item of toolItems){let fc=item.function_call??item,toolName=s(fc.name)??"",args=fc.arguments??fc.input;entries.push({targetTable:"history_tool_call",record:{_messageSplitIndex:messageSplitIndex,session_id:sessionId,seq,tool_name:toolName,call_id:s(fc.call_id),args_digest:argsDigest(args),args_raw:maybeArgsRaw("codex",toolName,args),status:"ok",started_at:void 0,completed_at:void 0,duration_ms:void 0,result_bytes:void 0,error_text:void 0}})}for(let record2 of extractSkillCalls(raw,context,{sessionId,seq,messageSplitIndex}))entries.push(skillCallEntry(record2));return entries}function agySplit(raw,context){let entries=[],recordType=String(raw.type??""),explicitSessionId=s(raw.session_id,raw.conversation_id,raw.conversationId),pathSessionId=context?.sourceFile?sessionIdFromSourcePath("agy",context.sourceFile):void 0,sessionId=explicitSessionId??pathSessionId??"unknown",seq=typeof raw.seq==="number"?raw.seq:typeof raw.step_index==="number"?raw.step_index:context?.sourceLine??0,ts=timestampOf(raw.created_at,raw.timestamp,raw.ts),role,disposition,contentText=null,messageRecordType=recordType;if(raw.display!==void 0)role="user",disposition="keep",contentText=s(raw.display)??null,messageRecordType=recordType.length>0?recordType:"USER_INPUT";else switch(recordType){case"USER_INPUT":case"ASK_QUESTION":role="user",disposition="keep",contentText=s(raw.content,raw.text,raw.message)??null;break;case"PLANNER_RESPONSE":role="assistant",disposition="keep",contentText=s(raw.content,raw.text,raw.message,raw.plan)??null;break;case"ERROR_MESSAGE":role="system",disposition="keep",contentText=s(raw.content,raw.text,raw.message)??null;break;case"RUN_COMMAND":case"VIEW_FILE":case"GREP_SEARCH":case"LIST_DIRECTORY":case"READ_URL_CONTENT":role="tool",disposition="keep",contentText=s(raw.content,raw.command,raw.file_path,raw.pattern)??null;break;case"CODE_ACTION":case"INVOKE_SUBAGENT":role="tool",disposition="keep",contentText=s(raw.content,raw.text)??null;break;case"CONVERSATION_HISTORY":case"CHECKPOINT":case"GENERIC":role="meta",disposition="meta",contentText=s(raw.content,raw.text)??null;break;default:if(recordType.length===0)role="unknown",disposition="unknown";else role="meta",disposition="meta",contentText=s(raw.content,raw.text)??null;break}let messageSplitIndex=entries.length;if(entries.push({targetTable:"history_message",record:{session_id:sessionId,seq,role,record_type:messageRecordType,disposition,ts,duration_ms:void 0,model:null,input_tokens:null,output_tokens:null,cache_read_tokens:null,cache_write_tokens:null,cost_usd:null,content_text:contentText,cwd:s(raw.workspace,raw.cwd)??null,provenance:"ambient"}}),recordType==="PLANNER_RESPONSE"&&Array.isArray(raw.tool_calls))for(let tc of raw.tool_calls)entries.push({targetTable:"history_tool_call",record:{_messageSplitIndex:messageSplitIndex,session_id:sessionId,seq:typeof tc.step_index==="number"?tc.step_index:seq,tool_name:String(tc.name??tc.tool_name??""),args_digest:argsDigest(tc.input??tc.arguments),args_raw:maybeArgsRaw("agy",String(tc.name??tc.tool_name??""),tc.input??tc.arguments),status:"ok",started_at:void 0,completed_at:void 0,duration_ms:void 0,result_bytes:void 0,error_text:void 0}});for(let record2 of extractSkillCalls(raw,context,{sessionId,seq,messageSplitIndex}))entries.push(skillCallEntry(record2));return entries}function geminiSplit(raw,context){let recordType=String(raw.type??(raw.kind!==void 0?"session":raw.$set!==void 0?"state":"")),state=o(raw.$set),sessionId=sessionIdFromContext(context,raw),seq=context?.sourceLine??0,ts=timestampOf(raw.timestamp,raw.startTime,raw.lastUpdated,state.lastUpdated);if(recordType==="session"||recordType==="state")return[{targetTable:"history_message",record:{session_id:sessionId,seq,role:"meta",record_type:recordType,disposition:"meta",ts,content_text:s(state.summary)??null,provenance:"ambient"}}];let role=recordType==="gemini"?"assistant":recordType==="user"?"user":"system",tokens=o(raw.tokens),content=geminiContent(raw),entries=[{targetTable:"history_message",record:{session_id:sessionId,seq,role,record_type:recordType,disposition:"keep",ts,duration_ms:null,model:s(raw.model)??null,input_tokens:numberOrNull(tokens.input),output_tokens:numberOrNull(tokens.output),cache_read_tokens:numberOrNull(tokens.cached),cache_write_tokens:null,cost_usd:null,content_text:content,cwd:null,provenance:"ambient"}}];if(Array.isArray(raw.toolCalls))for(let value of raw.toolCalls){if(value===null||typeof value!=="object"||Array.isArray(value))continue;let tool=value,status=s(tool.status)??"unknown",timestamp=s(tool.timestamp),result=tool.result??tool.resultDisplay;entries.push({targetTable:"history_tool_call",record:{_messageSplitIndex:0,session_id:sessionId,seq,tool_name:s(tool.name,tool.displayName)??"unknown",args_digest:argsDigest(tool.args),args_raw:maybeArgsRaw("gemini",s(tool.name,tool.displayName)??"",tool.args),status,started_at:timestamp,completed_at:timestamp,duration_ms:null,result_bytes:result===void 0?null:new TextEncoder().encode(JSON.stringify(result)).byteLength,error_text:status==="error"?s(tool.resultDisplay,tool.result)??null:null}})}for(let record2 of extractSkillCalls(raw,context,{sessionId,seq,messageSplitIndex:0}))entries.push(skillCallEntry(record2));return entries}function dshSplit(raw,context){let recordType=String(raw.type??"");if(recordType==="session")return[{targetTable:"history_message",record:{session_id:s(raw.id)??sessionIdFromSourcePath("deepseek",context?.sourceFile??"")??"unknown",seq:0,role:"meta",record_type:"session",disposition:"meta",ts:timestampOf(raw.createdAt),cwd:s(raw.cwd)??null,content_text:null,provenance:"ambient"}}];if(recordType!=="user/message"&&recordType!=="assistant/message")return[];let data=o(raw.data),msg=o(data.message),seq=typeof raw.seq==="number"?raw.seq:context?.sourceLine??0,sessionId=sessionIdFromSourcePath("deepseek",context?.sourceFile??"")??"unknown",role=recordType==="user/message"?"user":"assistant",source=o(data.source??msg.source),model=s(source.model,o(data.model??msg.model).model),usage=data.usage??msg.usage,messageId=s(msg.id,data.id);return[{targetTable:"history_message",record:{session_id:sessionId,seq,role,record_type:recordType,disposition:"keep",...messageId!==void 0?{source_record_id:messageId}:{},ts:timestampOf(raw.time,data.time,msg.time),duration_ms:null,model:model??null,input_tokens:numberOrNull(usage?.input_tokens??usage?.input)??null,output_tokens:numberOrNull(usage?.output_tokens??usage?.output)??null,cache_read_tokens:null,cache_write_tokens:null,cost_usd:null,content_text:extractContentText(data.content??msg.content)??s(data.text,msg.text)??null,cwd:null,provenance:"ambient"}}]}var UUID_PATTERN="[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}",AGY_BRAIN_REGEX=new RegExp(`(?:^|\\/)brain\\/(${UUID_PATTERN})(?:\\/|$)`,"i"),DSH_SESSION_REGEX=new RegExp(`(?:^|\\/)session-(${UUID_PATTERN})(?:\\/|$)`,"i"),CODEX_ROLLOUT_REGEX=new RegExp(`(?:^|-|_)(${UUID_PATTERN})$`,"i");function sessionIdFromSourcePath(source,sourceFile){let normalized=sourceFile.replace(/\\/g,"/"),sLower=source.toLowerCase();if(sLower==="agy"||sLower==="antigravity")return normalized.match(AGY_BRAIN_REGEX)?.[1];if(sLower==="deepseek")return normalized.match(DSH_SESSION_REGEX)?.[1];if(sLower==="codex"){let basename=normalized.split("/").at(-1)??"";if(basename.startsWith("rollout-")&&basename.endsWith(".jsonl"))return basename.slice(0,-6).match(CODEX_ROLLOUT_REGEX)?.[1]}return}function sessionIdFromContext(context,raw){if(context!==void 0){let file2=context.sourceFile.split("/").at(-1);if(file2!==void 0)return file2.replace(/\.jsonl$/,"")}return s(raw.sessionId,raw.id)??"unknown"}function geminiContent(raw){let content=extractContentText(raw.content)??s(raw.text),thoughts=Array.isArray(raw.thoughts)?raw.thoughts.map((value)=>value!==null&&typeof value==="object"?s(o(value).description):void 0).filter((value)=>value!==void 0).join(`
|
|
534
|
+
`.trim();init_zod();init_zod();import{createHash}from"node:crypto";function stableJson(value){if(Array.isArray(value))return`[${value.map((entry)=>entry===void 0?"null":stableJson(entry)).join(",")}]`;if(value!==null&&typeof value==="object"){let record2=value;return`{${Object.keys(record2).filter((key)=>record2[key]!==void 0).sort().map((key)=>`${JSON.stringify(key)}:${stableJson(record2[key])}`).join(",")}}`}return JSON.stringify(value)??"null"}function sha256(value){return createHash("sha256").update(stableJson(value)).digest("hex")}function sha256Text(text){return createHash("sha256").update(text,"utf8").digest("hex")}function matchCapabilityOrigin(origins,source,canonicalName,observable){let candidates=origins.filter((origin)=>origin.source===source&&origin.skillName===canonicalName);if(candidates.length===0)return{origin:void 0,conflict:null};if(observable.skillPath!=null&&observable.skillPath!==""){let byPath=candidates.filter((origin)=>origin.skillPath!==void 0&&origin.skillPath===observable.skillPath);if(byPath.length>0)candidates=byPath}if(observable.artifactDigest!=null&&observable.artifactDigest!==""){let byDigest=candidates.filter((origin)=>origin.artifactDigest===observable.artifactDigest);if(byDigest.length===1)return{origin:byDigest[0],conflict:null};if(byDigest.length>1)return{origin:void 0,conflict:`capabilityOrigins: ${byDigest.length} origins agree on digest for '${canonicalName}'.`};return{origin:void 0,conflict:`capabilityOrigins: observed artifact digest does not match the supplied origin for '${canonicalName}'.`}}if(candidates.length===1)return{origin:candidates[0],conflict:null};return{origin:void 0,conflict:`capabilityOrigins: ${candidates.length} origins match '${canonicalName}' without distinguishing evidence.`}}function capabilityInvocationId(parts){return sha256Text(JSON.stringify({domain:"capability-invocation",v:1,source:parts.source,sessionId:parts.sessionId,kind:parts.kind,id:parts.id??null,ordinal:parts.ordinal??null,file:parts.file??null,line:parts.line??null},Object.keys({domain:0,v:0,source:0,sessionId:0,kind:0,id:0,ordinal:0,file:0,line:0}).sort()))}function scanShellSegment(segment){let tokens=[],current="",quote=null,dynamic=!1;for(let i=0;i<segment.length;i+=1){let ch=segment[i];if(quote==="'"){if(ch==="'")quote=null;else current+=ch;continue}if(quote==='"'){if(ch==='"')quote=null;else if(ch==="$"||ch==="`")dynamic=!0;else current+=ch;continue}if(ch==="'"||ch==='"'){quote=ch;continue}if(ch==="\\"||ch==="$"||ch==="`"){dynamic=!0;continue}if(ch===" "||ch==="\t"||ch===`
|
|
535
|
+
`){if(current!=="")tokens.push(current);current="";continue}current+=ch}if(quote!==null)dynamic=!0;if(current!=="")tokens.push(current);return{tokens,dynamic}}function splitShellSegments(command){let segments=[],current="",quote=null;for(let i=0;i<command.length;i+=1){let ch=command[i];if(quote!==null){if(current+=ch,ch===quote)quote=null;continue}if(ch==="'"||ch==='"'){quote=ch,current+=ch;continue}if(ch===";"){segments.push(current),current="";continue}if(ch==="|"||ch==="&"){if(command[i+1]===ch){segments.push(current),current="",i+=1;continue}segments.push(current),current="";continue}current+=ch}return segments.push(current),segments}function lastPathSegment(path){let trimmed=path.replace(/\/+$/,""),idx=trimmed.lastIndexOf("/");return idx===-1?trimmed:trimmed.slice(idx+1)}function isSedPrintRange(token){return/^\$?[0-9]+(\s*,\s*(\$|[0-9]+))?p$/.test(token)||/^\$p$/.test(token)}function hasRedirection(segment){let quote=null;for(let i=0;i<segment.length;i+=1){let ch=segment[i];if(quote!==null){if(ch===quote)quote=null;continue}if(ch==="'"||ch==='"'){quote=ch;continue}if(ch===">"||ch==="<")return!0}return!1}function parseLiteralReadTargets(command){if(typeof command!=="string"||command.trim()==="")return[];let targets=[];for(let segment of splitShellSegments(command)){if(segment.trim()===""||hasRedirection(segment))continue;let trimmed=segment.trim();if(trimmed.startsWith("#"))continue;let scan=scanShellSegment(trimmed);if(scan.dynamic||scan.tokens.length===0)continue;let[cmd,...args]=scan.tokens;if(cmd==="cat"){for(let arg of args){if(arg==="--")continue;if(arg.startsWith("-"))continue;if(lastPathSegment(arg)==="SKILL.md")targets.push(arg)}continue}if(cmd==="sed"){let sawNoPrint=!1,rangeArgs=[];for(let arg of args){if(arg==="--")continue;if(arg==="-n"||arg==="--quiet"||arg==="--silent"){sawNoPrint=!0;continue}if(arg.startsWith("-")){sawNoPrint=!1;break}if(isSedPrintRange(arg)){rangeArgs.push(arg);continue}if(rangeArgs.length===0){sawNoPrint=!1;break}if(sawNoPrint&&lastPathSegment(arg)==="SKILL.md")targets.push(arg);break}if(!sawNoPrint)continue}}return targets}function extractNestedExecCommandLiterals(payloadText){if(typeof payloadText!=="string"||payloadText.trim()==="")return[];let literals=[],shape=/tools\.exec_command\(\s*\{\s*cmd:\s*("(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*')((?:\s*,\s*[A-Za-z_][A-Za-z0-9_]*\s*:\s*(?:"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'|[-0-9.eE+]+|true|false|null))*)\s*\}\s*\)/g,inBlockComment=!1;for(let rawLine of payloadText.split(/\r?\n/)){let line=rawLine;if(inBlockComment){let end=line.indexOf("*/");if(end===-1)continue;line=line.slice(end+2),inBlockComment=!1}if(line.trimStart().startsWith("//"))continue;let blockStart=line.indexOf("/*");if(blockStart!==-1){let end=line.indexOf("*/",blockStart+2);if(line=end===-1?line.slice(0,blockStart):line.slice(0,blockStart)+line.slice(end+2),end===-1)inBlockComment=!0}let statementStart=/(?:^|[{};])\s*$/;shape.lastIndex=0;let match=shape.exec(line);while(match!==null){let before=line.slice(0,match.index);if(statementStart.test(before)){let literal2=match[1]??"",quote=literal2[0]??'"',body=literal2.slice(1,-1).replaceAll(`\\${quote}`,quote).replaceAll("\\\\","\\").replaceAll("\\n",`
|
|
536
|
+
`).replaceAll("\\t","\t");literals.push(body)}match=shape.exec(line)}}return literals}var MESSAGE_MAPPER_KEYS=["_codexUsageCarrier","session_id","seq","turn_index","role","record_type","disposition","ts","duration_ms","model","input_tokens","output_tokens","cache_read_tokens","cache_write_tokens","cost_usd","content_text","cwd","provenance","run_id","task_wbs","request_id"],TOOL_CALL_MAPPER_KEYS=["_messageSplitIndex","session_id","seq","tool_name","call_id","args_digest","args_raw","status","started_at","completed_at","duration_ms","result_bytes","error_text"],SKILL_CALL_MAPPER_KEYS=["_messageSplitIndex","session_id","seq","skill_name","invocation_kind","skill_path","args_raw","args_digest","call_id","status","started_at","completed_at","duration_ms","capability_kind","evidence_kind","invocation_id","origin_identity","_capabilityConflict"];function identityFieldMap(keys){let map2={};for(let key of keys)map2[key]=key;return map2}var HARNESS_SKILL_PACKAGES=new Set(["sp","rd3"]);function canonicalizeSkillName(raw){let name=raw.trim();if(name.startsWith("/")||name.startsWith("$"))name=name.slice(1);if(name.startsWith("skill:"))name=name.slice(6);let canonical=name.match(/^([a-z][a-z0-9]*):([a-z0-9-]+)$/);if(canonical!==null&&HARNESS_SKILL_PACKAGES.has(canonical[1]??""))return name;let dialect=name.match(/^([a-z][a-z0-9]*)-([a-z0-9-]+)$/);if(dialect!==null&&HARNESS_SKILL_PACKAGES.has(dialect[1]??""))return`${dialect[1]}:${dialect[2]}`;return name}function extractSkillCalls(raw,context,identity){switch(context?.source){case"claude":return detectClaudeSkillCalls(raw,identity,context);case"pi":return detectPiSkillCalls(raw,identity,context);case"omp":return detectOmpSkillCalls(raw,identity,context);case"codex":return detectCodexSkillCalls(raw,identity,context);case"agy":return detectAgySkillCalls(raw,identity,context);case"gemini":return detectGeminiSkillCalls(raw,identity,context);case"grok":return detectGrokSkillCalls(raw,identity,context);default:return[]}}function skillCallEntry(record2){return{targetTable:"history_skill_call",record:record2}}function skillRecord(identity,skillName,invocationKind,extra={}){return{_messageSplitIndex:identity.messageSplitIndex,session_id:identity.sessionId,seq:identity.seq,skill_name:canonicalizeSkillName(skillName),invocation_kind:invocationKind,skill_path:null,args_raw:null,args_digest:null,call_id:null,status:"unknown",started_at:null,completed_at:null,duration_ms:null,capability_kind:null,evidence_kind:null,invocation_id:null,origin_identity:null,...extra}}function createOrdinalAllocator(){let ordinals=new Map;return(key)=>{let existing=ordinals.get(key);if(existing!==void 0)return existing;let ordinal=ordinals.size;return ordinals.set(key,ordinal),ordinal}}function originFields(context,canonicalName,observable){let origins=context?.capabilityOrigins;if(origins===void 0||origins.length===0)return{capability_kind:null,origin_identity:null,_capabilityConflict:void 0};let match=matchCapabilityOrigin(origins,context?.source??"",canonicalName,observable);return{capability_kind:match.origin?.capabilityKind??null,origin_identity:match.origin?.originIdentity??null,_capabilityConflict:match.conflict??void 0}}function invocationIdFor(context,sessionId,ref){let source=context?.source??"unknown";if(ref.invocationId!==void 0)return capabilityInvocationId({source,sessionId,kind:"invocation",id:ref.invocationId});if(ref.callId!==void 0)return capabilityInvocationId({source,sessionId,kind:"call",id:ref.callId,ordinal:ref.ordinal>0?ref.ordinal:void 0});if(ref.recordId!==void 0)return capabilityInvocationId({source,sessionId,kind:"record",id:ref.recordId,ordinal:ref.ordinal});return capabilityInvocationId({source,sessionId,kind:"line",file:context?.sourceFile??"",line:context?.sourceLine??0,ordinal:ref.ordinal})}function skillNameFromPath(path){let normalized=path.replace(/\\/g,"/"),bySkillsSegment=normalized.match(/\/skills\/([^/]+)\/SKILL\.md$/i);if(bySkillsSegment!==null)return bySkillsSegment[1]??"";let stem=normalized.slice(0,normalized.length-9);return stem.split("/").pop()??stem}function detectClaudeSkillCalls(raw,identity,context){let contentBlocks=raw.content??o(raw.message).content;if(!Array.isArray(contentBlocks))return[];let rows=[],role=mapRole(raw.type??o(raw.message).role),recordId=s(raw.uuid,raw.id,raw.requestId),ts=timestampOf(raw.timestamp,raw.ts,o(raw.message).timestamp)??null,ordinal=createOrdinalAllocator();for(let block of contentBlocks){if(typeof block!=="object"||block===null)continue;let b=block;if(b.type!=="tool_use")continue;let input=b.input??{},callId=s(b.id),invocation=callId!==void 0?{callId,ordinal:0}:{recordId,ordinal:ordinal(`tool:${rows.length}`)};if(b.name==="Skill"){let skill=s(input.skill);if(skill===void 0)continue;let canonical=canonicalizeSkillName(skill);rows.push(skillRecord(identity,skill,s(o(b.caller).type)==="direct"?"user":"model",{args_raw:maybeArgsRaw("claude","Skill",input)??null,args_digest:argsDigest(input),call_id:callId??null,started_at:ts,evidence_kind:"load",status:"unknown",invocation_id:invocationIdFor(context,identity.sessionId,invocation),...originFields(context,canonical,{})}));continue}if(b.name==="Task"){let subagent=s(input.subagent_type,input.agent_type,input.agent)??"subagent";rows.push(skillRecord(identity,subagent,"model",{args_raw:maybeArgsRaw("claude","Task",input)??null,args_digest:argsDigest(input),call_id:callId??null,started_at:ts,...originFields(context,canonicalizeSkillName(subagent),{}),capability_kind:"subagent",evidence_kind:"delegation",status:"unknown",invocation_id:invocationIdFor(context,identity.sessionId,invocation)}));continue}if(b.name==="Read"){let filePath=s(input.file_path,input.path);if(filePath===void 0||lastPathSegmentNorm(filePath)!=="SKILL.md")continue;let canonical=canonicalizeSkillName(skillNameFromPath(filePath));rows.push(skillRecord(identity,skillNameFromPath(filePath),"model",{skill_path:filePath,args_raw:maybeArgsRaw("claude","Read",input)??null,args_digest:argsDigest(input),call_id:callId??null,started_at:ts,evidence_kind:"load",status:"unknown",invocation_id:invocationIdFor(context,identity.sessionId,invocation),...originFields(context,canonical,{skillPath:filePath})}));continue}if(b.name==="Bash"){let command=s(input.command);if(command===void 0)continue;let targets=parseLiteralReadTargets(command);for(let i=0;i<targets.length;i+=1){let target=targets[i]??"",canonical=canonicalizeSkillName(skillNameFromPath(target));rows.push(skillRecord(identity,skillNameFromPath(target),"model",{skill_path:target,args_raw:maybeArgsRaw("claude","Bash",input)??null,args_digest:argsDigest(input),call_id:callId??null,started_at:ts,evidence_kind:"load",status:"unknown",invocation_id:invocationIdFor(context,identity.sessionId,{...invocation,ordinal:i}),...originFields(context,canonical,{skillPath:target})}))}}}if(role==="user"){let text=extractUserTextClaude(contentBlocks);if(text!==void 0){let rawName=leadingInjectionMatch(text,CLAUDE_COMMAND_NAME_ANCHORED)?.[1]??"";if(rawName.length>0){let canonical=canonicalizeSkillName(rawName);if(canonical.length>0)rows.push(skillRecord(identity,canonical,"user",{args_raw:text.match(CLAUDE_COMMAND_ARGS)?.[1]?.trim()||null,started_at:ts,capability_kind:"command",evidence_kind:"request",status:"unknown",invocation_id:invocationIdFor(context,identity.sessionId,{recordId,ordinal:ordinal(`cmd:${canonical}`)})}))}}}return rows}var CLAUDE_COMMAND_NAME_ANCHORED=/^<command-name>([^<]+)<\/command-name>/,CLAUDE_COMMAND_ARGS=/<command-args>([\s\S]*?)<\/command-args>/;function extractUserTextClaude(contentBlocks){let parts=[];for(let block of contentBlocks){if(typeof block!=="object"||block===null)continue;let b=block;if(b.type==="tool_result")continue;if(typeof b.text==="string")parts.push(b.text)}return parts.length>0?parts.join(`
|
|
537
|
+
`):void 0}function lastPathSegmentNorm(path){let normalized=path.replace(/\\/g,"/"),idx=normalized.lastIndexOf("/");return idx===-1?normalized:normalized.slice(idx+1)}function isQuotedSignatureContext(text,matchIndex){let lineStart=text.lastIndexOf(`
|
|
538
|
+
`,matchIndex-1)+1;if(text.slice(lineStart,matchIndex).trim().length>0)return!0;let openFence="";for(let line of text.slice(0,lineStart).split(`
|
|
539
|
+
`)){let fence=/^\s{0,3}(`{3,}|~{3,})/.exec(line);if(fence===null)continue;let run=fence[1]??"";if(openFence==="")openFence=run;else if(run[0]===openFence[0]&&run.length>=openFence.length)openFence=""}return openFence!==""}function isCodexMarkerLine(line){let trimmed=line.trim();return CODEX_DOLLAR_MARKER.test(trimmed)||CODEX_SLASH_MARKER.test(trimmed)||/^-\s+skill:\s*\S+/.test(trimmed)}function isCodexWrapperLeadPosition(text,matchIndex,chainStart){let before=text.slice(0,matchIndex);if(before.trim().length===0)return!0;if(chainStart!==void 0&&text.slice(chainStart,matchIndex).trim().length===0)return!0;let lines=before.split(`
|
|
540
|
+
`);if((lines[lines.length-1]??"").trim().length>0)return!1;if(lines.length<2)return!1;return isCodexMarkerLine(lines[lines.length-2]??"")}function leadingInjectionMatch(text,pattern){let trimmed=text.trimStart(),offset=text.length-trimmed.length,match=trimmed.match(pattern);if(match===null||match.index===void 0)return null;if(isQuotedSignatureContext(text,offset+match.index))return null;return match}var PI_SKILL_WRAPPER_ANCHORED=/^<skill\s+name="([^"]+)"(?:\s+location="([^"]*)")?\s*>/,READ_FAMILY_TOOLS=new Set(["read","read_file","view"]);function detectPiSkillCalls(raw,identity,context){let msg=raw.message,role=piRole(msg?.role??raw.role??raw.recordType??raw.type),recordId=s(raw.id,raw.uuid,raw.requestId),ts=timestampOf(raw.timestamp,raw.ts,o(msg).timestamp)??null,rows=[];if(role==="user"){let text=extractContentText(msg?.content??raw.content);if(text===void 0)return[];let ordinal=createOrdinalAllocator(),wrapper=leadingInjectionMatch(text,PI_SKILL_WRAPPER_ANCHORED);if(wrapper!==null){let skillPath=wrapper[2]||null,canonical=canonicalizeSkillName(wrapper[1]??"");if(canonical.length>0)rows.push(skillRecord(identity,canonical,"user",{skill_path:skillPath,started_at:ts,evidence_kind:"load",status:"ok",invocation_id:invocationIdFor(context,identity.sessionId,{recordId,ordinal:ordinal(`skill:${canonical}`)}),...originFields(context,canonical,{skillPath})}))}return rows}if(role==="assistant"){let contentBlocks=msg?.content??raw.content;if(!Array.isArray(contentBlocks))return[];for(let block of contentBlocks){if(typeof block!=="object"||block===null)continue;let call=normalizeOmpToolCall(block);if(call===null||!READ_FAMILY_TOOLS.has(String(call.name??"")))continue;let args=call.input??call.arguments??{},filePath=s(args.filePath,args.file_path,args.path,args.target_file);if(filePath===void 0||lastPathSegmentNorm(filePath)!=="SKILL.md")continue;let callId=s(call.id),canonical=canonicalizeSkillName(skillNameFromPath(filePath));rows.push(skillRecord(identity,canonical,"model",{skill_path:filePath,args_raw:maybeArgsRaw("pi",String(call.name??"read"),args)??null,args_digest:argsDigest(args),call_id:callId??null,started_at:ts,evidence_kind:"load",status:"unknown",invocation_id:invocationIdFor(context,identity.sessionId,{callId,recordId:callId===void 0?recordId:void 0,ordinal:rows.length}),...originFields(context,canonical,{skillPath:filePath})}))}}return rows}function detectOmpSkillCalls(raw,identity,context){let msg=raw.message,role=mapRole(msg?.role??raw.type??raw.role),recordId=s(raw.id,raw.uuid,raw.requestId),ts=timestampOf(raw.timestamp,raw.ts,o(msg).timestamp)??null,rows=[];if(role==="assistant"){let contentBlocks=msg?.content??raw.content;if(!Array.isArray(contentBlocks))return[];for(let block of contentBlocks){let call=normalizeOmpToolCall(block);if(call===null)continue;let input=call.input??call.arguments;if(call.name==="Skill"){let skill=s(input?.skill);if(skill===void 0)continue;let callId=s(call.id);rows.push(skillRecord(identity,skill,"model",{args_raw:maybeArgsRaw("omp","Skill",input)??null,args_digest:argsDigest(input),call_id:callId??null,started_at:ts,evidence_kind:"load",status:"unknown",invocation_id:invocationIdFor(context,identity.sessionId,{callId,recordId:callId===void 0?recordId:void 0,ordinal:rows.length}),...originFields(context,canonicalizeSkillName(skill),{})}));continue}if(READ_FAMILY_TOOLS.has(String(call.name??""))){let args=input??{},filePath=s(args.filePath,args.file_path,args.path,args.target_file);if(filePath===void 0||lastPathSegmentNorm(filePath)!=="SKILL.md")continue;let callId=s(call.id),canonical=canonicalizeSkillName(skillNameFromPath(filePath));rows.push(skillRecord(identity,canonical,"model",{skill_path:filePath,args_raw:maybeArgsRaw("omp",String(call.name??"read"),args)??null,args_digest:argsDigest(args),call_id:callId??null,started_at:ts,evidence_kind:"load",status:"unknown",invocation_id:invocationIdFor(context,identity.sessionId,{callId,recordId:callId===void 0?recordId:void 0,ordinal:rows.length}),...originFields(context,canonical,{skillPath:filePath})}))}}return rows}if(role==="user"){let text=extractContentText(msg?.content??raw.content);if(text===void 0)return[];let ordinal=createOrdinalAllocator(),wrapper=leadingInjectionMatch(text,PI_SKILL_WRAPPER_ANCHORED);if(wrapper!==null){let skillPath=wrapper[2]||null,canonical=canonicalizeSkillName(wrapper[1]??"");if(canonical.length>0)rows.push(skillRecord(identity,canonical,"user",{skill_path:skillPath,started_at:ts,evidence_kind:"load",status:"ok",invocation_id:invocationIdFor(context,identity.sessionId,{recordId,ordinal:ordinal(`skill:${canonical}`)}),...originFields(context,canonical,{skillPath})}))}}return rows}var CODEX_SKILL_BLOCK=/<skill>\s*<name>([^<]+)<\/name>\s*<path>([^<]+)<\/path>([\s\S]*?)<\/skill>/g,CODEX_DOLLAR_MARKER=/^\$([a-z][a-z0-9]*(?:-[a-z0-9]+)*)(?![\w./:])/,CODEX_SLASH_MARKER=/^\/([a-z][a-z0-9]*(?:-[a-z0-9]+)*)(?![\w./:])/,CODEX_SHELL_TOOLS=new Set(["shell","exec_command","exec"]);function detectCodexSkillCalls(raw,identity,context){let payload=raw.payload??raw,recordType=String(raw.type??""),payloadType=String(payload.type??""),role;if(recordType==="response_item")role=payloadType==="message"?mapRole(payload.role):payloadType==="agent_message"?"assistant":payloadType==="function_call"||payloadType==="custom_tool_call"?"tool":"meta";else if(recordType==="user"||recordType==="assistant")role=mapRole(recordType);else if(recordType==="message")role=mapRole(raw.role??payload.role);else return[];if(role==="tool"){let toolName=String(payload.name??"");if(!CODEX_SHELL_TOOLS.has(toolName)&&!toolName.endsWith(".exec"))return[];let callId=s(payload.call_id,payload.id),argsText=s(payload.arguments,payload.input);if(argsText===void 0)return[];let rows2=[],ts2=timestampOf(raw.timestamp,raw.ts,payload.created_at)??null,command=null;try{let parsed=JSON.parse(argsText);if(typeof parsed==="object"&&parsed!==null){let cmd=parsed.command;if(typeof cmd==="string")command=cmd;else if(Array.isArray(cmd))command=cmd.filter((c)=>typeof c==="string").join(" ")}}catch{command=null}let pushRead=(target,ordinal2)=>{let canonical=canonicalizeSkillName(skillNameFromPath(target));rows2.push(skillRecord(identity,canonical,"model",{skill_path:target,args_raw:argsText,args_digest:sha256Text(argsText),call_id:callId??null,started_at:ts2,evidence_kind:"load",status:"unknown",invocation_id:invocationIdFor(context,identity.sessionId,{callId:callId??recordIdFallback(raw),ordinal:ordinal2}),...originFields(context,canonical,{skillPath:target})}))};if(command!==null)for(let i=0;i<parseLiteralReadTargets(command).length;i+=1)pushRead(parseLiteralReadTargets(command)[i]??"",i);let nestedLiterals=extractNestedExecCommandLiterals(argsText),nestedOrdinal=0;for(let literal2 of nestedLiterals)for(let target of parseLiteralReadTargets(literal2))pushRead(target,1000+nestedOrdinal),nestedOrdinal+=1;return rows2}if(role!=="user")return[];let text=extractContentText(payload.content??raw.content)??s(payload.text,raw.text);if(text===void 0)return[];let rows=[],recordId=s(raw.id,payload.id,raw.uuid),ts=timestampOf(raw.timestamp,raw.ts)??null,ordinal=createOrdinalAllocator(),wrappers=[],acceptedWrapperEnd;for(let match of text.matchAll(CODEX_SKILL_BLOCK)){let start=match.index??0;if(isQuotedSignatureContext(text,start))continue;if(!isCodexWrapperLeadPosition(text,start,acceptedWrapperEnd))continue;acceptedWrapperEnd=start+match[0].length;let body=(match[3]??"").trim(),skillPath=match[2]||null;wrappers.push({name:canonicalizeSkillName(match[1]??""),path:skillPath,digest:body.length>0?sha256Text(body):null})}let wrapperOccurrences=new Map;for(let wrapper of wrappers){let occurrence=(wrapperOccurrences.get(wrapper.name)??0)+1;wrapperOccurrences.set(wrapper.name,occurrence);let ordinalKey=occurrence===1?`skill:${wrapper.name}`:`skill:${wrapper.name}#${occurrence}`;rows.push(skillRecord(identity,wrapper.name,"user",{skill_path:wrapper.path,args_digest:wrapper.digest,started_at:ts,evidence_kind:"load",status:"ok",invocation_id:invocationIdFor(context,identity.sessionId,{recordId,ordinal:ordinal(ordinalKey)}),...originFields(context,wrapper.name,{skillPath:wrapper.path,artifactDigest:wrapper.digest})}))}let leadingMarker=text.match(CODEX_DOLLAR_MARKER)??text.match(CODEX_SLASH_MARKER);if(leadingMarker!==null){let markerName=canonicalizeSkillName(leadingMarker[1]??"");rows.push(skillRecord(identity,markerName,"user",{started_at:ts,evidence_kind:"request",status:"unknown",invocation_id:invocationIdFor(context,identity.sessionId,{recordId,ordinal:ordinal(`skill:${markerName}`)}),...originFields(context,markerName,{})}))}return rows}function recordIdFallback(raw){return s(raw.id,raw.uuid)??"codex-record"}function detectAgySkillCalls(raw,identity,context){let recordType=String(raw.type??""),recordId=s(raw.id,raw.event_id,raw.request_id),ts=timestampOf(raw.created_at,raw.timestamp,raw.ts)??null,rows=[];if(recordType==="PLANNER_RESPONSE"&&Array.isArray(raw.tool_calls))for(let tc of raw.tool_calls){let tool=s(tc.name,tc.tool_name);if(tool==="view_file"){let args=tc.args??tc.arguments??{};if(args.toolAction!=="Viewing skill file")continue;let path=s(args.AbsolutePath,args.absolute_path);if(path===void 0||lastPathSegmentNorm(path)!=="SKILL.md")continue;let skillName=s(args.toolSummary)?.match(/SKILL\.md for (.+)$/)?.[1]??skillNameFromPath(path),canonical=canonicalizeSkillName(skillName),callId=s(tc.id,tc.call_id);rows.push(skillRecord(identity,canonical,"model",{skill_path:path,args_raw:maybeArgsRaw("agy","view_file",args)??null,args_digest:argsDigest(args),call_id:callId??null,started_at:ts,evidence_kind:"load",status:"unknown",invocation_id:invocationIdFor(context,identity.sessionId,{callId,recordId:callId===void 0?recordId:void 0,ordinal:rows.length}),...originFields(context,canonical,{skillPath:path})}));continue}if(tool==="INVOKE_SUBAGENT"){let args=tc.args??tc.arguments??{},subagent=s(args.subagent_type,args.subagent,args.agent_name,args.agent,args.name)??"subagent",callId=s(tc.id,tc.call_id);rows.push(skillRecord(identity,subagent,"model",{args_raw:maybeArgsRaw("agy","INVOKE_SUBAGENT",args)??null,args_digest:argsDigest(args),call_id:callId??null,started_at:ts,...originFields(context,canonicalizeSkillName(subagent),{}),capability_kind:"subagent",evidence_kind:"delegation",status:"unknown",invocation_id:invocationIdFor(context,identity.sessionId,{callId,recordId:callId===void 0?recordId:void 0,ordinal:rows.length})}))}}if(recordType==="slash_command"){let display=s(raw.display);if(display!==void 0){let commandName=s(raw.command,raw.name)??display.match(/(?:^|\s)\/([a-z][a-z0-9:-]*)/)?.[1];if(commandName!==void 0)rows.push(skillRecord(identity,canonicalizeSkillName(commandName),"user",{started_at:ts,capability_kind:"command",evidence_kind:"request",status:"unknown",invocation_id:invocationIdFor(context,identity.sessionId,{recordId,ordinal:0})}))}}return rows}var GEMINI_L0_PREFIX=/^\s*\/((?:sp|rd3)-[a-z0-9-]+)/;function detectGeminiSkillCalls(raw,identity,context){if(String(raw.type??"")!=="user")return[];let content=geminiContent(raw);if(content===null)return[];let match=content.match(GEMINI_L0_PREFIX);if(match===null)return[];let canonical=canonicalizeSkillName(match[1]??""),recordId=s(raw.id,raw.uuid),ts=timestampOf(raw.timestamp,raw.ts)??null;return[skillRecord(identity,canonical,"user",{started_at:ts,evidence_kind:"request",status:"unknown",invocation_id:invocationIdFor(context,identity.sessionId,{recordId,ordinal:0}),...originFields(context,canonical,{})})]}function detectGrokSkillCalls(raw,identity,context){let n=normalizeGrokRecord(raw);if(n.recordType!=="tool_call"||n.toolName!=="read_file")return[];let meta3=n.body._meta??raw._meta??{};if(o(meta3["x.ai/tool"]).namespace!=="grok_build")return[];let targetFile=s(o(n.toolArgs).target_file);if(targetFile===void 0||lastPathSegmentNorm(targetFile)!=="SKILL.md")return[];let canonical=canonicalizeSkillName(skillNameFromPath(targetFile)),recordId=s(n.body.id,raw.id,raw.uuid),callId=s(n.body.call_id,n.body.itemId,recordId),status=grokOutcomeStatus(typeof n.body.status==="string"?n.body.status:void 0);return[skillRecord(identity,canonical,"model",{skill_path:targetFile,args_raw:maybeArgsRaw("grok","read_file",n.toolArgs)??null,args_digest:argsDigest(n.toolArgs),call_id:callId??null,started_at:n.ts??null,status,evidence_kind:"load",invocation_id:invocationIdFor(context,identity.sessionId,{callId,ordinal:0}),...originFields(context,canonical,{skillPath:targetFile})})]}function grokOutcomeStatus(toolStatus){let value=String(toolStatus??"").toLowerCase();if(value==="ok"||value==="success"||value==="done"||value==="completed")return"ok";if(value==="error"||value==="failed")return"error";return"unknown"}function argsDigest(args){let redacted=redactArgs(args);return sha256(redacted)}function redactArgs(args){if(typeof args==="string"){if(args.length>80)return"[REDACTED:long]";if(/[A-Za-z0-9+/]{40,}=*|[A-Za-z0-9_-]{20,}/.test(args))return"[REDACTED:secret]";return args}if(Array.isArray(args))return args.map(redactArgs);if(args!==null&&typeof args==="object"){let result={};for(let[key,value]of Object.entries(args))result[key]=redactArgs(value);return result}return args}var BASH_COMMAND_MAX_CHARS=8192,GENERIC_ARGS_MAX_CHARS=8192;function bashCommandOf(args){if(args===null||typeof args!=="object")return;let rec=args,command=rec.command??rec.CommandLine??rec.cmd??rec.script;if(typeof command==="string")return command;if(Array.isArray(command))return command.map(String).join(" ");return}var BULKY_PAYLOAD_KEYS=new Set(["content","codecontent","replacementcontent","targetcontent","filedata","buffer","blob","image","imagebase64"]);function normalizeKey(key){return key.toLowerCase().replace(/[^a-z0-9]/g,"")}function isShellTool(toolName){return/^(?:bash|shell|cmd|command|exec|execcommand|executecommand|runcommand|shellcommand|runshellcommand)$/.test(normalizeKey(toolName))}function sanitizeValue(value){if(typeof value==="string")return value.length>1000?`${value.slice(0,1000)}[truncated ${value.length} chars]`:value;if(Array.isArray(value))return value.map(sanitizeValue);if(value!==null&&typeof value==="object"){let out={};for(let[key,entry]of Object.entries(value))out[key]=typeof entry==="string"&&entry.length>120&&BULKY_PAYLOAD_KEYS.has(normalizeKey(key))?`[omitted ${entry.length} chars]`:sanitizeValue(entry);return out}return value}function serializeBounded(value){let serialized=JSON.stringify(sanitizeValue(value));if(serialized.length<=GENERIC_ARGS_MAX_CHARS)return serialized;let preview=serialized;for(;;){let wrapper=JSON.stringify({_truncated:!0,omittedChars:serialized.length-preview.length,preview});if(wrapper.length<=GENERIC_ARGS_MAX_CHARS)return wrapper;preview=preview.slice(0,preview.length-(wrapper.length-GENERIC_ARGS_MAX_CHARS))}}function maybeArgsRaw(_source,toolName,args){if(args===void 0||args===null)return;let value=args;if(typeof args==="string")try{value=JSON.parse(args)}catch{return args.length>BASH_COMMAND_MAX_CHARS?args.slice(0,BASH_COMMAND_MAX_CHARS):args}if(value!==null&&typeof value==="object"){let cmd=bashCommandOf(value);if(cmd!==void 0&&isShellTool(toolName))return cmd.length>BASH_COMMAND_MAX_CHARS?cmd.slice(0,BASH_COMMAND_MAX_CHARS):cmd;return serializeBounded(value)}return JSON.stringify(value)}function claudeSplit(raw,context){let entries=[],sessionId=s(raw.sessionId,raw.conversation_uuid)??"unknown",seq=typeof raw.seq==="number"?raw.seq:typeof raw.messageIndex==="number"?raw.messageIndex:0,ts=timestampOf(raw.ts,raw.timestamp,raw.createdAt),role=mapRole(raw.type??raw.role),recordType=String(raw.type??""),model=s(raw.model,o(raw.message).model),cwd=s(raw.cwd,raw.dir);if(raw.subtype==="turn_duration"&&typeof raw.durationMs==="number")return entries.push({targetTable:"history_message",record:{session_id:sessionId,seq,role:"system",record_type:"turn_duration",disposition:"meta",ts,duration_ms:raw.durationMs,content_text:null,provenance:"ambient"}}),entries;if(recordType==="attachment"||recordType.startsWith("file-history"))return entries.push({targetTable:"history_message",record:{session_id:sessionId,seq,role:"meta",record_type:recordType,disposition:"meta",ts,provenance:"ambient"}}),entries;let usage=typeof raw.usage==="object"&&raw.usage!==null?raw.usage:o(raw.message).usage,inputTokens=raw.inputTokens??usage?.input_tokens,outputTokens=raw.outputTokens??usage?.output_tokens,cacheRead=usage?.cacheReadTokens??usage?.cache_read_tokens??usage?.cache_read_input_tokens,cacheWrite=usage?.cacheWriteTokens??usage?.cache_write_tokens??usage?.cache_creation_input_tokens,costUsd=computeCost(inputTokens,outputTokens,model),contentBlocks=raw.content??o(raw.message).content,contentText=extractContentText(contentBlocks),messageSplitIndex=entries.length;if(entries.push({targetTable:"history_message",record:{session_id:sessionId,seq,turn_index:typeof raw.turnIndex==="number"?raw.turnIndex:void 0,role,record_type:recordType,disposition:"keep",ts,duration_ms:void 0,model:model??null,input_tokens:inputTokens??null,output_tokens:outputTokens??null,cache_read_tokens:cacheRead??null,cache_write_tokens:cacheWrite??null,cost_usd:costUsd??null,content_text:contentText??null,cwd:cwd??null,provenance:"ambient",request_id:s(raw.requestId)??null}}),Array.isArray(contentBlocks)&&role==="assistant")for(let block of contentBlocks){if(typeof block!=="object"||block===null)continue;let b=block;if(b.type==="tool_use")entries.push({targetTable:"history_tool_call",record:{_messageSplitIndex:messageSplitIndex,session_id:sessionId,seq,call_id:s(b.id),tool_name:String(b.name??""),args_digest:argsDigest(b.input),args_raw:maybeArgsRaw("claude",String(b.name??""),b.input),status:"ok",started_at:void 0,completed_at:void 0,duration_ms:void 0,result_bytes:void 0,error_text:void 0}})}for(let record2 of extractSkillCalls(raw,context,{sessionId,seq,messageSplitIndex}))entries.push(skillCallEntry(record2));return entries}function piSplit(raw,context){let msg=raw.message,recordType=String(raw.type??raw.recordType??""),sessionId=sessionIdFromContext(context,raw),seq=context?.sourceLine??(typeof raw.seq==="number"?raw.seq:0),ts=timestampOf(raw.timestamp,raw.createdAt,raw.ts);if(recordType==="title"||recordType==="title_change"||recordType==="service_tier_change"||recordType==="session_info"||recordType==="ttsr_injection"||recordType==="session_init"||recordType==="session"||recordType==="model_change"||recordType==="thinking_level_change"||recordType==="compaction"||recordType==="custom"||recordType==="custom_message"||recordType.startsWith("custom."))return[{targetTable:"history_message",record:{session_id:sessionId,seq,role:"meta",record_type:recordType,disposition:"meta",ts,provenance:"ambient"}}];let entries=[],role=piRole(msg?.role??raw.role??recordType),model=s(raw.model,o(msg).model),cwd=s(raw.cwd,raw.dir),usage=msg?.usage??raw.usage,inputTokens=usage?.input??usage?.input_tokens??void 0,outputTokens=usage?.output??usage?.output_tokens??void 0,cacheRead=usage?.cacheRead??usage?.cache_read_tokens??void 0,cacheWrite=usage?.cacheWrite??usage?.cache_write_tokens??void 0,costObj=msg?.cost??raw.cost,costUsd=typeof costObj?.total==="number"?costObj.total:computeCost(inputTokens,outputTokens,model),contentBlocks=msg?.content??raw.content,durationMs=typeof msg?.duration==="number"&&Number.isFinite(msg.duration)?msg.duration:void 0,messageSplitIndex=entries.length;if(entries.push({targetTable:"history_message",record:{session_id:sessionId,seq,role,record_type:recordType,disposition:"keep",ts,duration_ms:durationMs,model:model??null,input_tokens:inputTokens??null,output_tokens:outputTokens??null,cache_read_tokens:cacheRead??null,cache_write_tokens:cacheWrite??null,cost_usd:costUsd??null,content_text:extractContentText(contentBlocks)??s(raw.content,raw.text,msg?.content)??null,cwd:cwd??null,provenance:"ambient"}}),Array.isArray(contentBlocks)&&role==="assistant")for(let block of contentBlocks){let call=normalizeOmpToolCall(block);if(call===null)continue;entries.push({targetTable:"history_tool_call",record:{_messageSplitIndex:messageSplitIndex,session_id:sessionId,seq,tool_name:String(call.name??""),call_id:s(call.id),args_digest:argsDigest(call.input??call.arguments),args_raw:maybeArgsRaw("pi",String(call.name??""),call.input??call.arguments),status:"ok",started_at:void 0,completed_at:void 0,duration_ms:void 0,result_bytes:void 0,error_text:void 0}})}for(let record2 of extractSkillCalls(raw,context,{sessionId,seq,messageSplitIndex}))entries.push(skillCallEntry(record2));return entries}function piRole(type){let t=String(type??"").toLowerCase();if(t==="toolresult"||t==="tool_result"||t==="bashexecution"||t==="tool")return"user";let mapped=mapRole(t);if(mapped==="user"||mapped==="assistant"||mapped==="system")return mapped;return"unknown"}function ompSplit(raw,context){let msg=raw.message,recordType=String(raw.type??""),sessionId=sessionIdFromContext(context,raw),seq=context?.sourceLine??(typeof raw.seq==="number"?raw.seq:0),ts=timestampOf(raw.ts,raw.timestamp,raw.createdAt);if(recordType==="title"||recordType==="title_change"||recordType==="service_tier_change"||recordType==="ttsr_injection"||recordType==="session_init"||recordType==="session"||recordType==="model_change"||recordType==="thinking_level_change"||recordType==="compaction"||recordType==="custom"||recordType==="custom_message"||recordType.startsWith("custom."))return[{targetTable:"history_message",record:{session_id:sessionId,seq,role:"meta",record_type:recordType,disposition:"meta",ts,provenance:"ambient"}}];let entries=[],role=mapRole(msg?.role??raw.type??raw.role),model=s(raw.model,o(msg).model),cwd=s(raw.cwd,raw.dir),usage=msg?.usage??raw.usage,inputTokens=usage?.input??usage?.input_tokens??void 0,outputTokens=usage?.output??usage?.output_tokens??void 0,cacheRead=usage?.cacheRead??usage?.cache_read_tokens??void 0,cacheWrite=usage?.cacheWrite??usage?.cache_write_tokens??void 0,costObj=msg?.cost??raw.cost,costUsd=typeof costObj?.total==="number"?costObj.total:computeCost(inputTokens,outputTokens,model),contentBlocks=msg?.content??raw.content,durationMs=typeof msg?.duration==="number"&&Number.isFinite(msg.duration)?msg.duration:void 0,messageSplitIndex=entries.length;if(entries.push({targetTable:"history_message",record:{session_id:sessionId,seq,role,record_type:recordType,disposition:"keep",ts,duration_ms:durationMs,model:model??null,input_tokens:inputTokens??null,output_tokens:outputTokens??null,cache_read_tokens:cacheRead??null,cache_write_tokens:cacheWrite??null,cost_usd:costUsd??null,content_text:extractContentText(contentBlocks)??s(raw.content,raw.text,msg?.content)??null,cwd:cwd??null,provenance:"ambient"}}),Array.isArray(contentBlocks)&&role==="assistant")for(let block of contentBlocks){let call=normalizeOmpToolCall(block);if(call===null)continue;entries.push({targetTable:"history_tool_call",record:{_messageSplitIndex:messageSplitIndex,session_id:sessionId,seq,tool_name:String(call.name??""),call_id:s(call.id),args_digest:argsDigest(call.input??call.arguments),args_raw:maybeArgsRaw("omp",String(call.name??""),call.input??call.arguments),status:"ok",started_at:void 0,completed_at:void 0,duration_ms:void 0,result_bytes:void 0,error_text:void 0}})}for(let record2 of extractSkillCalls(raw,context,{sessionId,seq,messageSplitIndex}))entries.push(skillCallEntry(record2));return entries}function normalizeOmpToolCall(block){if(typeof block!=="object"||block===null)return null;let nested=o(block.toolCall);if(Object.keys(nested).length>0)return nested;if(block.type==="toolCall")return block;return null}function codexSplit(raw,context){let entries=[],payload=raw.payload??raw,seq=typeof raw.seq==="number"?raw.seq:0,ts=timestampOf(raw.timestamp,raw.ts,payload.ts),recordType=String(raw.type??""),payloadType=String(payload.type??""),isShortFormat=recordType===""&&raw.id!==void 0&&raw.timestamp!==void 0&&raw.instructions!==void 0,explicitSessionId=s(raw.session_id,o(raw.session_meta).id);if(explicitSessionId===void 0&&recordType==="session_meta")explicitSessionId=s(payload.id,o(raw.payload).id);if(explicitSessionId===void 0&&isShortFormat)explicitSessionId=s(raw.id);let pathSessionId=context?.sourceFile?sessionIdFromSourcePath("codex",context.sourceFile):void 0,sessionId=explicitSessionId??pathSessionId??"unknown";if(isShortFormat)return[{targetTable:"history_message",record:{session_id:sessionId,seq,role:"meta",record_type:"short_format",disposition:"meta",ts,provenance:"ambient"}}];let role,disposition,contentText,usage;if(recordType==="response_item")if(payloadType==="message")role=mapRole(payload.role),disposition="keep",contentText=extractContentText(payload.content)??s(payload.text)??null;else if(payloadType==="agent_message")role="assistant",disposition="keep",contentText=extractContentText(payload.content)??s(payload.text,payload.message)??null;else if(payloadType==="reasoning")role="assistant",disposition="keep",contentText=extractContentText(payload.summary)??s(payload.text)??null;else if(payloadType==="function_call"||payloadType==="custom_tool_call")role="tool",disposition="keep",contentText=null;else role="meta",disposition="meta",contentText=s(payload.text)??null;else if(recordType==="user"||recordType==="assistant")role=mapRole(recordType),disposition="keep",contentText=extractContentText(payload.content)??s(raw.content,payload.text)??null;else if(recordType==="message")role=mapRole(raw.role??payload.role),disposition="keep",contentText=extractContentText(payload.content??raw.content)??s(payload.text,raw.text)??null;else if(recordType==="event_msg")role="meta",disposition="meta",contentText=s(payload.message,payload.text)??null,usage=o(o(payload.info).last_token_usage);else role="meta",disposition="meta",contentText=s(payload.text,raw.instructions)??null;let model=s(raw.model,payload.model,o(o(raw.turn_context).payload).model),cwd=s(raw.cwd,raw.dir),tokenCount=payload.token_count,usageInput=usage?.input_tokens??tokenCount?.input??tokenCount?.input_tokens??void 0,usageOutput=usage?.output_tokens??tokenCount?.output??tokenCount?.output_tokens??void 0,cacheRead=usage?.cached_input_tokens??void 0,turnPayload=raw.turn_context?.payload,turnInputTokens=turnPayload?.input_tokens,turnOutputTokens=turnPayload?.output_tokens,finalInput=usageInput!==void 0?usageInput:turnInputTokens,finalOutput=usageOutput!==void 0?usageOutput:turnOutputTokens,costUsd=computeCost(finalInput,finalOutput,model),usageCarrier=finalInput!==void 0||finalOutput!==void 0?{input:finalInput??null,output:finalOutput??null,cacheRead:cacheRead??null}:void 0,stripUsage=role==="meta"&&usageCarrier!==void 0,messageSplitIndex=entries.length;entries.push({targetTable:"history_message",record:{session_id:sessionId,seq,role,record_type:recordType,disposition,ts,duration_ms:void 0,model:model??null,input_tokens:stripUsage?null:finalInput??null,output_tokens:stripUsage?null:finalOutput??null,cache_read_tokens:stripUsage?null:cacheRead??null,...usageCarrier!==void 0?{_codexUsageCarrier:usageCarrier}:{},cache_write_tokens:null,cost_usd:costUsd??null,content_text:contentText,cwd:cwd??null,provenance:"ambient"}});let toolItems=[];if((recordType==="response_item"||recordType==="function_call"||recordType==="custom_tool_call")&&(payloadType==="function_call"||payloadType==="custom_tool_call"))toolItems.push(payload);else if(payload.response_item)toolItems.push(payload.response_item);else if(Array.isArray(payload.response_items))toolItems.push(...payload.response_items);for(let item of toolItems){let fc=item.function_call??item,toolName=s(fc.name)??"",args=fc.arguments??fc.input;entries.push({targetTable:"history_tool_call",record:{_messageSplitIndex:messageSplitIndex,session_id:sessionId,seq,tool_name:toolName,call_id:s(fc.call_id),args_digest:argsDigest(args),args_raw:maybeArgsRaw("codex",toolName,args),status:"ok",started_at:void 0,completed_at:void 0,duration_ms:void 0,result_bytes:void 0,error_text:void 0}})}for(let record2 of extractSkillCalls(raw,context,{sessionId,seq,messageSplitIndex}))entries.push(skillCallEntry(record2));return entries}function agySplit(raw,context){let entries=[],recordType=String(raw.type??""),explicitSessionId=s(raw.session_id,raw.conversation_id,raw.conversationId),pathSessionId=context?.sourceFile?sessionIdFromSourcePath("agy",context.sourceFile):void 0,sessionId=explicitSessionId??pathSessionId??"unknown",seq=typeof raw.seq==="number"?raw.seq:typeof raw.step_index==="number"?raw.step_index:context?.sourceLine??0,ts=timestampOf(raw.created_at,raw.timestamp,raw.ts),role,disposition,contentText=null,messageRecordType=recordType;if(raw.display!==void 0)role="user",disposition="keep",contentText=s(raw.display)??null,messageRecordType=recordType.length>0?recordType:"USER_INPUT";else switch(recordType){case"USER_INPUT":case"ASK_QUESTION":role="user",disposition="keep",contentText=s(raw.content,raw.text,raw.message)??null;break;case"PLANNER_RESPONSE":role="assistant",disposition="keep",contentText=s(raw.content,raw.text,raw.message,raw.plan)??null;break;case"ERROR_MESSAGE":role="system",disposition="keep",contentText=s(raw.content,raw.text,raw.message)??null;break;case"RUN_COMMAND":case"VIEW_FILE":case"GREP_SEARCH":case"LIST_DIRECTORY":case"READ_URL_CONTENT":role="tool",disposition="keep",contentText=s(raw.content,raw.command,raw.file_path,raw.pattern)??null;break;case"CODE_ACTION":case"INVOKE_SUBAGENT":role="tool",disposition="keep",contentText=s(raw.content,raw.text)??null;break;case"CONVERSATION_HISTORY":case"CHECKPOINT":case"GENERIC":role="meta",disposition="meta",contentText=s(raw.content,raw.text)??null;break;default:if(recordType.length===0)role="unknown",disposition="unknown";else role="meta",disposition="meta",contentText=s(raw.content,raw.text)??null;break}let messageSplitIndex=entries.length;if(entries.push({targetTable:"history_message",record:{session_id:sessionId,seq,role,record_type:messageRecordType,disposition,ts,duration_ms:void 0,model:null,input_tokens:null,output_tokens:null,cache_read_tokens:null,cache_write_tokens:null,cost_usd:null,content_text:contentText,cwd:s(raw.workspace,raw.cwd)??null,provenance:"ambient"}}),recordType==="PLANNER_RESPONSE"&&Array.isArray(raw.tool_calls))for(let tc of raw.tool_calls)entries.push({targetTable:"history_tool_call",record:{_messageSplitIndex:messageSplitIndex,session_id:sessionId,seq:typeof tc.step_index==="number"?tc.step_index:seq,tool_name:String(tc.name??tc.tool_name??""),args_digest:argsDigest(tc.input??tc.arguments),args_raw:maybeArgsRaw("agy",String(tc.name??tc.tool_name??""),tc.input??tc.arguments),status:"ok",started_at:void 0,completed_at:void 0,duration_ms:void 0,result_bytes:void 0,error_text:void 0}});for(let record2 of extractSkillCalls(raw,context,{sessionId,seq,messageSplitIndex}))entries.push(skillCallEntry(record2));return entries}function geminiSplit(raw,context){let recordType=String(raw.type??(raw.kind!==void 0?"session":raw.$set!==void 0?"state":"")),state=o(raw.$set),sessionId=sessionIdFromContext(context,raw),seq=context?.sourceLine??0,ts=timestampOf(raw.timestamp,raw.startTime,raw.lastUpdated,state.lastUpdated);if(recordType==="session"||recordType==="state")return[{targetTable:"history_message",record:{session_id:sessionId,seq,role:"meta",record_type:recordType,disposition:"meta",ts,content_text:s(state.summary)??null,provenance:"ambient"}}];let role=recordType==="gemini"?"assistant":recordType==="user"?"user":"system",tokens=o(raw.tokens),content=geminiContent(raw),entries=[{targetTable:"history_message",record:{session_id:sessionId,seq,role,record_type:recordType,disposition:"keep",ts,duration_ms:null,model:s(raw.model)??null,input_tokens:numberOrNull(tokens.input),output_tokens:numberOrNull(tokens.output),cache_read_tokens:numberOrNull(tokens.cached),cache_write_tokens:null,cost_usd:null,content_text:content,cwd:null,provenance:"ambient"}}];if(Array.isArray(raw.toolCalls))for(let value of raw.toolCalls){if(value===null||typeof value!=="object"||Array.isArray(value))continue;let tool=value,status=s(tool.status)??"unknown",timestamp=s(tool.timestamp),result=tool.result??tool.resultDisplay;entries.push({targetTable:"history_tool_call",record:{_messageSplitIndex:0,session_id:sessionId,seq,tool_name:s(tool.name,tool.displayName)??"unknown",args_digest:argsDigest(tool.args),args_raw:maybeArgsRaw("gemini",s(tool.name,tool.displayName)??"",tool.args),status,started_at:timestamp,completed_at:timestamp,duration_ms:null,result_bytes:result===void 0?null:new TextEncoder().encode(JSON.stringify(result)).byteLength,error_text:status==="error"?s(tool.resultDisplay,tool.result)??null:null}})}for(let record2 of extractSkillCalls(raw,context,{sessionId,seq,messageSplitIndex:0}))entries.push(skillCallEntry(record2));return entries}function dshSplit(raw,context){let recordType=String(raw.type??"");if(recordType==="session")return[{targetTable:"history_message",record:{session_id:s(raw.id)??sessionIdFromSourcePath("deepseek",context?.sourceFile??"")??"unknown",seq:0,role:"meta",record_type:"session",disposition:"meta",ts:timestampOf(raw.createdAt),cwd:s(raw.cwd)??null,content_text:null,provenance:"ambient"}}];if(recordType!=="user/message"&&recordType!=="assistant/message")return[];let data=o(raw.data),msg=o(data.message),seq=typeof raw.seq==="number"?raw.seq:context?.sourceLine??0,sessionId=sessionIdFromSourcePath("deepseek",context?.sourceFile??"")??"unknown",role=recordType==="user/message"?"user":"assistant",source=o(data.source??msg.source),model=s(source.model,o(data.model??msg.model).model),usage=data.usage??msg.usage,messageId=s(msg.id,data.id);return[{targetTable:"history_message",record:{session_id:sessionId,seq,role,record_type:recordType,disposition:"keep",...messageId!==void 0?{source_record_id:messageId}:{},ts:timestampOf(raw.time,data.time,msg.time),duration_ms:null,model:model??null,input_tokens:numberOrNull(usage?.input_tokens??usage?.input)??null,output_tokens:numberOrNull(usage?.output_tokens??usage?.output)??null,cache_read_tokens:null,cache_write_tokens:null,cost_usd:null,content_text:extractContentText(data.content??msg.content)??s(data.text,msg.text)??null,cwd:null,provenance:"ambient"}}]}var UUID_PATTERN="[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}",AGY_BRAIN_REGEX=new RegExp(`(?:^|\\/)brain\\/(${UUID_PATTERN})(?:\\/|$)`,"i"),DSH_SESSION_REGEX=new RegExp(`(?:^|\\/)session-(${UUID_PATTERN})(?:\\/|$)`,"i"),CODEX_ROLLOUT_REGEX=new RegExp(`(?:^|-|_)(${UUID_PATTERN})$`,"i");function sessionIdFromSourcePath(source,sourceFile){let normalized=sourceFile.replace(/\\/g,"/"),sLower=source.toLowerCase();if(sLower==="agy"||sLower==="antigravity")return normalized.match(AGY_BRAIN_REGEX)?.[1];if(sLower==="deepseek")return normalized.match(DSH_SESSION_REGEX)?.[1];if(sLower==="codex"){let basename=normalized.split("/").at(-1)??"";if(basename.startsWith("rollout-")&&basename.endsWith(".jsonl"))return basename.slice(0,-6).match(CODEX_ROLLOUT_REGEX)?.[1]}return}function sessionIdFromContext(context,raw){if(context!==void 0){let file2=context.sourceFile.split("/").at(-1);if(file2!==void 0)return file2.replace(/\.jsonl$/,"")}return s(raw.sessionId,raw.id)??"unknown"}function geminiContent(raw){let content=extractContentText(raw.content)??s(raw.text),thoughts=Array.isArray(raw.thoughts)?raw.thoughts.map((value)=>value!==null&&typeof value==="object"?s(o(value).description):void 0).filter((value)=>value!==void 0).join(`
|
|
528
541
|
`):"";return[content,thoughts].filter((value)=>value!==void 0&&value.length>0).join(`
|
|
529
542
|
`)||null}function numberOrNull(value){return typeof value==="number"&&Number.isFinite(value)?value:null}function normalizeGrokRecord(raw){let params=raw.params,update=params?.update,isUpdatesShape=typeof raw.method==="string"&¶ms!==void 0&&update!==void 0,body=isUpdatesShape?update:raw,recordType=String((isUpdatesShape?update?.sessionUpdate:raw.type)??raw.sessionUpdate??raw.eventType??(raw.file_snapshots!==void 0||raw.after_snapshots!==void 0?"file_snapshot":raw.prompt!==void 0?"user_message":raw.answer!==void 0||raw.question!==void 0?"assistant":"")),sessionId=s(params?.sessionId,raw.session_id,raw.sessionId,raw.parentSessionId,raw.btwSessionId,raw.params?.sessionId)??"unknown",ts=normalizeTs(raw.ts??raw.timestamp??raw.created_at??raw.askedAt??body.ts??body.timestamp),seq=typeof raw.seq==="number"?raw.seq:typeof body.seq==="number"?body.seq:0,meta3=body._meta??params?._meta??raw._meta,model=s(meta3?.modelId,body.model,raw.model),contentText=extractGrokContent(body.content??body.text??raw.content??raw.text??raw.prompt??(raw.answer!==void 0||raw.question!==void 0?[raw.question,raw.answer].filter((value)=>typeof value==="string").join(`
|
|
530
543
|
`):void 0)),usage=body.usage??raw.usage,toolMeta=meta3?.["x.ai/tool"],titleFallback=s(body.title)?.split("`")[0]?.trim(),toolName=s(toolMeta?.name,body.kind,body.tool_name,body.name,raw.tool_name,raw.name)??(titleFallback!==void 0&&titleFallback.length>0&&titleFallback.length<=40?titleFallback:""),toolArgs=body.rawInput??body.input??body.arguments??toolMeta?.input??raw.input??raw.arguments,toolStatus=s(body.status,raw.outcome,raw.status)??"ok",durationMs=typeof body.duration_ms==="number"?body.duration_ms:typeof raw.duration_ms==="number"?raw.duration_ms:typeof usage?.apiDurationMs==="number"?usage.apiDurationMs:void 0,errorText=body.error!==void 0?String(body.error):raw.error!==void 0?String(raw.error):void 0,hasTypeDiscriminator=recordType.length>0||isUpdatesShape;return{recordType,sessionId,ts,seq,body,model,contentText,usage,toolName,toolArgs,toolStatus,durationMs,errorText,hasTypeDiscriminator}}function normalizeTs(value){return timestampOf(value)}function extractGrokContent(content){if(typeof content==="string")return content;if(content!==null&&typeof content==="object"&&!Array.isArray(content)){let c=content;if(typeof c.text==="string")return c.text;if(typeof c.content==="string")return c.content}if(Array.isArray(content)){let parts=[];for(let block of content)if(typeof block==="string")parts.push(block);else if(block!==null&&typeof block==="object"){let b=block;if(typeof b.text==="string")parts.push(b.text)}return parts.length>0?parts.join(`
|
|
@@ -579,7 +592,7 @@ CREATE INDEX IF NOT EXISTS idx_history_skill_call_invocation_kind
|
|
|
579
592
|
WHERE id = ?3 AND status IN ('running', 'pending', 'paused', 'interrupted')`,nowIso,"cancelled by operator (spur workflow cancel)",runId)}async setPid(runId,pid){await this.adapter.run("UPDATE runs SET pid = ? WHERE id = ?",pid,runId)}async getPid(runId){return(await this.adapter.queryFirst("SELECT pid FROM runs WHERE id = ?",runId))?.pid??null}}async function redirectRunStorageReferences(db2,moves){let paths=new Map(moves.map((move)=>[move.source,move.target])),rewrite=(value)=>{if(typeof value==="string")return paths.get(value)??value;if(Array.isArray(value))return value.map(rewrite);if(value!==null&&typeof value==="object")return Object.fromEntries(Object.entries(value).map(([key,item])=>[key,rewrite(item)]));return value};await db2.exec("SAVEPOINT spur_storage_references");try{if((await db2.queryAll("SELECT a.path FROM artifacts a JOIN runs r ON r.id=a.run_id WHERE r.status NOT IN ('done','failed','cancelled')")).some((row)=>paths.has(row.path)))throw Error("live artifact consumer");for(let[table3,column2,owner]of[["runs","metadata_json","id"],["workflow_states","data_json","run_id"]]){let live=await db2.queryAll(`SELECT t.${column2} AS value FROM ${table3} t
|
|
580
593
|
WHERE t.${owner} IN (SELECT id FROM runs WHERE status NOT IN ('done','failed','cancelled'))`);for(let row of live){if(!moves.some((move)=>row.value.includes(move.source)))continue;let original=JSON.parse(row.value);if(JSON.stringify(rewrite(original))!==JSON.stringify(original))throw Error("live session or checkpoint consumer")}}for(let{source,target}of moves)await db2.run("UPDATE artifacts SET path = ? WHERE path = ?",target,source);for(let[table3,column2,owner]of[["runs","metadata_json","id"],["workflow_states","data_json","run_id"],["action_runs","result_json","run_id"]]){let rows=await db2.queryAll(`SELECT t.id, t.${column2} AS value FROM ${table3} t
|
|
581
594
|
WHERE t.${owner} IN (SELECT id FROM runs WHERE status IN ('done', 'failed', 'cancelled'))
|
|
582
|
-
AND t.${column2} IS NOT NULL`);for(let row of rows){if(!moves.some((move)=>row.value.includes(move.source)))continue;let value=JSON.stringify(rewrite(JSON.parse(row.value)));if(value!==row.value)await db2.run(`UPDATE ${table3} SET ${column2} = ? WHERE id = ?`,value,row.id)}}if(await db2.queryFirst("SELECT name FROM sqlite_master WHERE type='table' AND name='history_import_checkpoint'")!==void 0){await normalizeSourceFilePaths(db2,(path7)=>paths.get(path7)??path7);for(let move of moves){if(move.sourceSize===void 0||move.sourceMtimeMs===void 0)continue;await db2.run("UPDATE history_import_checkpoint SET source_size = ?, source_mtime_ms = ? WHERE source_file = ?",move.sourceSize,move.sourceMtimeMs,move.target)}}await db2.exec("RELEASE spur_storage_references")}catch(error51){throw await db2.exec("ROLLBACK TO spur_storage_references"),await db2.exec("RELEASE spur_storage_references"),error51}}var CHILD_TABLES=["action_runs","phase_runs","transition_runs","workflow_states","artifacts","task_run_links"];function insertIfAbsentOps(table3,rows,targetColumns){return rows.map((row)=>{let columns2=Object.keys(row).filter((column2)=>targetColumns.has(column2));return{sql:`INSERT INTO ${table3} (${columns2.join(", ")}) VALUES (${columns2.map(()=>"?").join(", ")}) ON CONFLICT(id) DO NOTHING`,params:columns2.map((column2)=>row[column2])}})}async function tableColumns(db2,table3){let rows=await db2.queryAll(`PRAGMA table_info(${table3})`);return new Set(rows.map((row)=>row.name))}async function listRunIdRows(from){return(await from.queryAll("SELECT id, workflow_name FROM runs")).map((row)=>({id:row.id,workflowName:row.workflow_name}))}async function transferRunTables(from,to){let persistedIds=[],skipped=[],targetRunsColumns=await tableColumns(to,"runs"),sourceRows=await from.queryAll("SELECT * FROM runs");for(let row of sourceRows){let id=String(row.id);if(await to.queryFirst("SELECT id FROM runs WHERE id = ?",id)!==void 0){skipped.push({id,reason:"id-exists"});continue}if(row.external_key!==null&&row.external_key!==void 0){if(await to.queryFirst("SELECT id FROM runs WHERE external_key IS NOT NULL AND workflow_name IS ? AND external_key = ?",row.workflow_name??null,row.external_key)!==void 0){skipped.push({id,reason:"external-key-conflict"});continue}}let ops=insertIfAbsentOps("runs",[row],targetRunsColumns);for(let table3 of CHILD_TABLES)ops.push(...insertIfAbsentOps(table3,await from.queryAll(`SELECT * FROM ${table3} WHERE run_id = ?`,id),await tableColumns(to,table3)));await to.batch(ops),persistedIds.push(id)}return{persistedIds,skipped}}init_schema();var transitionRunsTable=defineTable("transition_runs",{id:text("id").primaryKey(),runId:text("run_id").notNull().references(()=>runs.id),fromState:text("from_state").notNull(),toState:text("to_state").notNull(),trigger:text("trigger"),status:text("status").notNull(),...standardColumns}),transitionRuns=transitionRunsTable.table;init_schema();var workflowStatesTable=defineTable("workflow_states",{id:text("id").primaryKey(),runId:text("run_id").notNull().references(()=>runs.id),state:text("state").notNull(),dataJson:text("data_json").notNull(),...standardColumns}),workflowStates=workflowStatesTable.table;init_dist6();class WorkflowValidationError extends Error{details;constructor(message,details){super(message);this.details=details,this.name="WorkflowValidationError"}}class FSMError extends Error{details;constructor(message,details){super(message);this.details=details,this.name="FSMError"}}class RunCollisionError extends Error{constructor(runId){super(`Workflow run "${runId}" already exists`);this.name="RunCollisionError"}}class WorkflowResumeError extends Error{details;constructor(message,details){super(message);this.details=details,this.name="WorkflowResumeError"}}init_dist7();init_dist6();var RUNTIME_BUILTIN_KEYS=["workflow","runId","task","state","node","iteration","run","runtime"];function runtimeBuiltins(workflowName,stateOrNodeId,runId,transitionsTaken,mode){return{workflow:workflowName,runId,task:workflowName,state:stateOrNodeId,node:stateOrNodeId,iteration:transitionsTaken,run:runId,runtime:mode}}function allowedEnv(names,source=getProcessEnv()){return Object.fromEntries(names.flatMap((name)=>source[name]===void 0?[]:[[name,source[name]]]))}class RunLifecycle{workflowName;mode;runId;externalKey;persistence;events;logger;ownerAttempt;constructor(runId,workflowName,mode,deps,externalKey){this.workflowName=workflowName,this.mode=mode,this.runId=runId,this.externalKey=externalKey,this.persistence=deps.persistence,this.events=deps.events??(deps.lifecycleBus?new EventBus({lifecycleBus:deps.lifecycleBus}):void 0),this.logger=(deps.logger??getLogger2("workflow")).child({runId,workflow:workflowName,mode})}static forExternalTransition(workflowName,runId,deps,externalKey){return new RunLifecycle(runId,workflowName,"state-machine",deps,externalKey)}static async run(workflowName,mode,deps,options,loop){return await traceAsync("workflow.run",async()=>{let startedAt=new Date().toISOString(),proposed={...RunLifecycle.runRecord(options.runId??crypto.randomUUID(),workflowName,mode,startedAt,options.metadata,options.externalKey),owner_attempt:crypto.randomUUID()},record2=proposed;if(options.externalKey===void 0)await deps.persistence.createRun(proposed);else if(record2=await deps.persistence.createOrAttachRun(proposed),record2.owner_attempt!==proposed.owner_attempt){let snapshot=await deps.persistence.loadLatestStateSnapshot(record2.id);return{runId:record2.id,workflowName:record2.workflow_name,mode:record2.mode==="transition-flow"?"transition-flow":"state-machine",status:record2.status,finalState:snapshot?.state??"",transitionsTaken:snapshotTransitions(snapshot?.data)}}let extKey=record2.external_key??void 0,lifecycle=new RunLifecycle(record2.id,workflowName,mode,deps,extKey);return lifecycle.ownerAttempt=proposed.owner_attempt??void 0,lifecycle.logger.info("workflow run started"),addSpanEvent("workflow.run.started",{workflowName,mode,runId:lifecycle.runId,dryRun:options.dryRun??!1}),lifecycle.events?.emit("workflow.run.started",{workflowName,mode,runId:lifecycle.runId,dryRun:options.dryRun??!1,externalKey:extKey,severity:"info"}),await lifecycle.execute(loop)},{attributes:{"workflow.name":workflowName,"workflow.mode":mode}})}static async resume(workflowName,mode,deps,runId,externalKey,loop,ownerAttempt){return await traceAsync("workflow.run",async()=>{let lifecycle=new RunLifecycle(runId,workflowName,mode,deps,externalKey);return lifecycle.ownerAttempt=ownerAttempt,lifecycle.logger.info("workflow run resumed"),await lifecycle.execute(loop)},{attributes:{"workflow.name":workflowName,"workflow.mode":mode}})}async finalizeAsOwner(status,completedAt,reason){if(this.ownerAttempt===void 0){await this.persistence.finalizeRun(this.runId,status,completedAt,void 0,reason);return}if(await this.persistence.finalizeRun(this.runId,status,completedAt,{ownerAttempt:this.ownerAttempt},reason)===!1)throw this.events?.emit("workflow.run.stale_owner",{runId:this.runId,ownerAttemptId:this.ownerAttempt,status,severity:"warning"}),new WorkflowResumeError(`stale owner "${this.ownerAttempt}" cannot finalize run "${this.runId}" as "${status}": ownership was lost`)}async execute(loop){try{return await loop(this)}catch(error51){try{await this.finalizeAsOwner("failed",new Date().toISOString(),"failed")}catch(finalizeError){throw AggregateError([error51,finalizeError],"Workflow execution and failure persistence failed")}throw error51}}async enter(stateOrNodeId,transitionsTaken,persist=!0,vars){if(persist){let data={transitionsTaken};if(vars!==void 0)data.effectiveVars=vars;await this.persistence.saveWorkflowState(this.runId,stateOrNodeId,data),await this.persistence.savePhase(this.runId,stateOrNodeId,"running")}addSpanEvent("workflow.node.enter",{runId:this.runId,node:stateOrNodeId,transitionsTaken}),this.events?.emit("workflow.node.enter",{runId:this.runId,node:stateOrNodeId,transitionsTaken,severity:"info"})}async commitHop(from,to,trigger,transitionsTaken,phase,vars){let data={transitionsTaken};if(vars!==void 0)data.effectiveVars=vars;await this.persistence.commitTransition(this.runId,from,to,trigger,to,data,phase),addSpanEvent("workflow.node.transition",{runId:this.runId,from,to,...trigger===null?{}:{trigger}}),this.events?.emit("workflow.node.transition",{runId:this.runId,from,to,trigger,externalKey:this.externalKey,severity:"info"})}async recordTransition(from,to,trigger){await this.persistence.saveTransition(this.runId,from,to,trigger),addSpanEvent("workflow.node.transition",{runId:this.runId,from,to,...trigger===null?{}:{trigger}}),this.events?.emit("workflow.node.transition",{runId:this.runId,from,to,trigger,externalKey:this.externalKey,severity:"info"})}async done(finalState,transitionsTaken,reason){return await this.persistence.savePhase(this.runId,finalState,"done"),await this.finalizeAsOwner("done",new Date().toISOString(),reason),this.logger.info("workflow run done",{finalState,transitionsTaken}),addSpanEvent("workflow.run.done",{runId:this.runId,finalState,transitionsTaken}),this.events?.emit("workflow.run.done",{runId:this.runId,finalState,transitionsTaken,externalKey:this.externalKey,severity:"info"}),this.result("done",finalState,transitionsTaken,reason)}async fail(finalState,transitionsTaken,reason="failed"){return await this.persistence.savePhase(this.runId,finalState,"failed"),await this.finalizeAsOwner("failed",new Date().toISOString(),reason),addSpanEvent("workflow.run.failed",{runId:this.runId,finalState,reason}),this.events?.emit("workflow.run.failed",{runId:this.runId,finalState,reason,externalKey:this.externalKey,severity:"error"}),this.logger.warn("workflow run failed",{finalState,transitionsTaken,reason}),this.result("failed",finalState,transitionsTaken,reason)}async pause(stateOrNodeId,transitionsTaken,vars,lastActionResult,reason){let data={transitionsTaken};if(vars!==void 0)data.effectiveVars=vars;if(lastActionResult!==void 0)data.lastActionResult={ok:lastActionResult.ok};return await this.persistence.saveWorkflowState(this.runId,stateOrNodeId,data),await this.persistence.savePhase(this.runId,stateOrNodeId,"paused"),await this.finalizeAsOwner("paused",new Date().toISOString(),reason),this.logger.info("workflow run paused",{stateOrNodeId,transitionsTaken}),addSpanEvent("workflow.run.paused",{runId:this.runId,node:stateOrNodeId,transitionsTaken}),this.events?.emit("workflow.run.paused",{runId:this.runId,node:stateOrNodeId,transitionsTaken,externalKey:this.externalKey,severity:"warning"}),this.result("paused",stateOrNodeId,transitionsTaken)}actionStart(stateOrNodeId,kind){addSpanEvent("workflow.action.start",{runId:this.runId,node:stateOrNodeId,kind}),this.events?.emit("workflow.action.start",{runId:this.runId,node:stateOrNodeId,kind,severity:"info"})}actionDone(stateOrNodeId,kind,durationMs,ok){addSpanEvent("workflow.action.done",{runId:this.runId,node:stateOrNodeId,kind,durationMs,ok}),this.events?.emit("workflow.action.done",{runId:this.runId,node:stateOrNodeId,kind,durationMs,ok,severity:ok?"info":"error"})}warnActionFailed(stateOrNodeId,transitionsTaken,error51){addSpanEvent("workflow.action.failed_continue",{runId:this.runId,node:stateOrNodeId,transitionsTaken,...error51===void 0?{}:{error:error51}}),this.events?.emit("workflow.action.failed_continue",{runId:this.runId,node:stateOrNodeId,transitionsTaken,...error51===void 0?{}:{error:error51},severity:"warning"}),this.logger.warn("action failed (continuing)",{node:stateOrNodeId,transitionsTaken,error:error51})}guardEvaluated(from,to,kind,passed){this.events?.emit("workflow.guard.evaluated",{runId:this.runId,from,to,kind,passed,externalKey:this.externalKey,severity:passed?"info":"warning"})}hitlAsk(node,kind,message){this.events?.emit("workflow.hitl.ask",{runId:this.runId,node,kind,message,severity:"info"})}hitlResponse(node,ok){this.events?.emit("workflow.hitl.response",{runId:this.runId,node,ok,severity:ok?"info":"warning"})}result(status,finalState,transitionsTaken,reason){return{runId:this.runId,workflowName:this.workflowName,mode:this.mode,status,finalState,transitionsTaken,...reason===void 0?{}:{reason}}}static runRecord(runId,workflowName,mode,startedAt,metadata,externalKey){return{id:runId,workflow_name:workflowName,mode,status:"running",started_at:startedAt,metadata_json:JSON.stringify(metadata??{}),completed_at:null,external_key:externalKey??null}}}function snapshotTransitions(data){let value=data?.transitionsTaken;return typeof value==="number"&&Number.isSafeInteger(value)&&value>=0?value:0}function snapshotActionResult(data){let value=data?.lastActionResult;return value!==null&&typeof value==="object"&&"ok"in value&&typeof value.ok==="boolean"?{ok:value.ok}:void 0}class CapabilityRegistry{kind;capabilities=new Map;constructor(kind){this.kind=kind}register(name,capability,origin2="extension"){this.capabilities.set(name,{capability,origin:origin2})}has(name){return this.capabilities.has(name)}get(name){let entry=this.capabilities.get(name);if(entry===void 0)throw Error(`Unknown ${this.kind}: ${name}`);return entry.capability}getEntry(name){return this.capabilities.get(name)}list(){return[...this.capabilities.keys()]}entries(){return[...this.capabilities.entries()]}}function assertRelativeExtensionPath(path8,options={}){let where=options.sourceName!==void 0?` declared by "${options.sourceName}"`:"";if(/^([/\\]|[A-Za-z]:[/\\])/.test(path8))throw Error(`extension path "${path8}"${where} must be relative (no absolute paths)`);if(path8.split(/[/\\]/).includes(".."))throw Error(`extension path "${path8}"${where} must not contain ".." traversal`)}init_zod();var RESERVED_VAR_NAMES=new Set(["task","state","node","iteration","run","runtime"]),IDENTIFIER=/^[A-Za-z_][A-Za-z0-9_]*$/,VarsSchema=exports_external.record(exports_external.string(),exports_external.string()).superRefine((vars,ctx)=>{for(let key of Object.keys(vars)){if(!IDENTIFIER.test(key))ctx.addIssue({code:"custom",message:`Invalid variable name "${key}" (must be a valid identifier)`});if(RESERVED_VAR_NAMES.has(key))ctx.addIssue({code:"custom",message:`Variable name "${key}" is reserved for runtime use`})}}),EnvSchema=exports_external.object({allow:exports_external.array(exports_external.string().regex(IDENTIFIER,"env.allow entries must be valid identifiers")).optional()}),relativeExtensionPath=exports_external.string().min(1).superRefine((value,ctx)=>{try{assertRelativeExtensionPath(value)}catch(error51){ctx.addIssue({code:"custom",message:error51 instanceof Error?error51.message:"invalid extension path"})}}),WorkflowExtensionsSchema=exports_external.object({actions:exports_external.array(relativeExtensionPath).optional(),guards:exports_external.array(relativeExtensionPath).optional()}).strict(),ActionDefSchema=exports_external.object({kind:exports_external.string().min(1),options:exports_external.record(exports_external.string(),exports_external.unknown()).optional(),onError:exports_external.enum(["fail","continue"]).optional()}),GuardDefSchema=exports_external.object({kind:exports_external.string().min(1),options:exports_external.record(exports_external.string(),exports_external.unknown()).optional()}),StateMachineWorkflowDefSchema=exports_external.object({$schema:exports_external.string().optional(),kind:exports_external.literal("state-machine").optional(),name:exports_external.string().min(1),version:exports_external.string().optional(),description:exports_external.string().optional(),initialState:exports_external.string().min(1),terminalStates:exports_external.array(exports_external.string().min(1)).optional(),failureStates:exports_external.array(exports_external.string().min(1)).optional(),iterationBound:exports_external.number().int().positive().optional(),defaultOnError:exports_external.enum(["fail","continue"]).optional(),vars:VarsSchema.optional(),env:EnvSchema.optional(),states:exports_external.array(exports_external.object({id:exports_external.string().min(1),description:exports_external.string().optional(),onEnter:exports_external.array(ActionDefSchema).optional(),onExit:exports_external.array(ActionDefSchema).optional(),pause:exports_external.boolean().optional(),resumeRerun:exports_external.boolean().optional()}).strict()),transitions:exports_external.array(exports_external.object({from:exports_external.string().min(1),to:exports_external.string().min(1),description:exports_external.string().optional(),trigger:exports_external.string().optional(),guard:GuardDefSchema.optional(),terminalReason:exports_external.string().optional()}).strict()),extensions:WorkflowExtensionsSchema.optional()}).strict(),TransitionFlowWorkflowDefSchema=exports_external.object({$schema:exports_external.string().optional(),kind:exports_external.literal("transition-flow"),name:exports_external.string().min(1),version:exports_external.string().optional(),description:exports_external.string().optional(),initialNode:exports_external.string().min(1),terminalNodes:exports_external.array(exports_external.string().min(1)).optional(),iterationBound:exports_external.number().int().positive().optional(),defaultOnError:exports_external.enum(["fail","continue"]).optional(),vars:VarsSchema.optional(),env:EnvSchema.optional(),nodes:exports_external.array(exports_external.object({id:exports_external.string().min(1),description:exports_external.string().optional(),type:exports_external.enum(["action","gate","parallel","decision"]).optional(),action:ActionDefSchema.optional(),pause:exports_external.boolean().optional(),resumeRerun:exports_external.boolean().optional()}).strict()),edges:exports_external.array(exports_external.object({from:exports_external.string().min(1),to:exports_external.string().min(1),description:exports_external.string().optional(),condition:GuardDefSchema.optional()}).strict()),extensions:WorkflowExtensionsSchema.optional()}).strict(),WorkflowDefSchema=exports_external.union([StateMachineWorkflowDefSchema,TransitionFlowWorkflowDefSchema]);async function loadWorkflowDef(path8,options={}){return parseWorkflowDef(await loadStructuredConfig(path8,options),path8)}function validateWorkflowDef(workflow){if(workflow.kind==="transition-flow")validateTransitionFlow(workflow);else validateStateMachine(workflow)}function validateStateMachine(workflow){let errors6=[],ids=workflow.states.map((state)=>state.id),states=new Set(ids),terminals=new Set(workflow.terminalStates??[]),failures=new Set(workflow.failureStates??[]);for(let id of duplicates(ids))errors6.push(`State "${id}" is declared more than once`);for(let failure of failures)if(!states.has(failure))errors6.push(`Failure state "${failure}" is not declared`);else if(!terminals.has(failure))errors6.push(`Failure state "${failure}" must also be declared as a terminal state`);if(!states.has(workflow.initialState))errors6.push(`Initial state "${workflow.initialState}" is not declared`);else if(terminals.has(workflow.initialState))errors6.push(`Initial state "${workflow.initialState}" must not be a terminal state`);for(let terminal of terminals)if(!states.has(terminal))errors6.push(`Terminal state "${terminal}" is not declared`);let outboundByState=new Map;for(let transition of workflow.transitions){if(!states.has(transition.from))errors6.push(`Transition source "${transition.from}" is not declared`);if(!states.has(transition.to))errors6.push(`Transition target "${transition.to}" is not declared`);let list=outboundByState.get(transition.from)??[];list.push(transition),outboundByState.set(transition.from,list)}for(let state of workflow.states){let outbound=outboundByState.get(state.id)??[];if(terminals.has(state.id)){if(outbound.length>0)errors6.push(`Terminal state "${state.id}" must not declare transitions`);continue}let ungatedIndex=outbound.findIndex((transition)=>transition.guard===void 0);if(ungatedIndex!==-1&&ungatedIndex<outbound.length-1)errors6.push(`State "${state.id}" has an unguarded transition that is not last; later transitions are unreachable`)}errors6.push(...checkVariableReferences(collectActionOptions(workflow),workflow.vars,workflow.env)),throwIfErrors(workflow,errors6)}function parseWorkflowDef(parsed,source){let result=selectWorkflowSchema(parsed).safeParse(parsed);if(!result.success)throw new WorkflowValidationError(`Workflow definition failed schema validation for ${source}: ${formatWorkflowIssues(result.error.issues)}`,result.error.issues);return validateWorkflowDef(result.data),result.data}function selectWorkflowSchema(parsed){if(parsed!==null&&typeof parsed==="object"){let value=parsed;if(value.kind==="transition-flow"||"nodes"in value||"edges"in value||"initialNode"in value)return TransitionFlowWorkflowDefSchema}return StateMachineWorkflowDefSchema}function formatWorkflowIssues(issues){return issues.map((issue2)=>{let path8=issue2.path.map(String).join(".");return path8.length>0?`${path8}: ${issue2.message}`:issue2.message}).join("; ")}function validateTransitionFlow(workflow){let errors6=[],ids=workflow.nodes.map((node)=>node.id),nodes=new Set(ids);for(let id of duplicates(ids))errors6.push(`Node "${id}" is declared more than once`);if(!nodes.has(workflow.initialNode))errors6.push(`Initial node "${workflow.initialNode}" is not declared`);let seenEdges=new Set;for(let edge of workflow.edges){if(!nodes.has(edge.from))errors6.push(`Edge source "${edge.from}" is not declared`);if(!nodes.has(edge.to))errors6.push(`Edge target "${edge.to}" is not declared`);let key=`${edge.from}→${edge.to}`;if(seenEdges.has(key))errors6.push(`Duplicate edge "${key}"`);seenEdges.add(key)}for(let terminal of workflow.terminalNodes??[]){if(!nodes.has(terminal))errors6.push(`Terminal node "${terminal}" is not declared`);if(workflow.edges.some((edge)=>edge.from===terminal))errors6.push(`Terminal node "${terminal}" must not declare edges`)}for(let node of workflow.nodes){let outbound=workflow.edges.filter((edge)=>edge.from===node.id),unconditional=outbound.findIndex((edge)=>edge.condition===void 0);if(unconditional!==-1&&unconditional<outbound.length-1)errors6.push(`Node "${node.id}" has an unconditional edge that is not last; later edges are unreachable`)}errors6.push(...checkVariableReferences(collectActionOptions(workflow),workflow.vars,workflow.env)),throwIfErrors(workflow,errors6)}function duplicates(ids){let seen=new Set,dupes=new Set;for(let id of ids){if(seen.has(id))dupes.add(id);seen.add(id)}return[...dupes]}function collectActionOptions(workflow){let optionSets=[],actions=workflow.kind==="transition-flow"?workflow.nodes.flatMap((node)=>node.action?[node.action]:[]):workflow.states.flatMap((state)=>[...state.onEnter??[],...state.onExit??[]]);for(let action of actions)if(action.options)optionSets.push(action.options);return optionSets}var RUNTIME_TEMPLATE_NAMESPACES=new Set(RUNTIME_BUILTIN_KEYS);function checkVariableReferences(optionSets,vars,env2){let declaredVars=new Set(Object.keys(vars??{})),allowedEnv2=new Set(env2?.allow??[]),errors6=[],reference=/\$\{([^}]+)\}/g;for(let options of optionSets)for(let value of Object.values(options)){if(typeof value!=="string")continue;for(let match of value.matchAll(reference)){let expr=(match[1]??"").trim(),[namespace,name]=expr.includes(".")?expr.split(".",2):[expr,void 0];if(namespace==="vars"){if(name!==void 0&&!declaredVars.has(name))errors6.push(`Unknown variable reference "\${${expr}}" (no var "${name}" declared)`)}else if(namespace==="env"){if(name!==void 0&&!allowedEnv2.has(name))errors6.push(`Env reference "\${${expr}}" is not in env.allow`)}else if(namespace!==void 0&&!RUNTIME_TEMPLATE_NAMESPACES.has(namespace))errors6.push(`Unknown template reference "\${${expr}}"`)}}return errors6}function throwIfErrors(workflow,errors6){if(errors6.length>0)throw new WorkflowValidationError(`Workflow "${workflow.name}" is invalid: ${errors6.join("; ")}`,errors6)}init_dist6();var TEMPLATE_REF=/\$\{([^}]+)\}/g;function mergeVars(workflowVars={},overrideVars={}){return{...workflowVars,...overrideVars}}function mergeSetVars(vars,setVars){if(setVars===void 0)return vars;let filtered={};for(let[key,value]of Object.entries(setVars))if(typeof value==="string")filtered[key]=value;return mergeVars(vars,filtered)}function resolveTemplates(value,context4){if(typeof value==="string")return resolveTemplateString(value,context4);if(Array.isArray(value))return value.map((entry)=>resolveTemplates(entry,context4));if(value!==null&&typeof value==="object")return Object.fromEntries(Object.entries(value).map(([key,entry])=>[key,resolveTemplates(entry,context4)]));return value}function resolveTemplateString(value,context4){return value.replace(TEMPLATE_REF,(_match,name)=>{return lookupRef(name,context4)})}function lookupRef(name,context4){if(name.startsWith("vars.")){let key=name.slice(5),resolved2=context4.vars[key];if(resolved2===void 0)throw new WorkflowValidationError(`Workflow variable "${key}" is not defined`);return resolved2}if(name.startsWith("env.")){let key=name.slice(4),resolved2=context4.env[key];if(resolved2===void 0)throw new WorkflowValidationError(`Environment variable "${key}" is not defined`);return resolved2}let resolved=context4.builtins?.[name];if(resolved===void 0)throw new WorkflowValidationError(`Workflow builtin "${name}" is not defined`);return String(resolved)}var SHELL_ENV_OPTION="__wfShellEnv",SHELL_BINDING=/^\$\{__WF_\d+\}$/,SHELL_BINDING_ANY=/\$\{__WF_\d+\}|\$__WF_\d+\b/;function resolveShellCommandTemplates(options,context4){let{command,args,...rest}=options;if(typeof command!=="string")return resolveTemplates(rest,context4);if(args!==void 0&&!Array.isArray(args))throw Error(`shell action "args" must be a string array when defined; got ${typeof args}`);if(Array.isArray(args)&&args.length>0)return{...resolveTemplates(rest,context4),command:resolveTemplateString(command,context4),args:resolveTemplates(args,context4)};let env2={},index2=0;if(!(SHELL_ENV_OPTION in options)&&SHELL_BINDING_ANY.test(command))throw Error("shell command must not contain the reserved $__WF_ placeholder namespace; it is minted by the template-binding pass");let existingBindings=options[SHELL_ENV_OPTION];if(existingBindings!==void 0&&typeof existingBindings==="object"&&existingBindings!==null){Object.assign(env2,existingBindings);while(`__WF_${index2}`in env2)index2++}let bound=command.replace(TEMPLATE_REF,(match,name)=>{if(SHELL_BINDING.test(match))return match;let key=`__WF_${index2++}`;return env2[key]=lookupRef(name,context4),`\${${key}}`});return{...resolveTemplates(rest,context4),command:bound,[SHELL_ENV_OPTION]:env2}}function resolveOnErrorPolicy(actionOnError,workflowDefault,runOptionOverride){return actionOnError??workflowDefault??runOptionOverride??"fail"}class WorkflowEngineHost{lifecycleBus;actions=new CapabilityRegistry("workflow action");guards=new CapabilityRegistry("workflow guard");constructor(lifecycleBus){this.lifecycleBus=lifecycleBus}registerAction(action,origin2="extension"){return this.actions.register(action.kind,action,origin2),this}registerGuard(guard,origin2="extension"){return this.guards.register(guard.kind,guard,origin2),this}hasAction(kind){return this.actions.has(kind)}hasGuard(kind){return this.guards.has(kind)}listActions(){return this.actions.list()}listGuards(){return this.guards.list()}actionOrigin(kind){return this.actions.getEntry(kind)?.origin}guardOrigin(kind){return this.guards.getEntry(kind)?.origin}async runAction(kind,options,context4){if(!this.actions.has(kind))throw new WorkflowValidationError(`Unknown workflow action "${kind}"`);return await this.actions.get(kind).execute(options,context4)}async evaluateGuard(kind,options,context4){return(await this.evaluateGuardResult(kind,options,context4)).passed}async evaluateGuardResult(kind,options,context4){if(!this.guards.has(kind))throw new WorkflowValidationError(`Unknown workflow guard "${kind}"`);let result=await this.guards.get(kind).evaluate(options,context4);return typeof result==="boolean"?{passed:result}:result}}function createDefaultWorkflowEngineHost(options={}){let host=new WorkflowEngineHost(options.lifecycleBus);return host.registerAction(new NoteActionRunner,"builtin"),host.registerAction(new ShellActionRunner(options.processExecutor??nodeBunFactory2.createProcessExecutor()),"builtin"),host.registerAction(new EventEmitActionRunner,"builtin"),host.registerGuard(new ShellGuardRunner(options.processExecutor??nodeBunFactory2.createProcessExecutor()),"builtin"),host.registerGuard({kind:"always",evaluate:async()=>!0},"builtin"),host.registerGuard({kind:"never",evaluate:async()=>!1},"builtin"),host.registerGuard({kind:"action-ok",evaluate:async(_options,context4)=>context4.lastActionResult?.ok===!0},"builtin"),host}class NoteActionRunner{kind="note";async execute(options,context4){let message=String(options.message??"");return context4?.events?.emit("workflow.hitl.note",{runId:context4.runId,node:context4.stateOrNodeId,message,severity:"info"}),{ok:!0,data:{message}}}}class EventEmitActionRunner{kind="event.emit";async execute(options,context4){let name=String(options.name??"");if(!name)return{ok:!1,error:'event.emit requires a non-empty "name" option'};let payload=options.payload??{};return context4?.events?.emit("workflow.custom",{name,payload,severity:"info"}),{ok:!0,data:{name,payload}}}}async function spawnShellCommand(processExecutor,options,workdir){let command=stringOption(options,"command"),explicitArgs=arrayOption(options,"args"),spawn2=explicitArgs.length===0?{command:"/bin/sh",args:["-c",command]}:{command,args:explicitArgs},timeout=optionalTimeoutOption(options),envOption=options[SHELL_ENV_OPTION],env2=envOption!==null&&typeof envOption==="object"?envOption:void 0,result=await processExecutor.run({command:spawn2.command,args:spawn2.args,cwd:optionalStringOption(options,"cwd",workdir),...env2!==void 0?{env:env2,envMode:"merge"}:{},...timeout!==void 0?{timeout}:{},rejectOnError:!1,forceBuffered:!0});return{stdout:result.stdout,stderr:result.stderr,exitCode:result.exitCode,timedOut:result.outcome==="timeout"}}class ShellActionRunner{processExecutor;kind="shell";constructor(processExecutor){this.processExecutor=processExecutor}async execute(options,context4){let spawn2=await spawnShellCommand(this.processExecutor,options,context4.workdir);if(spawn2.timedOut){let timeout=optionalTimeoutOption(options);return{ok:!1,data:{stdout:spawn2.stdout,stderr:spawn2.stderr,exitCode:spawn2.exitCode,timedOut:!0},error:`Shell action timed out after ${timeout}ms`}}let command=stringOption(options,"command");return{ok:spawn2.exitCode===0,data:{stdout:spawn2.stdout,stderr:spawn2.stderr,exitCode:spawn2.exitCode},...spawn2.exitCode===0?{}:{error:`Command "${command}" exited with ${spawn2.exitCode}`}}}}class ShellGuardRunner{processExecutor;kind="shell";constructor(processExecutor){this.processExecutor=processExecutor}async evaluate(options,context4){let spawn2=await spawnShellCommand(this.processExecutor,options,context4.workdir);return{passed:!spawn2.timedOut&&spawn2.exitCode===0,report:{stdout:spawn2.stdout,stderr:spawn2.stderr,exitCode:spawn2.exitCode,...spawn2.timedOut?{timedOut:!0}:{}}}}}function stringOption(options,key,fallback){let value=options[key];if(typeof value==="string")return value;if(fallback!==void 0)return fallback;throw new WorkflowValidationError(`Action option "${key}" must be a string`)}function optionalStringOption(options,key,fallback){let value=options[key];if(typeof value==="string")return value;if(value===void 0)return fallback;throw new WorkflowValidationError(`Action option "${key}" must be a string`)}function arrayOption(options,key){let value=options[key];if(value===void 0)return[];if(Array.isArray(value)&&value.every((entry)=>typeof entry==="string"))return value;throw new WorkflowValidationError(`Action option "${key}" must be a string array`)}function optionalTimeoutOption(options){let value=options.timeout;if(value===void 0)return;if(typeof value==="number"&&Number.isFinite(value)&&value>0)return value;throw new WorkflowValidationError('shell option "timeout" must be a positive number of milliseconds')}var WORKFLOW_ENGINE_SCHEMA_SQL=`
|
|
595
|
+
AND t.${column2} IS NOT NULL`);for(let row of rows){if(!moves.some((move)=>row.value.includes(move.source)))continue;let value=JSON.stringify(rewrite(JSON.parse(row.value)));if(value!==row.value)await db2.run(`UPDATE ${table3} SET ${column2} = ? WHERE id = ?`,value,row.id)}}if(await db2.queryFirst("SELECT name FROM sqlite_master WHERE type='table' AND name='history_import_checkpoint'")!==void 0){await normalizeSourceFilePaths(db2,(path7)=>paths.get(path7)??path7);for(let move of moves){if(move.sourceSize===void 0||move.sourceMtimeMs===void 0)continue;await db2.run("UPDATE history_import_checkpoint SET source_size = ?, source_mtime_ms = ? WHERE source_file = ?",move.sourceSize,move.sourceMtimeMs,move.target)}}await db2.exec("RELEASE spur_storage_references")}catch(error51){throw await db2.exec("ROLLBACK TO spur_storage_references"),await db2.exec("RELEASE spur_storage_references"),error51}}var CHILD_TABLES=["action_runs","phase_runs","transition_runs","workflow_states","artifacts","task_run_links"];function insertIfAbsentOps(table3,rows,targetColumns){return rows.map((row)=>{let columns2=Object.keys(row).filter((column2)=>targetColumns.has(column2));return{sql:`INSERT INTO ${table3} (${columns2.join(", ")}) VALUES (${columns2.map(()=>"?").join(", ")}) ON CONFLICT(id) DO NOTHING`,params:columns2.map((column2)=>row[column2])}})}async function tableColumns(db2,table3){let rows=await db2.queryAll(`PRAGMA table_info(${table3})`);return new Set(rows.map((row)=>row.name))}async function listRunIdRows(from){return(await from.queryAll("SELECT id, workflow_name FROM runs")).map((row)=>({id:row.id,workflowName:row.workflow_name}))}async function transferRunTables(from,to){let persistedIds=[],skipped=[],targetRunsColumns=await tableColumns(to,"runs"),sourceRows=await from.queryAll("SELECT * FROM runs");for(let row of sourceRows){let id=String(row.id);if(await to.queryFirst("SELECT id FROM runs WHERE id = ?",id)!==void 0){skipped.push({id,reason:"id-exists"});continue}if(row.external_key!==null&&row.external_key!==void 0){if(await to.queryFirst("SELECT id FROM runs WHERE external_key IS NOT NULL AND workflow_name IS ? AND external_key = ?",row.workflow_name??null,row.external_key)!==void 0){let ownsChildren=!1;for(let table3 of CHILD_TABLES)if(((await from.queryFirst(`SELECT COUNT(*) AS c FROM ${table3} WHERE run_id = ?`,id))?.c??0)>0){ownsChildren=!0;break}skipped.push({id,reason:ownsChildren?"external-key-conflict":"external-key-conflict-bookkeeping"});continue}}let ops=insertIfAbsentOps("runs",[row],targetRunsColumns);for(let table3 of CHILD_TABLES)ops.push(...insertIfAbsentOps(table3,await from.queryAll(`SELECT * FROM ${table3} WHERE run_id = ?`,id),await tableColumns(to,table3)));await to.batch(ops),persistedIds.push(id)}return{persistedIds,skipped}}init_schema();var transitionRunsTable=defineTable("transition_runs",{id:text("id").primaryKey(),runId:text("run_id").notNull().references(()=>runs.id),fromState:text("from_state").notNull(),toState:text("to_state").notNull(),trigger:text("trigger"),status:text("status").notNull(),...standardColumns}),transitionRuns=transitionRunsTable.table;init_schema();var workflowStatesTable=defineTable("workflow_states",{id:text("id").primaryKey(),runId:text("run_id").notNull().references(()=>runs.id),state:text("state").notNull(),dataJson:text("data_json").notNull(),...standardColumns}),workflowStates=workflowStatesTable.table;init_dist6();class WorkflowValidationError extends Error{details;constructor(message,details){super(message);this.details=details,this.name="WorkflowValidationError"}}class FSMError extends Error{details;constructor(message,details){super(message);this.details=details,this.name="FSMError"}}class RunCollisionError extends Error{constructor(runId){super(`Workflow run "${runId}" already exists`);this.name="RunCollisionError"}}class WorkflowResumeError extends Error{details;constructor(message,details){super(message);this.details=details,this.name="WorkflowResumeError"}}init_dist7();init_dist6();var RUNTIME_BUILTIN_KEYS=["workflow","runId","task","state","node","iteration","run","runtime"];function runtimeBuiltins(workflowName,stateOrNodeId,runId,transitionsTaken,mode){return{workflow:workflowName,runId,task:workflowName,state:stateOrNodeId,node:stateOrNodeId,iteration:transitionsTaken,run:runId,runtime:mode}}function allowedEnv(names,source=getProcessEnv()){return Object.fromEntries(names.flatMap((name)=>source[name]===void 0?[]:[[name,source[name]]]))}class RunLifecycle{workflowName;mode;runId;externalKey;persistence;events;logger;ownerAttempt;constructor(runId,workflowName,mode,deps,externalKey){this.workflowName=workflowName,this.mode=mode,this.runId=runId,this.externalKey=externalKey,this.persistence=deps.persistence,this.events=deps.events??(deps.lifecycleBus?new EventBus({lifecycleBus:deps.lifecycleBus}):void 0),this.logger=(deps.logger??getLogger2("workflow")).child({runId,workflow:workflowName,mode})}static forExternalTransition(workflowName,runId,deps,externalKey){return new RunLifecycle(runId,workflowName,"state-machine",deps,externalKey)}static async run(workflowName,mode,deps,options,loop){return await traceAsync("workflow.run",async()=>{let startedAt=new Date().toISOString(),proposed={...RunLifecycle.runRecord(options.runId??crypto.randomUUID(),workflowName,mode,startedAt,options.metadata,options.externalKey),owner_attempt:crypto.randomUUID()},record2=proposed;if(options.externalKey===void 0)await deps.persistence.createRun(proposed);else if(record2=await deps.persistence.createOrAttachRun(proposed),record2.owner_attempt!==proposed.owner_attempt){let snapshot=await deps.persistence.loadLatestStateSnapshot(record2.id),recordMode=record2.mode;return{runId:record2.id,workflowName:record2.workflow_name,mode:recordMode==="transition-flow"?"transition-flow":recordMode==="dag"?"dag":"state-machine",status:record2.status,finalState:snapshot?.state??"",transitionsTaken:snapshotTransitions(snapshot?.data)}}let extKey=record2.external_key??void 0,lifecycle=new RunLifecycle(record2.id,workflowName,mode,deps,extKey);return lifecycle.ownerAttempt=proposed.owner_attempt??void 0,lifecycle.logger.info("workflow run started"),addSpanEvent("workflow.run.started",{workflowName,mode,runId:lifecycle.runId,dryRun:options.dryRun??!1}),lifecycle.events?.emit("workflow.run.started",{workflowName,mode,runId:lifecycle.runId,dryRun:options.dryRun??!1,externalKey:extKey,severity:"info"}),await lifecycle.execute(loop)},{attributes:{"workflow.name":workflowName,"workflow.mode":mode}})}static async resume(workflowName,mode,deps,runId,externalKey,loop,ownerAttempt){return await traceAsync("workflow.run",async()=>{let lifecycle=new RunLifecycle(runId,workflowName,mode,deps,externalKey);return lifecycle.ownerAttempt=ownerAttempt,lifecycle.logger.info("workflow run resumed"),await lifecycle.execute(loop)},{attributes:{"workflow.name":workflowName,"workflow.mode":mode}})}async finalizeAsOwner(status,completedAt,reason){if(this.ownerAttempt===void 0){await this.persistence.finalizeRun(this.runId,status,completedAt,void 0,reason);return}if(await this.persistence.finalizeRun(this.runId,status,completedAt,{ownerAttempt:this.ownerAttempt},reason)===!1)throw this.events?.emit("workflow.run.stale_owner",{runId:this.runId,ownerAttemptId:this.ownerAttempt,status,severity:"warning"}),new WorkflowResumeError(`stale owner "${this.ownerAttempt}" cannot finalize run "${this.runId}" as "${status}": ownership was lost`)}async execute(loop){try{return await loop(this)}catch(error51){try{await this.finalizeAsOwner("failed",new Date().toISOString(),"failed")}catch(finalizeError){throw AggregateError([error51,finalizeError],"Workflow execution and failure persistence failed")}throw error51}}async enter(stateOrNodeId,transitionsTaken,persist=!0,vars){if(persist){let data={transitionsTaken};if(vars!==void 0)data.effectiveVars=vars;await this.persistence.saveWorkflowState(this.runId,stateOrNodeId,data),await this.persistence.savePhase(this.runId,stateOrNodeId,"running")}addSpanEvent("workflow.node.enter",{runId:this.runId,node:stateOrNodeId,transitionsTaken}),this.events?.emit("workflow.node.enter",{runId:this.runId,node:stateOrNodeId,transitionsTaken,severity:"info"})}async commitHop(from,to,trigger,transitionsTaken,phase,vars){let data={transitionsTaken};if(vars!==void 0)data.effectiveVars=vars;await this.persistence.commitTransition(this.runId,from,to,trigger,to,data,phase),addSpanEvent("workflow.node.transition",{runId:this.runId,from,to,...trigger===null?{}:{trigger}}),this.events?.emit("workflow.node.transition",{runId:this.runId,from,to,trigger,externalKey:this.externalKey,severity:"info"})}async recordTransition(from,to,trigger){await this.persistence.saveTransition(this.runId,from,to,trigger),addSpanEvent("workflow.node.transition",{runId:this.runId,from,to,...trigger===null?{}:{trigger}}),this.events?.emit("workflow.node.transition",{runId:this.runId,from,to,trigger,externalKey:this.externalKey,severity:"info"})}async done(finalState,transitionsTaken,reason){return await this.persistence.savePhase(this.runId,finalState,"done"),await this.finalizeAsOwner("done",new Date().toISOString(),reason),this.logger.info("workflow run done",{finalState,transitionsTaken}),addSpanEvent("workflow.run.done",{runId:this.runId,finalState,transitionsTaken}),this.events?.emit("workflow.run.done",{runId:this.runId,finalState,transitionsTaken,externalKey:this.externalKey,severity:"info"}),this.result("done",finalState,transitionsTaken,reason)}async fail(finalState,transitionsTaken,reason="failed"){return await this.persistence.savePhase(this.runId,finalState,"failed"),await this.finalizeAsOwner("failed",new Date().toISOString(),reason),addSpanEvent("workflow.run.failed",{runId:this.runId,finalState,reason}),this.events?.emit("workflow.run.failed",{runId:this.runId,finalState,reason,externalKey:this.externalKey,severity:"error"}),this.logger.warn("workflow run failed",{finalState,transitionsTaken,reason}),this.result("failed",finalState,transitionsTaken,reason)}async pause(stateOrNodeId,transitionsTaken,vars,lastActionResult,reason){let data={transitionsTaken};if(vars!==void 0)data.effectiveVars=vars;if(lastActionResult!==void 0)data.lastActionResult={ok:lastActionResult.ok};return await this.persistence.saveWorkflowState(this.runId,stateOrNodeId,data),await this.persistence.savePhase(this.runId,stateOrNodeId,"paused"),await this.finalizeAsOwner("paused",new Date().toISOString(),reason),this.logger.info("workflow run paused",{stateOrNodeId,transitionsTaken}),addSpanEvent("workflow.run.paused",{runId:this.runId,node:stateOrNodeId,transitionsTaken}),this.events?.emit("workflow.run.paused",{runId:this.runId,node:stateOrNodeId,transitionsTaken,externalKey:this.externalKey,severity:"warning"}),this.result("paused",stateOrNodeId,transitionsTaken)}actionStart(stateOrNodeId,kind){addSpanEvent("workflow.action.start",{runId:this.runId,node:stateOrNodeId,kind}),this.events?.emit("workflow.action.start",{runId:this.runId,node:stateOrNodeId,kind,severity:"info"})}actionDone(stateOrNodeId,kind,durationMs,ok){addSpanEvent("workflow.action.done",{runId:this.runId,node:stateOrNodeId,kind,durationMs,ok}),this.events?.emit("workflow.action.done",{runId:this.runId,node:stateOrNodeId,kind,durationMs,ok,severity:ok?"info":"error"})}warnActionFailed(stateOrNodeId,transitionsTaken,error51){addSpanEvent("workflow.action.failed_continue",{runId:this.runId,node:stateOrNodeId,transitionsTaken,...error51===void 0?{}:{error:error51}}),this.events?.emit("workflow.action.failed_continue",{runId:this.runId,node:stateOrNodeId,transitionsTaken,...error51===void 0?{}:{error:error51},severity:"warning"}),this.logger.warn("action failed (continuing)",{node:stateOrNodeId,transitionsTaken,error:error51})}guardEvaluated(from,to,kind,passed){this.events?.emit("workflow.guard.evaluated",{runId:this.runId,from,to,kind,passed,externalKey:this.externalKey,severity:passed?"info":"warning"})}hitlAsk(node,kind,message){this.events?.emit("workflow.hitl.ask",{runId:this.runId,node,kind,message,severity:"info"})}hitlResponse(node,ok){this.events?.emit("workflow.hitl.response",{runId:this.runId,node,ok,severity:ok?"info":"warning"})}branchStarted(parallelNode,branchId,node){addSpanEvent("workflow.branch.started",{runId:this.runId,parallelNode,branchId,node}),this.events?.emit("workflow.branch.started",{runId:this.runId,parallelNode,branchId,node,severity:"info"})}branchDone(parallelNode,branchId,durationMs,ok){addSpanEvent("workflow.branch.done",{runId:this.runId,parallelNode,branchId,durationMs,ok}),this.events?.emit("workflow.branch.done",{runId:this.runId,parallelNode,branchId,durationMs,ok,severity:ok?"info":"error"})}branchFailed(parallelNode,branchId,error51){addSpanEvent("workflow.branch.failed",{runId:this.runId,parallelNode,branchId,...error51!==void 0?{error:error51}:{}}),this.events?.emit("workflow.branch.failed",{runId:this.runId,parallelNode,branchId,error:error51,severity:"error"})}branchPaused(parallelNode,branchId,node){addSpanEvent("workflow.branch.paused",{runId:this.runId,parallelNode,branchId,node}),this.events?.emit("workflow.branch.paused",{runId:this.runId,parallelNode,branchId,node,severity:"warning"})}result(status,finalState,transitionsTaken,reason){return{runId:this.runId,workflowName:this.workflowName,mode:this.mode,status,finalState,transitionsTaken,...reason===void 0?{}:{reason}}}static runRecord(runId,workflowName,mode,startedAt,metadata,externalKey){return{id:runId,workflow_name:workflowName,mode,status:"running",started_at:startedAt,metadata_json:JSON.stringify(metadata??{}),completed_at:null,external_key:externalKey??null}}}function snapshotTransitions(data){let value=data?.transitionsTaken;return typeof value==="number"&&Number.isSafeInteger(value)&&value>=0?value:0}function snapshotActionResult(data){let value=data?.lastActionResult;return value!==null&&typeof value==="object"&&"ok"in value&&typeof value.ok==="boolean"?{ok:value.ok}:void 0}class CapabilityRegistry{kind;capabilities=new Map;constructor(kind){this.kind=kind}register(name,capability,origin2="extension"){this.capabilities.set(name,{capability,origin:origin2})}has(name){return this.capabilities.has(name)}get(name){let entry=this.capabilities.get(name);if(entry===void 0)throw Error(`Unknown ${this.kind}: ${name}`);return entry.capability}getEntry(name){return this.capabilities.get(name)}list(){return[...this.capabilities.keys()]}entries(){return[...this.capabilities.entries()]}}function assertRelativeExtensionPath(path8,options={}){let where=options.sourceName!==void 0?` declared by "${options.sourceName}"`:"";if(/^([/\\]|[A-Za-z]:[/\\])/.test(path8))throw Error(`extension path "${path8}"${where} must be relative (no absolute paths)`);if(path8.split(/[/\\]/).includes(".."))throw Error(`extension path "${path8}"${where} must not contain ".." traversal`)}init_zod();var RESERVED_VAR_NAMES=new Set(["task","state","node","iteration","run","runtime"]),IDENTIFIER=/^[A-Za-z_][A-Za-z0-9_]*$/,VarsSchema=exports_external.record(exports_external.string(),exports_external.string()).superRefine((vars,ctx)=>{for(let key of Object.keys(vars)){if(!IDENTIFIER.test(key))ctx.addIssue({code:"custom",message:`Invalid variable name "${key}" (must be a valid identifier)`});if(RESERVED_VAR_NAMES.has(key))ctx.addIssue({code:"custom",message:`Variable name "${key}" is reserved for runtime use`})}}),EnvSchema=exports_external.object({allow:exports_external.array(exports_external.string().regex(IDENTIFIER,"env.allow entries must be valid identifiers")).optional()}),relativeExtensionPath=exports_external.string().min(1).superRefine((value,ctx)=>{try{assertRelativeExtensionPath(value)}catch(error51){ctx.addIssue({code:"custom",message:error51 instanceof Error?error51.message:"invalid extension path"})}}),WorkflowExtensionsSchema=exports_external.object({actions:exports_external.array(relativeExtensionPath).optional(),guards:exports_external.array(relativeExtensionPath).optional()}).strict(),ActionDefSchema=exports_external.object({kind:exports_external.string().min(1),options:exports_external.record(exports_external.string(),exports_external.unknown()).optional(),onError:exports_external.enum(["fail","continue"]).optional()}),GuardDefSchema=exports_external.object({kind:exports_external.string().min(1),options:exports_external.record(exports_external.string(),exports_external.unknown()).optional()}),StateMachineWorkflowDefSchema=exports_external.object({$schema:exports_external.string().optional(),kind:exports_external.literal("state-machine").optional(),name:exports_external.string().min(1),version:exports_external.string().optional(),description:exports_external.string().optional(),initialState:exports_external.string().min(1),terminalStates:exports_external.array(exports_external.string().min(1)).optional(),failureStates:exports_external.array(exports_external.string().min(1)).optional(),iterationBound:exports_external.number().int().positive().optional(),defaultOnError:exports_external.enum(["fail","continue"]).optional(),vars:VarsSchema.optional(),env:EnvSchema.optional(),states:exports_external.array(exports_external.object({id:exports_external.string().min(1),description:exports_external.string().optional(),onEnter:exports_external.array(ActionDefSchema).optional(),onExit:exports_external.array(ActionDefSchema).optional(),pause:exports_external.boolean().optional(),resumeRerun:exports_external.boolean().optional(),startable:exports_external.boolean().optional()}).strict()),transitions:exports_external.array(exports_external.object({from:exports_external.string().min(1),to:exports_external.string().min(1),description:exports_external.string().optional(),trigger:exports_external.string().optional(),guard:GuardDefSchema.optional(),terminalReason:exports_external.string().optional()}).strict()),extensions:WorkflowExtensionsSchema.optional()}).strict(),FlowParallelBranchDefSchema=exports_external.object({id:exports_external.string().min(1),startNode:exports_external.string().min(1),description:exports_external.string().optional()}).strict(),FlowNodeDefSchema=exports_external.object({id:exports_external.string().min(1),description:exports_external.string().optional(),type:exports_external.enum(["action","gate","parallel","decision"]).optional(),action:ActionDefSchema.optional(),pause:exports_external.boolean().optional(),resumeRerun:exports_external.boolean().optional(),startable:exports_external.boolean().optional(),branches:exports_external.array(FlowParallelBranchDefSchema).optional(),join:exports_external.string().min(1).optional(),joinPolicy:exports_external.enum(["all"]).optional(),failurePolicy:exports_external.enum(["collect","fail-fast"]).optional(),concurrencyLimit:exports_external.number().int().positive().optional()}).strict().superRefine((node,ctx)=>{if(node.type==="parallel"){if(!node.branches||node.branches.length===0)ctx.addIssue({code:"custom",message:"Parallel node must declare non-empty branches array",path:["branches"]});if(!node.join)ctx.addIssue({code:"custom",message:"Parallel node must declare join target node ID",path:["join"]})}else{if(node.branches!==void 0)ctx.addIssue({code:"custom",message:`Node "${node.id}" of type "${node.type??"action"}" must not declare branches`,path:["branches"]});if(node.join!==void 0)ctx.addIssue({code:"custom",message:`Node "${node.id}" of type "${node.type??"action"}" must not declare join`,path:["join"]})}}),TransitionFlowWorkflowDefSchema=exports_external.object({$schema:exports_external.string().optional(),kind:exports_external.literal("transition-flow"),name:exports_external.string().min(1),version:exports_external.string().optional(),description:exports_external.string().optional(),initialNode:exports_external.string().min(1),terminalNodes:exports_external.array(exports_external.string().min(1)).optional(),iterationBound:exports_external.number().int().positive().optional(),defaultOnError:exports_external.enum(["fail","continue"]).optional(),vars:VarsSchema.optional(),env:EnvSchema.optional(),nodes:exports_external.array(FlowNodeDefSchema),edges:exports_external.array(exports_external.object({from:exports_external.string().min(1),to:exports_external.string().min(1),description:exports_external.string().optional(),condition:GuardDefSchema.optional()}).strict()),extensions:WorkflowExtensionsSchema.optional()}).strict(),DagNodeDefSchema=exports_external.object({id:exports_external.string().min(1),description:exports_external.string().optional(),action:ActionDefSchema.optional(),dependsOn:exports_external.array(exports_external.string().min(1)).optional(),dependencyPolicy:exports_external.enum(["all","any"]).optional(),condition:GuardDefSchema.optional(),pause:exports_external.boolean().optional(),resumeRerun:exports_external.boolean().optional()}).strict(),DagWorkflowDefSchema=exports_external.object({$schema:exports_external.string().optional(),kind:exports_external.literal("dag"),name:exports_external.string().min(1),version:exports_external.string().optional(),description:exports_external.string().optional(),iterationBound:exports_external.number().int().positive().optional(),defaultOnError:exports_external.enum(["fail","continue"]).optional(),vars:VarsSchema.optional(),env:EnvSchema.optional(),nodes:exports_external.array(DagNodeDefSchema),extensions:WorkflowExtensionsSchema.optional()}).strict(),WorkflowDefSchema=exports_external.union([StateMachineWorkflowDefSchema,TransitionFlowWorkflowDefSchema,DagWorkflowDefSchema]);async function loadWorkflowDef(path8,options={}){return parseWorkflowDef(await loadStructuredConfig(path8,options),path8)}function validateWorkflowDef(workflow){if(workflow.kind==="transition-flow")validateTransitionFlow(workflow);else if(workflow.kind==="dag")validateDagWorkflowDef(workflow);else validateStateMachine(workflow)}function validateStateMachine(workflow){let errors6=[],ids=workflow.states.map((state)=>state.id),states=new Set(ids),terminals=new Set(workflow.terminalStates??[]),failures=new Set(workflow.failureStates??[]);for(let id of duplicates(ids))errors6.push(`State "${id}" is declared more than once`);for(let failure of failures)if(!states.has(failure))errors6.push(`Failure state "${failure}" is not declared`);else if(!terminals.has(failure))errors6.push(`Failure state "${failure}" must also be declared as a terminal state`);if(!states.has(workflow.initialState))errors6.push(`Initial state "${workflow.initialState}" is not declared`);else if(terminals.has(workflow.initialState))errors6.push(`Initial state "${workflow.initialState}" must not be a terminal state`);for(let terminal of terminals)if(!states.has(terminal))errors6.push(`Terminal state "${terminal}" is not declared`);let outboundByState=new Map;for(let transition of workflow.transitions){if(!states.has(transition.from))errors6.push(`Transition source "${transition.from}" is not declared`);if(!states.has(transition.to))errors6.push(`Transition target "${transition.to}" is not declared`);let list=outboundByState.get(transition.from)??[];list.push(transition),outboundByState.set(transition.from,list)}for(let state of workflow.states){let outbound=outboundByState.get(state.id)??[];if(terminals.has(state.id)){if(outbound.length>0)errors6.push(`Terminal state "${state.id}" must not declare transitions`);continue}let ungatedIndex=outbound.findIndex((transition)=>transition.guard===void 0);if(ungatedIndex!==-1&&ungatedIndex<outbound.length-1)errors6.push(`State "${state.id}" has an unguarded transition that is not last; later transitions are unreachable`)}errors6.push(...checkVariableReferences(collectActionOptions(workflow),workflow.vars,workflow.env)),throwIfErrors(workflow,errors6)}function parseWorkflowDef(parsed,source){let result=selectWorkflowSchema(parsed).safeParse(parsed);if(!result.success)throw new WorkflowValidationError(`Workflow definition failed schema validation for ${source}: ${formatWorkflowIssues(result.error.issues)}`,result.error.issues);return validateWorkflowDef(result.data),result.data}function selectWorkflowSchema(parsed){if(parsed!==null&&typeof parsed==="object"){let value=parsed;if(value.kind==="dag")return DagWorkflowDefSchema;if(value.kind==="transition-flow"||"edges"in value||"initialNode"in value)return TransitionFlowWorkflowDefSchema}return StateMachineWorkflowDefSchema}function formatWorkflowIssues(issues){return issues.map((issue2)=>{let path8=issue2.path.map(String).join(".");return path8.length>0?`${path8}: ${issue2.message}`:issue2.message}).join("; ")}function validateTransitionFlow(workflow){let errors6=[],ids=workflow.nodes.map((node)=>node.id),nodes=new Set(ids);for(let id of duplicates(ids))errors6.push(`Node "${id}" is declared more than once`);if(!nodes.has(workflow.initialNode))errors6.push(`Initial node "${workflow.initialNode}" is not declared`);let seenEdges=new Set;for(let edge of workflow.edges){if(!nodes.has(edge.from))errors6.push(`Edge source "${edge.from}" is not declared`);if(!nodes.has(edge.to))errors6.push(`Edge target "${edge.to}" is not declared`);let key=`${edge.from}→${edge.to}`;if(seenEdges.has(key))errors6.push(`Duplicate edge "${key}"`);seenEdges.add(key)}for(let terminal of workflow.terminalNodes??[]){if(!nodes.has(terminal))errors6.push(`Terminal node "${terminal}" is not declared`);if(workflow.edges.some((edge)=>edge.from===terminal))errors6.push(`Terminal node "${terminal}" must not declare edges`)}for(let node of workflow.nodes){if(node.type==="parallel")continue;let outbound=workflow.edges.filter((edge)=>edge.from===node.id),unconditional=outbound.findIndex((edge)=>edge.condition===void 0);if(unconditional!==-1&&unconditional<outbound.length-1)errors6.push(`Node "${node.id}" has an unconditional edge that is not last; later edges are unreachable`)}let nodeMap=new Map(workflow.nodes.map((n2)=>[n2.id,n2])),outboundByFrom=new Map;for(let edge of workflow.edges){let list=outboundByFrom.get(edge.from)??[];list.push(edge.to),outboundByFrom.set(edge.from,list)}for(let node of workflow.nodes)if(node.type==="parallel"){if(!node.branches||node.branches.length<2)errors6.push(`Parallel node "${node.id}" must declare at least 2 branches`);if(node.branches)for(let dupe of duplicates(node.branches.map((b)=>b.id)))errors6.push(`Parallel node "${node.id}" declares duplicate branch id "${dupe}"`);if(node.join!==void 0){if(!nodes.has(node.join))errors6.push(`Parallel node "${node.id}" references undeclared join node "${node.join}"`);else if(node.join===node.id)errors6.push(`Parallel node "${node.id}" cannot have join set to itself`)}if(node.branches&&node.join&&nodes.has(node.join)&&node.join!==node.id)for(let branch of node.branches){if(!nodes.has(branch.startNode)){errors6.push(`Branch "${branch.id}" in parallel node "${node.id}" references undeclared startNode "${branch.startNode}"`);continue}if(branch.startNode===node.join){errors6.push(`Branch "${branch.id}" in parallel node "${node.id}" has startNode equal to join node "${node.join}"`);continue}let visiting=new Set,visited=new Set,hasCycle=!1,walk=(currentId)=>{if(currentId===node.join)return;if(visiting.has(currentId)){hasCycle=!0;return}if(visited.has(currentId))return;let currentNode=nodeMap.get(currentId);if(currentNode&¤tNode.id!==node.id&¤tNode.type==="parallel")errors6.push(`Parallel node "${currentNode.id}" is nested inside parallel node "${node.id}" (nested parallel regions are forbidden)`);visiting.add(currentId);let nextIds=outboundByFrom.get(currentId)??[];for(let nextId of nextIds)walk(nextId);visiting.delete(currentId),visited.add(currentId)};if(walk(branch.startNode),hasCycle)errors6.push(`Parallel branch "${branch.id}" in node "${node.id}" contains a cycle`)}}errors6.push(...checkVariableReferences(collectActionOptions(workflow),workflow.vars,workflow.env)),throwIfErrors(workflow,errors6)}function validateDagWorkflowDef(workflow){let errors6=[],ids=workflow.nodes.map((node)=>node.id),nodes=new Set(ids);for(let id of duplicates(ids))errors6.push(`Node "${id}" is declared more than once`);for(let node of workflow.nodes)for(let dep of node.dependsOn??[])if(dep===node.id)errors6.push(`Node "${node.id}" cannot depend on itself`);else if(!nodes.has(dep))errors6.push(`Node "${node.id}" references undeclared dependency "${dep}"`);let inDegree=new Map,adjList=new Map;for(let id of ids)inDegree.set(id,0),adjList.set(id,[]);for(let node of workflow.nodes)for(let dep of node.dependsOn??[])if(nodes.has(dep)&&dep!==node.id)adjList.get(dep)?.push(node.id),inDegree.set(node.id,(inDegree.get(node.id)??0)+1);let queue=ids.filter((id)=>(inDegree.get(id)??0)===0),visitedCount=0;while(queue.length>0){let curr=queue.shift();if(curr===void 0)break;visitedCount++;for(let neighbor of adjList.get(curr)??[]){let newDeg=(inDegree.get(neighbor)??1)-1;if(inDegree.set(neighbor,newDeg),newDeg===0)queue.push(neighbor)}}if(visitedCount<ids.length&&errors6.length===0)errors6.push("Cycle detected in DAG dependencies");errors6.push(...checkVariableReferences(collectActionOptions(workflow),workflow.vars,workflow.env)),throwIfErrors(workflow,errors6)}function duplicates(ids){let seen=new Set,dupes=new Set;for(let id of ids){if(seen.has(id))dupes.add(id);seen.add(id)}return[...dupes]}function collectActionOptions(workflow){let optionSets=[],actions=workflow.kind==="transition-flow"?workflow.nodes.flatMap((node)=>node.action?[node.action]:[]):workflow.kind==="dag"?workflow.nodes.flatMap((node)=>node.action?[node.action]:[]):workflow.states.flatMap((state)=>[...state.onEnter??[],...state.onExit??[]]);for(let action of actions)if(action.options)optionSets.push(action.options);return optionSets}var RUNTIME_TEMPLATE_NAMESPACES=new Set(RUNTIME_BUILTIN_KEYS);function checkVariableReferences(optionSets,vars,env2){let declaredVars=new Set(Object.keys(vars??{})),allowedEnv2=new Set(env2?.allow??[]),errors6=[],reference=/\$\{([^}]+)\}/g;for(let options of optionSets)for(let value of Object.values(options)){if(typeof value!=="string")continue;for(let match of value.matchAll(reference)){let expr=(match[1]??"").trim(),[namespace,name]=expr.includes(".")?expr.split(".",2):[expr,void 0];if(namespace==="vars"){if(name!==void 0&&!declaredVars.has(name))errors6.push(`Unknown variable reference "\${${expr}}" (no var "${name}" declared)`)}else if(namespace==="env"){if(name!==void 0&&!allowedEnv2.has(name))errors6.push(`Env reference "\${${expr}}" is not in env.allow`)}else if(namespace!==void 0&&!RUNTIME_TEMPLATE_NAMESPACES.has(namespace))errors6.push(`Unknown template reference "\${${expr}}"`)}}return errors6}function throwIfErrors(workflow,errors6){if(errors6.length>0)throw new WorkflowValidationError(`Workflow "${workflow.name}" is invalid: ${errors6.join("; ")}`,errors6)}init_dist6();var TEMPLATE_REF=/\$\{([^}]+)\}/g;function mergeVars(workflowVars={},overrideVars={}){return{...workflowVars,...overrideVars}}function mergeSetVars(vars,setVars){if(setVars===void 0)return vars;let filtered={};for(let[key,value]of Object.entries(setVars))if(typeof value==="string")filtered[key]=value;return mergeVars(vars,filtered)}function resolveTemplates(value,context4){if(typeof value==="string")return resolveTemplateString(value,context4);if(Array.isArray(value))return value.map((entry)=>resolveTemplates(entry,context4));if(value!==null&&typeof value==="object")return Object.fromEntries(Object.entries(value).map(([key,entry])=>[key,resolveTemplates(entry,context4)]));return value}function resolveTemplateString(value,context4){return value.replace(TEMPLATE_REF,(_match,name)=>{return lookupRef(name,context4)})}function lookupRef(name,context4){if(name.startsWith("vars.")){let key=name.slice(5),resolved2=context4.vars[key];if(resolved2===void 0)throw new WorkflowValidationError(`Workflow variable "${key}" is not defined`);return resolved2}if(name.startsWith("env.")){let key=name.slice(4),resolved2=context4.env[key];if(resolved2===void 0)throw new WorkflowValidationError(`Environment variable "${key}" is not defined`);return resolved2}let resolved=context4.builtins?.[name];if(resolved===void 0)throw new WorkflowValidationError(`Workflow builtin "${name}" is not defined`);return String(resolved)}var SHELL_ENV_OPTION="__wfShellEnv",SHELL_BINDING=/^\$\{__WF_\d+\}$/,SHELL_BINDING_ANY=/\$\{__WF_\d+\}|\$__WF_\d+\b/;function resolveShellCommandTemplates(options,context4){let{command,args,...rest}=options;if(typeof command!=="string")return resolveTemplates(rest,context4);if(args!==void 0&&!Array.isArray(args))throw Error(`shell action "args" must be a string array when defined; got ${typeof args}`);if(Array.isArray(args)&&args.length>0)return{...resolveTemplates(rest,context4),command:resolveTemplateString(command,context4),args:resolveTemplates(args,context4)};let env2={},index2=0;if(!(SHELL_ENV_OPTION in options)&&SHELL_BINDING_ANY.test(command))throw Error("shell command must not contain the reserved $__WF_ placeholder namespace; it is minted by the template-binding pass");let existingBindings=options[SHELL_ENV_OPTION];if(existingBindings!==void 0&&typeof existingBindings==="object"&&existingBindings!==null){Object.assign(env2,existingBindings);while(`__WF_${index2}`in env2)index2++}let bound=command.replace(TEMPLATE_REF,(match,name)=>{if(SHELL_BINDING.test(match))return match;let key=`__WF_${index2++}`;return env2[key]=lookupRef(name,context4),`\${${key}}`});return{...resolveTemplates(rest,context4),command:bound,[SHELL_ENV_OPTION]:env2}}function resolveOnErrorPolicy(actionOnError,workflowDefault,runOptionOverride){return actionOnError??workflowDefault??runOptionOverride??"fail"}class WorkflowEngineHost{lifecycleBus;actions=new CapabilityRegistry("workflow action");guards=new CapabilityRegistry("workflow guard");constructor(lifecycleBus){this.lifecycleBus=lifecycleBus}registerAction(action,origin2="extension"){return this.actions.register(action.kind,action,origin2),this}registerGuard(guard,origin2="extension"){return this.guards.register(guard.kind,guard,origin2),this}hasAction(kind){return this.actions.has(kind)}hasGuard(kind){return this.guards.has(kind)}listActions(){return this.actions.list()}listGuards(){return this.guards.list()}actionOrigin(kind){return this.actions.getEntry(kind)?.origin}guardOrigin(kind){return this.guards.getEntry(kind)?.origin}async runAction(kind,options,context4){if(!this.actions.has(kind))throw new WorkflowValidationError(`Unknown workflow action "${kind}"`);return await this.actions.get(kind).execute(options,context4)}async evaluateGuard(kind,options,context4){return(await this.evaluateGuardResult(kind,options,context4)).passed}async evaluateGuardResult(kind,options,context4){if(!this.guards.has(kind))throw new WorkflowValidationError(`Unknown workflow guard "${kind}"`);let result=await this.guards.get(kind).evaluate(options,context4);return typeof result==="boolean"?{passed:result}:result}}function createDefaultWorkflowEngineHost(options={}){let host=new WorkflowEngineHost(options.lifecycleBus);return host.registerAction(new NoteActionRunner,"builtin"),host.registerAction(new ShellActionRunner(options.processExecutor??nodeBunFactory2.createProcessExecutor()),"builtin"),host.registerAction(new EventEmitActionRunner,"builtin"),host.registerGuard(new ShellGuardRunner(options.processExecutor??nodeBunFactory2.createProcessExecutor()),"builtin"),host.registerGuard({kind:"always",evaluate:async()=>!0},"builtin"),host.registerGuard({kind:"never",evaluate:async()=>!1},"builtin"),host.registerGuard({kind:"action-ok",evaluate:async(_options,context4)=>context4.lastActionResult?.ok===!0},"builtin"),host}class NoteActionRunner{kind="note";async execute(options,context4){let message=String(options.message??"");return context4?.events?.emit("workflow.hitl.note",{runId:context4.runId,node:context4.stateOrNodeId,message,severity:"info"}),{ok:!0,data:{message}}}}class EventEmitActionRunner{kind="event.emit";async execute(options,context4){let name=String(options.name??"");if(!name)return{ok:!1,error:'event.emit requires a non-empty "name" option'};let payload=options.payload??{};return context4?.events?.emit("workflow.custom",{name,payload,severity:"info"}),{ok:!0,data:{name,payload}}}}async function spawnShellCommand(processExecutor,options,workdir,signal){let command=stringOption(options,"command"),explicitArgs=arrayOption(options,"args"),spawn2=explicitArgs.length===0?{command:"/bin/sh",args:["-c",command]}:{command,args:explicitArgs},timeout=optionalTimeoutOption(options),envOption=options[SHELL_ENV_OPTION],env2=envOption!==null&&typeof envOption==="object"?envOption:void 0,result=await processExecutor.run({command:spawn2.command,args:spawn2.args,cwd:optionalStringOption(options,"cwd",workdir),...env2!==void 0?{env:env2,envMode:"merge"}:{},...timeout!==void 0?{timeout}:{},...signal!==void 0?{signal}:{},rejectOnError:!1,forceBuffered:!0});return{stdout:result.stdout,stderr:result.stderr,exitCode:result.exitCode,timedOut:result.outcome==="timeout"}}class ShellActionRunner{processExecutor;kind="shell";constructor(processExecutor){this.processExecutor=processExecutor}async execute(options,context4){let spawn2=await spawnShellCommand(this.processExecutor,options,context4.workdir,context4.signal);if(spawn2.timedOut){let timeout=optionalTimeoutOption(options);return{ok:!1,data:{stdout:spawn2.stdout,stderr:spawn2.stderr,exitCode:spawn2.exitCode,timedOut:!0},error:`Shell action timed out after ${timeout}ms`}}let command=stringOption(options,"command");return{ok:spawn2.exitCode===0,data:{stdout:spawn2.stdout,stderr:spawn2.stderr,exitCode:spawn2.exitCode},...spawn2.exitCode===0?{}:{error:`Command "${command}" exited with ${spawn2.exitCode}`}}}}class ShellGuardRunner{processExecutor;kind="shell";constructor(processExecutor){this.processExecutor=processExecutor}async evaluate(options,context4){let spawn2=await spawnShellCommand(this.processExecutor,options,context4.workdir,context4.signal);return{passed:!spawn2.timedOut&&spawn2.exitCode===0,report:{stdout:spawn2.stdout,stderr:spawn2.stderr,exitCode:spawn2.exitCode,...spawn2.timedOut?{timedOut:!0}:{}}}}}function stringOption(options,key,fallback){let value=options[key];if(typeof value==="string")return value;if(fallback!==void 0)return fallback;throw new WorkflowValidationError(`Action option "${key}" must be a string`)}function optionalStringOption(options,key,fallback){let value=options[key];if(typeof value==="string")return value;if(value===void 0)return fallback;throw new WorkflowValidationError(`Action option "${key}" must be a string`)}function arrayOption(options,key){let value=options[key];if(value===void 0)return[];if(Array.isArray(value)&&value.every((entry)=>typeof entry==="string"))return value;throw new WorkflowValidationError(`Action option "${key}" must be a string array`)}function optionalTimeoutOption(options){let value=options.timeout;if(value===void 0)return;if(typeof value==="number"&&Number.isFinite(value)&&value>0)return value;throw new WorkflowValidationError('shell option "timeout" must be a positive number of milliseconds')}var WORKFLOW_ENGINE_SCHEMA_SQL=`
|
|
583
596
|
CREATE TABLE IF NOT EXISTS runs (
|
|
584
597
|
id TEXT PRIMARY KEY,
|
|
585
598
|
workflow_name TEXT,
|
|
@@ -650,6 +663,26 @@ CREATE TABLE IF NOT EXISTS action_runs (
|
|
|
650
663
|
updated_at INTEGER NOT NULL DEFAULT 0,
|
|
651
664
|
FOREIGN KEY (run_id) REFERENCES runs(id)
|
|
652
665
|
);
|
|
666
|
+
|
|
667
|
+
CREATE TABLE IF NOT EXISTS workflow_branches (
|
|
668
|
+
id TEXT PRIMARY KEY,
|
|
669
|
+
run_id TEXT NOT NULL,
|
|
670
|
+
parallel_node TEXT NOT NULL,
|
|
671
|
+
branch_id TEXT NOT NULL,
|
|
672
|
+
status TEXT NOT NULL,
|
|
673
|
+
node TEXT NOT NULL,
|
|
674
|
+
started_at TEXT NOT NULL,
|
|
675
|
+
completed_at TEXT,
|
|
676
|
+
duration_ms INTEGER,
|
|
677
|
+
output_vars_json TEXT,
|
|
678
|
+
error TEXT,
|
|
679
|
+
created_at INTEGER NOT NULL DEFAULT 0,
|
|
680
|
+
updated_at INTEGER NOT NULL DEFAULT 0,
|
|
681
|
+
FOREIGN KEY (run_id) REFERENCES runs(id)
|
|
682
|
+
);
|
|
683
|
+
|
|
684
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_workflow_branches_run_branch
|
|
685
|
+
ON workflow_branches (run_id, parallel_node, branch_id);
|
|
653
686
|
`.trim(),WORKFLOW_ENGINE_MIGRATIONS_SQL=`
|
|
654
687
|
ALTER TABLE runs ADD COLUMN owner_attempt TEXT;
|
|
655
688
|
ALTER TABLE runs ADD COLUMN owner_pid INTEGER;
|
|
@@ -663,7 +696,12 @@ ALTER TABLE runs ADD COLUMN terminal_reason TEXT;
|
|
|
663
696
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,params:[`${runId}:phase:${phase}:${crypto.randomUUID()}`,runId,phase,status,new Date(now).toISOString(),status==="running"?null:new Date(now).toISOString(),now,now]}}async saveActionStart(runId,node,kind,_options){let id=crypto.randomUUID(),now=Date.now();return await this.db.run(`INSERT INTO action_runs (id, run_id, node, kind, status, started_at, created_at, updated_at)
|
|
664
697
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,id,runId,node,kind,"running",new Date(now).toISOString(),now,now),id}async saveActionFinalize(actionId,status,durationMs,ok,kind,result,redactor){let now=Date.now();await this.db.run(`UPDATE action_runs
|
|
665
698
|
SET status = ?, duration_ms = ?, ok = ?, result_json = ?, completed_at = ?, updated_at = ?
|
|
666
|
-
WHERE id = ?`,status,durationMs,ok?1:0,result!==void 0?JSON.stringify(applyRedactor(redactor,kind,result)):null,new Date(now).toISOString(),now,actionId)}async loadRun(runId){return await this.ensureSchema(),await this.db.queryFirst("SELECT * FROM runs WHERE id = ?",runId)??void 0}async listRuns(){return await this.ensureSchema(),await this.db.queryAll("SELECT * FROM runs ORDER BY started_at DESC")}async findRunByKey(workflowName,externalKey){return await this.ensureSchema(),await this.db.queryFirst("SELECT * FROM runs WHERE workflow_name = ? AND external_key = ?",workflowName,externalKey)??void 0}async createOrAttachRun(record2){if(await this.ensureSchema(),record2.external_key!==void 0&&record2.external_key!==null){let existing=await this.findRunByKey(record2.workflow_name,record2.external_key);if(existing)return existing}try{await this.createRun(record2)}catch(error51){if(record2.external_key!==void 0&&record2.external_key!==null){let existing=await this.findRunByKey(record2.workflow_name,record2.external_key);if(existing)return existing}throw error51}return{...record2}}async reseedRun(runId,newState){await this.ensureSchema();let previous=await this.loadLatestStateSnapshot(runId),now=Date.now(),data={...previous?.data??{},reseeded:!0,reseededAt:new Date(now).toISOString()};return await this.commitTransition(runId,previous?.state??"",newState,"__reseed__",newState,data),{fromState:previous?.state??null,toState:newState}}async loadCurrentState(runId){return await this.ensureSchema(),(await this.db.queryFirst("SELECT state FROM workflow_states WHERE run_id = ? ORDER BY created_at DESC, rowid DESC LIMIT 1",runId))?.state}async loadLatestStateSnapshot(runId){await this.ensureSchema();let row=await this.db.queryFirst("SELECT state, data_json FROM workflow_states WHERE run_id = ? ORDER BY created_at DESC, rowid DESC LIMIT 1",runId);if(row==null)return;let data={};if(row.data_json!==null&&row.data_json.length>0)try{data=JSON.parse(row.data_json)}catch{data={}}return{state:row.state,data}}async listPausedRuns(options){await this.ensureSchema();let where=["status = 'paused'"],params=[];if(options?.workflowName!==void 0)where.push("workflow_name = ?"),params.push(options.workflowName);let limit=options?.limit??100,sql4=`SELECT * FROM runs WHERE ${where.join(" AND ")} ORDER BY updated_at DESC, rowid DESC LIMIT ?`;return params.push(limit),await this.db.queryAll(sql4,...params)}}init_dist7();async function runActionStep(action,vars,deps){let{host,persistence,lifecycle,stateOrNodeId,runId}=deps,templateContext={vars,env:deps.env,builtins:runtimeBuiltins(deps.workflowName,stateOrNodeId,runId,deps.transitionsTaken,deps.mode)},resolvedWithEnv=action.kind==="shell"?resolveShellCommandTemplates(action.options??{},templateContext):resolveTemplates(action.options??{},templateContext),{[SHELL_ENV_OPTION]:_shellEnv,...resolved}=resolvedWithEnv,actionId=await persistence.saveActionStart(runId,stateOrNodeId,action.kind,resolved),actionStartMs=Date.now();lifecycle.actionStart(stateOrNodeId,action.kind);let result;try{result=await host.runAction(action.kind,resolvedWithEnv,{runId,actionId,workdir:deps.options.workdir,stateOrNodeId,vars,env:deps.env,metadata:deps.options.metadata,events:deps.options.events})}catch(error51){result={ok:!1,error:error51 instanceof Error?error51.message:String(error51)}}finally{let durationMs=Date.now()-actionStartMs;lifecycle.actionDone(stateOrNodeId,action.kind,durationMs,result?.ok??!1),await persistence.saveActionFinalize(actionId,result?.ok===!0?"done":"failed",durationMs,result?.ok??!1,action.kind,result,deps.options.redactor??defaultActionRedactor)}if(result.terminal===!0)return{outcome:"terminal",result};if(!result.ok){if(resolveOnErrorPolicy(action.onError,deps.defaultOnError,deps.options.onError)==="fail")return{outcome:"fail",result};lifecycle.warnActionFailed(stateOrNodeId,deps.transitionsTaken,result.error)}return{outcome:"completed",result}}async function runActionSequence(actions,vars,deps){let last,acc;for(let action of actions){let step=await runActionStep(action,vars,deps);if(step.result!==void 0)last=step.result;if(step.result?.setVars)acc=mergeSetVars(acc??{},step.result.setVars),vars=mergeSetVars(vars,step.result.setVars);if(step.outcome==="terminal")return{outcome:"terminal",result:last,setVars:acc};if(step.outcome==="fail")return{outcome:"fail",result:last,setVars:acc}}return{outcome:"completed",result:last,setVars:acc}}class StateMachineDriver{options;constructor(options){this.options=options}async run(workflow,options={}){return await RunLifecycle.run(workflow.name,"state-machine",{persistence:this.options.persistence,events:options.events},options,(lifecycle)=>this.loop(workflow,options,lifecycle))}async resume(workflow,runId,resumeFromState,externalKey,options={}){return await RunLifecycle.resume(workflow.name,"state-machine",{persistence:this.options.persistence,events:options.events},runId,externalKey,(lifecycle)=>this.loop(workflow,options,lifecycle,resumeFromState),options.resumeOwner?.attemptId)}async loop(workflow,options,lifecycle,resumeFromState){let runId=lifecycle.runId,states=new Map(workflow.states.map((state)=>[state.id,state])),terminal=new Set(workflow.terminalStates??[]),failure=new Set(workflow.failureStates??[]),vars=mergeVars(workflow.vars,options.vars),env2=allowedEnv(workflow.env?.allow??[],options.env),current=resumeFromState!==void 0?states.get(resumeFromState):states.get(workflow.initialState),snapshot=resumeFromState===void 0?void 0:await this.options.persistence.loadLatestStateSnapshot(runId),transitionsTaken=snapshotTransitions(snapshot?.data),lastActionResult=snapshotActionResult(snapshot?.data),iterationBound=workflow.iterationBound??50,defaultOnError=workflow.defaultOnError,resumeMode=resumeFromState!==void 0?options.resumeMode??"skip-enter":void 0,persistedViaHop=!1,declaredTerminalReason;if(current===void 0){let label=resumeFromState??workflow.initialState;throw new FSMError(`State "${label}" is not declared`)}while(!0){if(resumeMode==="skip-enter")resumeMode=void 0,persistedViaHop=!0;else{if(resumeMode==="rerun-enter"){if(current.resumeRerun!==!0)throw new FSMError(`Cannot rerun-resume into state "${current.id}": not marked resumeRerun: true (mark its on-enter actions as safe to re-run, or resume with resumeMode: "skip-enter")`);resumeMode=void 0,persistedViaHop=!0}await lifecycle.enter(current.id,transitionsTaken,!persistedViaHop,vars);let enter=options.dryRun?EMPTY_OUTCOME:await runActionSequence(current.onEnter??[],vars,{host:this.options.host,persistence:this.options.persistence,lifecycle,workflowName:workflow.name,stateOrNodeId:current.id,runId,mode:"state-machine",transitionsTaken,env:env2,options,defaultOnError});if(enter.result!==void 0)lastActionResult=enter.result;if(enter.setVars)vars=mergeSetVars(vars,enter.setVars);if(enter.outcome==="terminal")return failure.has(current.id)?await lifecycle.fail(current.id,transitionsTaken,`terminal:${current.id}`):await lifecycle.done(current.id,transitionsTaken);if(enter.outcome==="fail")return await lifecycle.fail(current.id,transitionsTaken,lastActionResult?.error);if(current.pause===!0)return await lifecycle.pause(current.id,transitionsTaken,vars,lastActionResult)}let outbound=workflow.transitions.filter((transition)=>transition.from===current?.id);if(terminal.has(current.id)||outbound.length===0){let declared=declaredTerminalReason;return declaredTerminalReason=void 0,failure.has(current.id)?await lifecycle.fail(current.id,transitionsTaken,declared??`terminal:${current.id}`):await lifecycle.done(current.id,transitionsTaken,declared)}let nextTransition=await firstPassingTransition(outbound,this.options.host,{runId,current:current.id,vars,env:env2,lastActionResult,workdir:options.workdir},lifecycle);if(nextTransition===void 0)return await lifecycle.fail(current.id,transitionsTaken,"no-passing-transition");let exit=options.dryRun?EMPTY_OUTCOME:await runActionSequence(current.onExit??[],vars,{host:this.options.host,persistence:this.options.persistence,lifecycle,workflowName:workflow.name,stateOrNodeId:current.id,runId,mode:"state-machine",transitionsTaken,env:env2,options,defaultOnError});if(exit.result!==void 0)lastActionResult=exit.result;if(exit.setVars)vars=mergeSetVars(vars,exit.setVars);if(exit.outcome==="terminal")return failure.has(current.id)?await lifecycle.fail(current.id,transitionsTaken,`terminal:${current.id}`):await lifecycle.done(current.id,transitionsTaken);if(exit.outcome==="fail")return await lifecycle.fail(current.id,transitionsTaken,exit.result?.error);if(transitionsTaken+=1,await lifecycle.commitHop(current.id,nextTransition.to,nextTransition.trigger??null,transitionsTaken,{phase:nextTransition.to,status:"running"},vars),transitionsTaken>iterationBound)return await lifecycle.fail(current.id,transitionsTaken,"iteration-bound-exceeded");let nextState=states.get(nextTransition.to);if(nextState===void 0)throw new FSMError(`Transition target "${nextTransition.to}" is not declared`);current=nextState,declaredTerminalReason=nextTransition.terminalReason,persistedViaHop=!0}}}var EMPTY_OUTCOME={outcome:"completed",result:void 0,setVars:void 0};async function firstPassingTransition(transitions,host,context4,lifecycle){for(let transition of transitions){if(transition.guard===void 0)return transition;let resolvedOptions=transition.guard.kind==="shell"?resolveShellCommandTemplates(transition.guard.options??{},{vars:context4.vars,env:context4.env??{}}):resolveTemplates(transition.guard.options??{},{vars:context4.vars,env:context4.env??{}}),passed=await host.evaluateGuard(transition.guard.kind,resolvedOptions,context4);if(lifecycle.guardEvaluated(context4.current,transition.to,transition.guard.kind,passed),passed)return transition}return}class TransitionFlowDriver{options;constructor(options){this.options=options}async run(workflow,options={}){return await RunLifecycle.run(workflow.name,"transition-flow",{persistence:this.options.persistence,events:options.events},options,(lifecycle)=>this.loop(workflow,options,lifecycle))}async resume(workflow,runId,resumeFromNode,externalKey,options={}){return await RunLifecycle.resume(workflow.name,"transition-flow",{persistence:this.options.persistence,events:options.events},runId,externalKey,(lifecycle)=>this.loop(workflow,options,lifecycle,resumeFromNode),options.resumeOwner?.attemptId)}async loop(workflow,options,lifecycle,resumeFromNode){let runId=lifecycle.runId,nodes=new Map(workflow.nodes.map((node)=>[node.id,node])),terminal=new Set(workflow.terminalNodes??[]),vars=mergeVars(workflow.vars,options.vars),env2=allowedEnv(workflow.env?.allow??[],options.env),current=resumeFromNode!==void 0?nodes.get(resumeFromNode):nodes.get(workflow.initialNode),snapshot=resumeFromNode===void 0?void 0:await this.options.persistence.loadLatestStateSnapshot(runId),transitionsTaken=snapshotTransitions(snapshot?.data),lastActionResult=snapshotActionResult(snapshot?.data),iterationBound=workflow.iterationBound??50,defaultOnError=workflow.defaultOnError,resumeMode=resumeFromNode!==void 0?options.resumeMode??"skip-enter":void 0,persistedViaHop=!1;if(current===void 0){let label=resumeFromNode??workflow.initialNode;throw new FSMError(`Node "${label}" is not declared`)}while(!0){if(resumeMode==="skip-enter")resumeMode=void 0,persistedViaHop=!0;else{if(resumeMode==="rerun-enter"){if(current.resumeRerun!==!0)throw new FSMError(`Cannot rerun-resume into node "${current.id}": not marked resumeRerun: true (mark its action as safe to re-run, or resume with resumeMode: "skip-enter")`);resumeMode=void 0,persistedViaHop=!0}if(await lifecycle.enter(current.id,transitionsTaken,!persistedViaHop,vars),options.dryRun){if(current.action!==void 0)lastActionResult=void 0}else if(current.action!==void 0){let step=await runActionStep(current.action,vars,{host:this.options.host,persistence:this.options.persistence,lifecycle,workflowName:workflow.name,stateOrNodeId:current.id,runId,mode:"transition-flow",transitionsTaken,env:env2,options,defaultOnError});if(lastActionResult=step.result,step.result?.setVars)vars=mergeSetVars(vars,step.result.setVars);if(step.outcome==="terminal")return await lifecycle.done(current.id,transitionsTaken);if(step.outcome==="fail")return await lifecycle.fail(current.id,transitionsTaken,step.result?.error)}if(current.pause===!0)return await lifecycle.pause(current.id,transitionsTaken,vars,lastActionResult)}let outbound=workflow.edges.filter((edge2)=>edge2.from===current?.id);if(terminal.has(current.id)||outbound.length===0)return await lifecycle.done(current.id,transitionsTaken);let edge=await firstPassingEdge(outbound,this.options.host,{runId,current:current.id,vars,env:env2,lastActionResult,workdir:options.workdir},lifecycle);if(edge===void 0)return await lifecycle.fail(current.id,transitionsTaken,"no-passing-edge");if(transitionsTaken+=1,await lifecycle.commitHop(current.id,edge.to,edge.condition?.kind??null,transitionsTaken,{phase:edge.to,status:"running"},vars),transitionsTaken>iterationBound)return await lifecycle.fail(current.id,transitionsTaken,"iteration-bound-exceeded");let nextNode=nodes.get(edge.to);if(nextNode===void 0)throw new FSMError(`Edge target "${edge.to}" is not declared`);current=nextNode,persistedViaHop=!0}}}async function firstPassingEdge(edges,host,context4,lifecycle){for(let edge of edges){if(edge.condition===void 0)return edge;let resolvedOptions=edge.condition.kind==="shell"?resolveShellCommandTemplates(edge.condition.options??{},{vars:context4.vars,env:context4.env??{}}):resolveTemplates(edge.condition.options??{},{vars:context4.vars,env:context4.env??{}}),passed=await host.evaluateGuard(edge.condition.kind,resolvedOptions,context4);if(lifecycle.guardEvaluated(context4.current,edge.to,edge.condition.kind,passed),passed)return edge}return}class WorkflowService{host;persistence;runLocks=new Map;lifecycleBus;constructor(host,persistence,lifecycleBus){this.host=host,this.persistence=persistence,this.lifecycleBus=lifecycleBus??host.lifecycleBus}resolveEvents(events){return events??(this.lifecycleBus?new EventBus({lifecycleBus:this.lifecycleBus}):void 0)}async load(path8){return await loadWorkflowDef(path8)}async run(workflow,options={}){let events=this.resolveEvents(options.events);if(workflow.kind==="transition-flow")return await new TransitionFlowDriver({host:this.host,persistence:this.persistence}).run(workflow,{...options,events});return await new StateMachineDriver({host:this.host,persistence:this.persistence}).run(workflow,{...options,events})}async runFile(path8,options={}){return await this.run(await this.load(path8),options)}async listRuns(){return await this.persistence.listRuns()}async findRunByKey(workflowName,externalKey){return await this.persistence.findRunByKey(workflowName,externalKey)}async createOrAttachRun(record2){return await this.persistence.createOrAttachRun(record2)}async reseedRun(workflowOrRunId,runIdOrNewState,newStateOrOptions,maybeOptions){let args=typeof workflowOrRunId==="string"?{workflow:void 0,runId:workflowOrRunId,newState:runIdOrNewState,options:newStateOrOptions}:{workflow:workflowOrRunId,runId:runIdOrNewState,newState:newStateOrOptions,options:maybeOptions};if(args.workflow!==void 0)this.assertReseedTargetDeclared(args.workflow,args.runId,args.newState);await this.commitReseed(args.runId,args.newState,args.options)}assertReseedTargetDeclared(workflow,runId,newState){if(workflow.kind==="transition-flow")throw new FSMError("reseedRun only supports state-machine workflows");if(!workflow.states.some((state)=>state.id===newState))throw new FSMError(`Cannot reseed run "${runId}" to undeclared state "${newState}"`)}async commitReseed(runId,newState,options){let extKey=(await this.persistence.loadRun(runId))?.external_key??void 0,result=await this.persistence.reseedRun(runId,newState);this.resolveEvents(options?.events)?.emit("workflow.run.reseeded",{runId,fromState:result.fromState??"",toState:result.toState,externalKey:extKey,severity:"warning"})}async resumeRun(workflow,runId,options){let run=await this.persistence.loadRun(runId);if(run===void 0)throw new WorkflowResumeError(`Run "${runId}" not found`);if(run.status!=="paused"&&run.status!=="interrupted")throw new WorkflowResumeError(`Run "${runId}" is not resumable (status: ${run.status})`);let currentState=await this.persistence.loadCurrentState(runId);if(currentState===void 0)throw new WorkflowResumeError(`Run "${runId}" has no persisted state to resume from`);let resumeMode=options?.resumeMode??(run.status==="interrupted"?"rerun-enter":"skip-enter");this.assertResumeRerunAllowed(workflow,currentState,resumeMode);let snapshot=await this.persistence.loadLatestStateSnapshot(runId),persistedVars=extractEffectiveVars(snapshot?.data),restoredVars=mergeVars(persistedVars,options?.vars),owner=options?.resumeOwner??{attemptId:crypto.randomUUID()},mergedOptions={...options,vars:restoredVars,resumeMode,resumeOwner:owner},claimed=await this.persistence.claimRunOwnership(runId,owner,["paused","interrupted"]);if(claimed===void 0){let current=await this.persistence.loadRun(runId);throw new WorkflowResumeError(`Run "${runId}" could not be claimed for resume (status: ${current?.status??"unknown"}, owner: ${current?.owner_attempt??"none"})`)}let extKey=claimed.external_key??void 0;if(this.resolveEvents(mergedOptions.events)?.emit("workflow.run.resumed",{runId,node:currentState,resumeMode,ownerAttemptId:owner.attemptId,externalKey:extKey,severity:"info"}),workflow.kind==="transition-flow")return await new TransitionFlowDriver({host:this.host,persistence:this.persistence}).resume(workflow,runId,currentState,extKey,mergedOptions);return await new StateMachineDriver({host:this.host,persistence:this.persistence}).resume(workflow,runId,currentState,extKey,mergedOptions)}async interruptRun(runId,reason){let interrupted=await this.persistence.interruptRun(runId,reason);if(interrupted!==void 0)this.resolveEvents(void 0)?.emit("workflow.run.interrupted",{runId,reason,externalKey:interrupted.external_key??void 0,severity:"warning"});return interrupted}assertResumeRerunAllowed(workflow,currentState,resumeMode){if(resumeMode!=="rerun-enter")return;let node=workflow.kind==="transition-flow"?workflow.nodes.find((candidate)=>candidate.id===currentState):workflow.states.find((candidate)=>candidate.id===currentState);if(node!==void 0&&node.resumeRerun!==!0)throw new FSMError(`Cannot rerun-resume into "${currentState}": not marked resumeRerun: true `+'(mark its actions as safe to re-run — idempotent or deduped by runId+state — or resume with resumeMode: "skip-enter")')}async listPausedRuns(options){return await this.persistence.listPausedRuns(options)}async requestTransition(workflow,runId,toState,options){let release,previous=this.runLocks.get(runId)??Promise.resolve(),next=previous.then(()=>new Promise((resolve)=>{release=resolve}));this.runLocks.set(runId,next),await previous;try{return await this.evaluateAndCommit(workflow,runId,toState,options)}finally{if(release(),this.runLocks.get(runId)===next)this.runLocks.delete(runId)}}async evaluateAndCommit(workflow,runId,toState,options){let currentState=await this.persistence.loadCurrentState(runId),extKey=(await this.persistence.loadRun(runId))?.external_key??void 0;if(currentState===void 0)return{allowed:!1,reason:"no-such-transition",detail:`No state recorded for run "${runId}"`};let events=this.resolveEvents(options?.events),lifecycle=RunLifecycle.forExternalTransition(workflow.name,runId,{persistence:this.persistence,events},extKey),transition=workflow.transitions.find((t)=>t.from===currentState&&t.to===toState);if(transition===void 0)return this.denyTransition(events,runId,currentState,toState,extKey,{reason:"no-such-transition",detail:`No transition from "${currentState}" to "${toState}"`});let snapshot=await this.persistence.loadLatestStateSnapshot(runId),vars=mergeVars(mergeVars(workflow.vars,extractEffectiveVars(snapshot?.data)),options?.vars),env2=allowedEnv(workflow.env?.allow??[],options?.env);if(transition.guard!==void 0){let resolvedGuardOptions=transition.guard.kind==="shell"?resolveShellCommandTemplates(transition.guard.options??{},{vars,env:env2}):resolveTemplates(transition.guard.options??{},{vars,env:env2}),guardResult=await this.host.evaluateGuardResult(transition.guard.kind,resolvedGuardOptions,{runId,current:currentState,lastActionResult:snapshotActionResult(snapshot?.data),vars,env:env2,workdir:options?.workdir});if(lifecycle.guardEvaluated(currentState,toState,transition.guard.kind,guardResult.passed),!guardResult.passed)return this.denyTransition(events,runId,currentState,toState,extKey,{reason:"guard-failed",detail:`Guard "${transition.guard.kind}" denied transition from "${currentState}" to "${toState}"`,guardKind:transition.guard.kind,...guardResult.report===void 0?{}:{guardReport:guardResult.report}})}let trigger=transition.trigger??null;return await lifecycle.commitHop(currentState,toState,trigger,snapshotTransitions(snapshot?.data)+1,void 0,vars),events?.emit("workflow.transition.requested",{runId,from:currentState,to:toState,trigger,externalKey:extKey,severity:"info"}),{allowed:!0,fromState:currentState,toState}}denyTransition(events,runId,from,to,externalKey,denial){return events?.emit("workflow.transition.denied",{runId,from,to,reason:denial.reason,externalKey,severity:"error"}),{allowed:!1,...denial}}}function extractEffectiveVars(data){if(data===void 0)return{};let raw=data.effectiveVars;if(raw===void 0||raw===null)return{};if(typeof raw!=="object")return{};let filtered={};for(let[key,value]of Object.entries(raw))if(typeof value==="string")filtered[key]=value;return filtered}var RULE_ENGINE_SCHEMA_SQL=`
|
|
699
|
+
WHERE id = ?`,status,durationMs,ok?1:0,result!==void 0?JSON.stringify(applyRedactor(redactor,kind,result)):null,new Date(now).toISOString(),now,actionId)}async loadRun(runId){return await this.ensureSchema(),await this.db.queryFirst("SELECT * FROM runs WHERE id = ?",runId)??void 0}async listRuns(){return await this.ensureSchema(),await this.db.queryAll("SELECT * FROM runs ORDER BY started_at DESC")}async findRunByKey(workflowName,externalKey){return await this.ensureSchema(),await this.db.queryFirst("SELECT * FROM runs WHERE workflow_name = ? AND external_key = ?",workflowName,externalKey)??void 0}async createOrAttachRun(record2){if(await this.ensureSchema(),record2.external_key!==void 0&&record2.external_key!==null){let existing=await this.findRunByKey(record2.workflow_name,record2.external_key);if(existing)return existing}try{await this.createRun(record2)}catch(error51){if(record2.external_key!==void 0&&record2.external_key!==null){let existing=await this.findRunByKey(record2.workflow_name,record2.external_key);if(existing)return existing}throw error51}return{...record2}}async reseedRun(runId,newState){await this.ensureSchema();let previous=await this.loadLatestStateSnapshot(runId),now=Date.now(),data={...previous?.data??{},reseeded:!0,reseededAt:new Date(now).toISOString()};return await this.commitTransition(runId,previous?.state??"",newState,"__reseed__",newState,data),{fromState:previous?.state??null,toState:newState}}async loadCurrentState(runId){return await this.ensureSchema(),(await this.db.queryFirst("SELECT state FROM workflow_states WHERE run_id = ? ORDER BY created_at DESC, rowid DESC LIMIT 1",runId))?.state}async loadLatestStateSnapshot(runId){await this.ensureSchema();let row=await this.db.queryFirst("SELECT state, data_json FROM workflow_states WHERE run_id = ? ORDER BY created_at DESC, rowid DESC LIMIT 1",runId);if(row==null)return;let data={};if(row.data_json!==null&&row.data_json.length>0)try{data=JSON.parse(row.data_json)}catch{data={}}return{state:row.state,data}}async listPausedRuns(options){await this.ensureSchema();let where=["status = 'paused'"],params=[];if(options?.workflowName!==void 0)where.push("workflow_name = ?"),params.push(options.workflowName);let limit=options?.limit??100,sql4=`SELECT * FROM runs WHERE ${where.join(" AND ")} ORDER BY updated_at DESC, rowid DESC LIMIT ?`;return params.push(limit),await this.db.queryAll(sql4,...params)}async saveBranchStart(runId,parallelNode,branchId,startNode){await this.ensureSchema();let id=crypto.randomUUID(),now=Date.now();return await this.db.run(`INSERT INTO workflow_branches (id, run_id, parallel_node, branch_id, status, node, started_at, created_at, updated_at)
|
|
700
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
701
|
+
ON CONFLICT(run_id, parallel_node, branch_id) DO UPDATE SET
|
|
702
|
+
status = 'running', node = excluded.node, started_at = excluded.started_at, completed_at = NULL, error = NULL, updated_at = excluded.updated_at`,id,runId,parallelNode,branchId,"running",startNode,new Date(now).toISOString(),now,now),id}async saveBranchFinalize(runId,branchId,status,durationMs,outputVars,error51){await this.ensureSchema();let now=Date.now();await this.db.run(`UPDATE workflow_branches
|
|
703
|
+
SET status = ?, duration_ms = ?, output_vars_json = ?, error = ?, completed_at = ?, updated_at = ?
|
|
704
|
+
WHERE run_id = ? AND branch_id = ?`,status,durationMs,outputVars!==void 0?JSON.stringify(outputVars):null,error51??null,new Date(now).toISOString(),now,runId,branchId)}async listRunBranches(runId,parallelNode){if(await this.ensureSchema(),parallelNode!==void 0)return await this.db.queryAll("SELECT * FROM workflow_branches WHERE run_id = ? AND parallel_node = ? ORDER BY created_at ASC",runId,parallelNode);return await this.db.queryAll("SELECT * FROM workflow_branches WHERE run_id = ? ORDER BY created_at ASC",runId)}async commitJoin(runId,parallelNode,joinNode,mergedVars,phase){await this.ensureSchema();let data={};if(mergedVars!==void 0)data.effectiveVars=mergedVars;await this.commitTransition(runId,parallelNode,joinNode,"__join__",joinNode,data,phase)}}init_dist7();async function runActionStep(action,vars,deps){let{host,persistence,lifecycle,stateOrNodeId,runId}=deps,templateContext={vars,env:deps.env,builtins:runtimeBuiltins(deps.workflowName,stateOrNodeId,runId,deps.transitionsTaken,deps.mode)},resolvedWithEnv=action.kind==="shell"?resolveShellCommandTemplates(action.options??{},templateContext):resolveTemplates(action.options??{},templateContext),{[SHELL_ENV_OPTION]:_shellEnv,...resolved}=resolvedWithEnv,actionId=await persistence.saveActionStart(runId,stateOrNodeId,action.kind,resolved),actionStartMs=Date.now();lifecycle.actionStart(stateOrNodeId,action.kind);let result;try{result=await host.runAction(action.kind,resolvedWithEnv,{runId,actionId,workdir:deps.options.workdir,stateOrNodeId,vars,env:deps.env,metadata:deps.options.metadata,events:deps.options.events,signal:deps.signal??deps.options.signal})}catch(error51){result={ok:!1,error:error51 instanceof Error?error51.message:String(error51)}}finally{let durationMs=Date.now()-actionStartMs;lifecycle.actionDone(stateOrNodeId,action.kind,durationMs,result?.ok??!1),await persistence.saveActionFinalize(actionId,result?.ok===!0?"done":"failed",durationMs,result?.ok??!1,action.kind,result,deps.options.redactor??defaultActionRedactor)}if(result.terminal===!0)return{outcome:"terminal",result};if(!result.ok){if(resolveOnErrorPolicy(action.onError,deps.defaultOnError,deps.options.onError)==="fail")return{outcome:"fail",result};lifecycle.warnActionFailed(stateOrNodeId,deps.transitionsTaken,result.error)}return{outcome:"completed",result}}async function runActionSequence(actions,vars,deps){let last,acc;for(let action of actions){let step=await runActionStep(action,vars,deps);if(step.result!==void 0)last=step.result;if(step.result?.setVars)acc=mergeSetVars(acc??{},step.result.setVars),vars=mergeSetVars(vars,step.result.setVars);if(step.outcome==="terminal")return{outcome:"terminal",result:last,setVars:acc};if(step.outcome==="fail")return{outcome:"fail",result:last,setVars:acc}}return{outcome:"completed",result:last,setVars:acc}}var DAG_LEDGER_NAMESPACE="__dag__";class DagDriver{options;constructor(options){this.options=options}async run(workflow,options={}){return await RunLifecycle.run(workflow.name,"dag",{persistence:this.options.persistence,events:options.events},options,(lifecycle)=>this.loop(workflow,options,lifecycle))}async resume(workflow,runId,externalKey,options={}){return await RunLifecycle.resume(workflow.name,"dag",{persistence:this.options.persistence,events:options.events},runId,externalKey,(lifecycle)=>this.loop(workflow,options,lifecycle),options.resumeOwner?.attemptId)}async loop(workflow,options,lifecycle){let runId=lifecycle.runId,vars=mergeVars(workflow.vars,options.vars),env2=allowedEnv(workflow.env?.allow??[],options.env),defaultOnError=workflow.defaultOnError,snapshot=await this.options.persistence.loadLatestStateSnapshot(runId),transitionsTaken=snapshotTransitions(snapshot?.data);if(snapshot?.data?.effectiveVars&&typeof snapshot.data.effectiveVars==="object")vars=mergeVars(vars,snapshot.data.effectiveVars);let nodeStatuses=new Map,pausedNodeId=snapshot?.state,priorRows=await this.options.persistence.listRunBranches(runId,DAG_LEDGER_NAMESPACE),priorByNode=new Map(priorRows.map((r)=>[r.branch_id,r.status]));for(let node of workflow.nodes){let deps=node.dependsOn??[],prior=priorByNode.get(node.id);if(prior==="done")nodeStatuses.set(node.id,"done");else if(prior==="cancelled")nodeStatuses.set(node.id,"skipped");else if(prior==="failed")nodeStatuses.set(node.id,"failed");else if(pausedNodeId&&node.id===pausedNodeId)nodeStatuses.set(node.id,"done");else nodeStatuses.set(node.id,deps.length===0?"ready":"pending")}let checkDependenciesSatisfied=(node)=>{let deps=node.dependsOn??[];if(deps.length===0)return{ready:!0,shouldSkip:!1};let policy=node.dependencyPolicy??"all",depStatuses=deps.map((d)=>nodeStatuses.get(d)??"pending");if(policy==="any"){if(depStatuses.some((s2)=>s2==="done"))return{ready:!0,shouldSkip:!1};let allSettled2=depStatuses.every((s2)=>s2==="done"||s2==="skipped"||s2==="failed"),allSkipped=depStatuses.every((s2)=>s2==="skipped");return{ready:!1,shouldSkip:allSettled2&&allSkipped}}if(depStatuses.every((s2)=>s2==="done"))return{ready:!0,shouldSkip:!1};let allSettled=depStatuses.every((s2)=>s2==="done"||s2==="skipped"),hasSkipped=depStatuses.some((s2)=>s2==="skipped");if(allSettled&&hasSkipped){if(depStatuses.every((s2)=>s2==="skipped"))return{ready:!1,shouldSkip:!0};return{ready:!0,shouldSkip:!1}}return{ready:!1,shouldSkip:!1}},pausedNode,failureError;while(!0){let readyNodes=[];for(let node of workflow.nodes){let status=nodeStatuses.get(node.id);if(status==="pending"){let check2=checkDependenciesSatisfied(node);if(check2.shouldSkip)nodeStatuses.set(node.id,"skipped");else if(check2.ready)nodeStatuses.set(node.id,"ready"),readyNodes.push(node)}else if(status==="ready")readyNodes.push(node)}if(readyNodes.length===0)break;let results=await Promise.all(readyNodes.map(async(node)=>{nodeStatuses.set(node.id,"running");let nodeStartMs=Date.now();if(!options.dryRun)await this.options.persistence.saveBranchStart(runId,DAG_LEDGER_NAMESPACE,node.id,node.id);if(node.condition){let resolvedOptions=node.condition.kind==="shell"?resolveShellCommandTemplates(node.condition.options??{},{vars,env:env2}):resolveTemplates(node.condition.options??{},{vars,env:env2});if(!await this.options.host.evaluateGuard(node.condition.kind,resolvedOptions,{runId,current:node.id,vars,env:env2,workdir:options.workdir})){if(nodeStatuses.set(node.id,"skipped"),!options.dryRun)await this.options.persistence.saveBranchFinalize(runId,node.id,"cancelled",Date.now()-nodeStartMs);return{id:node.id,status:"skipped"}}}if(node.pause===!0){if(nodeStatuses.set(node.id,"paused"),!options.dryRun)await this.options.persistence.saveBranchFinalize(runId,node.id,"paused",Date.now()-nodeStartMs);return{id:node.id,status:"paused"}}if(!options.dryRun&&node.action){let step=await runActionStep(node.action,vars,{host:this.options.host,persistence:this.options.persistence,lifecycle,workflowName:workflow.name,stateOrNodeId:node.id,runId,mode:"dag",transitionsTaken,env:env2,options,defaultOnError});if(step.outcome==="fail"){if(nodeStatuses.set(node.id,"failed"),!options.dryRun)await this.options.persistence.saveBranchFinalize(runId,node.id,"failed",Date.now()-nodeStartMs,void 0,step.result?.error??"failed");return{id:node.id,status:"failed",error:step.result?.error??"failed"}}if(step.result?.setVars)vars=mergeSetVars(vars,step.result.setVars)}if(nodeStatuses.set(node.id,"done"),transitionsTaken++,!options.dryRun)await this.options.persistence.saveBranchFinalize(runId,node.id,"done",Date.now()-nodeStartMs);return{id:node.id,status:"done"}}));for(let res of results)if(res.status==="failed")failureError=res.error;else if(res.status==="paused")pausedNode=res.id;if(failureError)return await lifecycle.fail("dag",transitionsTaken,failureError);if(pausedNode)return await lifecycle.pause(pausedNode,transitionsTaken,vars)}if(Array.from(nodeStatuses.values()).some((s2)=>s2==="failed"))return await lifecycle.fail("dag",transitionsTaken,failureError??"dag-failed");let stuck=workflow.nodes.filter((n2)=>nodeStatuses.get(n2.id)==="pending").map((n2)=>n2.id);if(stuck.length>0)return await lifecycle.fail("dag",transitionsTaken,`dag-unreachable-nodes: ${stuck.join(",")}`);return await lifecycle.done("dag",transitionsTaken)}}class StateMachineDriver{options;constructor(options){this.options=options}async run(workflow,options={}){return await RunLifecycle.run(workflow.name,"state-machine",{persistence:this.options.persistence,events:options.events},options,(lifecycle)=>this.loop(workflow,options,lifecycle,void 0,options.startState))}async resume(workflow,runId,resumeFromState,externalKey,options={}){return await RunLifecycle.resume(workflow.name,"state-machine",{persistence:this.options.persistence,events:options.events},runId,externalKey,(lifecycle)=>this.loop(workflow,options,lifecycle,resumeFromState),options.resumeOwner?.attemptId)}async loop(workflow,options,lifecycle,resumeFromState,startAtState){let runId=lifecycle.runId,states=new Map(workflow.states.map((state)=>[state.id,state])),terminal=new Set(workflow.terminalStates??[]),failure=new Set(workflow.failureStates??[]),vars=mergeVars(workflow.vars,options.vars),env2=allowedEnv(workflow.env?.allow??[],options.env),entryState=resumeFromState??startAtState,current=entryState!==void 0?states.get(entryState):states.get(workflow.initialState),snapshot=resumeFromState===void 0?void 0:await this.options.persistence.loadLatestStateSnapshot(runId),transitionsTaken=snapshotTransitions(snapshot?.data),lastActionResult=snapshotActionResult(snapshot?.data),iterationBound=workflow.iterationBound??50,defaultOnError=workflow.defaultOnError,resumeMode=resumeFromState!==void 0?options.resumeMode??"skip-enter":void 0,persistedViaHop=!1,declaredTerminalReason;if(current===void 0){let label=entryState??workflow.initialState;throw new FSMError(`State "${label}" is not declared`)}while(!0){if(resumeMode==="skip-enter")resumeMode=void 0,persistedViaHop=!0;else{if(resumeMode==="rerun-enter"){if(current.resumeRerun!==!0)throw new FSMError(`Cannot rerun-resume into state "${current.id}": not marked resumeRerun: true (mark its on-enter actions as safe to re-run, or resume with resumeMode: "skip-enter")`);resumeMode=void 0,persistedViaHop=!0}await lifecycle.enter(current.id,transitionsTaken,!persistedViaHop,vars);let enter=options.dryRun?EMPTY_OUTCOME:await runActionSequence(current.onEnter??[],vars,{host:this.options.host,persistence:this.options.persistence,lifecycle,workflowName:workflow.name,stateOrNodeId:current.id,runId,mode:"state-machine",transitionsTaken,env:env2,options,defaultOnError});if(enter.result!==void 0)lastActionResult=enter.result;if(enter.setVars)vars=mergeSetVars(vars,enter.setVars);if(enter.outcome==="terminal")return failure.has(current.id)?await lifecycle.fail(current.id,transitionsTaken,`terminal:${current.id}`):await lifecycle.done(current.id,transitionsTaken);if(enter.outcome==="fail")return await lifecycle.fail(current.id,transitionsTaken,lastActionResult?.error);if(current.pause===!0)return await lifecycle.pause(current.id,transitionsTaken,vars,lastActionResult)}let outbound=workflow.transitions.filter((transition)=>transition.from===current?.id);if(terminal.has(current.id)||outbound.length===0){let declared=declaredTerminalReason;return declaredTerminalReason=void 0,failure.has(current.id)?await lifecycle.fail(current.id,transitionsTaken,declared??`terminal:${current.id}`):await lifecycle.done(current.id,transitionsTaken,declared)}let nextTransition=await firstPassingTransition(outbound,this.options.host,{runId,current:current.id,vars,env:env2,lastActionResult,workdir:options.workdir},lifecycle);if(nextTransition===void 0)return await lifecycle.fail(current.id,transitionsTaken,"no-passing-transition");let exit=options.dryRun?EMPTY_OUTCOME:await runActionSequence(current.onExit??[],vars,{host:this.options.host,persistence:this.options.persistence,lifecycle,workflowName:workflow.name,stateOrNodeId:current.id,runId,mode:"state-machine",transitionsTaken,env:env2,options,defaultOnError});if(exit.result!==void 0)lastActionResult=exit.result;if(exit.setVars)vars=mergeSetVars(vars,exit.setVars);if(exit.outcome==="terminal")return failure.has(current.id)?await lifecycle.fail(current.id,transitionsTaken,`terminal:${current.id}`):await lifecycle.done(current.id,transitionsTaken);if(exit.outcome==="fail")return await lifecycle.fail(current.id,transitionsTaken,exit.result?.error);if(transitionsTaken+=1,await lifecycle.commitHop(current.id,nextTransition.to,nextTransition.trigger??null,transitionsTaken,{phase:nextTransition.to,status:"running"},vars),transitionsTaken>iterationBound)return await lifecycle.fail(current.id,transitionsTaken,"iteration-bound-exceeded");let nextState=states.get(nextTransition.to);if(nextState===void 0)throw new FSMError(`Transition target "${nextTransition.to}" is not declared`);current=nextState,declaredTerminalReason=nextTransition.terminalReason,persistedViaHop=!0}}}var EMPTY_OUTCOME={outcome:"completed",result:void 0,setVars:void 0};async function firstPassingTransition(transitions,host,context4,lifecycle){for(let transition of transitions){if(transition.guard===void 0)return transition;let resolvedOptions=transition.guard.kind==="shell"?resolveShellCommandTemplates(transition.guard.options??{},{vars:context4.vars,env:context4.env??{}}):resolveTemplates(transition.guard.options??{},{vars:context4.vars,env:context4.env??{}}),passed=await host.evaluateGuard(transition.guard.kind,resolvedOptions,context4);if(lifecycle.guardEvaluated(context4.current,transition.to,transition.guard.kind,passed),passed)return transition}return}class TransitionFlowDriver{options;constructor(options){this.options=options}async run(workflow,options={}){return await RunLifecycle.run(workflow.name,"transition-flow",{persistence:this.options.persistence,events:options.events},options,(lifecycle)=>this.loop(workflow,options,lifecycle,void 0,options.startState))}async resume(workflow,runId,resumeFromNode,externalKey,options={}){return await RunLifecycle.resume(workflow.name,"transition-flow",{persistence:this.options.persistence,events:options.events},runId,externalKey,(lifecycle)=>this.loop(workflow,options,lifecycle,resumeFromNode),options.resumeOwner?.attemptId)}async loop(workflow,options,lifecycle,resumeFromNode,startAtNode){let runId=lifecycle.runId,nodes=new Map(workflow.nodes.map((node)=>[node.id,node])),terminal=new Set(workflow.terminalNodes??[]),vars=mergeVars(workflow.vars,options.vars),env2=allowedEnv(workflow.env?.allow??[],options.env),entryNode=resumeFromNode??startAtNode,current=entryNode!==void 0?nodes.get(entryNode):nodes.get(workflow.initialNode),snapshot=resumeFromNode===void 0?void 0:await this.options.persistence.loadLatestStateSnapshot(runId),transitionsTaken=snapshotTransitions(snapshot?.data),lastActionResult=snapshotActionResult(snapshot?.data),iterationBound=workflow.iterationBound??50,defaultOnError=workflow.defaultOnError,resumeMode=resumeFromNode!==void 0?options.resumeMode??"skip-enter":void 0,persistedViaHop=!1;if(current===void 0){let label=entryNode??workflow.initialNode;throw new FSMError(`Node "${label}" is not declared`)}while(!0){if(resumeMode==="skip-enter")resumeMode=void 0,persistedViaHop=!0;else{if(resumeMode==="rerun-enter"){if(current.resumeRerun!==!0)throw new FSMError(`Cannot rerun-resume into node "${current.id}": not marked resumeRerun: true (mark its action as safe to re-run, or resume with resumeMode: "skip-enter")`);resumeMode=void 0,persistedViaHop=!0}if(await lifecycle.enter(current.id,transitionsTaken,!persistedViaHop,vars),options.dryRun){if(current.action!==void 0)lastActionResult=void 0}else if(current.action!==void 0){let step=await runActionStep(current.action,vars,{host:this.options.host,persistence:this.options.persistence,lifecycle,workflowName:workflow.name,stateOrNodeId:current.id,runId,mode:"transition-flow",transitionsTaken,env:env2,options,defaultOnError,signal:options.signal});if(lastActionResult=step.result,step.result?.setVars)vars=mergeSetVars(vars,step.result.setVars);if(step.outcome==="terminal")return await lifecycle.done(current.id,transitionsTaken);if(step.outcome==="fail")return await lifecycle.fail(current.id,transitionsTaken,step.result?.error)}if(current.pause===!0)return await lifecycle.pause(current.id,transitionsTaken,vars,lastActionResult)}if(current.type==="parallel"){if(!current.branches||!current.join)throw new FSMError(`Parallel node "${current.id}" must declare branches and join target`);let parallelNode=current,concurrency=parallelNode.concurrencyLimit??4;if(!options.dryRun){let existingBranches=await this.options.persistence.listRunBranches(runId,parallelNode.id),branchControllers=new Map;for(let b of parallelNode.branches){let ctrl=new AbortController;if(branchControllers.set(b.id,ctrl),options.signal)if(options.signal.aborted)ctrl.abort();else options.signal.addEventListener("abort",()=>ctrl.abort(),{once:!0})}let abortSiblings=(failingBranchId)=>{if(parallelNode.failurePolicy==="fail-fast"){for(let[id,ctrl]of branchControllers.entries())if(id!==failingBranchId)ctrl.abort()}},branchResults=await runWithConcurrencyLimit(parallelNode.branches,concurrency,async(branch)=>{let existing=existingBranches.find((b)=>b.branch_id===branch.id);if(existing?.status==="done"){let restoredVars={};if(existing.output_vars_json)try{restoredVars=JSON.parse(existing.output_vars_json)}catch{restoredVars={}}return{ok:!0,branchId:branch.id,setVars:restoredVars}}let branchCtrl=branchControllers.get(branch.id)??new AbortController,branchStartMs=Date.now(),branchCurrent,skipEnter=!1;if(existing?.status==="paused")branchCurrent=nodes.get(existing.node)??nodes.get(branch.startNode),skipEnter=(resumeMode??options.resumeMode??"skip-enter")==="skip-enter";else branchCurrent=nodes.get(branch.startNode),await this.options.persistence.saveBranchStart(runId,parallelNode.id,branch.id,branch.startNode);lifecycle.branchStarted(parallelNode.id,branch.id,branchCurrent?.id??branch.startNode);let branchVars={...vars},branchSetVars={};while(branchCurrent&&branchCurrent.id!==parallelNode.join){if(branchCtrl.signal.aborted)return lifecycle.branchFailed(parallelNode.id,branch.id,"cancelled"),await this.options.persistence.saveBranchFinalize(runId,branch.id,"cancelled",Date.now()-branchStartMs,void 0,"cancelled"),{ok:!1,branchId:branch.id,error:"cancelled"};if(skipEnter)skipEnter=!1;else{if(branchCurrent.action!==void 0){let step=await runActionStep(branchCurrent.action,branchVars,{host:this.options.host,persistence:this.options.persistence,lifecycle,workflowName:workflow.name,stateOrNodeId:branchCurrent.id,runId,mode:"transition-flow",transitionsTaken,env:env2,options,defaultOnError,signal:branchCtrl.signal});if(step.result?.setVars)branchVars=mergeSetVars(branchVars,step.result.setVars),branchSetVars=mergeSetVars(branchSetVars,step.result.setVars);if(branchCtrl.signal.aborted)return lifecycle.branchFailed(parallelNode.id,branch.id,"cancelled"),await this.options.persistence.saveBranchFinalize(runId,branch.id,"cancelled",Date.now()-branchStartMs,void 0,"cancelled"),{ok:!1,branchId:branch.id,error:"cancelled"};if(step.outcome==="fail"){abortSiblings(branch.id);let err=step.result?.error??"action-failed";return lifecycle.branchFailed(parallelNode.id,branch.id,err),await this.options.persistence.saveBranchFinalize(runId,branch.id,"failed",Date.now()-branchStartMs,void 0,err),{ok:!1,branchId:branch.id,error:err}}if(step.outcome==="terminal")break}if(branchCurrent.pause===!0)return lifecycle.branchPaused(parallelNode.id,branch.id,branchCurrent.id),await this.options.persistence.saveBranchFinalize(runId,branch.id,"paused",Date.now()-branchStartMs,branchSetVars),{ok:!0,branchId:branch.id,paused:!0,setVars:branchSetVars}}let outbound2=workflow.edges.filter((e)=>e.from===branchCurrent?.id);if(outbound2.length===0||terminal.has(branchCurrent.id))break;let edge2=await firstPassingEdge(outbound2,this.options.host,{runId,current:branchCurrent.id,vars:branchVars,env:env2,workdir:options.workdir,signal:branchCtrl.signal},lifecycle);if(edge2===void 0)return abortSiblings(branch.id),lifecycle.branchFailed(parallelNode.id,branch.id,"no-passing-edge"),await this.options.persistence.saveBranchFinalize(runId,branch.id,"failed",Date.now()-branchStartMs,void 0,"no-passing-edge"),{ok:!1,branchId:branch.id,error:"no-passing-edge"};branchCurrent=nodes.get(edge2.to)}if(branchCtrl.signal.aborted)return lifecycle.branchFailed(parallelNode.id,branch.id,"cancelled"),await this.options.persistence.saveBranchFinalize(runId,branch.id,"cancelled",Date.now()-branchStartMs,void 0,"cancelled"),{ok:!1,branchId:branch.id,error:"cancelled"};return lifecycle.branchDone(parallelNode.id,branch.id,Date.now()-branchStartMs,!0),await this.options.persistence.saveBranchFinalize(runId,branch.id,"done",Date.now()-branchStartMs,branchSetVars),{ok:!0,branchId:branch.id,setVars:branchSetVars}}),failed=branchResults.find((r)=>!r.ok);if(failed)return await lifecycle.fail(current.id,transitionsTaken,failed.error??"branch-failed");let anyPaused=branchResults.some((r)=>("paused"in r)&&r.paused===!0);for(let res of branchResults)if(res.setVars)vars=mergeSetVars(vars,res.setVars);if(anyPaused)return await lifecycle.pause(current.id,transitionsTaken,vars)}transitionsTaken+=1,await this.options.persistence.commitJoin(runId,current.id,parallelNode.join,vars,{phase:parallelNode.join,status:"running"});let joinNode=nodes.get(parallelNode.join);if(joinNode===void 0)throw new FSMError(`Join target "${parallelNode.join}" is not declared`);current=joinNode,persistedViaHop=!0;continue}let outbound=workflow.edges.filter((edge2)=>edge2.from===current?.id);if(terminal.has(current.id)||outbound.length===0)return await lifecycle.done(current.id,transitionsTaken);let edge=await firstPassingEdge(outbound,this.options.host,{runId,current:current.id,vars,env:env2,lastActionResult,workdir:options.workdir,signal:options.signal},lifecycle);if(edge===void 0)return await lifecycle.fail(current.id,transitionsTaken,"no-passing-edge");if(transitionsTaken+=1,await lifecycle.commitHop(current.id,edge.to,edge.condition?.kind??null,transitionsTaken,{phase:edge.to,status:"running"},vars),transitionsTaken>iterationBound)return await lifecycle.fail(current.id,transitionsTaken,"iteration-bound-exceeded");let nextNode=nodes.get(edge.to);if(nextNode===void 0)throw new FSMError(`Edge target "${edge.to}" is not declared`);current=nextNode,persistedViaHop=!0}}}async function firstPassingEdge(edges,host,context4,lifecycle){for(let edge of edges){if(edge.condition===void 0)return edge;let resolvedOptions=edge.condition.kind==="shell"?resolveShellCommandTemplates(edge.condition.options??{},{vars:context4.vars,env:context4.env??{}}):resolveTemplates(edge.condition.options??{},{vars:context4.vars,env:context4.env??{}}),passed=await host.evaluateGuard(edge.condition.kind,resolvedOptions,context4);if(lifecycle.guardEvaluated(context4.current,edge.to,edge.condition.kind,passed),passed)return edge}return}async function runWithConcurrencyLimit(items,limit,fn){let results=Array(items.length),nextIndex=0,workerCount=Math.max(1,Math.min(limit,items.length)),workers=Array(workerCount).fill(null).map(async()=>{while(nextIndex<items.length){let index2=nextIndex++,item=items[index2];if(item!==void 0)results[index2]=await fn(item)}});return await Promise.all(workers),results}class WorkflowService{host;persistence;runLocks=new Map;lifecycleBus;constructor(host,persistence,lifecycleBus){this.host=host,this.persistence=persistence,this.lifecycleBus=lifecycleBus??host.lifecycleBus}resolveEvents(events){return events??(this.lifecycleBus?new EventBus({lifecycleBus:this.lifecycleBus}):void 0)}async load(path8){return await loadWorkflowDef(path8)}async run(workflow,options={}){let events=this.resolveEvents(options.events);if(options.startState!==void 0)this.assertStartStateAllowed(workflow,options.startState);if(workflow.kind==="transition-flow")return await new TransitionFlowDriver({host:this.host,persistence:this.persistence}).run(workflow,{...options,events});if(workflow.kind==="dag")return await new DagDriver({host:this.host,persistence:this.persistence}).run(workflow,{...options,events});return await new StateMachineDriver({host:this.host,persistence:this.persistence}).run(workflow,{...options,events})}async runFile(path8,options={}){return await this.run(await this.load(path8),options)}async listRuns(){return await this.persistence.listRuns()}async findRunByKey(workflowName,externalKey){return await this.persistence.findRunByKey(workflowName,externalKey)}async createOrAttachRun(record2){return await this.persistence.createOrAttachRun(record2)}async reseedRun(workflowOrRunId,runIdOrNewState,newStateOrOptions,maybeOptions){let args=typeof workflowOrRunId==="string"?{workflow:void 0,runId:workflowOrRunId,newState:runIdOrNewState,options:newStateOrOptions}:{workflow:workflowOrRunId,runId:runIdOrNewState,newState:newStateOrOptions,options:maybeOptions};if(args.workflow!==void 0)this.assertReseedTargetDeclared(args.workflow,args.runId,args.newState);await this.commitReseed(args.runId,args.newState,args.options)}assertReseedTargetDeclared(workflow,runId,newState){if(workflow.kind!=="state-machine"&&workflow.kind!==void 0)throw new FSMError("reseedRun only supports state-machine workflows");if(!workflow.states.some((state)=>state.id===newState))throw new FSMError(`Cannot reseed run "${runId}" to undeclared state "${newState}"`)}assertStartStateAllowed(workflow,startState){if(workflow.kind==="dag")throw new FSMError(`Cannot start at "${startState}": startState is not supported for kind: "dag" workflows`);let nodes=workflow.kind==="transition-flow"?workflow.nodes:workflow.states,terminal=workflow.kind==="transition-flow"?workflow.terminalNodes??[]:workflow.terminalStates??[],failure=workflow.kind==="transition-flow"?[]:workflow.failureStates??[],declared=nodes.find((node)=>node.id===startState);if(declared===void 0){let startable=nodes.filter((node)=>node.startable===!0).map((node)=>node.id);throw new FSMError(`Cannot start at "${startState}": it is not declared. `+(startable.length>0?`Startable ids: ${startable.join(", ")}`:"No state or node declares startable: true"))}if(failure.includes(startState))throw new FSMError(`Cannot start at "${startState}": it is declared as a failure state`);if(terminal.includes(startState))throw new FSMError(`Cannot start at "${startState}": it is declared as a terminal state`);if(declared.startable!==!0)throw new FSMError(`Cannot start at "${startState}": not marked startable: true. `+"Opt in from the definition — there is no caller override.")}async commitReseed(runId,newState,options){let extKey=(await this.persistence.loadRun(runId))?.external_key??void 0,result=await this.persistence.reseedRun(runId,newState);this.resolveEvents(options?.events)?.emit("workflow.run.reseeded",{runId,fromState:result.fromState??"",toState:result.toState,externalKey:extKey,severity:"warning"})}async resumeRun(workflow,runId,options){let run=await this.persistence.loadRun(runId);if(run===void 0)throw new WorkflowResumeError(`Run "${runId}" not found`);if(run.status!=="paused"&&run.status!=="interrupted")throw new WorkflowResumeError(`Run "${runId}" is not resumable (status: ${run.status})`);let currentState=await this.persistence.loadCurrentState(runId);if(currentState===void 0)throw new WorkflowResumeError(`Run "${runId}" has no persisted state to resume from`);let resumeMode=options?.resumeMode??(run.status==="interrupted"?"rerun-enter":"skip-enter");this.assertResumeRerunAllowed(workflow,currentState,resumeMode);let snapshot=await this.persistence.loadLatestStateSnapshot(runId),persistedVars=extractEffectiveVars(snapshot?.data),restoredVars=mergeVars(persistedVars,options?.vars),owner=options?.resumeOwner??{attemptId:crypto.randomUUID()},mergedOptions={...options,vars:restoredVars,resumeMode,resumeOwner:owner},claimed=await this.persistence.claimRunOwnership(runId,owner,["paused","interrupted"]);if(claimed===void 0){let current=await this.persistence.loadRun(runId);throw new WorkflowResumeError(`Run "${runId}" could not be claimed for resume (status: ${current?.status??"unknown"}, owner: ${current?.owner_attempt??"none"})`)}let extKey=claimed.external_key??void 0;if(this.resolveEvents(mergedOptions.events)?.emit("workflow.run.resumed",{runId,node:currentState,resumeMode,ownerAttemptId:owner.attemptId,externalKey:extKey,severity:"info"}),workflow.kind==="transition-flow")return await new TransitionFlowDriver({host:this.host,persistence:this.persistence}).resume(workflow,runId,currentState,extKey,mergedOptions);if(workflow.kind==="dag")return await new DagDriver({host:this.host,persistence:this.persistence}).resume(workflow,runId,extKey,mergedOptions);return await new StateMachineDriver({host:this.host,persistence:this.persistence}).resume(workflow,runId,currentState,extKey,mergedOptions)}async interruptRun(runId,reason){let interrupted=await this.persistence.interruptRun(runId,reason);if(interrupted!==void 0)this.resolveEvents(void 0)?.emit("workflow.run.interrupted",{runId,reason,externalKey:interrupted.external_key??void 0,severity:"warning"});return interrupted}assertResumeRerunAllowed(workflow,currentState,resumeMode){if(resumeMode!=="rerun-enter")return;let node=workflow.kind==="transition-flow"||workflow.kind==="dag"?workflow.nodes.find((candidate)=>candidate.id===currentState):workflow.states.find((candidate)=>candidate.id===currentState);if(node!==void 0&&node.resumeRerun!==!0)throw new FSMError(`Cannot rerun-resume into "${currentState}": not marked resumeRerun: true `+'(mark its actions as safe to re-run — idempotent or deduped by runId+state — or resume with resumeMode: "skip-enter")')}async listPausedRuns(options){return await this.persistence.listPausedRuns(options)}async requestTransition(workflow,runId,toState,options){let release,previous=this.runLocks.get(runId)??Promise.resolve(),next=previous.then(()=>new Promise((resolve)=>{release=resolve}));this.runLocks.set(runId,next),await previous;try{return await this.evaluateAndCommit(workflow,runId,toState,options)}finally{if(release(),this.runLocks.get(runId)===next)this.runLocks.delete(runId)}}async evaluateAndCommit(workflow,runId,toState,options){let currentState=await this.persistence.loadCurrentState(runId),extKey=(await this.persistence.loadRun(runId))?.external_key??void 0;if(currentState===void 0)return{allowed:!1,reason:"no-such-transition",detail:`No state recorded for run "${runId}"`};let events=this.resolveEvents(options?.events),lifecycle=RunLifecycle.forExternalTransition(workflow.name,runId,{persistence:this.persistence,events},extKey),transition=workflow.transitions.find((t)=>t.from===currentState&&t.to===toState);if(transition===void 0)return this.denyTransition(events,runId,currentState,toState,extKey,{reason:"no-such-transition",detail:`No transition from "${currentState}" to "${toState}"`});let snapshot=await this.persistence.loadLatestStateSnapshot(runId),vars=mergeVars(mergeVars(workflow.vars,extractEffectiveVars(snapshot?.data)),options?.vars),env2=allowedEnv(workflow.env?.allow??[],options?.env);if(transition.guard!==void 0){let resolvedGuardOptions=transition.guard.kind==="shell"?resolveShellCommandTemplates(transition.guard.options??{},{vars,env:env2}):resolveTemplates(transition.guard.options??{},{vars,env:env2}),guardResult=await this.host.evaluateGuardResult(transition.guard.kind,resolvedGuardOptions,{runId,current:currentState,lastActionResult:snapshotActionResult(snapshot?.data),vars,env:env2,workdir:options?.workdir});if(lifecycle.guardEvaluated(currentState,toState,transition.guard.kind,guardResult.passed),!guardResult.passed)return this.denyTransition(events,runId,currentState,toState,extKey,{reason:"guard-failed",detail:`Guard "${transition.guard.kind}" denied transition from "${currentState}" to "${toState}"`,guardKind:transition.guard.kind,...guardResult.report===void 0?{}:{guardReport:guardResult.report}})}let trigger=transition.trigger??null;return await lifecycle.commitHop(currentState,toState,trigger,snapshotTransitions(snapshot?.data)+1,void 0,vars),events?.emit("workflow.transition.requested",{runId,from:currentState,to:toState,trigger,externalKey:extKey,severity:"info"}),{allowed:!0,fromState:currentState,toState}}denyTransition(events,runId,from,to,externalKey,denial){return events?.emit("workflow.transition.denied",{runId,from,to,reason:denial.reason,externalKey,severity:"error"}),{allowed:!1,...denial}}}function extractEffectiveVars(data){if(data===void 0)return{};let raw=data.effectiveVars;if(raw===void 0||raw===null)return{};if(typeof raw!=="object")return{};let filtered={};for(let[key,value]of Object.entries(raw))if(typeof value==="string")filtered[key]=value;return filtered}var RULE_ENGINE_SCHEMA_SQL=`
|
|
667
705
|
CREATE TABLE IF NOT EXISTS rule_runs (
|
|
668
706
|
id TEXT PRIMARY KEY,
|
|
669
707
|
preset TEXT,
|
|
@@ -806,16 +844,21 @@ CREATE TABLE IF NOT EXISTS coordination_runs (
|
|
|
806
844
|
artifact_refs_json TEXT NOT NULL DEFAULT '[]',
|
|
807
845
|
message_ids_json TEXT NOT NULL DEFAULT '[]',
|
|
808
846
|
task_id TEXT,
|
|
809
|
-
outcome TEXT NOT NULL DEFAULT 'run-exit-only'
|
|
847
|
+
outcome TEXT NOT NULL DEFAULT 'run-exit-only',
|
|
848
|
+
parent_run_id TEXT
|
|
810
849
|
);
|
|
811
850
|
|
|
812
851
|
CREATE INDEX IF NOT EXISTS idx_coordination_runs_spec ON coordination_runs (spec_id, generation DESC);
|
|
813
852
|
CREATE INDEX IF NOT EXISTS idx_coordination_runs_task ON coordination_runs (task_id);
|
|
853
|
+
CREATE INDEX IF NOT EXISTS idx_coordination_runs_parent ON coordination_runs (parent_run_id);
|
|
814
854
|
`,COORDINATION_RUNS_RECEIPT_COLUMNS_SCHEMA_SQL=`
|
|
815
855
|
ALTER TABLE coordination_runs ADD COLUMN message_ids_json TEXT NOT NULL DEFAULT '[]';
|
|
816
856
|
ALTER TABLE coordination_runs ADD COLUMN task_id TEXT;
|
|
817
857
|
ALTER TABLE coordination_runs ADD COLUMN outcome TEXT NOT NULL DEFAULT 'run-exit-only';
|
|
818
858
|
CREATE INDEX IF NOT EXISTS idx_coordination_runs_task ON coordination_runs (task_id);
|
|
859
|
+
`,COORDINATION_RUNS_PARENT_SCHEMA_SQL=`
|
|
860
|
+
ALTER TABLE coordination_runs ADD COLUMN parent_run_id TEXT;
|
|
861
|
+
CREATE INDEX IF NOT EXISTS idx_coordination_runs_parent ON coordination_runs (parent_run_id);
|
|
819
862
|
`,HISTORY_RUN_SESSION_SCHEMA_SQL=`
|
|
820
863
|
CREATE TABLE IF NOT EXISTS history_run_session (
|
|
821
864
|
run_id TEXT NOT NULL,
|
|
@@ -1193,6 +1236,26 @@ CREATE TABLE IF NOT EXISTS history_board_skill_5m (
|
|
|
1193
1236
|
calls INTEGER NOT NULL,
|
|
1194
1237
|
PRIMARY KEY (bucket_start, source, skill_name, invocation_kind)
|
|
1195
1238
|
);
|
|
1239
|
+
CREATE INDEX IF NOT EXISTS idx_history_board_skill_5m_skill_bucket
|
|
1240
|
+
ON history_board_skill_5m (skill_name, bucket_start);
|
|
1241
|
+
`,HISTORY_BOARD_SKILL_5M_CAPABILITY_GRAIN_SCHEMA_SQL=`
|
|
1242
|
+
CREATE TABLE history_board_skill_5m_capability_grain (
|
|
1243
|
+
bucket_start TEXT NOT NULL,
|
|
1244
|
+
source TEXT NOT NULL,
|
|
1245
|
+
skill_name TEXT NOT NULL,
|
|
1246
|
+
invocation_kind TEXT NOT NULL,
|
|
1247
|
+
capability_kind TEXT NOT NULL DEFAULT '',
|
|
1248
|
+
evidence_kind TEXT NOT NULL DEFAULT '',
|
|
1249
|
+
status TEXT NOT NULL DEFAULT '',
|
|
1250
|
+
calls INTEGER NOT NULL,
|
|
1251
|
+
PRIMARY KEY (bucket_start, source, skill_name, invocation_kind, capability_kind, evidence_kind, status)
|
|
1252
|
+
);
|
|
1253
|
+
INSERT INTO history_board_skill_5m_capability_grain
|
|
1254
|
+
(bucket_start, source, skill_name, invocation_kind, capability_kind, evidence_kind, status, calls)
|
|
1255
|
+
SELECT bucket_start, source, skill_name, invocation_kind, '', '', '', calls
|
|
1256
|
+
FROM history_board_skill_5m;
|
|
1257
|
+
DROP TABLE history_board_skill_5m;
|
|
1258
|
+
ALTER TABLE history_board_skill_5m_capability_grain RENAME TO history_board_skill_5m;
|
|
1196
1259
|
CREATE INDEX IF NOT EXISTS idx_history_board_skill_5m_skill_bucket
|
|
1197
1260
|
ON history_board_skill_5m (skill_name, bucket_start);
|
|
1198
1261
|
`,HISTORY_MESSAGE_TS_NULLABLE_SCHEMA_SQL=`
|
|
@@ -1232,7 +1295,7 @@ FROM history_message;
|
|
|
1232
1295
|
DROP TABLE history_message;
|
|
1233
1296
|
ALTER TABLE history_message_rebuild RENAME TO history_message;
|
|
1234
1297
|
CREATE INDEX IF NOT EXISTS idx_history_message_provenance_run ON history_message (provenance, run_id);
|
|
1235
|
-
|
|
1298
|
+
`,SCHEDULER_CUSTOM_ACTIVE_UNIQUE_SCHEMA_SQL=`
|
|
1236
1299
|
UPDATE queue_jobs
|
|
1237
1300
|
SET status = 'failed',
|
|
1238
1301
|
last_error = 'retired by migration 0047_spur_cli_scheduler_custom_active_unique: superseded duplicate active scheduler.custom job name',
|
|
@@ -1453,7 +1516,7 @@ ALTER TABLE queue_jobs ADD COLUMN timeout_ms INTEGER;
|
|
|
1453
1516
|
ALTER TABLE queue_jobs ADD COLUMN timeout_unlimited INTEGER NOT NULL DEFAULT 0;
|
|
1454
1517
|
ALTER TABLE queue_jobs ADD COLUMN attempt_token TEXT;
|
|
1455
1518
|
ALTER TABLE queue_jobs ADD COLUMN lease_expires_at INTEGER;
|
|
1456
|
-
`,CLI_MIGRATIONS=[{id:"0000_spur_cli_foundation",sql:CLI_SCHEMA_SQL},{id:"0001_spur_cli_team_inbox",sql:INBOX_MESSAGES_SCHEMA_SQL},{id:"0002_spur_cli_rule_history",sql:RULE_ENGINE_SCHEMA_SQL},{id:"0003_spur_cli_planning",sql:PLANNING_SCHEMA_SQL},{id:"0004_spur_cli_queue_jobs",sql:QUEUE_JOBS_SCHEMA_SQL},{id:"0005_spur_cli_run_pid",sql:RUN_PID_COLUMN_SCHEMA_SQL,addColumnIfMissing:{table:"runs",column:"pid"}},{id:"0006_spur_cli_system_events",sql:SYSTEM_EVENTS_SCHEMA_SQL},{id:"0007_spur_cli_runs_external_key",sql:RUNS_EXTERNAL_KEY_COLUMN_SCHEMA_SQL,addColumnIfMissing:{table:"runs",column:"external_key"}},{id:"0008_spur_cli_system_events_correlation",sql:SYSTEM_EVENTS_CORRELATION_COLUMNS_SCHEMA_SQL,addColumnIfMissing:{table:"system_events",column:"sequence"}},{id:"0009_spur_cli_history_message_run_idx",sql:HISTORY_MESSAGE_RUN_INDEX_SCHEMA_SQL},{id:"0010_spur_cli_coordination_runs",sql:COORDINATION_RUNS_SCHEMA_SQL},{id:"0011_spur_cli_system_events_sequence_idx",sql:SYSTEM_EVENTS_SEQUENCE_INDEX_SCHEMA_SQL},{id:"0012_spur_cli_history_tool_call_args_raw",sql:HISTORY_TOOL_CALL_ARGS_RAW_SCHEMA_SQL,addColumnIfMissing:{table:"history_tool_call",column:"args_raw"}},{id:"0013_spur_cli_history_run_session",sql:HISTORY_RUN_SESSION_SCHEMA_SQL},{id:"0014_spur_cli_system_events_name_occurred_idx",sql:SYSTEM_EVENTS_NAME_OCCURRED_INDEX_SCHEMA_SQL},{id:"0015_spur_cli_history_tool_call_call_id",sql:HISTORY_TOOL_CALL_CALL_ID_SCHEMA_SQL,addColumnIfMissing:{table:"history_tool_call",column:"call_id"}},{id:"0016_spur_cli_history_message_ts_nullable",sql:HISTORY_MESSAGE_TS_NULLABLE_SCHEMA_SQL},{id:"0017_spur_cli_runs_status_completed_to_done",sql:"UPDATE runs SET status = 'done' WHERE status = 'completed'"},{id:"0018_spur_cli_history_message_request_id",sql:HISTORY_MESSAGE_REQUEST_ID_SCHEMA_SQL,addColumnIfMissing:{table:"history_message",column:"request_id"}},{id:"0019_spur_cli_history_etl_tables_drop",sql:HISTORY_ETL_TABLES_DROP_SCHEMA_SQL},{id:"0020_spur_cli_history_board_query_indexes",sql:HISTORY_BOARD_QUERY_INDEXES_SCHEMA_SQL},{id:"0021_spur_cli_history_board_rollups",sql:HISTORY_BOARD_ROLLUPS_SCHEMA_SQL},{id:"0022_spur_cli_history_performance_indexes",sql:HISTORY_PERFORMANCE_INDEXES_SCHEMA_SQL},{id:"0023_spur_cli_history_message_request_id_idx",sql:HISTORY_MESSAGE_REQUEST_ID_INDEX_SCHEMA_SQL},{id:"0024_spur_cli_history_checkpoint_identity",sql:"ALTER TABLE history_import_checkpoint ADD COLUMN source_size INTEGER",addColumnIfMissing:{table:"history_import_checkpoint",column:"source_size"}},{id:"0025_spur_cli_history_checkpoint_identity_mtime",sql:"ALTER TABLE history_import_checkpoint ADD COLUMN source_mtime_ms REAL",addColumnIfMissing:{table:"history_import_checkpoint",column:"source_mtime_ms"}},{id:"0026_spur_cli_history_message_duration_source",sql:"ALTER TABLE history_message ADD COLUMN duration_source TEXT",addColumnIfMissing:{table:"history_message",column:"duration_source"}},{id:"0027_spur_cli_history_refresh_active_unique",sql:HISTORY_REFRESH_ACTIVE_UNIQUE_SCHEMA_SQL},{id:"0028_spur_cli_history_task_session",sql:HISTORY_TASK_SESSION_SCHEMA_SQL},{id:"0029_spur_cli_history_tool_call_indexes",sql:HISTORY_TOOL_CALL_INDEXES_SCHEMA_SQL},{id:"0030_spur_cli_history_board_covering_indexes",sql:HISTORY_BOARD_COVERING_INDEXES_SCHEMA_SQL},{id:"0031_spur_cli_history_board_tool_stats_columns",sql:HISTORY_BOARD_TOOL_STATS_COLUMNS_SCHEMA_SQL},{id:"0032_spur_cli_history_board_skill_5m",sql:HISTORY_BOARD_SKILL_5M_SCHEMA_SQL},{id:"0033_spur_cli_importer_schema_version",sql:`INSERT OR REPLACE INTO "__spur_cli_migrations" (id, applied_at) VALUES ('${IMPORTER_SCHEMA_LEDGER_PREFIX}${HISTORY_IMPORT_SCHEMA_VERSION}', strftime('%s', 'now') * 1000);`},{id:"0034_spur_cli_history_tool_identity",sql:HISTORY_TOOL_IDENTITY_SCHEMA_SQL},{id:"0035_spur_cli_history_measure_vector",sql:HISTORY_MEASURE_VECTOR_SCHEMA_SQL},{id:"0036_spur_cli_history_rollup_watermark",sql:HISTORY_ROLLUP_WATERMARK_SCHEMA_SQL},{id:"0037_spur_cli_history_dimension_marts",sql:HISTORY_DIMENSION_MARTS_SCHEMA_SQL},{id:"0038_spur_cli_retention_compaction_meta",sql:RETENTION_COMPACTION_META_SCHEMA_SQL},{id:"0039_spur_cli_bounded_rollup_derivations",sql:BOUNDED_ROLLUP_DERIVATIONS_SCHEMA_SQL,addColumnIfMissing:{table:"history_board_source_daily",column:"raw_messages"}},{id:"0040_spur_cli_agent_executor_updates",sql:AGENT_EXECUTOR_UPDATES_SCHEMA_SQL},{id:"0041_spur_cli_queue_jobs_deadline_lease_columns",sql:QUEUE_JOBS_DEADLINE_LEASE_COLUMNS_SCHEMA_SQL,addColumnIfMissing:{table:"queue_jobs",column:"timeout_ms"}},{id:"0042_spur_cli_history_model_fallback_index",sql:HISTORY_MESSAGE_MODEL_FALLBACK_INDEX_SCHEMA_SQL},{id:"0043_spur_cli_inbox_messages_request_key",sql:INBOX_MESSAGES_REQUEST_KEY_SCHEMA_SQL,addColumnIfMissing:{table:"inbox_messages",column:"request_key"}},{id:"0044_spur_cli_coordination_runs_receipt_columns",sql:COORDINATION_RUNS_RECEIPT_COLUMNS_SCHEMA_SQL,addColumnIfMissing:{table:"coordination_runs",column:"message_ids_json"}},{id:"0045_spur_cli_project_claims",sql:PROJECT_CLAIMS_SCHEMA_SQL},{id:"0046_spur_cli_project_strategy",sql:PROJECT_STRATEGY_SCHEMA_SQL},{id:"0047_spur_cli_scheduler_custom_active_unique",sql:SCHEDULER_CUSTOM_ACTIVE_UNIQUE_SCHEMA_SQL},{id:"0048_spur_cli_agent_executor_updates_owner_columns",sql:AGENT_EXECUTOR_UPDATES_OWNER_COLUMNS_SCHEMA_SQL,addColumnIfMissing:{table:"agent_executor_updates",column:"owner"}},{id:"0049_spur_cli_runs_terminal_reason",sql:CLI_RUNS_TERMINAL_REASON_SCHEMA_SQL,addColumnIfMissing:{table:"runs",column:"terminal_reason"}}];async function allMigrationsJournaled(adapter,migrations){if(migrations.length===0)return!0;if(!await tableExists2(adapter,"__spur_cli_migrations"))return!1;let placeholders=migrations.map(()=>"?").join(", ");if(((await adapter.queryFirst(`SELECT COUNT(*) AS n FROM "__spur_cli_migrations" WHERE id IN (${placeholders})`,...migrations.map((m)=>m.id)))?.n??0)!==migrations.length)return!1;if(migrations.some((m)=>m.id==="0033_spur_cli_importer_schema_version")){if(!await adapter.queryFirst('SELECT id FROM "__spur_cli_migrations" WHERE id = ?',IMPORTER_SCHEMA_LEDGER_PREFIX+HISTORY_IMPORT_SCHEMA_VERSION))return!1}return!0}async function applyCliMigrations(adapter,migrations=CLI_MIGRATIONS){if(await allMigrationsJournaled(adapter,migrations))return 0;await adapter.exec('CREATE TABLE IF NOT EXISTS "__spur_cli_migrations" (id TEXT PRIMARY KEY, applied_at INTEGER NOT NULL)');let applied=0;for(let migration of migrations){if(await adapter.queryFirst('SELECT id FROM "__spur_cli_migrations" WHERE id = ?',migration.id)!=null)continue;if(migration.id==="0009_spur_cli_history_message_run_idx"&&!await tableExists2(adapter,"history_message")){for(let statement of splitSqlStatements(HISTORY_IMPORT_SCHEMA_SQL))await adapter.exec(statement);let versionLedgerId=IMPORTER_SCHEMA_LEDGER_PREFIX+HISTORY_IMPORT_SCHEMA_VERSION;await adapter.run('INSERT OR REPLACE INTO "__spur_cli_migrations" (id, applied_at) VALUES (?, ?)',[versionLedgerId,Date.now()])}if((migration.id==="0024_spur_cli_history_checkpoint_identity"||migration.id==="0025_spur_cli_history_checkpoint_identity_mtime")&&!await tableExists2(adapter,"history_import_checkpoint")){await adapter.run('INSERT INTO "__spur_cli_migrations" (id, applied_at) VALUES (?, ?)',[migration.id,Date.now()]);continue}if(migration.id==="0034_spur_cli_history_tool_identity"&&await tableExists2(adapter,"history_tool_call")){if(!await columnExists(adapter,"history_tool_call","effective_tool_name"))await adapter.exec("ALTER TABLE history_tool_call ADD COLUMN effective_tool_name TEXT NOT NULL DEFAULT 'unknown'");if(!await columnExists(adapter,"history_tool_call","tool_name_alias"))await adapter.exec("ALTER TABLE history_tool_call ADD COLUMN tool_name_alias TEXT NOT NULL DEFAULT 'unknown'")}let addColumnGuard=migration.addColumnIfMissing,shouldApplySql=addColumnGuard===void 0||!await columnExists(adapter,addColumnGuard.table,addColumnGuard.column),tsNullableSkip=migration.id==="0016_spur_cli_history_message_ts_nullable"&&(!await tableExists2(adapter,"history_message")||!await columnNotNull(adapter,"history_message","ts")),sequenceIndexSkip=migration.id==="0011_spur_cli_system_events_sequence_idx"&&!await tableExists2(adapter,"system_events"),argsRawSkip=migration.id==="0012_spur_cli_history_tool_call_args_raw"&&!await tableExists2(adapter,"history_tool_call"),callIdSkip=migration.id==="0015_spur_cli_history_tool_call_call_id"&&!await tableExists2(adapter,"history_tool_call"),nameOccurredIndexSkip=migration.id==="0014_spur_cli_system_events_name_occurred_idx"&&!await tableExists2(adapter,"system_events"),historyBoardQueryIndexesSkip=migration.id==="0020_spur_cli_history_board_query_indexes"&&(!await tableExists2(adapter,"history_message")||!await columnExists(adapter,"history_message","seq")||!await columnExists(adapter,"history_message","duration_ms")||!await columnExists(adapter,"history_message","role")||!await columnExists(adapter,"history_message","input_tokens")||!await columnExists(adapter,"history_message","cache_read_tokens")),historyPerformanceIndexesSkip=migration.id==="0022_spur_cli_history_performance_indexes"&&(!await tableExists2(adapter,"history_message")||!await columnExists(adapter,"history_message","ts")||!await columnExists(adapter,"history_message","model")||!await tableExists2(adapter,"history_tool_call")),historyToolCallIndexesSkip=migration.id==="0029_spur_cli_history_tool_call_indexes"&&(!await tableExists2(adapter,"history_message")||!await columnExists(adapter,"history_message","ts")||!await tableExists2(adapter,"history_tool_call")),historyBoardCoveringIndexesSkip=migration.id==="0030_spur_cli_history_board_covering_indexes"&&(!await tableExists2(adapter,"history_daily_stats")||!await tableExists2(adapter,"history_board_tool_5m")||!await tableExists2(adapter,"history_board_message_5m")||!await tableExists2(adapter,"history_board_session_stats")||!await tableExists2(adapter,"history_board_source_daily")||!await tableExists2(adapter,"history_tool_call")||!await tableExists2(adapter,"history_task_session")),runsStatusDoneSkip=migration.id==="0017_spur_cli_runs_status_completed_to_done"&&(!await tableExists2(adapter,"runs")||!await columnExists(adapter,"runs","status")),historyBoardToolStatsColumnsSkip=migration.id==="0031_spur_cli_history_board_tool_stats_columns"&&(!await tableExists2(adapter,"history_board_tool_stats")||await columnExists(adapter,"history_board_tool_stats","fresh_input_tokens")),queueJobsActiveIndexSkip=migration.id==="0027_spur_cli_history_refresh_active_unique"&&!await tableExists2(adapter,"queue_jobs"),schedulerCustomActiveIndexSkip=migration.id==="0047_spur_cli_scheduler_custom_active_unique"&&!await tableExists2(adapter,"queue_jobs"),queueJobsDeadlineLeaseSkip=migration.id==="0041_spur_cli_queue_jobs_deadline_lease_columns"&&!await tableExists2(adapter,"queue_jobs"),runsTerminalReasonSkip=migration.id==="0049_spur_cli_runs_terminal_reason"&&!await tableExists2(adapter,"runs"),inboxRequestKeySkip=migration.id==="0043_spur_cli_inbox_messages_request_key"&&!await tableExists2(adapter,"inbox_messages"),coordinationReceiptColumnsSkip=migration.id==="0044_spur_cli_coordination_runs_receipt_columns"&&!await tableExists2(adapter,"coordination_runs"),historyToolIdentitySkip=migration.id==="0034_spur_cli_history_tool_identity"&&!await tableExists2(adapter,"history_tool_call"),historyMeasureVectorSkip=migration.id==="0035_spur_cli_history_measure_vector"&&(!await tableExists2(adapter,"history_board_message_5m")||await columnExists(adapter,"history_board_message_5m","cache_write_tokens")),historyRollupWatermarkSkip=migration.id==="0036_spur_cli_history_rollup_watermark"&&(await tableExists2(adapter,"history_board_rollup_watermark")||!await tableExists2(adapter,"history_message")||!await columnExists(adapter,"history_message","imported_at")),boundedRollupDerivationsSkip=migration.id==="0039_spur_cli_bounded_rollup_derivations"&&(!await tableExists2(adapter,"history_message")||!await columnExists(adapter,"history_message","source_file")||!await tableExists2(adapter,"history_board_source_daily")),historyModelFallbackIndexSkip=migration.id==="0042_spur_cli_history_model_fallback_index"&&(!await tableExists2(adapter,"history_message")||!await columnExists(adapter,"history_message","model"));if(shouldApplySql&&!sequenceIndexSkip&&!argsRawSkip&&!runsStatusDoneSkip&&!nameOccurredIndexSkip&&!historyBoardQueryIndexesSkip&&!historyPerformanceIndexesSkip&&!historyToolCallIndexesSkip&&!historyBoardCoveringIndexesSkip&&!historyBoardToolStatsColumnsSkip&&!callIdSkip&&!tsNullableSkip&&!queueJobsActiveIndexSkip&&!schedulerCustomActiveIndexSkip&&!queueJobsDeadlineLeaseSkip&&!runsTerminalReasonSkip&&!inboxRequestKeySkip&&!coordinationReceiptColumnsSkip&&!historyToolIdentitySkip&&!historyMeasureVectorSkip&&!historyRollupWatermarkSkip&&!boundedRollupDerivationsSkip&&!historyModelFallbackIndexSkip)for(let statement of splitSqlStatements(migration.sql))await adapter.exec(statement);if(historyToolIdentitySkip&&!await tableExists2(adapter,"history_tool_alias_map"))await adapter.exec("CREATE TABLE IF NOT EXISTS history_tool_alias_map (source TEXT NOT NULL, effective_tool_name TEXT NOT NULL, alias TEXT NOT NULL, PRIMARY KEY (source, effective_tool_name));");await adapter.run('INSERT INTO "__spur_cli_migrations" (id, applied_at) VALUES (?, ?)',migration.id,Date.now()),applied+=1}if(migrations.some((m)=>m.id==="0033_spur_cli_importer_schema_version")){let currentVersionLedgerId=IMPORTER_SCHEMA_LEDGER_PREFIX+HISTORY_IMPORT_SCHEMA_VERSION;if(!await adapter.queryFirst('SELECT id FROM "__spur_cli_migrations" WHERE id = ?',currentVersionLedgerId)){for(let statement of splitSqlStatements(HISTORY_IMPORT_SCHEMA_SQL))if(statement.startsWith("CREATE TABLE"))await adapter.exec(statement);await adapter.run('INSERT OR REPLACE INTO "__spur_cli_migrations" (id, applied_at) VALUES (?, ?)',[currentVersionLedgerId,Date.now()]),applied+=1}}return applied}async function columnExists(adapter,table3,column2){return(await adapter.queryAll(`PRAGMA table_info("${table3}")`)).some((row)=>row.name===column2)}async function columnNotNull(adapter,table3,column2){return(await adapter.queryAll(`PRAGMA table_info("${table3}")`)).some((row)=>row.name===column2&&row.notnull===1)}async function tableExists2(adapter,table3){return await adapter.queryFirst("SELECT name FROM sqlite_master WHERE type = 'table' AND name = ?",table3)!=null}function splitSqlStatements(sql4){return sql4.split(";").map((statement)=>statement.trim()).filter(Boolean)}var SQLITE_BUSY_TIMEOUT_MS=30000;async function createMigratedDb(options){let{createDbAdapter:createDbAdapter3}=await Promise.resolve().then(() => (init_dist4(),exports_dist)),adapter=await createDbAdapter3({driver:"bun-sqlite",url:options.url});return await adapter.exec(`PRAGMA busy_timeout = ${SQLITE_BUSY_TIMEOUT_MS}`),await applyCliMigrations(adapter),adapter}init_zod();init_zod();var STAGE_REGISTRY_SCHEMA_VERSION={major:1,minor:3},stageSchemaVersionSchema=exports_external.object({major:exports_external.number().int().nonnegative(),minor:exports_external.number().int().nonnegative()}).strict();var MUTATION_CLASSES=["none","corpus","code","tests","verdict","learnings","driver","irreversible"];var inlineExecutionSchema=exports_external.object({kind:exports_external.literal("inline"),current_agent_allowed:exports_external.literal(!0),may_reuse_captured_layers:exports_external.boolean().optional()}).strict(),subprocessExecutionSchema=exports_external.object({kind:exports_external.literal("subprocess"),current_agent_allowed:exports_external.literal(!1),via:exports_external.literal("spur-agent-run")}).strict(),deterministicExecutionSchema=exports_external.object({kind:exports_external.literal("deterministic"),current_agent_allowed:exports_external.literal(!1),executor:exports_external.enum(["cli","script"])}).strict(),hitlExecutionSchema=exports_external.object({kind:exports_external.literal("hitl"),current_agent_allowed:exports_external.literal(!0),gate_timing:exports_external.enum(["pre","post","both"])}).strict(),irreversibleExecutionSchema=exports_external.object({kind:exports_external.literal("irreversible"),requires_operator_intent:exports_external.literal(!0),current_agent_allowed:exports_external.boolean(),rollback_disclaimer:exports_external.string().min(1)}).strict(),executionKindSchema=exports_external.discriminatedUnion("kind",[inlineExecutionSchema,subprocessExecutionSchema,deterministicExecutionSchema,hitlExecutionSchema,irreversibleExecutionSchema]),ARTIFACT_DIRECTIONS=["input","output"],stageArtifactSchema=exports_external.object({kind:exports_external.string().min(1),direction:exports_external.enum(ARTIFACT_DIRECTIONS),identity:exports_external.string().optional(),description:exports_external.string().optional(),required:exports_external.boolean().optional().default(!0)}).strict(),stageGateSchema=exports_external.object({name:exports_external.string().min(1),timing:exports_external.enum(["pre","post","transition"]),min_verdict:exports_external.enum(["pass","partial","fail"]).optional(),description:exports_external.string().optional()}).strict(),stageRetryPolicySchema=exports_external.object({max_attempts:exports_external.number().int().min(1),terminal_stop:exports_external.enum(["block","escalate","fail"]),timeout_seconds:exports_external.number().int().positive().optional()}).strict(),CAPABILITY_TIERS=["cheap","standard","capable-1","capable-2","capable-3"],LEGACY_CAPABLE_ALIAS="capable";function normalizeCapabilityTier(value){return value===LEGACY_CAPABLE_ALIAS?"capable-1":value}var capabilityTierSchema=exports_external.preprocess(normalizeCapabilityTier,exports_external.enum(CAPABILITY_TIERS)),objectiveEscalationTriggerSchema=exports_external.enum(["gate-fail","timeout","insufficient-evidence","retry-exhausted","resource-exhaustion","auth"]),stageModelPolicySchema=exports_external.object({min_tier:capabilityTierSchema,fallback:exports_external.array(exports_external.object({tier:capabilityTierSchema,trigger:objectiveEscalationTriggerSchema}).strict()),override_key:exports_external.string().optional()}).strict();var CONTEXT_LAYER_NAMES=["harness-policy","project-authority","stage-contract","task-state","indexed-evidence","run-state","tool-observations"],stageContextLayerSchema=exports_external.object({layer:exports_external.enum(CONTEXT_LAYER_NAMES),required:exports_external.literal(!0)}).strict(),stageEventSchema=exports_external.object({name:exports_external.string().min(1),description:exports_external.string().optional()}).strict(),STAGE_ID_PATTERN=/^[a-z][a-z0-9-]*$/,stageRecordSchema=exports_external.object({schema_version:stageSchemaVersionSchema,id:exports_external.string().regex(STAGE_ID_PATTERN,{message:"stage id must be lowercase kebab-case"}),aliases:exports_external.array(exports_external.string().min(1)).optional().default([]),description:exports_external.string().min(1),artifacts:exports_external.array(stageArtifactSchema).min(1),reasoning_skill:exports_external.string().min(1),required_references:exports_external.array(exports_external.string().min(1)).optional().default([]),gates:exports_external.array(stageGateSchema).optional().default([]),mutation_class:exports_external.enum(MUTATION_CLASSES),retry:stageRetryPolicySchema,model_policy:stageModelPolicySchema,context_layers:exports_external.array(stageContextLayerSchema).optional().default([]),observability:exports_external.array(stageEventSchema).optional().default([]),execution:executionKindSchema}).strict();var REGISTERED_CANONICAL_STAGES=[{schema_version:STAGE_REGISTRY_SCHEMA_VERSION,id:"refine",aliases:["dev-refine"],description:"dev-refine: Q&A refinement, section filling, AC tightening",artifacts:[{kind:"task-section",direction:"input",required:!0,description:"Background/Requirements sections"},{kind:"task-section",direction:"output",required:!0,description:"Q&A/Design/Plan/AC sections"}],reasoning_skill:"sp:spur-dev",required_references:[],gates:[],mutation_class:"corpus",retry:{max_attempts:3,terminal_stop:"block"},model_policy:{min_tier:"standard",fallback:[{tier:"capable-2",trigger:"gate-fail"},{tier:"capable-2",trigger:"auth"},{tier:"capable-2",trigger:"resource-exhaustion"}]},context_layers:[],observability:[],execution:{kind:"inline",current_agent_allowed:!0}},{schema_version:STAGE_REGISTRY_SCHEMA_VERSION,id:"plan",aliases:["dev-plan"],description:"dev-plan: feature intake -> AC generation -> decomposition",artifacts:[{kind:"feature-frontmatter",direction:"input",required:!0},{kind:"task-batch",direction:"output",required:!0}],reasoning_skill:"sp:spur-dev",required_references:[],gates:[{name:"feature-check",timing:"post",min_verdict:"pass"},{name:"batch-create",timing:"post",min_verdict:"pass"}],mutation_class:"corpus",retry:{max_attempts:3,terminal_stop:"block"},model_policy:{min_tier:"capable-2",fallback:[{tier:"capable-3",trigger:"gate-fail"},{tier:"capable-3",trigger:"auth"},{tier:"capable-3",trigger:"resource-exhaustion"}]},context_layers:[],observability:[],execution:{kind:"inline",current_agent_allowed:!0}},{schema_version:STAGE_REGISTRY_SCHEMA_VERSION,id:"implement",aliases:["dev-run"],description:"dev-run --mode implement: code edits in worktree",artifacts:[{kind:"worktree-diff",direction:"output",required:!0},{kind:"task-section",direction:"output",required:!0,identity:"Solution"}],reasoning_skill:"sp:code-implementation",required_references:[],gates:[],mutation_class:"code",retry:{max_attempts:3,terminal_stop:"block"},model_policy:{min_tier:"standard",fallback:[{tier:"capable-1",trigger:"gate-fail"},{tier:"capable-1",trigger:"timeout"},{tier:"capable-1",trigger:"auth"},{tier:"capable-1",trigger:"resource-exhaustion"}]},context_layers:[],observability:[],execution:{kind:"inline",current_agent_allowed:!0}},{schema_version:STAGE_REGISTRY_SCHEMA_VERSION,id:"test",aliases:["dev-unit","dev-fixall"],description:"dev-unit: generate/extend tests to coverage target",artifacts:[{kind:"test-file",direction:"output",required:!0},{kind:"coverage-report",direction:"output",required:!1}],reasoning_skill:"sp:code-testing",required_references:[],gates:[],mutation_class:"tests",retry:{max_attempts:3,terminal_stop:"block"},model_policy:{fallback:[{tier:"capable-1",trigger:"gate-fail"},{tier:"capable-1",trigger:"auth"},{tier:"capable-1",trigger:"resource-exhaustion"}],min_tier:"standard"},context_layers:[],observability:[],execution:{kind:"inline",current_agent_allowed:!0}},{schema_version:STAGE_REGISTRY_SCHEMA_VERSION,id:"verify",aliases:["dev-verify"],description:"dev-verify: SECUA review + requirements traceability",artifacts:[{kind:"worktree-diff",direction:"input",required:!0},{kind:"verdict-artifact",direction:"output",required:!0,identity:"<wbs>-verdict.json"}],reasoning_skill:"sp:code-verification",required_references:[],gates:[{name:"verdict-artifact",timing:"post",min_verdict:"pass"},{name:"strict-core",timing:"post",min_verdict:"pass"}],mutation_class:"verdict",retry:{max_attempts:2,terminal_stop:"escalate"},model_policy:{min_tier:"capable-1",fallback:[{tier:"capable-2",trigger:"auth"},{tier:"capable-2",trigger:"resource-exhaustion"},{tier:"capable-2",trigger:"gate-fail"}]},context_layers:[],observability:[],execution:{kind:"inline",current_agent_allowed:!0}},{schema_version:STAGE_REGISTRY_SCHEMA_VERSION,id:"wrap",aliases:["dev-wrap"],description:"dev-wrap: learnings/doc-sync/feature transition",artifacts:[{kind:"learning-entry",direction:"output",required:!0}],reasoning_skill:"sp:spur-dev",required_references:[],gates:[{name:"task-check",timing:"pre",min_verdict:"pass"}],mutation_class:"learnings",retry:{max_attempts:2,terminal_stop:"block"},model_policy:{min_tier:"standard",fallback:[{tier:"capable-1",trigger:"gate-fail"},{tier:"capable-1",trigger:"auth"},{tier:"capable-1",trigger:"resource-exhaustion"}]},context_layers:[],observability:[],execution:{kind:"hitl",current_agent_allowed:!0,gate_timing:"both"}},{schema_version:STAGE_REGISTRY_SCHEMA_VERSION,id:"review",aliases:["dev-review"],description:"dev-review: multi-dimensional code review (coordinator writes the combined Review)",artifacts:[{kind:"review-findings",direction:"output",required:!0,identity:"Review"}],reasoning_skill:"sp:code-verification",required_references:[],gates:[],mutation_class:"verdict",retry:{max_attempts:2,terminal_stop:"block"},model_policy:{min_tier:"standard",fallback:[{tier:"capable-1",trigger:"gate-fail"},{tier:"capable-1",trigger:"auth"},{tier:"capable-1",trigger:"resource-exhaustion"}]},context_layers:[],observability:[],execution:{kind:"inline",current_agent_allowed:!0}},{schema_version:STAGE_REGISTRY_SCHEMA_VERSION,id:"record",aliases:["dev-record"],description:"record: deterministic Testing write-back from the verdict artifact; bare-Review fallback only",artifacts:[{kind:"verdict-artifact",direction:"input",required:!0,identity:"<wbs>-verdict.json"},{kind:"task-section",direction:"output",required:!0,identity:"Testing"},{kind:"task-section",direction:"output",required:!1,identity:"Review",description:"fallback-only: backfills Review only when the section is bare; never overwrites authored Review"}],reasoning_skill:"inline",required_references:[],gates:[],mutation_class:"corpus",retry:{max_attempts:1,terminal_stop:"block"},model_policy:{min_tier:"cheap",fallback:[]},context_layers:[],observability:[],execution:{kind:"deterministic",current_agent_allowed:!1,executor:"cli"}},{schema_version:STAGE_REGISTRY_SCHEMA_VERSION,id:"dogfood",aliases:["dev-dogfood"],description:"dev-dogfood: end-to-end driver test",artifacts:[{kind:"dogfood-report",direction:"output",required:!0},{kind:"monitor-ledger",direction:"output",required:!1}],reasoning_skill:"sp:dogfood-testing",required_references:[],gates:[],mutation_class:"driver",retry:{max_attempts:3,terminal_stop:"block"},model_policy:{min_tier:"capable-1",fallback:[{tier:"capable-2",trigger:"auth"},{tier:"capable-2",trigger:"resource-exhaustion"},{tier:"capable-2",trigger:"gate-fail"}]},context_layers:[],observability:[],execution:{kind:"inline",current_agent_allowed:!0}},{schema_version:STAGE_REGISTRY_SCHEMA_VERSION,id:"brainstorm",aliases:["dev-brainstorm"],description:"dev-brainstorm: structured ideation",artifacts:[{kind:"brainstorm-outline",direction:"output",required:!0}],reasoning_skill:"sp:brainstorm",required_references:[],gates:[],mutation_class:"corpus",retry:{max_attempts:2,terminal_stop:"block"},model_policy:{min_tier:"standard",fallback:[]},context_layers:[],observability:[],execution:{kind:"inline",current_agent_allowed:!0}},{schema_version:STAGE_REGISTRY_SCHEMA_VERSION,id:"changelog",aliases:["dev-changelog"],description:"dev-changelog: generate changelog from git commits",artifacts:[{kind:"changelog-entry",direction:"output",required:!0}],reasoning_skill:"inline",required_references:[],gates:[],mutation_class:"none",retry:{max_attempts:1,terminal_stop:"block"},model_policy:{min_tier:"cheap",fallback:[]},context_layers:[],observability:[],execution:{kind:"deterministic",current_agent_allowed:!1,executor:"cli"}}],CANONICAL_STAGE_BY_KEY=new Map;for(let s2 of REGISTERED_CANONICAL_STAGES){CANONICAL_STAGE_BY_KEY.set(s2.id,s2);for(let a2 of s2.aliases??[])CANONICAL_STAGE_BY_KEY.set(a2,s2)}var CACHEABILITY_CLASSES=["stable-prefix-eligible","volatile"],SENSITIVITY_CLASSES=["public","internal","confidential"],envelopeProvenanceSchema=exports_external.object({owner:exports_external.string().min(1),schema_version:exports_external.string().min(1),source_revision:exports_external.string().nullable().optional(),generated_at:exports_external.string().datetime()}).strict(),envelopeSizeBudgetSchema=exports_external.object({max_bytes:exports_external.number().int().positive()}).strict(),envelopeLayerSchema=exports_external.object({layer:exports_external.enum(CONTEXT_LAYER_NAMES),content:exports_external.string(),size_bytes:exports_external.number().int().nonnegative(),content_hash:exports_external.string().length(64),provenance:envelopeProvenanceSchema,cacheability:exports_external.enum(CACHEABILITY_CLASSES),sensitivity:exports_external.enum(SENSITIVITY_CLASSES).default("internal"),size_budget:envelopeSizeBudgetSchema.optional(),disclosure_handle:exports_external.string().optional()}).strict(),STABLE_LAYER_NAMES=["harness-policy","project-authority","stage-contract","task-state","indexed-evidence"],VOLATILE_LAYER_NAMES=["run-state","tool-observations"];var envelopeSchema=exports_external.object({schema_version:exports_external.string().default("1.0"),layers:exports_external.array(envelopeLayerSchema).min(1),stage_id:exports_external.string().optional(),run_id:exports_external.string().optional(),assembled_at:exports_external.string().datetime(),total_size_bytes:exports_external.number().int().nonnegative()}).strict(),projectSnapshotSchema=exports_external.object({name:exports_external.string(),version:exports_external.string(),task_counts:exports_external.object({backlog:exports_external.number().int().nonnegative(),todo:exports_external.number().int().nonnegative(),wip:exports_external.number().int().nonnegative(),testing:exports_external.number().int().nonnegative(),done:exports_external.number().int().nonnegative(),blocked:exports_external.number().int().nonnegative(),cancelled:exports_external.number().int().nonnegative()}).strict(),feature_counts:exports_external.object({backlog:exports_external.number().int().nonnegative(),active:exports_external.number().int().nonnegative(),verifying:exports_external.number().int().nonnegative(),done:exports_external.number().int().nonnegative(),blocked:exports_external.number().int().nonnegative(),cancelled:exports_external.number().int().nonnegative()}).strict(),active_features:exports_external.array(exports_external.string()),content_hash:exports_external.string().length(64).optional()}).strict(),taskSnapshotSchema=exports_external.object({wbs:exports_external.string().regex(/^\d{4}$/),name:exports_external.string(),status:exports_external.string(),priority:exports_external.string().optional(),feature_id:exports_external.string().optional(),acceptance_criteria:exports_external.string().optional(),locked_qa:exports_external.array(exports_external.string()).optional(),solution:exports_external.string().optional(),content_hash:exports_external.string().length(64).optional()}).strict(),featureSnapshotSchema=exports_external.object({id:exports_external.string(),name:exports_external.string(),status:exports_external.string(),priority:exports_external.string().optional(),scenarios:exports_external.array(exports_external.string()).optional(),content_hash:exports_external.string().length(64).optional()}).strict();var ALL_LAYER_NAMES=[...STABLE_LAYER_NAMES,...VOLATILE_LAYER_NAMES],LAYER_ORDER={};ALL_LAYER_NAMES.forEach((name,idx)=>{LAYER_ORDER[name]=idx});init_dist2();var TASK_CANONICAL_SECTIONS=["Background","Requirements","Acceptance Criteria","Q&A","Design","Plan","Root Cause","Solution","Testing","Review","References","History"],FEATURE_CANONICAL_SECTIONS=["Goal","Scope","Acceptance Criteria","Tasks","Notes","History"],UNIVERSAL_SECTIONS=["History","References","Notes"],HEADING_LEVELS={task:3,feature:2},START_MARKER="<!-- AUTO-GENERATED by spur feature refresh -->",END_MARKER="<!-- END AUTO-GENERATED -->",MARKER_START_RE=/<!--[ \t]*AUTO-GENERATED.*?-->/,MARKER_END_RE=/<!--[ \t]*END[ \t]*AUTO-GENERATED.*?-->/;function findHeadings(body,hashes){let hits=[],prefix=`${hashes} `,inCodeBlock=!1,lineStart=0;for(let i2=0;i2<=body.length;i2++){if(i2!==body.length&&body[i2]!==`
|
|
1519
|
+
`,CLI_MIGRATIONS=[{id:"0000_spur_cli_foundation",sql:CLI_SCHEMA_SQL},{id:"0001_spur_cli_team_inbox",sql:INBOX_MESSAGES_SCHEMA_SQL},{id:"0002_spur_cli_rule_history",sql:RULE_ENGINE_SCHEMA_SQL},{id:"0003_spur_cli_planning",sql:PLANNING_SCHEMA_SQL},{id:"0004_spur_cli_queue_jobs",sql:QUEUE_JOBS_SCHEMA_SQL},{id:"0005_spur_cli_run_pid",sql:RUN_PID_COLUMN_SCHEMA_SQL,addColumnIfMissing:{table:"runs",column:"pid"}},{id:"0006_spur_cli_system_events",sql:SYSTEM_EVENTS_SCHEMA_SQL},{id:"0007_spur_cli_runs_external_key",sql:RUNS_EXTERNAL_KEY_COLUMN_SCHEMA_SQL,addColumnIfMissing:{table:"runs",column:"external_key"}},{id:"0008_spur_cli_system_events_correlation",sql:SYSTEM_EVENTS_CORRELATION_COLUMNS_SCHEMA_SQL,addColumnIfMissing:{table:"system_events",column:"sequence"}},{id:"0009_spur_cli_history_message_run_idx",sql:HISTORY_MESSAGE_RUN_INDEX_SCHEMA_SQL},{id:"0010_spur_cli_coordination_runs",sql:COORDINATION_RUNS_SCHEMA_SQL},{id:"0011_spur_cli_system_events_sequence_idx",sql:SYSTEM_EVENTS_SEQUENCE_INDEX_SCHEMA_SQL},{id:"0012_spur_cli_history_tool_call_args_raw",sql:HISTORY_TOOL_CALL_ARGS_RAW_SCHEMA_SQL,addColumnIfMissing:{table:"history_tool_call",column:"args_raw"}},{id:"0013_spur_cli_history_run_session",sql:HISTORY_RUN_SESSION_SCHEMA_SQL},{id:"0014_spur_cli_system_events_name_occurred_idx",sql:SYSTEM_EVENTS_NAME_OCCURRED_INDEX_SCHEMA_SQL},{id:"0015_spur_cli_history_tool_call_call_id",sql:HISTORY_TOOL_CALL_CALL_ID_SCHEMA_SQL,addColumnIfMissing:{table:"history_tool_call",column:"call_id"}},{id:"0016_spur_cli_history_message_ts_nullable",sql:HISTORY_MESSAGE_TS_NULLABLE_SCHEMA_SQL},{id:"0017_spur_cli_runs_status_completed_to_done",sql:"UPDATE runs SET status = 'done' WHERE status = 'completed'"},{id:"0018_spur_cli_history_message_request_id",sql:HISTORY_MESSAGE_REQUEST_ID_SCHEMA_SQL,addColumnIfMissing:{table:"history_message",column:"request_id"}},{id:"0019_spur_cli_history_etl_tables_drop",sql:HISTORY_ETL_TABLES_DROP_SCHEMA_SQL},{id:"0020_spur_cli_history_board_query_indexes",sql:HISTORY_BOARD_QUERY_INDEXES_SCHEMA_SQL},{id:"0021_spur_cli_history_board_rollups",sql:HISTORY_BOARD_ROLLUPS_SCHEMA_SQL},{id:"0022_spur_cli_history_performance_indexes",sql:HISTORY_PERFORMANCE_INDEXES_SCHEMA_SQL},{id:"0023_spur_cli_history_message_request_id_idx",sql:HISTORY_MESSAGE_REQUEST_ID_INDEX_SCHEMA_SQL},{id:"0024_spur_cli_history_checkpoint_identity",sql:"ALTER TABLE history_import_checkpoint ADD COLUMN source_size INTEGER",addColumnIfMissing:{table:"history_import_checkpoint",column:"source_size"}},{id:"0025_spur_cli_history_checkpoint_identity_mtime",sql:"ALTER TABLE history_import_checkpoint ADD COLUMN source_mtime_ms REAL",addColumnIfMissing:{table:"history_import_checkpoint",column:"source_mtime_ms"}},{id:"0026_spur_cli_history_message_duration_source",sql:"ALTER TABLE history_message ADD COLUMN duration_source TEXT",addColumnIfMissing:{table:"history_message",column:"duration_source"}},{id:"0027_spur_cli_history_refresh_active_unique",sql:HISTORY_REFRESH_ACTIVE_UNIQUE_SCHEMA_SQL},{id:"0028_spur_cli_history_task_session",sql:HISTORY_TASK_SESSION_SCHEMA_SQL},{id:"0029_spur_cli_history_tool_call_indexes",sql:HISTORY_TOOL_CALL_INDEXES_SCHEMA_SQL},{id:"0030_spur_cli_history_board_covering_indexes",sql:HISTORY_BOARD_COVERING_INDEXES_SCHEMA_SQL},{id:"0031_spur_cli_history_board_tool_stats_columns",sql:HISTORY_BOARD_TOOL_STATS_COLUMNS_SCHEMA_SQL},{id:"0032_spur_cli_history_board_skill_5m",sql:HISTORY_BOARD_SKILL_5M_SCHEMA_SQL},{id:"0033_spur_cli_importer_schema_version",sql:`INSERT OR REPLACE INTO "__spur_cli_migrations" (id, applied_at) VALUES ('${IMPORTER_SCHEMA_LEDGER_PREFIX}${HISTORY_IMPORT_SCHEMA_VERSION}', strftime('%s', 'now') * 1000);`},{id:"0034_spur_cli_history_tool_identity",sql:HISTORY_TOOL_IDENTITY_SCHEMA_SQL},{id:"0035_spur_cli_history_measure_vector",sql:HISTORY_MEASURE_VECTOR_SCHEMA_SQL},{id:"0036_spur_cli_history_rollup_watermark",sql:HISTORY_ROLLUP_WATERMARK_SCHEMA_SQL},{id:"0037_spur_cli_history_dimension_marts",sql:HISTORY_DIMENSION_MARTS_SCHEMA_SQL},{id:"0038_spur_cli_retention_compaction_meta",sql:RETENTION_COMPACTION_META_SCHEMA_SQL},{id:"0039_spur_cli_bounded_rollup_derivations",sql:BOUNDED_ROLLUP_DERIVATIONS_SCHEMA_SQL,addColumnIfMissing:{table:"history_board_source_daily",column:"raw_messages"}},{id:"0040_spur_cli_agent_executor_updates",sql:AGENT_EXECUTOR_UPDATES_SCHEMA_SQL},{id:"0041_spur_cli_queue_jobs_deadline_lease_columns",sql:QUEUE_JOBS_DEADLINE_LEASE_COLUMNS_SCHEMA_SQL,addColumnIfMissing:{table:"queue_jobs",column:"timeout_ms"}},{id:"0042_spur_cli_history_model_fallback_index",sql:HISTORY_MESSAGE_MODEL_FALLBACK_INDEX_SCHEMA_SQL},{id:"0043_spur_cli_inbox_messages_request_key",sql:INBOX_MESSAGES_REQUEST_KEY_SCHEMA_SQL,addColumnIfMissing:{table:"inbox_messages",column:"request_key"}},{id:"0044_spur_cli_coordination_runs_receipt_columns",sql:COORDINATION_RUNS_RECEIPT_COLUMNS_SCHEMA_SQL,addColumnIfMissing:{table:"coordination_runs",column:"message_ids_json"}},{id:"0045_spur_cli_project_claims",sql:PROJECT_CLAIMS_SCHEMA_SQL},{id:"0046_spur_cli_project_strategy",sql:PROJECT_STRATEGY_SCHEMA_SQL},{id:"0047_spur_cli_scheduler_custom_active_unique",sql:SCHEDULER_CUSTOM_ACTIVE_UNIQUE_SCHEMA_SQL},{id:"0048_spur_cli_agent_executor_updates_owner_columns",sql:AGENT_EXECUTOR_UPDATES_OWNER_COLUMNS_SCHEMA_SQL,addColumnIfMissing:{table:"agent_executor_updates",column:"owner"}},{id:"0049_spur_cli_runs_terminal_reason",sql:CLI_RUNS_TERMINAL_REASON_SCHEMA_SQL,addColumnIfMissing:{table:"runs",column:"terminal_reason"}},{id:"0050_spur_cli_history_board_skill_5m_capability_grain",sql:HISTORY_BOARD_SKILL_5M_CAPABILITY_GRAIN_SCHEMA_SQL},{id:"0051_spur_cli_coordination_runs_parent",sql:COORDINATION_RUNS_PARENT_SCHEMA_SQL,addColumnIfMissing:{table:"coordination_runs",column:"parent_run_id"}}];async function allMigrationsJournaled(adapter,migrations){if(migrations.length===0)return!0;if(!await tableExists2(adapter,"__spur_cli_migrations"))return!1;let placeholders=migrations.map(()=>"?").join(", ");if(((await adapter.queryFirst(`SELECT COUNT(*) AS n FROM "__spur_cli_migrations" WHERE id IN (${placeholders})`,...migrations.map((m)=>m.id)))?.n??0)!==migrations.length)return!1;if(migrations.some((m)=>m.id==="0033_spur_cli_importer_schema_version")){if(!await adapter.queryFirst('SELECT id FROM "__spur_cli_migrations" WHERE id = ?',IMPORTER_SCHEMA_LEDGER_PREFIX+HISTORY_IMPORT_SCHEMA_VERSION))return!1}return!0}async function applyCliMigrations(adapter,migrations=CLI_MIGRATIONS){if(await allMigrationsJournaled(adapter,migrations))return 0;await adapter.exec('CREATE TABLE IF NOT EXISTS "__spur_cli_migrations" (id TEXT PRIMARY KEY, applied_at INTEGER NOT NULL)');let applied=0;for(let migration of migrations){if(await adapter.queryFirst('SELECT id FROM "__spur_cli_migrations" WHERE id = ?',migration.id)!=null)continue;if(migration.id==="0009_spur_cli_history_message_run_idx"&&!await tableExists2(adapter,"history_message")){for(let statement of splitSqlStatements(HISTORY_IMPORT_SCHEMA_SQL))await adapter.exec(statement);let versionLedgerId=IMPORTER_SCHEMA_LEDGER_PREFIX+HISTORY_IMPORT_SCHEMA_VERSION;await adapter.run('INSERT OR REPLACE INTO "__spur_cli_migrations" (id, applied_at) VALUES (?, ?)',[versionLedgerId,Date.now()])}if((migration.id==="0024_spur_cli_history_checkpoint_identity"||migration.id==="0025_spur_cli_history_checkpoint_identity_mtime")&&!await tableExists2(adapter,"history_import_checkpoint")){await adapter.run('INSERT INTO "__spur_cli_migrations" (id, applied_at) VALUES (?, ?)',[migration.id,Date.now()]);continue}if(migration.id==="0034_spur_cli_history_tool_identity"&&await tableExists2(adapter,"history_tool_call")){if(!await columnExists(adapter,"history_tool_call","effective_tool_name"))await adapter.exec("ALTER TABLE history_tool_call ADD COLUMN effective_tool_name TEXT NOT NULL DEFAULT 'unknown'");if(!await columnExists(adapter,"history_tool_call","tool_name_alias"))await adapter.exec("ALTER TABLE history_tool_call ADD COLUMN tool_name_alias TEXT NOT NULL DEFAULT 'unknown'")}let addColumnGuard=migration.addColumnIfMissing,shouldApplySql=addColumnGuard===void 0||!await columnExists(adapter,addColumnGuard.table,addColumnGuard.column),tsNullableSkip=migration.id==="0016_spur_cli_history_message_ts_nullable"&&(!await tableExists2(adapter,"history_message")||!await columnNotNull(adapter,"history_message","ts")),sequenceIndexSkip=migration.id==="0011_spur_cli_system_events_sequence_idx"&&!await tableExists2(adapter,"system_events"),argsRawSkip=migration.id==="0012_spur_cli_history_tool_call_args_raw"&&!await tableExists2(adapter,"history_tool_call"),callIdSkip=migration.id==="0015_spur_cli_history_tool_call_call_id"&&!await tableExists2(adapter,"history_tool_call"),nameOccurredIndexSkip=migration.id==="0014_spur_cli_system_events_name_occurred_idx"&&!await tableExists2(adapter,"system_events"),historyBoardQueryIndexesSkip=migration.id==="0020_spur_cli_history_board_query_indexes"&&(!await tableExists2(adapter,"history_message")||!await columnExists(adapter,"history_message","seq")||!await columnExists(adapter,"history_message","duration_ms")||!await columnExists(adapter,"history_message","role")||!await columnExists(adapter,"history_message","input_tokens")||!await columnExists(adapter,"history_message","cache_read_tokens")),historyPerformanceIndexesSkip=migration.id==="0022_spur_cli_history_performance_indexes"&&(!await tableExists2(adapter,"history_message")||!await columnExists(adapter,"history_message","ts")||!await columnExists(adapter,"history_message","model")||!await tableExists2(adapter,"history_tool_call")),historyToolCallIndexesSkip=migration.id==="0029_spur_cli_history_tool_call_indexes"&&(!await tableExists2(adapter,"history_message")||!await columnExists(adapter,"history_message","ts")||!await tableExists2(adapter,"history_tool_call")),historyBoardCoveringIndexesSkip=migration.id==="0030_spur_cli_history_board_covering_indexes"&&(!await tableExists2(adapter,"history_daily_stats")||!await tableExists2(adapter,"history_board_tool_5m")||!await tableExists2(adapter,"history_board_message_5m")||!await tableExists2(adapter,"history_board_session_stats")||!await tableExists2(adapter,"history_board_source_daily")||!await tableExists2(adapter,"history_tool_call")||!await tableExists2(adapter,"history_task_session")),runsStatusDoneSkip=migration.id==="0017_spur_cli_runs_status_completed_to_done"&&(!await tableExists2(adapter,"runs")||!await columnExists(adapter,"runs","status")),historyBoardToolStatsColumnsSkip=migration.id==="0031_spur_cli_history_board_tool_stats_columns"&&(!await tableExists2(adapter,"history_board_tool_stats")||await columnExists(adapter,"history_board_tool_stats","fresh_input_tokens")),queueJobsActiveIndexSkip=migration.id==="0027_spur_cli_history_refresh_active_unique"&&!await tableExists2(adapter,"queue_jobs"),schedulerCustomActiveIndexSkip=migration.id==="0047_spur_cli_scheduler_custom_active_unique"&&!await tableExists2(adapter,"queue_jobs"),queueJobsDeadlineLeaseSkip=migration.id==="0041_spur_cli_queue_jobs_deadline_lease_columns"&&!await tableExists2(adapter,"queue_jobs"),runsTerminalReasonSkip=migration.id==="0049_spur_cli_runs_terminal_reason"&&!await tableExists2(adapter,"runs"),skillCapabilityGrainSkip=migration.id==="0050_spur_cli_history_board_skill_5m_capability_grain"&&!await tableExists2(adapter,"history_board_skill_5m"),inboxRequestKeySkip=migration.id==="0043_spur_cli_inbox_messages_request_key"&&!await tableExists2(adapter,"inbox_messages"),coordinationReceiptColumnsSkip=migration.id==="0044_spur_cli_coordination_runs_receipt_columns"&&!await tableExists2(adapter,"coordination_runs"),historyToolIdentitySkip=migration.id==="0034_spur_cli_history_tool_identity"&&!await tableExists2(adapter,"history_tool_call"),historyMeasureVectorSkip=migration.id==="0035_spur_cli_history_measure_vector"&&(!await tableExists2(adapter,"history_board_message_5m")||await columnExists(adapter,"history_board_message_5m","cache_write_tokens")),historyRollupWatermarkSkip=migration.id==="0036_spur_cli_history_rollup_watermark"&&(await tableExists2(adapter,"history_board_rollup_watermark")||!await tableExists2(adapter,"history_message")||!await columnExists(adapter,"history_message","imported_at")),boundedRollupDerivationsSkip=migration.id==="0039_spur_cli_bounded_rollup_derivations"&&(!await tableExists2(adapter,"history_message")||!await columnExists(adapter,"history_message","source_file")||!await tableExists2(adapter,"history_board_source_daily")),historyModelFallbackIndexSkip=migration.id==="0042_spur_cli_history_model_fallback_index"&&(!await tableExists2(adapter,"history_message")||!await columnExists(adapter,"history_message","model"));if(shouldApplySql&&!sequenceIndexSkip&&!argsRawSkip&&!runsStatusDoneSkip&&!nameOccurredIndexSkip&&!historyBoardQueryIndexesSkip&&!historyPerformanceIndexesSkip&&!historyToolCallIndexesSkip&&!historyBoardCoveringIndexesSkip&&!historyBoardToolStatsColumnsSkip&&!callIdSkip&&!tsNullableSkip&&!queueJobsActiveIndexSkip&&!schedulerCustomActiveIndexSkip&&!queueJobsDeadlineLeaseSkip&&!runsTerminalReasonSkip&&!skillCapabilityGrainSkip&&!inboxRequestKeySkip&&!coordinationReceiptColumnsSkip&&!historyToolIdentitySkip&&!historyMeasureVectorSkip&&!historyRollupWatermarkSkip&&!boundedRollupDerivationsSkip&&!historyModelFallbackIndexSkip)for(let statement of splitSqlStatements(migration.sql))await adapter.exec(statement);if(historyToolIdentitySkip&&!await tableExists2(adapter,"history_tool_alias_map"))await adapter.exec("CREATE TABLE IF NOT EXISTS history_tool_alias_map (source TEXT NOT NULL, effective_tool_name TEXT NOT NULL, alias TEXT NOT NULL, PRIMARY KEY (source, effective_tool_name));");await adapter.run('INSERT INTO "__spur_cli_migrations" (id, applied_at) VALUES (?, ?)',migration.id,Date.now()),applied+=1}if(migrations.some((m)=>m.id==="0033_spur_cli_importer_schema_version")){let currentVersionLedgerId=IMPORTER_SCHEMA_LEDGER_PREFIX+HISTORY_IMPORT_SCHEMA_VERSION;if(!await adapter.queryFirst('SELECT id FROM "__spur_cli_migrations" WHERE id = ?',currentVersionLedgerId)){for(let statement of splitSqlStatements(HISTORY_IMPORT_SCHEMA_SQL))if(statement.startsWith("CREATE TABLE"))await adapter.exec(statement);await adapter.run('INSERT OR REPLACE INTO "__spur_cli_migrations" (id, applied_at) VALUES (?, ?)',[currentVersionLedgerId,Date.now()]),applied+=1}}return applied}async function columnExists(adapter,table3,column2){return(await adapter.queryAll(`PRAGMA table_info("${table3}")`)).some((row)=>row.name===column2)}async function columnNotNull(adapter,table3,column2){return(await adapter.queryAll(`PRAGMA table_info("${table3}")`)).some((row)=>row.name===column2&&row.notnull===1)}async function tableExists2(adapter,table3){return await adapter.queryFirst("SELECT name FROM sqlite_master WHERE type = 'table' AND name = ?",table3)!=null}function splitSqlStatements(sql4){return sql4.split(";").map((statement)=>statement.trim()).filter(Boolean)}var SQLITE_BUSY_TIMEOUT_MS=30000;async function createMigratedDb(options){let{createDbAdapter:createDbAdapter3}=await Promise.resolve().then(() => (init_dist4(),exports_dist)),adapter=await createDbAdapter3({driver:"bun-sqlite",url:options.url});return await adapter.exec(`PRAGMA busy_timeout = ${SQLITE_BUSY_TIMEOUT_MS}`),await applyCliMigrations(adapter),adapter}init_zod();init_zod();var STAGE_REGISTRY_SCHEMA_VERSION={major:1,minor:3},stageSchemaVersionSchema=exports_external.object({major:exports_external.number().int().nonnegative(),minor:exports_external.number().int().nonnegative()}).strict();var MUTATION_CLASSES=["none","corpus","code","tests","verdict","learnings","driver","irreversible"];var inlineExecutionSchema=exports_external.object({kind:exports_external.literal("inline"),current_agent_allowed:exports_external.literal(!0),may_reuse_captured_layers:exports_external.boolean().optional()}).strict(),subprocessExecutionSchema=exports_external.object({kind:exports_external.literal("subprocess"),current_agent_allowed:exports_external.literal(!1),via:exports_external.literal("spur-agent-run")}).strict(),deterministicExecutionSchema=exports_external.object({kind:exports_external.literal("deterministic"),current_agent_allowed:exports_external.literal(!1),executor:exports_external.enum(["cli","script"])}).strict(),hitlExecutionSchema=exports_external.object({kind:exports_external.literal("hitl"),current_agent_allowed:exports_external.literal(!0),gate_timing:exports_external.enum(["pre","post","both"])}).strict(),irreversibleExecutionSchema=exports_external.object({kind:exports_external.literal("irreversible"),requires_operator_intent:exports_external.literal(!0),current_agent_allowed:exports_external.boolean(),rollback_disclaimer:exports_external.string().min(1)}).strict(),executionKindSchema=exports_external.discriminatedUnion("kind",[inlineExecutionSchema,subprocessExecutionSchema,deterministicExecutionSchema,hitlExecutionSchema,irreversibleExecutionSchema]),ARTIFACT_DIRECTIONS=["input","output"],stageArtifactSchema=exports_external.object({kind:exports_external.string().min(1),direction:exports_external.enum(ARTIFACT_DIRECTIONS),identity:exports_external.string().optional(),description:exports_external.string().optional(),required:exports_external.boolean().optional().default(!0)}).strict(),stageGateSchema=exports_external.object({name:exports_external.string().min(1),timing:exports_external.enum(["pre","post","transition"]),min_verdict:exports_external.enum(["pass","partial","fail"]).optional(),description:exports_external.string().optional()}).strict(),stageRetryPolicySchema=exports_external.object({max_attempts:exports_external.number().int().min(1),terminal_stop:exports_external.enum(["block","escalate","fail"]),timeout_seconds:exports_external.number().int().positive().optional()}).strict(),CAPABILITY_TIERS=["cheap","standard","capable-1","capable-2","capable-3"],LEGACY_CAPABLE_ALIAS="capable";function normalizeCapabilityTier(value){return value===LEGACY_CAPABLE_ALIAS?"capable-1":value}var capabilityTierSchema=exports_external.preprocess(normalizeCapabilityTier,exports_external.enum(CAPABILITY_TIERS)),objectiveEscalationTriggerSchema=exports_external.enum(["gate-fail","timeout","insufficient-evidence","retry-exhausted","resource-exhaustion","auth"]),stageModelPolicySchema=exports_external.object({min_tier:capabilityTierSchema,fallback:exports_external.array(exports_external.object({tier:capabilityTierSchema,trigger:objectiveEscalationTriggerSchema}).strict()),override_key:exports_external.string().optional()}).strict();var CONTEXT_LAYER_NAMES=["harness-policy","project-authority","stage-contract","task-state","indexed-evidence","run-state","tool-observations"],stageContextLayerSchema=exports_external.object({layer:exports_external.enum(CONTEXT_LAYER_NAMES),required:exports_external.literal(!0)}).strict(),stageEventSchema=exports_external.object({name:exports_external.string().min(1),description:exports_external.string().optional()}).strict(),STAGE_ID_PATTERN=/^[a-z][a-z0-9-]*$/,stageRecordSchema=exports_external.object({schema_version:stageSchemaVersionSchema,id:exports_external.string().regex(STAGE_ID_PATTERN,{message:"stage id must be lowercase kebab-case"}),aliases:exports_external.array(exports_external.string().min(1)).optional().default([]),description:exports_external.string().min(1),artifacts:exports_external.array(stageArtifactSchema).min(1),reasoning_skill:exports_external.string().min(1),required_references:exports_external.array(exports_external.string().min(1)).optional().default([]),gates:exports_external.array(stageGateSchema).optional().default([]),mutation_class:exports_external.enum(MUTATION_CLASSES),retry:stageRetryPolicySchema,model_policy:stageModelPolicySchema,context_layers:exports_external.array(stageContextLayerSchema).optional().default([]),observability:exports_external.array(stageEventSchema).optional().default([]),execution:executionKindSchema}).strict();var REGISTERED_CANONICAL_STAGES=[{schema_version:STAGE_REGISTRY_SCHEMA_VERSION,id:"refine",aliases:["dev-refine"],description:"dev-refine: Q&A refinement, section filling, AC tightening",artifacts:[{kind:"task-section",direction:"input",required:!0,description:"Background/Requirements sections"},{kind:"task-section",direction:"output",required:!0,description:"Q&A/Design/Plan/AC sections"}],reasoning_skill:"sp:spur-dev",required_references:[],gates:[],mutation_class:"corpus",retry:{max_attempts:3,terminal_stop:"block"},model_policy:{min_tier:"standard",fallback:[{tier:"capable-2",trigger:"gate-fail"},{tier:"capable-2",trigger:"auth"},{tier:"capable-2",trigger:"resource-exhaustion"}]},context_layers:[],observability:[],execution:{kind:"inline",current_agent_allowed:!0}},{schema_version:STAGE_REGISTRY_SCHEMA_VERSION,id:"plan",aliases:["dev-plan"],description:"dev-plan: feature intake -> AC generation -> decomposition",artifacts:[{kind:"feature-frontmatter",direction:"input",required:!0},{kind:"task-batch",direction:"output",required:!0}],reasoning_skill:"sp:spur-dev",required_references:[],gates:[{name:"feature-check",timing:"post",min_verdict:"pass"},{name:"batch-create",timing:"post",min_verdict:"pass"}],mutation_class:"corpus",retry:{max_attempts:3,terminal_stop:"block"},model_policy:{min_tier:"capable-2",fallback:[{tier:"capable-3",trigger:"gate-fail"},{tier:"capable-3",trigger:"auth"},{tier:"capable-3",trigger:"resource-exhaustion"}]},context_layers:[],observability:[],execution:{kind:"inline",current_agent_allowed:!0}},{schema_version:STAGE_REGISTRY_SCHEMA_VERSION,id:"implement",aliases:["dev-run"],description:"dev-run --mode implement: code edits in worktree",artifacts:[{kind:"worktree-diff",direction:"output",required:!0},{kind:"task-section",direction:"output",required:!0,identity:"Solution"}],reasoning_skill:"sp:code-implementation",required_references:[],gates:[],mutation_class:"code",retry:{max_attempts:3,terminal_stop:"block"},model_policy:{min_tier:"standard",fallback:[{tier:"capable-1",trigger:"gate-fail"},{tier:"capable-1",trigger:"timeout"},{tier:"capable-1",trigger:"auth"},{tier:"capable-1",trigger:"resource-exhaustion"}]},context_layers:[],observability:[],execution:{kind:"inline",current_agent_allowed:!0}},{schema_version:STAGE_REGISTRY_SCHEMA_VERSION,id:"test",aliases:["dev-unit","dev-fixall"],description:"dev-unit: generate/extend tests to coverage target",artifacts:[{kind:"test-file",direction:"output",required:!0},{kind:"coverage-report",direction:"output",required:!1}],reasoning_skill:"sp:code-testing",required_references:[],gates:[],mutation_class:"tests",retry:{max_attempts:3,terminal_stop:"block"},model_policy:{fallback:[{tier:"capable-1",trigger:"gate-fail"},{tier:"capable-1",trigger:"auth"},{tier:"capable-1",trigger:"resource-exhaustion"}],min_tier:"standard"},context_layers:[],observability:[],execution:{kind:"inline",current_agent_allowed:!0}},{schema_version:STAGE_REGISTRY_SCHEMA_VERSION,id:"verify",aliases:["dev-verify"],description:"dev-verify: SECUA review + requirements traceability",artifacts:[{kind:"worktree-diff",direction:"input",required:!0},{kind:"verdict-artifact",direction:"output",required:!0,identity:"<wbs>-verdict.json"}],reasoning_skill:"sp:code-verification",required_references:[],gates:[{name:"verdict-artifact",timing:"post",min_verdict:"pass"},{name:"strict-core",timing:"post",min_verdict:"pass"}],mutation_class:"verdict",retry:{max_attempts:2,terminal_stop:"escalate"},model_policy:{min_tier:"capable-1",fallback:[{tier:"capable-2",trigger:"auth"},{tier:"capable-2",trigger:"resource-exhaustion"},{tier:"capable-2",trigger:"gate-fail"}]},context_layers:[],observability:[],execution:{kind:"inline",current_agent_allowed:!0}},{schema_version:STAGE_REGISTRY_SCHEMA_VERSION,id:"wrap",aliases:["dev-wrap"],description:"dev-wrap: learnings/doc-sync/feature transition",artifacts:[{kind:"learning-entry",direction:"output",required:!0}],reasoning_skill:"sp:spur-dev",required_references:[],gates:[{name:"task-check",timing:"pre",min_verdict:"pass"}],mutation_class:"learnings",retry:{max_attempts:2,terminal_stop:"block"},model_policy:{min_tier:"standard",fallback:[{tier:"capable-1",trigger:"gate-fail"},{tier:"capable-1",trigger:"auth"},{tier:"capable-1",trigger:"resource-exhaustion"}]},context_layers:[],observability:[],execution:{kind:"hitl",current_agent_allowed:!0,gate_timing:"both"}},{schema_version:STAGE_REGISTRY_SCHEMA_VERSION,id:"review",aliases:["dev-review"],description:"dev-review: multi-dimensional code review (coordinator writes the combined Review)",artifacts:[{kind:"review-findings",direction:"output",required:!0,identity:"Review"}],reasoning_skill:"sp:code-verification",required_references:[],gates:[],mutation_class:"verdict",retry:{max_attempts:2,terminal_stop:"block"},model_policy:{min_tier:"standard",fallback:[{tier:"capable-1",trigger:"gate-fail"},{tier:"capable-1",trigger:"auth"},{tier:"capable-1",trigger:"resource-exhaustion"}]},context_layers:[],observability:[],execution:{kind:"inline",current_agent_allowed:!0}},{schema_version:STAGE_REGISTRY_SCHEMA_VERSION,id:"record",aliases:["dev-record"],description:"record: deterministic Testing write-back from the verdict artifact; bare-Review fallback only",artifacts:[{kind:"verdict-artifact",direction:"input",required:!0,identity:"<wbs>-verdict.json"},{kind:"task-section",direction:"output",required:!0,identity:"Testing"},{kind:"task-section",direction:"output",required:!1,identity:"Review",description:"fallback-only: backfills Review only when the section is bare; never overwrites authored Review"}],reasoning_skill:"inline",required_references:[],gates:[],mutation_class:"corpus",retry:{max_attempts:1,terminal_stop:"block"},model_policy:{min_tier:"cheap",fallback:[]},context_layers:[],observability:[],execution:{kind:"deterministic",current_agent_allowed:!1,executor:"cli"}},{schema_version:STAGE_REGISTRY_SCHEMA_VERSION,id:"dogfood",aliases:["dev-dogfood"],description:"dev-dogfood: end-to-end driver test",artifacts:[{kind:"dogfood-report",direction:"output",required:!0},{kind:"monitor-ledger",direction:"output",required:!1}],reasoning_skill:"sp:dogfood-testing",required_references:[],gates:[],mutation_class:"driver",retry:{max_attempts:3,terminal_stop:"block"},model_policy:{min_tier:"capable-1",fallback:[{tier:"capable-2",trigger:"auth"},{tier:"capable-2",trigger:"resource-exhaustion"},{tier:"capable-2",trigger:"gate-fail"}]},context_layers:[],observability:[],execution:{kind:"inline",current_agent_allowed:!0}},{schema_version:STAGE_REGISTRY_SCHEMA_VERSION,id:"brainstorm",aliases:["dev-brainstorm"],description:"dev-brainstorm: structured ideation",artifacts:[{kind:"brainstorm-outline",direction:"output",required:!0}],reasoning_skill:"sp:brainstorm",required_references:[],gates:[],mutation_class:"corpus",retry:{max_attempts:2,terminal_stop:"block"},model_policy:{min_tier:"standard",fallback:[]},context_layers:[],observability:[],execution:{kind:"inline",current_agent_allowed:!0}},{schema_version:STAGE_REGISTRY_SCHEMA_VERSION,id:"changelog",aliases:["dev-changelog"],description:"dev-changelog: generate changelog from git commits",artifacts:[{kind:"changelog-entry",direction:"output",required:!0}],reasoning_skill:"inline",required_references:[],gates:[],mutation_class:"none",retry:{max_attempts:1,terminal_stop:"block"},model_policy:{min_tier:"cheap",fallback:[]},context_layers:[],observability:[],execution:{kind:"deterministic",current_agent_allowed:!1,executor:"cli"}}],CANONICAL_STAGE_BY_KEY=new Map;for(let s2 of REGISTERED_CANONICAL_STAGES){CANONICAL_STAGE_BY_KEY.set(s2.id,s2);for(let a2 of s2.aliases??[])CANONICAL_STAGE_BY_KEY.set(a2,s2)}var CACHEABILITY_CLASSES=["stable-prefix-eligible","volatile"],SENSITIVITY_CLASSES=["public","internal","confidential"],envelopeProvenanceSchema=exports_external.object({owner:exports_external.string().min(1),schema_version:exports_external.string().min(1),source_revision:exports_external.string().nullable().optional(),generated_at:exports_external.string().datetime()}).strict(),envelopeSizeBudgetSchema=exports_external.object({max_bytes:exports_external.number().int().positive()}).strict(),envelopeLayerSchema=exports_external.object({layer:exports_external.enum(CONTEXT_LAYER_NAMES),content:exports_external.string(),size_bytes:exports_external.number().int().nonnegative(),content_hash:exports_external.string().length(64),provenance:envelopeProvenanceSchema,cacheability:exports_external.enum(CACHEABILITY_CLASSES),sensitivity:exports_external.enum(SENSITIVITY_CLASSES).default("internal"),size_budget:envelopeSizeBudgetSchema.optional(),disclosure_handle:exports_external.string().optional()}).strict(),STABLE_LAYER_NAMES=["harness-policy","project-authority","stage-contract","task-state","indexed-evidence"],VOLATILE_LAYER_NAMES=["run-state","tool-observations"];var envelopeSchema=exports_external.object({schema_version:exports_external.string().default("1.0"),layers:exports_external.array(envelopeLayerSchema).min(1),stage_id:exports_external.string().optional(),run_id:exports_external.string().optional(),assembled_at:exports_external.string().datetime(),total_size_bytes:exports_external.number().int().nonnegative()}).strict(),projectSnapshotSchema=exports_external.object({name:exports_external.string(),version:exports_external.string(),task_counts:exports_external.object({backlog:exports_external.number().int().nonnegative(),todo:exports_external.number().int().nonnegative(),wip:exports_external.number().int().nonnegative(),testing:exports_external.number().int().nonnegative(),done:exports_external.number().int().nonnegative(),blocked:exports_external.number().int().nonnegative(),cancelled:exports_external.number().int().nonnegative()}).strict(),feature_counts:exports_external.object({backlog:exports_external.number().int().nonnegative(),active:exports_external.number().int().nonnegative(),verifying:exports_external.number().int().nonnegative(),done:exports_external.number().int().nonnegative(),blocked:exports_external.number().int().nonnegative(),cancelled:exports_external.number().int().nonnegative()}).strict(),active_features:exports_external.array(exports_external.string()),content_hash:exports_external.string().length(64).optional()}).strict(),taskSnapshotSchema=exports_external.object({wbs:exports_external.string().regex(/^\d{4}$/),name:exports_external.string(),status:exports_external.string(),priority:exports_external.string().optional(),feature_id:exports_external.string().optional(),acceptance_criteria:exports_external.string().optional(),locked_qa:exports_external.array(exports_external.string()).optional(),solution:exports_external.string().optional(),content_hash:exports_external.string().length(64).optional()}).strict(),featureSnapshotSchema=exports_external.object({id:exports_external.string(),name:exports_external.string(),status:exports_external.string(),priority:exports_external.string().optional(),scenarios:exports_external.array(exports_external.string()).optional(),content_hash:exports_external.string().length(64).optional()}).strict();var ALL_LAYER_NAMES=[...STABLE_LAYER_NAMES,...VOLATILE_LAYER_NAMES],LAYER_ORDER={};ALL_LAYER_NAMES.forEach((name,idx)=>{LAYER_ORDER[name]=idx});init_dist2();var TASK_CANONICAL_SECTIONS=["Background","Requirements","Acceptance Criteria","Q&A","Design","Plan","Root Cause","Solution","Testing","Review","References","History"],FEATURE_CANONICAL_SECTIONS=["Goal","Scope","Acceptance Criteria","Tasks","Notes","History"],UNIVERSAL_SECTIONS=["History","References","Notes"],HEADING_LEVELS={task:3,feature:2},START_MARKER="<!-- AUTO-GENERATED by spur feature refresh -->",END_MARKER="<!-- END AUTO-GENERATED -->",MARKER_START_RE=/<!--[ \t]*AUTO-GENERATED.*?-->/,MARKER_END_RE=/<!--[ \t]*END[ \t]*AUTO-GENERATED.*?-->/;function findHeadings(body,hashes){let hits=[],prefix=`${hashes} `,inCodeBlock=!1,lineStart=0;for(let i2=0;i2<=body.length;i2++){if(i2!==body.length&&body[i2]!==`
|
|
1457
1520
|
`)continue;let line=body.slice(lineStart,i2);if(line.startsWith("```"))inCodeBlock=!inCodeBlock;else if(!inCodeBlock&&line.startsWith(prefix)){let name=line.slice(prefix.length).trim();hits.push({index:lineStart,headingLine:line,name})}lineStart=i2+1}return hits}function findUnclosedFenceLine(text3){let inCodeBlock=!1,openLine=0,lineNo=0,lineStart=0;for(let i2=0;i2<=text3.length;i2++){if(i2!==text3.length&&text3[i2]!==`
|
|
1458
1521
|
`)continue;let line=text3.slice(lineStart,i2);if(lineNo++,line.startsWith("```"))if(inCodeBlock)inCodeBlock=!1;else inCodeBlock=!0,openLine=lineNo;lineStart=i2+1}return inCodeBlock?openLine:null}function normalizeYamlScalars(data){let out={};for(let[key,value]of Object.entries(data))if(value instanceof Date)out[key]=value.toISOString();else if(value!==null&&typeof value==="object"&&!Array.isArray(value))out[key]=normalizeYamlScalars(value);else out[key]=value;return out}class MarkdownDocument{_domain;_frontmatterBlock;_frontmatter;_preamble;_sections;_demotedHeadings=[];_duplicateSectionNames=[];_unclosedFenceLine;constructor(domain2,frontmatterBlock,frontmatter,preamble,sections,unclosedFenceLine){this._domain=domain2,this._frontmatterBlock=frontmatterBlock,this._frontmatter=frontmatter,this._preamble=preamble,this._sections=sections,this._unclosedFenceLine=unclosedFenceLine}static parse(content,domain2){let level=HEADING_LEVELS[domain2],hashes="#".repeat(level),frontmatterBlock="",frontmatter=null,body=content,fmMatch=/^---\r?\n([\s\S]*?)\r?\n---\r?\n?/.exec(content);if(fmMatch&&fmMatch.index===0){let raw=fmMatch[1]??"",data={};try{let parsed=$parse(raw);if(parsed!==null&&typeof parsed==="object"&&!Array.isArray(parsed))data=normalizeYamlScalars(parsed)}catch{}frontmatter={raw,data},frontmatterBlock=fmMatch[0],body=content.slice(fmMatch[0].length)}let bodyUnclosedFenceLine=findUnclosedFenceLine(body),unclosedFenceLine=bodyUnclosedFenceLine===null?null:bodyUnclosedFenceLine+(frontmatterBlock.match(/\n/g)??[]).length,hits=findHeadings(body,hashes),first=hits[0],preamble=first!==void 0?body.slice(0,first.index):body,allSections=hits.map((hit,idx)=>{let next=hits[idx+1],end=next!==void 0?next.index:body.length;return{name:hit.name,headingLine:hit.headingLine,originalText:body.slice(hit.index,end),modifiedText:null}}),seen=new Set,sections=[],duplicateNames=[];for(let s2 of allSections)if(seen.has(s2.name))duplicateNames.push(s2.name);else seen.add(s2.name),sections.push(s2);let doc2=new MarkdownDocument(domain2,frontmatterBlock,frontmatter,preamble,sections,unclosedFenceLine);return doc2._duplicateSectionNames.push(...duplicateNames),doc2}get domain(){return this._domain}replacePreamble(newBody){this._preamble=newBody}get frontmatter(){return this._frontmatter}get frontmatterRaw(){return this._frontmatter?.raw??null}get frontmatterData(){return this._frontmatter?.data??null}get bodyWithoutFrontmatter(){let result=this._preamble;for(let section of this._sections)result+=section.modifiedText??section.originalText;return result}get sectionNames(){return this._sections.map((s2)=>s2.name)}get demotedHeadings(){return this._demotedHeadings}get duplicateSectionNames(){return this._duplicateSectionNames}unclosedFenceLine(){return this._unclosedFenceLine}assertFenceBalance(name,body){let docFenceLine=this._unclosedFenceLine;if(docFenceLine!==null)throw Error(`Cannot write section "${name}": the document has an unclosed code fence at line ${docFenceLine}; later sections are hidden and would be dropped by this write. Close the fence and re-parse.`);if(this._duplicateSectionNames.length>0){let names=this._duplicateSectionNames.map((n2)=>`"${n2}"`).join(", ");throw Error(`Cannot write section "${name}": the document has duplicate top-level sections (${names}); the serialized result would have fewer sections than the input and the duplicates would be dropped. Merge or remove the duplicates and re-parse.`)}let bodyFenceLine=findUnclosedFenceLine(body);if(bodyFenceLine!==null)throw Error(`Cannot write section "${name}": the new body has an unclosed code fence (opening at body line ${bodyFenceLine}); writing it would leave the document inside an open fence and hide later sections.`)}get canonicalSections(){let base2=this._domain==="task"?TASK_CANONICAL_SECTIONS:FEATURE_CANONICAL_SECTIONS,extra=UNIVERSAL_SECTIONS.filter((s2)=>!base2.includes(s2));return[...base2,...extra]}validateSectionName(name){if(!this.canonicalSections.includes(name))throw Error(`Unknown section "${name}" for domain "${this._domain}". Canonical sections: ${this.canonicalSections.join(", ")}.`)}findSection(name){return this._sections.find((s2)=>s2.name===name)}hasSection(name){return this.findSection(name)!==void 0}getSection(name){this.validateSectionName(name);let section=this.findSection(name);if(section===void 0)return null;let text3=section.modifiedText??section.originalText,newlineIdx=text3.indexOf(`
|
|
1459
1522
|
`);return newlineIdx===-1?"":text3.slice(newlineIdx+1)}replaceSection(name,body){this.validateSectionName(name),this.assertFenceBalance(name,body);let cleaned=this.stripSameLevelHeadings(body),section=this.findSection(name);if(section!==void 0){let trimmed=cleaned.trim();section.modifiedText=trimmed.length>0?`${section.headingLine}
|
|
@@ -1475,7 +1538,7 @@ ${raw2}
|
|
|
1475
1538
|
---
|
|
1476
1539
|
|
|
1477
1540
|
`;return}let oldRaw=this._frontmatter.raw,lines=oldRaw.split(`
|
|
1478
|
-
`),keyPrefix=`${key}:`,idx=lines.findIndex((line)=>line===keyPrefix||line.startsWith(`${keyPrefix} `));if(idx===-1)lines.push(fieldLine);else lines
|
|
1541
|
+
`),keyPrefix=`${key}:`,idx=lines.findIndex((line)=>line===keyPrefix||line.startsWith(`${keyPrefix} `));if(idx===-1)lines.push(fieldLine);else replaceFieldLines(lines,idx,fieldLine);let raw=lines.join(`
|
|
1479
1542
|
`);this._frontmatter={raw,data:{...this._frontmatter.data,[key]:value}};let rawStart=this._frontmatterBlock.indexOf(oldRaw);this._frontmatterBlock=rawStart===-1?`---
|
|
1480
1543
|
${raw}
|
|
1481
1544
|
---
|
|
@@ -1484,39 +1547,39 @@ ${fieldLine}
|
|
|
1484
1547
|
---
|
|
1485
1548
|
|
|
1486
1549
|
`;return}let oldRaw=this._frontmatter.raw,lines=oldRaw.split(`
|
|
1487
|
-
`),keyPrefix=`${key}:`,idx=lines.findIndex((line)=>line===keyPrefix||line.startsWith(`${keyPrefix} `));if(idx===-1)lines.push(fieldLine);else lines
|
|
1550
|
+
`),keyPrefix=`${key}:`,idx=lines.findIndex((line)=>line===keyPrefix||line.startsWith(`${keyPrefix} `));if(idx===-1)lines.push(fieldLine);else replaceFieldLines(lines,idx,fieldLine);let raw=lines.join(`
|
|
1488
1551
|
`);this._frontmatter={raw,data:{...this._frontmatter.data,[key]:values}};let rawStart=this._frontmatterBlock.indexOf(oldRaw);this._frontmatterBlock=rawStart===-1?`---
|
|
1489
1552
|
${raw}
|
|
1490
1553
|
---
|
|
1491
|
-
`:this._frontmatterBlock.slice(0,rawStart)+raw+this._frontmatterBlock.slice(rawStart+oldRaw.length)}serialize(){let result=this._frontmatterBlock;result+=this._preamble;for(let section of this._sections)result+=section.modifiedText??section.originalText;return result}}function escapeYamlArrayElement(value){return`"${value.replace(/\\/g,"\\\\").replace(/"/g,"\\\"")}"`}function escapeYamlValue(value){if(value.startsWith('"')&&value.endsWith('"'))return value;if(/[:{}[\],&*?|>!%@`#"'\\\n\r]/.test(value))return`"${value.replace(/\\/g,"\\\\").replace(/"/g,"\\\"")}"`;if(/^(null|true|false|yes|no|on|off)$/i.test(value))return`"${value}"`;if(/^\d/.test(value)&&!/^\d{4}-\d{2}-\d{2}/.test(value))return`"${value}"`;return value}init_zod();var TASK_STATUSES=["backlog","todo","wip","testing","blocked","done","cancelled"],FEATURE_STATUSES=["backlog","active","verifying","blocked","done","cancelled"];var PRIORITIES=["P0","P1","P2","P3"],PROFILES=["simple","standard","complex","research","refine","plan","unit","review","docs"],TASK_TYPES=["task","issue","review","meta","brainstorm"],TASK_VARIANTS=["standard","feature-impl","issue","review","meta","brainstorm"];var FEATURE_ID_PATTERN=/^[A-Z][1-9]*$/;var TASK_STATUS_ALIASES={completed:"done",complete:"done","in-progress":"wip","in progress":"wip",in_progress:"wip",dropped:"cancelled",cancel:"cancelled",canceled:"cancelled",new:"backlog",pending:"backlog",blocked:"blocked",wip:"wip",testing:"testing",done:"done",cancelled:"cancelled",backlog:"backlog",todo:"todo"};function normalizeTaskStatus(raw){let key=raw.trim().toLowerCase(),resolved=TASK_STATUS_ALIASES[key];if(resolved===void 0)throw Error(`Unknown task status: ${JSON.stringify(raw)} (allowed: ${TASK_STATUSES.join(", ")})`);return resolved}var isoDateString=exports_external.string().min(1).refine((value)=>!Number.isNaN(Date.parse(value)),{message:"must be an ISO 8601 timestamp"}),featureId=exports_external.string().regex(FEATURE_ID_PATTERN,{message:"feature id must match ^[A-Z][1-9]*$ (DD-14)"}).nullable().optional(),wbsString=exports_external.string().regex(/^\d{4}$/,{message:"parent_wbs must be a 4-digit WBS string"}).nullable().optional(),taskFrontmatterSchema=exports_external.object({schema_version:exports_external.literal(1),name:exports_external.string().min(1),description:exports_external.string().optional(),status:exports_external.preprocess((val)=>{if(typeof val==="string")try{return normalizeTaskStatus(val)}catch{}return val},exports_external.enum(TASK_STATUSES)),type:exports_external.enum(TASK_TYPES).optional().default("task"),template:exports_external.enum(TASK_VARIANTS).optional(),profile:exports_external.enum(PROFILES).optional(),feature_id:featureId,parent_wbs:wbsString,priority:exports_external.enum(PRIORITIES).optional(),tags:exports_external.array(exports_external.string()).optional(),dependencies:exports_external.array(exports_external.string()).optional(),ac_numbering:exports_external.literal("task-local").optional(),ac_altitude:exports_external.enum(["graduating","task-local"]).optional(),done_forced:exports_external.preprocess((v)=>typeof v==="string"?v==="true":v,exports_external.boolean().optional()),done_reason:exports_external.string().optional(),feature_link_declined:exports_external.preprocess((v)=>typeof v==="string"?v==="true":v,exports_external.boolean().optional()),estimate_hours:exports_external.preprocess((v)=>typeof v==="string"&&v.trim()!==""?Number(v):v,exports_external.number().positive().optional()),created_at:isoDateString,updated_at:isoDateString}),featureFrontmatterSchema=exports_external.object({schema_version:exports_external.literal(1),id:exports_external.string().regex(FEATURE_ID_PATTERN,{message:"feature id must match ^[A-Z][1-9]*$ (DD-14)"}),name:exports_external.string().min(1),status:exports_external.enum(FEATURE_STATUSES),priority:exports_external.enum(PRIORITIES).optional(),tags:exports_external.array(exports_external.string()).optional(),created_at:isoDateString,updated_at:isoDateString});var taskBatchItemSchema=exports_external.object({name:exports_external.string().min(1,"name is required"),background:exports_external.string().optional(),requirements:exports_external.string().optional(),design:exports_external.string().optional(),plan:exports_external.string().optional(),acceptance_criteria:exports_external.string().optional(),feature_id:featureId,parent_wbs:wbsString,priority:exports_external.enum(PRIORITIES).optional(),tags:exports_external.array(exports_external.string()).optional(),template:exports_external.enum(TASK_VARIANTS).optional(),estimate_hours:exports_external.number().positive().optional()}).strict(),taskBatchSchema=exports_external.array(taskBatchItemSchema).min(1,"batch must contain at least one task");init_dist2();init_zod();var sectionNameSchema=exports_external.enum(TASK_CANONICAL_SECTIONS),matrixEntrySchema=exports_external.object({required:exports_external.array(sectionNameSchema).optional(),optional:exports_external.array(sectionNameSchema).optional(),forbidden:exports_external.array(sectionNameSchema).optional(),gate:exports_external.boolean().optional()}).strict(),matrixStatusSchema=exports_external.enum(["backlog","todo","wip","testing","blocked","done","cancelled"]),sectionMatrixSchema=exports_external.object({variants:exports_external.record(exports_external.string(),exports_external.partialRecord(matrixStatusSchema,matrixEntrySchema))}).strict();var CANONICAL_INDEX=new Map(TASK_CANONICAL_SECTIONS.map((s2,i2)=>[s2,i2]));init_dist6();import{appendFileSync as appendFileSync3,existsSync as existsSync2,linkSync,lstatSync,mkdirSync as mkdirSync2,readdirSync as readdirSync2,readFileSync as readFileSync4,renameSync as renameSync2,statSync as statSync3,unlinkSync,writeFileSync as writeFileSync3}from"node:fs";import{tmpdir as tmpdir2}from"node:os";import{basename as basename2,dirname as dirname5,isAbsolute,join as join4,relative as relative2,resolve as resolve3,sep as sep3}from"node:path";import{dirname as dirname2,join,normalize,relative,resolve,sep}from"node:path";class RunArtifactPathError extends Error{constructor(message){super(message);this.name="RunArtifactPathError"}}function within(child,ancestor){return child===ancestor||child.startsWith(`${ancestor}${sep}`)}async function resolveDurableArtifactPath(fileSystem,workdir,pathRaw,plane){return resolveConfinedArtifactPath(fileSystem,workdir,pathRaw,plane==="memory"?".spur/memory":`.spur/memory/${plane}`)}async function resolveConfinedArtifactPath(fileSystem,workdir,pathRaw,root){if(typeof fileSystem.realPath!=="function")throw new RunArtifactPathError("physical path confinement requires a FileSystem with realPath support — refusing to skip confinement (0785 R2)");let workdirAbs=resolve(workdir),canonicalWorkdir;try{canonicalWorkdir=fileSystem.realPath(workdirAbs)}catch(error51){throw new RunArtifactPathError(`project workdir could not be canonicalized: ${error51.message}`)}let lexicalTarget=normalize(resolve(workdir,pathRaw)),lexicalRunRoot=normalize(join(resolve(workdir),root)),canonicalAlias=join(canonicalWorkdir,root);if(lexicalTarget.startsWith(`${canonicalAlias}${sep}`))lexicalTarget=join(lexicalRunRoot,relative(canonicalAlias,lexicalTarget));if(!lexicalTarget.startsWith(`${lexicalRunRoot}${sep}`))throw new RunArtifactPathError(`must resolve beneath ${root}/ (got ${pathRaw})`);let canonicalRunRootCandidate=join(canonicalWorkdir,root),canonicalRunRoot=canonicalRunRootCandidate;if(await fileSystem.stat(canonicalRunRootCandidate)!==null){try{canonicalRunRoot=fileSystem.realPath(canonicalRunRootCandidate)}catch(error51){throw new RunArtifactPathError(`${root} could not be canonicalized: ${error51.message}`)}if(!within(canonicalRunRoot,canonicalWorkdir))throw new RunArtifactPathError(`${root} resolves outside the project workdir through a symlink`)}let probe=lexicalTarget;for(;;){if(await fileSystem.stat(probe)!==null)break;let parent=dirname2(probe),listed;try{listed=await fileSystem.readDir(parent)}catch(error51){if(String(error51.message).includes("ENOENT"))listed=null;else throw new RunArtifactPathError(`ancestor ${parent} is unreadable: ${error51.message}`)}let base2=probe.slice(parent.length+1);if(listed?.includes(base2))throw new RunArtifactPathError(`dangling symlink at ${probe} — refusing artifact path`);let parentNorm=normalize(parent);if(parentNorm===probe)throw new RunArtifactPathError(`no existing ancestor found for ${pathRaw}`);probe=parentNorm}let anchor;try{anchor=fileSystem.realPath(probe)}catch(error51){throw new RunArtifactPathError(`ancestor ${probe} could not be canonicalized: ${error51.message}`)}if(!within(anchor,canonicalWorkdir))throw new RunArtifactPathError(`ancestor ${probe} escapes the project workdir through a symlink`);let reconstructed=normalize(join(anchor,relative(probe,lexicalTarget)));if(!reconstructed.startsWith(`${canonicalRunRoot}${sep}`))throw new RunArtifactPathError(`path escapes ${root}/ through a symlink (got ${pathRaw})`);return reconstructed}import{basename,dirname as dirname4,join as join3}from"node:path";import crypto4 from"node:crypto";import{tmpdir}from"node:os";import{dirname as dirname3,join as join2,resolve as resolve2,sep as sep2}from"node:path";init_zod();init_zod();var BOARD_MODULE_ID_PATTERN=/^[a-z][a-z0-9-]*$/;function isSafeFrameUrl(value){let parsed;try{parsed=new URL(value)}catch{return!1}if(parsed.protocol!=="http:"&&parsed.protocol!=="https:")return!1;return parsed.username===""&&parsed.password===""}var sharedDeclarationFields={id:exports_external.string().regex(BOARD_MODULE_ID_PATTERN,"module id must match ^[a-z][a-z0-9-]*$"),name:exports_external.string().min(1,"module name must not be empty"),icon:exports_external.string().min(1,"module icon must not be empty"),sidebarLabel:exports_external.string().optional(),description:exports_external.string().optional(),order:exports_external.number().refine((value)=>Number.isFinite(value),{message:"module order must be a finite number"}).optional(),enabled:exports_external.boolean().optional().default(!0)},boardModuleDeclarationSchema=exports_external.discriminatedUnion("type",[exports_external.object({...sharedDeclarationFields,type:exports_external.literal("react"),directory:exports_external.string().min(1),entry:exports_external.string().min(1),styles:exports_external.array(exports_external.string().min(1)).optional().default(()=>[])}).strict(),exports_external.object({...sharedDeclarationFields,type:exports_external.literal("iframe"),url:exports_external.string().refine(isSafeFrameUrl,{message:"iframe url must be an absolute http(s) URL without embedded credentials (relative URLs and other schemes are rejected)"})}).strict()]),boardModuleDeclarationsSchema=exports_external.array(boardModuleDeclarationSchema);var RFC3339_PATTERN=/^\d{4}-\d{2}-\d{2}[Tt]\d{2}:\d{2}:\d{2}(\.\d+)?([Zz]|[+-]\d{2}:\d{2})$/;function isRfc3339Timestamp(value){return RFC3339_PATTERN.test(value)&&Number.isFinite(Date.parse(value))}var ALL_FINDING_CODES=["L1.markdown-parse","L1.schema-validation","L2.missing-required-section","L2.forbidden-section","L2.disallowed-section","L2.heading-level","L2.section-order","L2.unclosed-code-fence","L3.requirements-format","L3.requirements-checkbox","L3.requirements-empty","L3.ac-empty","L3.ac-requirement-coverage","L3.solution-file-line","L3.review-priority-table","L3.required-section-placeholder","L3.plan-format","L3.unchecked-checklist","L3.ac-checklist-text","L3.ac-bdd-error","L3.ac-bdd-warning","L3.ac-bdd-invalid","L3.scope-delineation","L3.one-active-goal","L3.children-limit","L3.review-testing-contradiction","L4.design-placeholder","L4.feature-not-found","L4.feature-terminal","L4.missing-feature-id","L4.parent-not-found","L4.dependency-not-found","L4.rollup-subtasks-open","L4.rollup-parent-open","L4.rollup-missing-roster","L4.rollup-roster-not-declared-dependency","L4.readiness-blocked","L4.prose-prerequisite-unlisted","L4.prerequisite-cycle","L4.prerequisite-not-done","L4.gate-language","L4.linked-task-parse-failed","L4.orphan-scenarios","L4.uncovered-task-scenario","L4.uncovered-feature-scenario","L4.verdict-rows-match-no-scenario","L4.verifying-incomplete-tasks","L4.dogfood-missing","L4.stale-line-anchor","L4.anchor-unresolved","L4.anchor-subject-mismatch","L4.malformed-verdict-artifact","L4.scenario-unverified","L4.testing-verdict-stub","L4.evidence-not-recoverable","L4.feature-receipt-missing","L4.feature-receipt-malformed","L4.feature-receipt-cross-feature","L4.feature-receipt-divergent","L4.feature-receipt-failed","L4.feature-receipt-run","L4.feature-receipt-stale","L4.feature-receipt-contract","precheck-size","precheck-evidence","inventory-coverage"];function isFindingCode(code){return ALL_FINDING_CODES.includes(code)}init_dist();init_zod();var projectEntrySchema=exports_external.object({name:exports_external.string().min(1),path:exports_external.string().min(1),port:exports_external.number().int().nonnegative().default(0)}),projectsFileSchema=exports_external.object({schema_version:exports_external.literal(1).default(1),projects:exports_external.array(projectEntrySchema).default([])});init_zod();var slashCommandCategorySchema=exports_external.enum(["git","dev","sys","harness"]),slashCommandItemSchema=exports_external.object({name:exports_external.string().min(1),description:exports_external.string().min(1),category:slashCommandCategorySchema.default("dev"),argumentHint:exports_external.string().optional(),tags:exports_external.array(exports_external.string()).default([]),role:exports_external.string().optional(),source:exports_external.string().optional()}),slashCommandsFileSchema=exports_external.object({version:exports_external.number().int().default(1),updatedAt:exports_external.string().optional(),commands:exports_external.array(slashCommandItemSchema).default([])});var SPUR_LOG_LEVELS=["debug","info","warn","error"],DEFAULT_TASKS_DIR="docs/tasks",DEFAULT_FEATURES_DIR="docs/features",DEFAULT_DATABASE_URL=".spur/spur.db";var folderConfigSchema=exports_external.object({baseCounter:exports_external.number().int().nonnegative().default(0),label:exports_external.string().optional()});function folderPathWithDefault(defaultPath){return exports_external.preprocess((v)=>v==null?void 0:v,exports_external.string().default(defaultPath))}var tasksConfigSchema=exports_external.object({folders:exports_external.record(exports_external.string(),folderConfigSchema).default({}),active:folderPathWithDefault(DEFAULT_TASKS_DIR),severity:exports_external.record(exports_external.string(),exports_external.enum(["error","warning","off"])).optional()}).superRefine((data,ctx)=>{if(data.severity){for(let code of Object.keys(data.severity))if(!isFindingCode(code))ctx.addIssue({code:exports_external.ZodIssueCode.custom,path:["severity",code],message:`Unknown finding code "${code}" in severity overrides map`})}}),featuresConfigSchema=exports_external.object({dir:folderPathWithDefault(DEFAULT_FEATURES_DIR)}),EXECUTOR_CAPABILITY_TIERS=["cheap","standard","capable-1","capable-2","capable-3"];function normalizeExecutorTier(value){return value==="capable"?"capable-1":value}var executorCapabilityTierSchema=exports_external.preprocess((value)=>{if(value===void 0||value===null)return;return typeof value==="string"?normalizeExecutorTier(value):value},exports_external.enum(EXECUTOR_CAPABILITY_TIERS).optional()),AGENT_ROLE_NAMES=["scribe","coder","reviewer","planner"];var EXECUTION_CAPABILITY_AXES=["fsRead","fsWrite","networkEgress","processSpawn","externalMutationApproval"],SESSION_CAPABILITY_AXES=["resumeById","sessionDir","persistentStdin","structuredOutput"],AGENT_RUN_CAPABILITY_AXES=[...EXECUTION_CAPABILITY_AXES,...SESSION_CAPABILITY_AXES],EXECUTION_CAPABILITY_STATES=["enforced","available","unavailable","unknown"],EXECUTION_CAPABILITY_PROVENANCES=["native-known","operator-configured","unattested"],ExecutionCapabilityAttestationSchema=exports_external.object({state:exports_external.enum(EXECUTION_CAPABILITY_STATES),provenance:exports_external.enum(EXECUTION_CAPABILITY_PROVENANCES)}),ExecutionCapabilitiesSchema=exports_external.object({version:exports_external.literal(1),axes:exports_external.partialRecord(exports_external.enum(EXECUTION_CAPABILITY_AXES),ExecutionCapabilityAttestationSchema)}),EXECUTION_CAPABILITY_REQUIREMENTS=["available","enforced"],RequiresCapabilitiesSchema=exports_external.partialRecord(exports_external.enum(AGENT_RUN_CAPABILITY_AXES),exports_external.enum(EXECUTION_CAPABILITY_REQUIREMENTS)),executorAvailabilityOwnerSchema=exports_external.enum(["operator","quota","probe"]),executorDisabledObjectSchema=exports_external.object({owner:executorAvailabilityOwnerSchema,since:exports_external.string().refine(isRfc3339Timestamp,{message:"since must be an RFC 3339 timestamp"}),reason:exports_external.string().min(1)}),AgentExecutorConfigSchema=exports_external.object({name:exports_external.string().min(1),agent:exports_external.string().min(1),model:exports_external.string().min(1).optional(),tier:executorCapabilityTierSchema.optional(),executionCapabilities:ExecutionCapabilitiesSchema.optional(),disabled:exports_external.union([exports_external.boolean(),executorDisabledObjectSchema]).default(!1)});var AgentRoleConfigSchema=exports_external.object({tier:exports_external.enum(EXECUTOR_CAPABILITY_TIERS).optional(),stages:exports_external.array(exports_external.string().min(1)).min(1).optional()});var FleetMemberSchema=exports_external.object({id:exports_external.string().min(1).optional(),role:exports_external.enum(AGENT_ROLE_NAMES,{error:(issue2)=>Error(`Unknown role "${issue2.input}" — expected one of: ${AGENT_ROLE_NAMES.join(", ")}`)}).optional(),executor:exports_external.string().min(1).optional(),purpose:exports_external.string().optional(),enabled:exports_external.boolean().optional()}),FLEET_STRATEGIES=["rest","gtd"],FleetMemberEntrySchema=FleetMemberSchema.superRefine((member,ctx)=>{if(member.role===void 0&&member.executor===void 0)ctx.addIssue({code:exports_external.ZodIssueCode.custom,message:"must declare a role or an executor — at least one is required"})}),AgentFleetSchema=exports_external.object({enabled:exports_external.boolean().default(!1),strategy:exports_external.enum(FLEET_STRATEGIES).default("rest"),orchestrator:exports_external.string().min(1).optional(),members:exports_external.array(FleetMemberEntrySchema).default([])});var AgentOutputConfigSchema=exports_external.object({"max-bytes":exports_external.number().int().positive().optional(),"max-lines":exports_external.number().int().positive().optional()}),AgentConfigSchema=exports_external.object({default:exports_external.string().optional(),executors:exports_external.array(AgentExecutorConfigSchema).optional(),roles:exports_external.record(exports_external.string(),AgentRoleConfigSchema).optional(),output:AgentOutputConfigSchema.optional(),sessionAffinity:exports_external.boolean().optional(),fleet:AgentFleetSchema.optional()}).superRefine((value,ctx)=>{for(let key of Object.keys(value.roles??{}))if(!AGENT_ROLE_NAMES.includes(key))ctx.addIssue({code:exports_external.ZodIssueCode.custom,path:["roles",key],message:`Unknown role "${key}" — expected one of: ${AGENT_ROLE_NAMES.join(", ")}`});let executors=value.executors,executorNames=new Set;if(executors!==void 0){let seen=new Set;for(let[index2,executor]of executors.entries()){if(seen.has(executor.name))ctx.addIssue({code:exports_external.ZodIssueCode.custom,message:`Duplicate executor name: ${executor.name}`,path:["executors",index2,"name"]});if(executor.name==="inline"||executor.name==="auto")ctx.addIssue({code:exports_external.ZodIssueCode.custom,message:`Executor name "${executor.name}" is reserved (the --agent selector value '${executor.name}' has fixed semantics); rename executor at index ${index2}.`,path:["executors",index2,"name"]});if(AGENT_ROLE_NAMES.includes(executor.name))ctx.addIssue({code:exports_external.ZodIssueCode.custom,message:`Executor name "${executor.name}" collides with the role selector namespace ("${executor.name}"); rename executor at index ${index2}.`,path:["executors",index2,"name"]});seen.add(executor.name),executorNames.add(executor.name)}}}),RulesConfigSchema=exports_external.object({paths:exports_external.array(exports_external.string()).optional()}),WorkflowsConfigSchema=exports_external.object({paths:exports_external.array(exports_external.string()).optional()}),WorkflowConfigSchema=exports_external.object({hitlDecisionMaker:exports_external.boolean().optional(),decideDecisionMaker:exports_external.boolean().optional(),logRetentionDays:exports_external.number().int().positive().default(30)}),RedactionConfigSchema=exports_external.object({enabled:exports_external.boolean().optional()}),HistoryRefreshConfigSchema=exports_external.object({on_completion:exports_external.boolean().default(!1),debounce_ms:exports_external.number().int().min(1000).default(600000)}),HistoryConfigSchema=exports_external.object({refresh:HistoryRefreshConfigSchema.optional()}),VersionCarrierEntrySchema=exports_external.looseObject({type:exports_external.string().min(1)}),BuilderBumpVerConfigSchema=exports_external.object({tagVersionSeparator:exports_external.string().min(1).default("-v"),aggregatePackage:exports_external.string().min(1).optional(),publishWorkflow:exports_external.string().min(1).default("publish.yml"),releaseCommitType:exports_external.string().min(1).default("chore"),releaseCommitScope:exports_external.string().min(1).default("release"),ghRunListLimit:exports_external.number().int().positive().default(5),versionCarriers:exports_external.array(VersionCarrierEntrySchema).default([])}),BuilderConfigSchema=exports_external.object({"bump-ver":BuilderBumpVerConfigSchema.optional()});var bootstrapOptionsSchema=exports_external.object({options:exports_external.record(exports_external.string(),exports_external.unknown()).optional()}),bootstrapSectionSchema=bootstrapOptionsSchema.extend({modules:boardModuleDeclarationsSchema.optional()}),spurConfigSchema=exports_external.object({version:exports_external.string().optional(),name:exports_external.string().optional(),bootstrap:bootstrapSectionSchema.optional(),agent:AgentConfigSchema.optional(),rules:RulesConfigSchema.optional(),workflows:WorkflowsConfigSchema.optional(),workflow:WorkflowConfigSchema.optional(),redaction:RedactionConfigSchema.optional(),history:HistoryConfigSchema.optional(),builder:BuilderConfigSchema.optional(),tasks:tasksConfigSchema.optional(),features:featuresConfigSchema.optional()});var configSchema3=exports_external.object({database:exports_external.object({url:exports_external.string().default(DEFAULT_DATABASE_URL)}).default({url:DEFAULT_DATABASE_URL}),server:exports_external.object({port:exports_external.coerce.number().int().positive().default(3000),host:exports_external.string().default("localhost"),openBrowser:exports_external.boolean().default(!0),webDistPath:exports_external.string().nullable().default(null)}).default({port:3000,host:"localhost",openBrowser:!0,webDistPath:null}),telemetry:exports_external.object({enabled:exports_external.boolean().default(!1),endpoint:exports_external.string().optional()}).default({enabled:!1}),logging:exports_external.object({level:exports_external.enum(SPUR_LOG_LEVELS).default("info")}).default({level:"info"})});init_dist6();import crypto3 from"node:crypto";function canonicalJsonStringify(obj){if(obj===null||typeof obj!=="object")return JSON.stringify(obj);if(Array.isArray(obj))return`[${obj.map(canonicalJsonStringify).join(",")}]`;return`{${Object.keys(obj).sort().map((key)=>`${JSON.stringify(key)}:${canonicalJsonStringify(obj[key])}`).join(",")}}`}function computeDefinitionDigest(workflow){let canonical=canonicalJsonStringify(workflow);return`sha256:${crypto3.createHash("sha256").update(canonical,"utf8").digest("hex")}`}class ProofCaptureError extends Error{stderr;constructor(message,stderr){super(message);this.stderr=stderr;this.name="ProofCaptureError"}}var TASK_SPEC_SECTIONS=["Background","Requirements","Acceptance Criteria","Design","Plan"],CANONICAL_TASK_HEADING_RE=/^##[ \t]+(\d+)\.[ \t]+(\S.*)$/m;function taskDocumentShapeError(content){let doc2=MarkdownDocument.parse(content,"task"),heading=CANONICAL_TASK_HEADING_RE.exec(doc2.bodyWithoutFrontmatter);if(heading===null)return"no canonical task heading (`## <WBS>. <title>`) was found";if((heading[2]??"").trim()==="")return`the canonical task heading for WBS ${heading[1]} has an empty title`;if(TASK_SPEC_SECTIONS.filter((section)=>doc2.hasSection(section)).length===0)return`no task specification section (${TASK_SPEC_SECTIONS.join(", ")}) was found`;return null}async function readProofInputContents(fileSystem=createNodeFileSystem2(),workdir,options){for(let name of["taskFile","featureFile"]){let value=options[name];if(value!==void 0&&typeof value!=="string")return{ok:!1,error:`${name} must be a string when supplied (got ${typeof value})`}}let readOne=async(name)=>{let raw=name==="taskFile"?options.taskFile:options.featureFile;if(raw===void 0||raw==="")return{};let workdirAbs=resolve2(workdir),resolved=resolve2(workdirAbs,raw);if(!(resolved===workdirAbs||resolved.startsWith(`${workdirAbs}${sep2}`)))return{error:`${name} must resolve under the workflow workdir (${workdirAbs}): ${raw}`};let stat;try{stat=await fileSystem.stat(resolved)}catch(error51){return{error:`${name} could not be inspected: ${error51.message}`}}if(stat===null)return{error:`${name} does not exist: ${raw} (resolved ${resolved}) — an explicitly supplied spec must be readable, not silently omitted`};if(!stat.isFile())return{error:`${name} is not a regular file: ${resolved}`};let content;try{content=await fileSystem.readFile(resolved)}catch(error51){return{error:`${name} is not readable: ${error51.message}`}}if(name==="taskFile"){let shapeError=taskDocumentShapeError(content);if(shapeError!==null)return{error:`taskFile is not a task document: ${raw} (resolved ${resolved}) — ${shapeError}. Supply the task specification markdown itself: a \`## <WBS>. <title>\` heading plus at least one of ${TASK_SPEC_SECTIONS.join(", ")}. A file containing only a path is not dereferenced.`}}return{content}},task=await readOne("taskFile");if(task.error!==void 0)return{ok:!1,error:task.error};let feature=await readOne("featureFile");if(feature.error!==void 0)return{ok:!1,error:feature.error};return{ok:!0,...task.content!==void 0?{taskContent:task.content}:{},...feature.content!==void 0?{featureContent:feature.content}:{}}}var DEFAULT_EXCLUDE_GLOBS=["docs/tasks*","docs/features*"];async function createGitAlternateTree(cwd,excludeGlobs=DEFAULT_EXCLUDE_GLOBS,executor=new NodeProcessExecutor2,fs2=createNodeFileSystem2()){let indexFile=join2(tmpdir(),`spur-proof-fingerprint-${crypto4.randomUUID()}.index`);try{await fs2.ensureDir(dirname3(indexFile));let env2=Object.fromEntries(Object.entries(getEnvVars()).filter((entry)=>entry[1]!==void 0));env2.GIT_INDEX_FILE=indexFile;let common4={cwd,env:env2,forceBuffered:!0,rejectOnError:!1},read=await executor.run({command:"git",args:["read-tree","HEAD"],...common4});if(read.exitCode!==0)throw new ProofCaptureError(`git read-tree HEAD failed with exit code ${read.exitCode}`,read.stderr);let excludes=excludeGlobs.map((glob)=>`:(exclude)${glob}`),add=await executor.run({command:"git",args:["add","-A","--",".",...excludes],...common4});if(add.exitCode!==0)throw new ProofCaptureError(`git add -A failed with exit code ${add.exitCode}`,add.stderr);let tree=await executor.run({command:"git",args:["write-tree"],...common4});if(tree.exitCode!==0)throw new ProofCaptureError(`git write-tree failed with exit code ${tree.exitCode}`,tree.stderr);return tree.stdout.trim()}catch(error51){if(error51 instanceof ProofCaptureError)throw error51;throw new ProofCaptureError(`git alternate-tree capture threw: ${error51.message}`)}finally{if(await fs2.exists(indexFile))try{await fs2.deleteFile(indexFile)}catch{}}}function canonicalizeCheckboxMarkers(body){return body.replace(/^([ \t]*)[-*+][ \t]+\[[ xX]\]/gm,"$1- [x]")}function extractTaskProofData(content){let doc2=MarkdownDocument.parse(content,"task"),fm=doc2.frontmatterData??{},wbs=typeof fm.wbs==="string"?fm.wbs:void 0,name=typeof fm.name==="string"?fm.name:void 0,feature_id=typeof fm.feature_id==="string"?fm.feature_id:void 0,depends_on;if(Array.isArray(fm.depends_on))depends_on=fm.depends_on.filter((d)=>typeof d==="string");else if(Array.isArray(fm.dependencies))depends_on=fm.dependencies.filter((d)=>typeof d==="string");let sections={},taskSections=["Background","Requirements","Acceptance Criteria","Design","Plan"];for(let sec of taskSections)if(doc2.hasSection(sec)){let body=doc2.getSection(sec);if(body!==null)sections[sec]=canonicalizeCheckboxMarkers(body.trim())}return{...wbs!==void 0?{wbs}:{},...name!==void 0?{name}:{},...feature_id!==void 0?{feature_id}:{},...depends_on!==void 0?{depends_on}:{},sections}}function extractFeatureProofData(content){let doc2=MarkdownDocument.parse(content,"feature"),fm=doc2.frontmatterData??{},id=typeof fm.id==="string"?fm.id:void 0,name=typeof fm.name==="string"?fm.name:void 0,sections={},featureSections=["Goal","Scope","Acceptance Criteria"];for(let sec of featureSections)if(doc2.hasSection(sec)){let body=doc2.getSection(sec);if(body!==null)sections[sec]=canonicalizeCheckboxMarkers(body.trim())}return{...id!==void 0?{id}:{},...name!==void 0?{name}:{},sections}}async function computeProofInputFingerprint(options={}){let cwd=options.cwd??process.cwd(),gitTree=await createGitAlternateTree(cwd,options.excludeGlobs??DEFAULT_EXCLUDE_GLOBS,options.processExecutor,options.fileSystem),task;if(options.taskContent!==void 0)task=extractTaskProofData(options.taskContent);let feature;if(options.featureContent!==void 0)feature=extractFeatureProofData(options.featureContent);let canonical=canonicalJsonStringify({gitTree,...task!==void 0?{task}:{},...feature!==void 0?{feature}:{},...options.learningsContent!==void 0?{learnings:options.learningsContent}:{}});return`sha256:${crypto4.createHash("sha256").update(canonical,"utf8").digest("hex")}`}var ProofInputFingerprint={compute:computeProofInputFingerprint};var FEATURE_RECEIPT_SCHEMA_VERSION=1,DEFAULT_FEATURE_VERIFICATION_CMD="bun run spur-check-feature",RECEIPT_ID_PATTERN=/^[A-Za-z0-9][A-Za-z0-9._-]*$/;function assertReceiptId(kind,id){if(!RECEIPT_ID_PATTERN.test(id)||id.includes(".."))throw Error(`invalid ${kind} for receipt path: ${JSON.stringify(id)}`)}function featureReceiptPaths(runDir,featureId2,runId){return assertReceiptId("featureId",featureId2),assertReceiptId("runId",runId),{runScoped:join3(dirname4(runDir),"memory","evidence",`${runId}-feature-verification.json`),featureScoped:join3(dirname4(runDir),"memory","evidence",`${featureId2}-feature-verification.json`),log:join3(runDir,`${runId}-feature-verification.log`),status:join3(runDir,`${runId}-feature-verification.status`)}}async function atomicWriteReceipt(fs2,path8,receipt){path8=await resolveDurableArtifactPath(fs2,receipt.workdir,path8,"evidence"),ensureDurablePlaneIgnored(receipt.workdir),await fs2.ensureDir(dirname4(path8));let body=`${JSON.stringify(receipt,null,4)}
|
|
1554
|
+
`:this._frontmatterBlock.slice(0,rawStart)+raw+this._frontmatterBlock.slice(rawStart+oldRaw.length)}serialize(){let result=this._frontmatterBlock;result+=this._preamble;for(let section of this._sections)result+=section.modifiedText??section.originalText;return result}}function replaceFieldLines(lines,idx,fieldLine){let end=idx+1;while(end<lines.length&&/^(\s|-(\s|$))/.test(lines[end]??""))end++;lines.splice(idx,end-idx,fieldLine)}function escapeYamlArrayElement(value){return`"${value.replace(/\\/g,"\\\\").replace(/"/g,"\\\"")}"`}function escapeYamlValue(value){if(value.startsWith('"')&&value.endsWith('"'))return value;if(/[:{}[\],&*?|>!%@`#"'\\\n\r]/.test(value))return`"${value.replace(/\\/g,"\\\\").replace(/"/g,"\\\"")}"`;if(/^(null|true|false|yes|no|on|off)$/i.test(value))return`"${value}"`;if(/^\d/.test(value)&&!/^\d{4}-\d{2}-\d{2}/.test(value))return`"${value}"`;return value}init_zod();var TASK_STATUSES=["backlog","todo","wip","testing","blocked","done","cancelled"],FEATURE_STATUSES=["backlog","active","verifying","blocked","done","cancelled"];var PRIORITIES=["P0","P1","P2","P3"],PROFILES=["simple","standard","complex","research","refine","plan","unit","review","docs"],TASK_TYPES=["task","issue","review","meta","brainstorm"],TASK_VARIANTS=["standard","feature-impl","issue","review","meta","brainstorm"];var FEATURE_ID_PATTERN=/^[A-Z][1-9]*$/;var TASK_STATUS_ALIASES={completed:"done",complete:"done","in-progress":"wip","in progress":"wip",in_progress:"wip",dropped:"cancelled",cancel:"cancelled",canceled:"cancelled",new:"backlog",pending:"backlog",blocked:"blocked",wip:"wip",testing:"testing",done:"done",cancelled:"cancelled",backlog:"backlog",todo:"todo"};function normalizeTaskStatus(raw){let key=raw.trim().toLowerCase(),resolved=TASK_STATUS_ALIASES[key];if(resolved===void 0)throw Error(`Unknown task status: ${JSON.stringify(raw)} (allowed: ${TASK_STATUSES.join(", ")})`);return resolved}var isoDateString=exports_external.string().min(1).refine((value)=>!Number.isNaN(Date.parse(value)),{message:"must be an ISO 8601 timestamp"}),featureId=exports_external.string().regex(FEATURE_ID_PATTERN,{message:"feature id must match ^[A-Z][1-9]*$ (DD-14)"}).nullable().optional(),wbsString=exports_external.string().regex(/^\d{4}$/,{message:"parent_wbs must be a 4-digit WBS string"}).nullable().optional(),taskFrontmatterSchema=exports_external.object({schema_version:exports_external.literal(1),name:exports_external.string().min(1),description:exports_external.string().optional(),status:exports_external.preprocess((val)=>{if(typeof val==="string")try{return normalizeTaskStatus(val)}catch{}return val},exports_external.enum(TASK_STATUSES)),type:exports_external.enum(TASK_TYPES).optional().default("task"),template:exports_external.enum(TASK_VARIANTS).optional(),profile:exports_external.enum(PROFILES).optional(),feature_id:featureId,parent_wbs:wbsString,priority:exports_external.enum(PRIORITIES).optional(),tags:exports_external.array(exports_external.string()).optional(),dependencies:exports_external.array(exports_external.string()).optional(),ac_numbering:exports_external.literal("task-local").optional(),ac_altitude:exports_external.enum(["graduating","task-local"]).optional(),done_forced:exports_external.preprocess((v)=>typeof v==="string"?v==="true":v,exports_external.boolean().optional()),done_reason:exports_external.string().optional(),feature_link_declined:exports_external.preprocess((v)=>typeof v==="string"?v==="true":v,exports_external.boolean().optional()),estimate_hours:exports_external.preprocess((v)=>typeof v==="string"&&v.trim()!==""?Number(v):v,exports_external.number().positive().optional()),created_at:isoDateString,updated_at:isoDateString}),featureFrontmatterSchema=exports_external.object({schema_version:exports_external.literal(1),id:exports_external.string().regex(FEATURE_ID_PATTERN,{message:"feature id must match ^[A-Z][1-9]*$ (DD-14)"}),name:exports_external.string().min(1),status:exports_external.enum(FEATURE_STATUSES),priority:exports_external.enum(PRIORITIES).optional(),tags:exports_external.array(exports_external.string()).optional(),created_at:isoDateString,updated_at:isoDateString});var taskBatchItemSchema=exports_external.object({name:exports_external.string().min(1,"name is required"),background:exports_external.string().optional(),requirements:exports_external.string().optional(),design:exports_external.string().optional(),plan:exports_external.string().optional(),acceptance_criteria:exports_external.string().optional(),feature_id:featureId,parent_wbs:wbsString,priority:exports_external.enum(PRIORITIES).optional(),tags:exports_external.array(exports_external.string()).optional(),template:exports_external.enum(TASK_VARIANTS).optional(),estimate_hours:exports_external.number().positive().optional()}).strict(),taskBatchSchema=exports_external.array(taskBatchItemSchema).min(1,"batch must contain at least one task");init_dist2();init_zod();var sectionNameSchema=exports_external.enum(TASK_CANONICAL_SECTIONS),matrixEntrySchema=exports_external.object({required:exports_external.array(sectionNameSchema).optional(),optional:exports_external.array(sectionNameSchema).optional(),forbidden:exports_external.array(sectionNameSchema).optional(),gate:exports_external.boolean().optional()}).strict(),matrixStatusSchema=exports_external.enum(["backlog","todo","wip","testing","blocked","done","cancelled"]),sectionMatrixSchema=exports_external.object({variants:exports_external.record(exports_external.string(),exports_external.partialRecord(matrixStatusSchema,matrixEntrySchema))}).strict();var CANONICAL_INDEX=new Map(TASK_CANONICAL_SECTIONS.map((s2,i2)=>[s2,i2]));init_dist6();import{appendFileSync as appendFileSync3,existsSync as existsSync2,linkSync,lstatSync,mkdirSync as mkdirSync2,readdirSync as readdirSync2,readFileSync as readFileSync4,renameSync as renameSync2,statSync as statSync3,unlinkSync,writeFileSync as writeFileSync3}from"node:fs";import{tmpdir as tmpdir2}from"node:os";import{basename as basename2,dirname as dirname5,isAbsolute,join as join4,relative as relative2,resolve as resolve3,sep as sep3}from"node:path";import{dirname as dirname2,join,normalize,relative,resolve,sep}from"node:path";class RunArtifactPathError extends Error{constructor(message){super(message);this.name="RunArtifactPathError"}}function within(child,ancestor){return child===ancestor||child.startsWith(`${ancestor}${sep}`)}async function resolveDurableArtifactPath(fileSystem,workdir,pathRaw,plane){return resolveConfinedArtifactPath(fileSystem,workdir,pathRaw,plane==="memory"?".spur/memory":`.spur/memory/${plane}`)}async function resolveConfinedArtifactPath(fileSystem,workdir,pathRaw,root){if(typeof fileSystem.realPath!=="function")throw new RunArtifactPathError("physical path confinement requires a FileSystem with realPath support — refusing to skip confinement (0785 R2)");let workdirAbs=resolve(workdir),canonicalWorkdir;try{canonicalWorkdir=fileSystem.realPath(workdirAbs)}catch(error51){throw new RunArtifactPathError(`project workdir could not be canonicalized: ${error51.message}`)}let lexicalTarget=normalize(resolve(workdir,pathRaw)),lexicalRunRoot=normalize(join(resolve(workdir),root)),canonicalAlias=join(canonicalWorkdir,root);if(lexicalTarget.startsWith(`${canonicalAlias}${sep}`))lexicalTarget=join(lexicalRunRoot,relative(canonicalAlias,lexicalTarget));if(!lexicalTarget.startsWith(`${lexicalRunRoot}${sep}`))throw new RunArtifactPathError(`must resolve beneath ${root}/ (got ${pathRaw})`);let canonicalRunRootCandidate=join(canonicalWorkdir,root),canonicalRunRoot=canonicalRunRootCandidate;if(await fileSystem.stat(canonicalRunRootCandidate)!==null){try{canonicalRunRoot=fileSystem.realPath(canonicalRunRootCandidate)}catch(error51){throw new RunArtifactPathError(`${root} could not be canonicalized: ${error51.message}`)}if(!within(canonicalRunRoot,canonicalWorkdir))throw new RunArtifactPathError(`${root} resolves outside the project workdir through a symlink`)}let probe=lexicalTarget;for(;;){if(await fileSystem.stat(probe)!==null)break;let parent=dirname2(probe),listed;try{listed=await fileSystem.readDir(parent)}catch(error51){if(String(error51.message).includes("ENOENT"))listed=null;else throw new RunArtifactPathError(`ancestor ${parent} is unreadable: ${error51.message}`)}let base2=probe.slice(parent.length+1);if(listed?.includes(base2))throw new RunArtifactPathError(`dangling symlink at ${probe} — refusing artifact path`);let parentNorm=normalize(parent);if(parentNorm===probe)throw new RunArtifactPathError(`no existing ancestor found for ${pathRaw}`);probe=parentNorm}let anchor;try{anchor=fileSystem.realPath(probe)}catch(error51){throw new RunArtifactPathError(`ancestor ${probe} could not be canonicalized: ${error51.message}`)}if(!within(anchor,canonicalWorkdir))throw new RunArtifactPathError(`ancestor ${probe} escapes the project workdir through a symlink`);let reconstructed=normalize(join(anchor,relative(probe,lexicalTarget)));if(!reconstructed.startsWith(`${canonicalRunRoot}${sep}`))throw new RunArtifactPathError(`path escapes ${root}/ through a symlink (got ${pathRaw})`);return reconstructed}import{basename,dirname as dirname4,join as join3}from"node:path";import crypto4 from"node:crypto";import{tmpdir}from"node:os";import{dirname as dirname3,join as join2,resolve as resolve2,sep as sep2}from"node:path";init_zod();init_zod();var BOARD_MODULE_ID_PATTERN=/^[a-z][a-z0-9-]*$/;function isSafeFrameUrl(value){let parsed;try{parsed=new URL(value)}catch{return!1}if(parsed.protocol!=="http:"&&parsed.protocol!=="https:")return!1;return parsed.username===""&&parsed.password===""}var sharedDeclarationFields={id:exports_external.string().regex(BOARD_MODULE_ID_PATTERN,"module id must match ^[a-z][a-z0-9-]*$"),name:exports_external.string().min(1,"module name must not be empty"),icon:exports_external.string().min(1,"module icon must not be empty"),sidebarLabel:exports_external.string().optional(),description:exports_external.string().optional(),order:exports_external.number().refine((value)=>Number.isFinite(value),{message:"module order must be a finite number"}).optional(),enabled:exports_external.boolean().optional().default(!0)},boardModuleDeclarationSchema=exports_external.discriminatedUnion("type",[exports_external.object({...sharedDeclarationFields,type:exports_external.literal("react"),directory:exports_external.string().min(1),entry:exports_external.string().min(1),styles:exports_external.array(exports_external.string().min(1)).optional().default(()=>[])}).strict(),exports_external.object({...sharedDeclarationFields,type:exports_external.literal("iframe"),url:exports_external.string().refine(isSafeFrameUrl,{message:"iframe url must be an absolute http(s) URL without embedded credentials (relative URLs and other schemes are rejected)"})}).strict()]),boardModuleDeclarationsSchema=exports_external.array(boardModuleDeclarationSchema);var RFC3339_PATTERN=/^\d{4}-\d{2}-\d{2}[Tt]\d{2}:\d{2}:\d{2}(\.\d+)?([Zz]|[+-]\d{2}:\d{2})$/;function isRfc3339Timestamp(value){return RFC3339_PATTERN.test(value)&&Number.isFinite(Date.parse(value))}var ALL_FINDING_CODES=["L1.markdown-parse","L1.schema-validation","L2.missing-required-section","L2.forbidden-section","L2.disallowed-section","L2.heading-level","L2.section-order","L2.unclosed-code-fence","L3.requirements-format","L3.requirements-checkbox","L3.requirements-empty","L3.ac-empty","L3.ac-requirement-coverage","L3.solution-file-line","L3.review-priority-table","L3.required-section-placeholder","L3.plan-format","L3.unchecked-checklist","L3.ac-checklist-text","L3.ac-bdd-error","L3.ac-bdd-warning","L3.ac-bdd-invalid","L3.scope-delineation","L3.one-active-goal","L3.children-limit","L3.review-testing-contradiction","L4.design-placeholder","L4.feature-not-found","L4.feature-terminal","L4.missing-feature-id","L4.parent-not-found","L4.dependency-not-found","L4.rollup-subtasks-open","L4.rollup-parent-open","L4.rollup-missing-roster","L4.rollup-roster-not-declared-dependency","L4.readiness-blocked","L4.prose-prerequisite-unlisted","L4.prerequisite-cycle","L4.prerequisite-not-done","L4.gate-language","L4.linked-task-parse-failed","L4.orphan-scenarios","L4.uncovered-task-scenario","L4.uncovered-feature-scenario","L4.verdict-rows-match-no-scenario","L4.verifying-incomplete-tasks","L4.dogfood-missing","L4.stale-line-anchor","L4.anchor-unresolved","L4.anchor-subject-mismatch","L4.malformed-verdict-artifact","L4.scenario-unverified","L4.testing-verdict-stub","L4.evidence-not-recoverable","L4.feature-receipt-missing","L4.feature-receipt-malformed","L4.feature-receipt-cross-feature","L4.feature-receipt-divergent","L4.feature-receipt-failed","L4.feature-receipt-run","L4.feature-receipt-stale","L4.feature-receipt-contract","precheck-size","precheck-evidence","inventory-coverage"];function isFindingCode(code){return ALL_FINDING_CODES.includes(code)}init_dist();init_zod();var projectEntrySchema=exports_external.object({name:exports_external.string().min(1),path:exports_external.string().min(1),port:exports_external.number().int().nonnegative().default(0)}),projectsFileSchema=exports_external.object({schema_version:exports_external.literal(1).default(1),projects:exports_external.array(projectEntrySchema).default([])});init_zod();var slashCommandCategorySchema=exports_external.enum(["git","dev","sys","harness"]),slashCommandItemSchema=exports_external.object({name:exports_external.string().min(1),description:exports_external.string().min(1),category:slashCommandCategorySchema.default("dev"),argumentHint:exports_external.string().optional(),tags:exports_external.array(exports_external.string()).default([]),role:exports_external.string().optional(),source:exports_external.string().optional()}),slashCommandsFileSchema=exports_external.object({version:exports_external.number().int().default(1),updatedAt:exports_external.string().optional(),commands:exports_external.array(slashCommandItemSchema).default([])});var SPUR_LOG_LEVELS=["debug","info","warn","error"],DEFAULT_TASKS_DIR="docs/tasks",DEFAULT_FEATURES_DIR="docs/features",DEFAULT_DATABASE_URL=".spur/spur.db";var folderConfigSchema=exports_external.object({baseCounter:exports_external.number().int().nonnegative().default(0),label:exports_external.string().optional()});function folderPathWithDefault(defaultPath){return exports_external.preprocess((v)=>v==null?void 0:v,exports_external.string().default(defaultPath))}var tasksConfigSchema=exports_external.object({folders:exports_external.record(exports_external.string(),folderConfigSchema).default({}),active:folderPathWithDefault(DEFAULT_TASKS_DIR),severity:exports_external.record(exports_external.string(),exports_external.enum(["error","warning","off"])).optional()}).superRefine((data,ctx)=>{if(data.severity){for(let code of Object.keys(data.severity))if(!isFindingCode(code))ctx.addIssue({code:exports_external.ZodIssueCode.custom,path:["severity",code],message:`Unknown finding code "${code}" in severity overrides map`})}}),featuresConfigSchema=exports_external.object({dir:folderPathWithDefault(DEFAULT_FEATURES_DIR)}),EXECUTOR_CAPABILITY_TIERS=["cheap","standard","capable-1","capable-2","capable-3"];function normalizeExecutorTier(value){return value==="capable"?"capable-1":value}var executorCapabilityTierSchema=exports_external.preprocess((value)=>{if(value===void 0||value===null)return;return typeof value==="string"?normalizeExecutorTier(value):value},exports_external.enum(EXECUTOR_CAPABILITY_TIERS).optional()),AGENT_ROLE_NAMES=["scribe","coder","reviewer","planner"];var EXECUTION_CAPABILITY_AXES=["fsRead","fsWrite","networkEgress","processSpawn","externalMutationApproval"],SESSION_CAPABILITY_AXES=["resumeById","sessionDir","persistentStdin","structuredOutput"],AGENT_RUN_CAPABILITY_AXES=[...EXECUTION_CAPABILITY_AXES,...SESSION_CAPABILITY_AXES],EXECUTION_CAPABILITY_STATES=["enforced","available","unavailable","unknown"],EXECUTION_CAPABILITY_PROVENANCES=["native-known","operator-configured","unattested"],ExecutionCapabilityAttestationSchema=exports_external.object({state:exports_external.enum(EXECUTION_CAPABILITY_STATES),provenance:exports_external.enum(EXECUTION_CAPABILITY_PROVENANCES)}),ExecutionCapabilitiesSchema=exports_external.object({version:exports_external.literal(1),axes:exports_external.partialRecord(exports_external.enum(EXECUTION_CAPABILITY_AXES),ExecutionCapabilityAttestationSchema)}),EXECUTION_CAPABILITY_REQUIREMENTS=["available","enforced"],RequiresCapabilitiesSchema=exports_external.partialRecord(exports_external.enum(AGENT_RUN_CAPABILITY_AXES),exports_external.enum(EXECUTION_CAPABILITY_REQUIREMENTS)),executorAvailabilityOwnerSchema=exports_external.enum(["operator","quota","probe"]),executorDisabledObjectSchema=exports_external.object({owner:executorAvailabilityOwnerSchema,since:exports_external.string().refine(isRfc3339Timestamp,{message:"since must be an RFC 3339 timestamp"}),reason:exports_external.string().min(1)}),AgentExecutorConfigSchema=exports_external.object({name:exports_external.string().min(1),agent:exports_external.string().min(1),model:exports_external.string().min(1).optional(),tier:executorCapabilityTierSchema.optional(),executionCapabilities:ExecutionCapabilitiesSchema.optional(),disabled:exports_external.union([exports_external.boolean(),executorDisabledObjectSchema]).default(!1)});var AgentRoleConfigSchema=exports_external.object({tier:exports_external.enum(EXECUTOR_CAPABILITY_TIERS).optional(),stages:exports_external.array(exports_external.string().min(1)).min(1).optional()});var FleetMemberSchema=exports_external.object({id:exports_external.string().min(1).optional(),role:exports_external.enum(AGENT_ROLE_NAMES,{error:(issue2)=>Error(`Unknown role "${issue2.input}" — expected one of: ${AGENT_ROLE_NAMES.join(", ")}`)}).optional(),executor:exports_external.string().min(1).optional(),purpose:exports_external.string().optional(),enabled:exports_external.boolean().optional()}),FLEET_STRATEGIES=["rest","gtd"],FleetMemberEntrySchema=FleetMemberSchema.superRefine((member,ctx)=>{if(member.role===void 0&&member.executor===void 0)ctx.addIssue({code:exports_external.ZodIssueCode.custom,message:"must declare a role or an executor — at least one is required"})}),AgentFleetSchema=exports_external.object({enabled:exports_external.boolean().default(!1),strategy:exports_external.enum(FLEET_STRATEGIES).default("rest"),orchestrator:exports_external.string().min(1).optional(),members:exports_external.array(FleetMemberEntrySchema).default([])});var AgentOutputConfigSchema=exports_external.object({"max-bytes":exports_external.number().int().positive().optional(),"max-lines":exports_external.number().int().positive().optional()}),AgentConfigSchema=exports_external.object({default:exports_external.string().optional(),executors:exports_external.array(AgentExecutorConfigSchema).optional(),roles:exports_external.record(exports_external.string(),AgentRoleConfigSchema).optional(),output:AgentOutputConfigSchema.optional(),sessionAffinity:exports_external.boolean().optional(),fleet:AgentFleetSchema.optional()}).superRefine((value,ctx)=>{for(let key of Object.keys(value.roles??{}))if(!AGENT_ROLE_NAMES.includes(key))ctx.addIssue({code:exports_external.ZodIssueCode.custom,path:["roles",key],message:`Unknown role "${key}" — expected one of: ${AGENT_ROLE_NAMES.join(", ")}`});let executors=value.executors,executorNames=new Set;if(executors!==void 0){let seen=new Set;for(let[index2,executor]of executors.entries()){if(seen.has(executor.name))ctx.addIssue({code:exports_external.ZodIssueCode.custom,message:`Duplicate executor name: ${executor.name}`,path:["executors",index2,"name"]});if(executor.name==="inline"||executor.name==="auto")ctx.addIssue({code:exports_external.ZodIssueCode.custom,message:`Executor name "${executor.name}" is reserved (the --agent selector value '${executor.name}' has fixed semantics); rename executor at index ${index2}.`,path:["executors",index2,"name"]});if(AGENT_ROLE_NAMES.includes(executor.name))ctx.addIssue({code:exports_external.ZodIssueCode.custom,message:`Executor name "${executor.name}" collides with the role selector namespace ("${executor.name}"); rename executor at index ${index2}.`,path:["executors",index2,"name"]});seen.add(executor.name),executorNames.add(executor.name)}}}),RulesConfigSchema=exports_external.object({paths:exports_external.array(exports_external.string()).optional()}),WorkflowsConfigSchema=exports_external.object({paths:exports_external.array(exports_external.string()).optional()}),DecisionsConfigSchema=exports_external.object({paths:exports_external.array(exports_external.string()).optional(),maker:exports_external.string().optional(),makers:exports_external.record(exports_external.string(),exports_external.string()).optional()}),WorkflowConfigSchema=exports_external.object({hitlDecisionMaker:exports_external.boolean().optional(),decideDecisionMaker:exports_external.boolean().optional(),logRetentionDays:exports_external.number().int().positive().default(30)}),RedactionConfigSchema=exports_external.object({enabled:exports_external.boolean().optional()}),HistoryRefreshConfigSchema=exports_external.object({on_completion:exports_external.boolean().default(!1),debounce_ms:exports_external.number().int().min(1000).default(600000)}),HistoryConfigSchema=exports_external.object({refresh:HistoryRefreshConfigSchema.optional()}),VersionCarrierEntrySchema=exports_external.looseObject({type:exports_external.string().min(1)}),BuilderBumpVerConfigSchema=exports_external.object({tagVersionSeparator:exports_external.string().min(1).default("-v"),aggregatePackage:exports_external.string().min(1).optional(),publishWorkflow:exports_external.string().min(1).default("publish.yml"),releaseCommitType:exports_external.string().min(1).default("chore"),releaseCommitScope:exports_external.string().min(1).default("release"),ghRunListLimit:exports_external.number().int().positive().default(5),versionCarriers:exports_external.array(VersionCarrierEntrySchema).default([])}),BuilderConfigSchema=exports_external.object({"bump-ver":BuilderBumpVerConfigSchema.optional()});var bootstrapOptionsSchema=exports_external.object({options:exports_external.record(exports_external.string(),exports_external.unknown()).optional()}),bootstrapSectionSchema=bootstrapOptionsSchema.extend({modules:boardModuleDeclarationsSchema.optional()}),spurConfigSchema=exports_external.object({version:exports_external.string().optional(),name:exports_external.string().optional(),bootstrap:bootstrapSectionSchema.optional(),agent:AgentConfigSchema.optional(),rules:RulesConfigSchema.optional(),workflows:WorkflowsConfigSchema.optional(),decisions:DecisionsConfigSchema.optional(),workflow:WorkflowConfigSchema.optional(),redaction:RedactionConfigSchema.optional(),history:HistoryConfigSchema.optional(),builder:BuilderConfigSchema.optional(),tasks:tasksConfigSchema.optional(),features:featuresConfigSchema.optional()});var configSchema3=exports_external.object({database:exports_external.object({url:exports_external.string().default(DEFAULT_DATABASE_URL)}).default({url:DEFAULT_DATABASE_URL}),server:exports_external.object({port:exports_external.coerce.number().int().positive().default(3000),host:exports_external.string().default("localhost"),openBrowser:exports_external.boolean().default(!0),webDistPath:exports_external.string().nullable().default(null)}).default({port:3000,host:"localhost",openBrowser:!0,webDistPath:null}),telemetry:exports_external.object({enabled:exports_external.boolean().default(!1),endpoint:exports_external.string().optional()}).default({enabled:!1}),logging:exports_external.object({level:exports_external.enum(SPUR_LOG_LEVELS).default("info")}).default({level:"info"})});init_dist6();import crypto3 from"node:crypto";function canonicalJsonStringify(obj){if(obj===null||typeof obj!=="object")return JSON.stringify(obj);if(Array.isArray(obj))return`[${obj.map(canonicalJsonStringify).join(",")}]`;return`{${Object.keys(obj).sort().map((key)=>`${JSON.stringify(key)}:${canonicalJsonStringify(obj[key])}`).join(",")}}`}function computeDefinitionDigest(workflow){let canonical=canonicalJsonStringify(workflow);return`sha256:${crypto3.createHash("sha256").update(canonical,"utf8").digest("hex")}`}class ProofCaptureError extends Error{stderr;constructor(message,stderr){super(message);this.stderr=stderr;this.name="ProofCaptureError"}}var TASK_SPEC_SECTIONS=["Background","Requirements","Acceptance Criteria","Design","Plan"],CANONICAL_TASK_HEADING_RE=/^##[ \t]+(\d+)\.[ \t]+(\S.*)$/m;function taskDocumentShapeError(content){let doc2=MarkdownDocument.parse(content,"task"),heading=CANONICAL_TASK_HEADING_RE.exec(doc2.bodyWithoutFrontmatter);if(heading===null)return"no canonical task heading (`## <WBS>. <title>`) was found";if((heading[2]??"").trim()==="")return`the canonical task heading for WBS ${heading[1]} has an empty title`;if(TASK_SPEC_SECTIONS.filter((section)=>doc2.hasSection(section)).length===0)return`no task specification section (${TASK_SPEC_SECTIONS.join(", ")}) was found`;return null}async function readProofInputContents(fileSystem=createNodeFileSystem2(),workdir,options){for(let name of["taskFile","featureFile"]){let value=options[name];if(value!==void 0&&typeof value!=="string")return{ok:!1,error:`${name} must be a string when supplied (got ${typeof value})`}}let readOne=async(name)=>{let raw=name==="taskFile"?options.taskFile:options.featureFile;if(raw===void 0||raw==="")return{};let workdirAbs=resolve2(workdir),resolved=resolve2(workdirAbs,raw);if(!(resolved===workdirAbs||resolved.startsWith(`${workdirAbs}${sep2}`)))return{error:`${name} must resolve under the workflow workdir (${workdirAbs}): ${raw}`};let stat;try{stat=await fileSystem.stat(resolved)}catch(error51){return{error:`${name} could not be inspected: ${error51.message}`}}if(stat===null)return{error:`${name} does not exist: ${raw} (resolved ${resolved}) — an explicitly supplied spec must be readable, not silently omitted`};if(!stat.isFile())return{error:`${name} is not a regular file: ${resolved}`};let content;try{content=await fileSystem.readFile(resolved)}catch(error51){return{error:`${name} is not readable: ${error51.message}`}}if(name==="taskFile"){let shapeError=taskDocumentShapeError(content);if(shapeError!==null)return{error:`taskFile is not a task document: ${raw} (resolved ${resolved}) — ${shapeError}. Supply the task specification markdown itself: a \`## <WBS>. <title>\` heading plus at least one of ${TASK_SPEC_SECTIONS.join(", ")}. A file containing only a path is not dereferenced.`}}return{content}},task=await readOne("taskFile");if(task.error!==void 0)return{ok:!1,error:task.error};let feature=await readOne("featureFile");if(feature.error!==void 0)return{ok:!1,error:feature.error};return{ok:!0,...task.content!==void 0?{taskContent:task.content}:{},...feature.content!==void 0?{featureContent:feature.content}:{}}}var DEFAULT_EXCLUDE_GLOBS=["docs/tasks*","docs/features*"];async function createGitAlternateTree(cwd,excludeGlobs=DEFAULT_EXCLUDE_GLOBS,executor=new NodeProcessExecutor2,fs2=createNodeFileSystem2()){let indexFile=join2(tmpdir(),`spur-proof-fingerprint-${crypto4.randomUUID()}.index`);try{await fs2.ensureDir(dirname3(indexFile));let env2=Object.fromEntries(Object.entries(getEnvVars()).filter((entry)=>entry[1]!==void 0));env2.GIT_INDEX_FILE=indexFile;let common4={cwd,env:env2,forceBuffered:!0,rejectOnError:!1},read=await executor.run({command:"git",args:["read-tree","HEAD"],...common4});if(read.exitCode!==0)throw new ProofCaptureError(`git read-tree HEAD failed with exit code ${read.exitCode}`,read.stderr);let excludes=excludeGlobs.map((glob)=>`:(exclude)${glob}`),add=await executor.run({command:"git",args:["add","-A","--",".",...excludes],...common4});if(add.exitCode!==0)throw new ProofCaptureError(`git add -A failed with exit code ${add.exitCode}`,add.stderr);let tree=await executor.run({command:"git",args:["write-tree"],...common4});if(tree.exitCode!==0)throw new ProofCaptureError(`git write-tree failed with exit code ${tree.exitCode}`,tree.stderr);return tree.stdout.trim()}catch(error51){if(error51 instanceof ProofCaptureError)throw error51;throw new ProofCaptureError(`git alternate-tree capture threw: ${error51.message}`)}finally{if(await fs2.exists(indexFile))try{await fs2.deleteFile(indexFile)}catch{}}}function canonicalizeCheckboxMarkers(body){return body.replace(/^([ \t]*)[-*+][ \t]+\[[ xX]\]/gm,"$1- [x]")}function extractTaskProofData(content){let doc2=MarkdownDocument.parse(content,"task"),fm=doc2.frontmatterData??{},wbs=typeof fm.wbs==="string"?fm.wbs:void 0,name=typeof fm.name==="string"?fm.name:void 0,feature_id=typeof fm.feature_id==="string"?fm.feature_id:void 0,depends_on;if(Array.isArray(fm.depends_on))depends_on=fm.depends_on.filter((d)=>typeof d==="string");else if(Array.isArray(fm.dependencies))depends_on=fm.dependencies.filter((d)=>typeof d==="string");let sections={},taskSections=["Background","Requirements","Acceptance Criteria","Design","Plan"];for(let sec of taskSections)if(doc2.hasSection(sec)){let body=doc2.getSection(sec);if(body!==null)sections[sec]=canonicalizeCheckboxMarkers(body.trim())}return{...wbs!==void 0?{wbs}:{},...name!==void 0?{name}:{},...feature_id!==void 0?{feature_id}:{},...depends_on!==void 0?{depends_on}:{},sections}}function extractFeatureProofData(content){let doc2=MarkdownDocument.parse(content,"feature"),fm=doc2.frontmatterData??{},id=typeof fm.id==="string"?fm.id:void 0,name=typeof fm.name==="string"?fm.name:void 0,sections={},featureSections=["Goal","Scope","Acceptance Criteria"];for(let sec of featureSections)if(doc2.hasSection(sec)){let body=doc2.getSection(sec);if(body!==null)sections[sec]=canonicalizeCheckboxMarkers(body.trim())}return{...id!==void 0?{id}:{},...name!==void 0?{name}:{},sections}}async function computeProofInputFingerprint(options={}){let cwd=options.cwd??process.cwd(),gitTree=await createGitAlternateTree(cwd,options.excludeGlobs??DEFAULT_EXCLUDE_GLOBS,options.processExecutor,options.fileSystem),task;if(options.taskContent!==void 0)task=extractTaskProofData(options.taskContent);let feature;if(options.featureContent!==void 0)feature=extractFeatureProofData(options.featureContent);let canonical=canonicalJsonStringify({gitTree,...task!==void 0?{task}:{},...feature!==void 0?{feature}:{},...options.learningsContent!==void 0?{learnings:options.learningsContent}:{}});return`sha256:${crypto4.createHash("sha256").update(canonical,"utf8").digest("hex")}`}var ProofInputFingerprint={compute:computeProofInputFingerprint};var FEATURE_RECEIPT_SCHEMA_VERSION=1,DEFAULT_FEATURE_VERIFICATION_CMD="bun run spur-check-feature",RECEIPT_ID_PATTERN=/^[A-Za-z0-9][A-Za-z0-9._-]*$/;function assertReceiptId(kind,id){if(!RECEIPT_ID_PATTERN.test(id)||id.includes(".."))throw Error(`invalid ${kind} for receipt path: ${JSON.stringify(id)}`)}function featureReceiptPaths(runDir,featureId2,runId){return assertReceiptId("featureId",featureId2),assertReceiptId("runId",runId),{runScoped:join3(dirname4(runDir),"memory","evidence",`${runId}-feature-verification.json`),featureScoped:join3(dirname4(runDir),"memory","evidence",`${featureId2}-feature-verification.json`),log:join3(runDir,`${runId}-feature-verification.log`),status:join3(runDir,`${runId}-feature-verification.status`)}}async function atomicWriteReceipt(fs2,path8,receipt){path8=await resolveDurableArtifactPath(fs2,receipt.workdir,path8,"evidence"),ensureDurablePlaneIgnored(receipt.workdir),await fs2.ensureDir(dirname4(path8));let body=`${JSON.stringify(receipt,null,4)}
|
|
1492
1555
|
`,tmp=`${path8}.tmp`;await fs2.writeFile(tmp,body),await fs2.rename(tmp,path8)}async function startFeatureVerificationReceipt(fs2,runDir,options){let receipt={schemaVersion:FEATURE_RECEIPT_SCHEMA_VERSION,featureId:options.featureId,runId:options.runId,workdir:options.workdir,verifier:options.verifier,verificationCmd:options.verificationCmd,inputDigest:options.inputDigest,status:"RUNNING",startedAt:options.startedAt??new Date().toISOString().replace(/\.\d{3}Z$/,"Z"),completedAt:null},paths=featureReceiptPaths(runDir,options.featureId,options.runId);return await fs2.ensureDir(runDir),await atomicWriteReceipt(fs2,paths.featureScoped,receipt),await atomicWriteReceipt(fs2,paths.runScoped,receipt),receipt}async function completeFeatureVerificationReceipt(fs2,runDir,running,options){if(running.status!=="RUNNING")throw Error(`receipt for run ${running.runId} is already ${running.status}`);let receipt={...running,status:options.status,inputDigest:options.inputDigest??running.inputDigest,completedAt:options.completedAt??new Date().toISOString().replace(/\.\d{3}Z$/,"Z")},paths=featureReceiptPaths(runDir,receipt.featureId,receipt.runId);return await fs2.ensureDir(runDir),await atomicWriteReceipt(fs2,paths.runScoped,receipt),await atomicWriteReceipt(fs2,paths.featureScoped,receipt),await fs2.writeFile(paths.status,`${receipt.status}
|
|
1493
|
-
`),receipt}function parseFeatureVerificationReceipt(raw){let parsed;try{parsed=JSON.parse(raw)}catch(err){throw Error(`not JSON (${String(err)})`)}if(parsed===null||typeof parsed!=="object")throw Error("not an object");let r=parsed;if(r.schemaVersion!==FEATURE_RECEIPT_SCHEMA_VERSION)throw Error(`schemaVersion must be ${FEATURE_RECEIPT_SCHEMA_VERSION}`);let v=r.verifier;if(typeof r.featureId!=="string"||typeof r.runId!=="string"||typeof r.workdir!=="string"||typeof v?.name!=="string"||typeof v?.sourcePath!=="string"||typeof v?.layer!=="string"||typeof v?.definitionDigest!=="string"||typeof r.verificationCmd!=="string"||typeof r.inputDigest!=="string"||r.status!=="RUNNING"&&r.status!=="PASS"&&r.status!=="FAIL"||typeof r.startedAt!=="string"||r.completedAt!==null&&typeof r.completedAt!=="string")throw Error("required fields missing or mistyped");return parsed}async function readReceiptCopy(fs2,path8,label){let raw;try{raw=await fs2.readFile(path8)}catch{throw Error(`no ${label} receipt at ${path8}; run the feature-scoped verification pass`)}try{return parseFeatureVerificationReceipt(raw)}catch(err){throw Error(`${label} receipt at ${basename(path8)} is not a valid schema-v1 artifact (${String(err)})`)}}async function validateFeatureVerificationReceipt(fs2,options){let latest;try{latest=await readReceiptCopy(fs2,featureReceiptPaths(options.runDir,options.featureId,options.featureId).featureScoped,"feature-latest")}catch(err){let message=String(err);return{ok:!1,reason:message.includes("not a valid")?"malformed":"missing",detail:message}}let paths=featureReceiptPaths(options.runDir,options.featureId,latest.runId);try{let runScoped=await readReceiptCopy(fs2,paths.runScoped,"run-scoped");if(JSON.stringify(runScoped)!==JSON.stringify(latest))return{ok:!1,reason:"divergent",detail:`run-scoped ${paths.runScoped} and feature-latest receipts disagree — a newer attempt started or the evidence was tampered with`}}catch(err){let message=String(err);return{ok:!1,reason:message.includes("not a valid")?"malformed":"missing",detail:message}}if(latest.featureId!==options.featureId)return{ok:!1,reason:"cross-feature",detail:`receipt belongs to feature "${latest.featureId}", not "${options.featureId}"`};if(latest.status==="FAIL")return{ok:!1,reason:"failed",detail:`verification pass recorded FAIL (started ${latest.startedAt}, ended ${latest.completedAt})`};if(latest.status==="RUNNING")return{ok:!1,reason:"run",detail:`verification pass is still RUNNING (started ${latest.startedAt}); no completion evidence exists`};if(options.runPort?.readRunRow){let row=await options.runPort.readRunRow(latest.runId);if(!row)return{ok:!1,reason:"run",detail:`run ${latest.runId} that recorded the receipt does not exist in the run store`};if(row.status!=="done")return{ok:!1,reason:"run",detail:`run ${latest.runId} is "${row.status}", not terminal done — the recording run never finished`};if(row.definitionDigest&&row.definitionDigest!==latest.verifier.definitionDigest)return{ok:!1,reason:"run",detail:`run ${latest.runId} attached with definition digest ${row.definitionDigest}, receipt records ${latest.verifier.definitionDigest} (receipt sourcePath=${latest.verifier.sourcePath}) — a different spur install may have attached the run; re-run the verification pass and the transition with the same spur binary`};let recordedCmd;try{let vars=row.varsJson?JSON.parse(row.varsJson):void 0;if(vars&&typeof vars==="object"&&typeof vars.verificationCmd==="string")recordedCmd=vars.verificationCmd}catch{recordedCmd=void 0}if(recordedCmd!==void 0&&recordedCmd!==latest.verificationCmd)return{ok:!1,reason:"run",detail:`run ${latest.runId} recorded effective command "${recordedCmd}", receipt records "${latest.verificationCmd}"`};if(options.runPort.hasArtifact&&!await options.runPort.hasArtifact(latest.runId,paths.runScoped))return{ok:!1,reason:"run",detail:`receipt ${basename(paths.runScoped)} is not registered as an artifact of run ${latest.runId}`}}let verifier=latest.verifier,current=options.currentVerifier,drifted=["name","layer","definitionDigest"].filter((k)=>verifier[k]!==current[k]);if(drifted.length>0)return{ok:!1,reason:"contract-mismatch",detail:`receipt recorded verifier ${verifier.name}@${verifier.layer} (${verifier.definitionDigest}), completion evaluates ${current.name}@${current.layer} (${current.definitionDigest}) — the selected definition changed after the pass (${drifted.join(", ")}); receipt sourcePath=${verifier.sourcePath}, current sourcePath=${current.sourcePath}${verifier.sourcePath!==current.sourcePath?" — a different spur install resolved a different definition; re-run the verification pass and the transition with the same spur binary":""}`};if(latest.verificationCmd!==options.currentVerificationCmd)return{ok:!1,reason:"contract-mismatch",detail:`receipt recorded with verifier "${latest.verificationCmd}", completion evaluates the configured command "${options.currentVerificationCmd}"`};if(latest.inputDigest!==options.currentDigest)return{ok:!1,reason:"stale",detail:`receipt digest ${latest.inputDigest} ≠ current inputs ${options.currentDigest} — tree, spec, learnings or check contract changed after the pass`};return{ok:!0,receipt:latest}}async function captureFeatureReceiptDigest(repoRoot,featureContent,learningsContent){return ProofInputFingerprint.compute({cwd:repoRoot,featureContent,learningsContent})}var SECRET_PATTERN=/(?:sk-[a-z0-9_-]{8,}|(?:api[_-]?key|token|secret|password)\s*[:=]\s*\S+|bearer\s+\S+)/gi;function redactAndBound(value,secrets,maxChars){let redacted=value.replace(SECRET_PATTERN,"[REDACTED]");for(let secret of secrets)if(secret!=="")redacted=redacted.split(secret).join("[REDACTED]");return redacted.length<=maxChars?redacted:`${redacted.slice(0,maxChars)}…`}class InvalidWorkflowRunIdError extends Error{code="invalid-run-id";constructor(runId){super(`Invalid workflow run id: ${JSON.stringify(runId)}`);this.name="InvalidWorkflowRunIdError"}}init_zod();var VERDICT_AGGREGATES=["PASS","PARTIAL","FAIL","UNKNOWN"],ROW_STATUSES=["MET","PARTIAL","UNMET","N/A"],CHECK_SEVERITIES=["blocker","major","minor","advisory"],verdictSchema=exports_external.string().transform((v,ctx)=>{let up=v.toUpperCase();if(!VERDICT_AGGREGATES.includes(up))return ctx.addIssue({code:"custom",message:`invalid verdict "${v}" (expected PASS|PARTIAL|FAIL|UNKNOWN)`}),"UNKNOWN";return up}),coverageRowSchema=exports_external.object({id:exports_external.string().optional(),scenario:exports_external.string().optional(),status:exports_external.string(),evidenceType:exports_external.string().optional(),evidence:exports_external.string().optional()}).superRefine((r,ctx)=>{if(r.id!==void 0&&r.scenario!==void 0&&r.id!==r.scenario)ctx.addIssue({code:"custom",message:`id/scenario conflict ("${r.id}" vs "${r.scenario}")`,path:["scenario"]});if(!ROW_STATUSES.includes(r.status.toUpperCase()))ctx.addIssue({code:"custom",message:`invalid row status "${r.status}"`,path:["status"]})}).transform((r)=>({id:r.id??r.scenario??"",status:r.status.toUpperCase(),evidenceType:r.evidenceType??"",evidence:r.evidence??""})),checkSchema=exports_external.object({name:exports_external.string().optional(),check:exports_external.string().optional(),id:exports_external.string().optional(),status:exports_external.string(),evidence:exports_external.string().optional().default(""),severity:exports_external.enum(CHECK_SEVERITIES).optional()}).superRefine((c3,ctx)=>{if(c3.name===void 0&&c3.check===void 0&&c3.id===void 0)ctx.addIssue({code:"custom",message:"check row needs one of name/check/id",path:["name"]})}).transform((c3)=>({name:c3.name??c3.check??c3.id??"",status:c3.status,evidence:c3.evidence,severity:c3.severity})),verifyVerdictSchema=exports_external.object({wbs:exports_external.string().optional().default(""),verdict:verdictSchema,requirements:exports_external.array(coverageRowSchema).optional().default([]),acceptanceCriteria:exports_external.array(coverageRowSchema).optional().default([]),checks:exports_external.array(checkSchema).optional().default([]),source:exports_external.string().optional(),pipelineRunId:exports_external.string().optional(),recordedAt:exports_external.string().optional()});function parseVerifyVerdict(raw,fallbackWbs){let wbs=fallbackWbs??"";if(raw.trim()==="")return{kind:"missing",wbs};let parsed;try{parsed=JSON.parse(raw)}catch(err){return{kind:"malformed",wbs,message:err.message}}if(parsed===null||typeof parsed!=="object"||Array.isArray(parsed))return{kind:"invalid",wbs,reason:"root must be a JSON object"};let result=verifyVerdictSchema.safeParse(parsed);if(!result.success){let issues=result.error.issues.map((i2)=>`${i2.path.join(".")}: ${i2.message}`);return{kind:"invalid",wbs,reason:issues.join("; "),issues}}let verdict={...result.data,wbs:result.data.wbs!==""?result.data.wbs:wbs};return{kind:"valid",wbs,verdict}}function runStoragePaths(cwd){let projectRoot=resolveRunStorageRoot(cwd);return{projectRoot,scratchDir:join4(projectRoot,".spur","run"),evidenceDir:join4(projectRoot,".spur","memory","evidence"),recordsDir:join4(projectRoot,".spur","memory","runs")}}function resolveRunStorageRoot(cwd){let start=resolve3(cwd),sharedTmp=resolve3(tmpdir2()),current=start;for(;;){if(current!==sharedTmp&&(existsSync2(join4(current,".spur"))||existsSync2(join4(current,"package.json"))))return current;let parent=resolve3(current,"..");if(parent===current)return start;current=parent}}var DURABLE_PLANE_EXCLUDE=".spur/memory/";function ensureDurablePlaneIgnored(workdir){try{let gitPath=join4(workdir,".git");if(!existsSync2(gitPath))return;let excludePath=join4(gitPath,"info","exclude");try{if(statSync3(gitPath).isFile()){let gitdir=readFileSync4(gitPath,"utf8").split(/\r?\n/).find((line)=>line.startsWith("gitdir:"))?.slice(7).trim();if(gitdir){let resolved=isAbsolute(gitdir)?gitdir:resolve3(workdir,gitdir),common4=/[/\\]worktrees[/\\][^/\\]+$/.test(resolved)?resolve3(resolved,"..",".."):resolved;excludePath=join4(common4,"info","exclude")}}}catch{}let current="";try{current=readFileSync4(excludePath,"utf8")}catch{current=""}if(current.includes(DURABLE_PLANE_EXCLUDE))return;mkdirSync2(dirname5(excludePath),{recursive:!0});let sep4=current===""||current.endsWith(`
|
|
1556
|
+
`),receipt}function parseFeatureVerificationReceipt(raw){let parsed;try{parsed=JSON.parse(raw)}catch(err){throw Error(`not JSON (${String(err)})`)}if(parsed===null||typeof parsed!=="object")throw Error("not an object");let r=parsed;if(r.schemaVersion!==FEATURE_RECEIPT_SCHEMA_VERSION)throw Error(`schemaVersion must be ${FEATURE_RECEIPT_SCHEMA_VERSION}`);let v=r.verifier;if(typeof r.featureId!=="string"||typeof r.runId!=="string"||typeof r.workdir!=="string"||typeof v?.name!=="string"||typeof v?.sourcePath!=="string"||typeof v?.layer!=="string"||typeof v?.definitionDigest!=="string"||typeof r.verificationCmd!=="string"||typeof r.inputDigest!=="string"||r.status!=="RUNNING"&&r.status!=="PASS"&&r.status!=="FAIL"||typeof r.startedAt!=="string"||r.completedAt!==null&&typeof r.completedAt!=="string")throw Error("required fields missing or mistyped");return parsed}async function readReceiptCopy(fs2,path8,label){let raw;try{raw=await fs2.readFile(path8)}catch{throw Error(`no ${label} receipt at ${path8}; run the feature-scoped verification pass`)}try{return parseFeatureVerificationReceipt(raw)}catch(err){throw Error(`${label} receipt at ${basename(path8)} is not a valid schema-v1 artifact (${String(err)})`)}}async function validateFeatureVerificationReceipt(fs2,options){let latest;try{latest=await readReceiptCopy(fs2,featureReceiptPaths(options.runDir,options.featureId,options.featureId).featureScoped,"feature-latest")}catch(err){let message=String(err);return{ok:!1,reason:message.includes("not a valid")?"malformed":"missing",detail:message}}let paths=featureReceiptPaths(options.runDir,options.featureId,latest.runId);try{let runScoped=await readReceiptCopy(fs2,paths.runScoped,"run-scoped");if(JSON.stringify(runScoped)!==JSON.stringify(latest))return{ok:!1,reason:"divergent",detail:`run-scoped ${paths.runScoped} and feature-latest receipts disagree — a newer attempt started or the evidence was tampered with`}}catch(err){let message=String(err);return{ok:!1,reason:message.includes("not a valid")?"malformed":"missing",detail:message}}if(latest.featureId!==options.featureId)return{ok:!1,reason:"cross-feature",detail:`receipt belongs to feature "${latest.featureId}", not "${options.featureId}"`};if(latest.status==="FAIL")return{ok:!1,reason:"failed",detail:`verification pass recorded FAIL (started ${latest.startedAt}, ended ${latest.completedAt})`};if(latest.status==="RUNNING")return{ok:!1,reason:"run",detail:`verification pass is still RUNNING (started ${latest.startedAt}); no completion evidence exists`};if(options.runPort?.readRunRow){let row=await options.runPort.readRunRow(latest.runId);if(!row)return{ok:!1,reason:"run",detail:`run ${latest.runId} that recorded the receipt does not exist in the run store`};if(row.status!=="done")return{ok:!1,reason:"run",detail:`run ${latest.runId} is "${row.status}", not terminal done — the recording run never finished`};if(row.definitionDigest&&row.definitionDigest!==latest.verifier.definitionDigest)return{ok:!1,reason:"run",detail:`run ${latest.runId} attached with definition digest ${row.definitionDigest}, receipt records ${latest.verifier.definitionDigest} (receipt sourcePath=${latest.verifier.sourcePath}) — a different spur install may have attached the run; re-run the verification pass and the transition with the same spur binary`};let recordedCmd;try{let vars=row.varsJson?JSON.parse(row.varsJson):void 0;if(vars&&typeof vars==="object"&&typeof vars.verificationCmd==="string")recordedCmd=vars.verificationCmd}catch{recordedCmd=void 0}if(recordedCmd!==void 0&&recordedCmd!==latest.verificationCmd)return{ok:!1,reason:"run",detail:`run ${latest.runId} recorded effective command "${recordedCmd}", receipt records "${latest.verificationCmd}"`};if(options.runPort.hasArtifact&&!await options.runPort.hasArtifact(latest.runId,paths.runScoped))return{ok:!1,reason:"run",detail:`receipt ${basename(paths.runScoped)} is not registered as an artifact of run ${latest.runId}`}}let verifier=latest.verifier,current=options.currentVerifier,drifted=["name","layer","definitionDigest"].filter((k)=>verifier[k]!==current[k]);if(drifted.length>0)return{ok:!1,reason:"contract-mismatch",detail:`receipt recorded verifier ${verifier.name}@${verifier.layer} (${verifier.definitionDigest}), completion evaluates ${current.name}@${current.layer} (${current.definitionDigest}) — the selected definition changed after the pass (${drifted.join(", ")}); receipt sourcePath=${verifier.sourcePath}, current sourcePath=${current.sourcePath}${verifier.sourcePath!==current.sourcePath?" — a different spur install resolved a different definition; re-run the verification pass and the transition with the same spur binary":""}`};if(latest.verificationCmd!==options.currentVerificationCmd)return{ok:!1,reason:"contract-mismatch",detail:`receipt recorded with verifier "${latest.verificationCmd}", completion evaluates the configured command "${options.currentVerificationCmd}"`};if(latest.inputDigest!==options.currentDigest)return{ok:!1,reason:"stale",detail:`receipt digest ${latest.inputDigest} ≠ current inputs ${options.currentDigest} — tree, spec, learnings or check contract changed after the pass`};return{ok:!0,receipt:latest}}async function captureFeatureReceiptDigest(repoRoot,featureContent,learningsContent){return ProofInputFingerprint.compute({cwd:repoRoot,featureContent,learningsContent})}var SECRET_PATTERN=/(?:sk-[a-z0-9_-]{8,}|(?:api[_-]?key|token|secret|password)\s*[:=]\s*\S+|bearer\s+\S+)/gi;function redactAndBound(value,secrets,maxChars){let redacted=value.replace(SECRET_PATTERN,"[REDACTED]");for(let secret of secrets)if(secret!=="")redacted=redacted.split(secret).join("[REDACTED]");return redacted.length<=maxChars?redacted:`${redacted.slice(0,maxChars)}…`}class InvalidWorkflowRunIdError extends Error{code="invalid-run-id";constructor(runId){super(`Invalid workflow run id: ${JSON.stringify(runId)}`);this.name="InvalidWorkflowRunIdError"}}init_zod();var VERDICT_AGGREGATES=["PASS","PARTIAL","FAIL","UNKNOWN"],ROW_STATUSES=["MET","PARTIAL","UNMET","N/A"],CHECK_SEVERITIES=["blocker","major","minor","advisory"],verdictSchema=exports_external.string().transform((v,ctx)=>{let up=v.toUpperCase();if(!VERDICT_AGGREGATES.includes(up))return ctx.addIssue({code:"custom",message:`invalid verdict "${v}" (expected PASS|PARTIAL|FAIL|UNKNOWN)`}),"UNKNOWN";return up}),coverageRowSchema=exports_external.object({id:exports_external.string().optional(),scenario:exports_external.string().optional(),status:exports_external.string(),evidenceType:exports_external.string().optional(),evidence:exports_external.string().optional()}).superRefine((r,ctx)=>{if(r.id!==void 0&&r.scenario!==void 0&&r.id!==r.scenario)ctx.addIssue({code:"custom",message:`id/scenario conflict ("${r.id}" vs "${r.scenario}")`,path:["scenario"]});if(!ROW_STATUSES.includes(r.status.toUpperCase()))ctx.addIssue({code:"custom",message:`invalid row status "${r.status}"`,path:["status"]})}).transform((r)=>({id:r.id??r.scenario??"",status:r.status.toUpperCase(),evidenceType:r.evidenceType??"",evidence:r.evidence??""})),checkSchema=exports_external.object({name:exports_external.string().optional(),check:exports_external.string().optional(),id:exports_external.string().optional(),status:exports_external.string(),evidence:exports_external.string().optional().default(""),severity:exports_external.enum(CHECK_SEVERITIES).optional()}).superRefine((c3,ctx)=>{if(c3.name===void 0&&c3.check===void 0&&c3.id===void 0)ctx.addIssue({code:"custom",message:"check row needs one of name/check/id",path:["name"]})}).transform((c3)=>({name:c3.name??c3.check??c3.id??"",status:c3.status,evidence:c3.evidence,severity:c3.severity})),verifyVerdictSchema=exports_external.object({wbs:exports_external.string().optional().default(""),verdict:verdictSchema,requirements:exports_external.array(coverageRowSchema).optional().default([]),acceptanceCriteria:exports_external.array(coverageRowSchema).optional().default([]),checks:exports_external.array(checkSchema).optional().default([]),source:exports_external.string().optional(),confidence:exports_external.enum(["HIGH","MEDIUM","LOW"]).optional(),pipelineRunId:exports_external.string().optional(),recordedAt:exports_external.string().optional()});function parseVerifyVerdict(raw,fallbackWbs){let wbs=fallbackWbs??"";if(raw.trim()==="")return{kind:"missing",wbs};let parsed;try{parsed=JSON.parse(raw)}catch(err){return{kind:"malformed",wbs,message:err.message}}if(parsed===null||typeof parsed!=="object"||Array.isArray(parsed))return{kind:"invalid",wbs,reason:"root must be a JSON object"};let result=verifyVerdictSchema.safeParse(parsed);if(!result.success){let issues=result.error.issues.map((i2)=>`${i2.path.join(".")}: ${i2.message}`);return{kind:"invalid",wbs,reason:issues.join("; "),issues}}let verdict={...result.data,wbs:result.data.wbs!==""?result.data.wbs:wbs};return{kind:"valid",wbs,verdict}}function runStoragePaths(cwd){let projectRoot=resolveRunStorageRoot(cwd);return{projectRoot,scratchDir:join4(projectRoot,".spur","run"),evidenceDir:join4(projectRoot,".spur","memory","evidence"),recordsDir:join4(projectRoot,".spur","memory","runs")}}function resolveRunStorageRoot(cwd){let start=resolve3(cwd),sharedTmp=new Set([resolve3(tmpdir2()),"/tmp","/private/tmp"]),current=start;for(;;){if(!sharedTmp.has(current)&&(existsSync2(join4(current,".spur"))||existsSync2(join4(current,"package.json"))))return current;let parent=resolve3(current,"..");if(parent===current)return start;current=parent}}var DURABLE_PLANE_EXCLUDE=".spur/memory/";function ensureDurablePlaneIgnored(workdir){try{let gitPath=join4(workdir,".git");if(!existsSync2(gitPath))return;let excludePath=join4(gitPath,"info","exclude");try{if(statSync3(gitPath).isFile()){let gitdir=readFileSync4(gitPath,"utf8").split(/\r?\n/).find((line)=>line.startsWith("gitdir:"))?.slice(7).trim();if(gitdir){let resolved=isAbsolute(gitdir)?gitdir:resolve3(workdir,gitdir),common4=/[/\\]worktrees[/\\][^/\\]+$/.test(resolved)?resolve3(resolved,"..",".."):resolved;excludePath=join4(common4,"info","exclude")}}}catch{}let current="";try{current=readFileSync4(excludePath,"utf8")}catch{current=""}if(current.includes(DURABLE_PLANE_EXCLUDE))return;mkdirSync2(dirname5(excludePath),{recursive:!0});let sep4=current===""||current.endsWith(`
|
|
1494
1557
|
`)?"":`
|
|
1495
1558
|
`;appendFileSync3(excludePath,`${sep4}# spur durable run-record plane (E71/1026): must stay proof-fingerprint-inert
|
|
1496
1559
|
${DURABLE_PLANE_EXCLUDE}
|
|
1497
|
-
`,"utf8")}catch{}}var TERMINAL_REASONS=["done","paused-operator","failed-check","failed-agent","failed-timeout","failed-guard","cancelled","interrupted","retry-exhausted"];function isTerminalReason(value){return TERMINAL_REASONS.includes(value)}var BOOKKEEPING_WORKFLOWS=["task-lifecycle","feature-lifecycle"];function isBookkeepingWorkflow(workflowName){return BOOKKEEPING_WORKFLOWS.includes(workflowName)}function classifyTerminalReason({status,engineReason,actionKind,errorText}){if(engineReason!==void 0&&engineReason!==null&&isTerminalReason(engineReason))return engineReason;if(status==="interrupted")return"interrupted";if(status==="paused")return"paused-operator";if(status==="done")return"done";if(engineReason==="no-passing-transition"||engineReason==="no-passing-edge")return"failed-guard";if(engineReason==="iteration-bound-exceeded")return"retry-exhausted";if(errorText!==void 0&&errorText!==null&&/timeout/i.test(errorText))return"failed-timeout";if(actionKind==="agent.run")return"failed-agent";return"failed-check"}var UNPERSISTED_PREFIX="trace-unpersisted:";class RunRowNotFoundError extends Error{runId;constructor(runId){super(`run row not found: ${runId}`);this.name="RunRowNotFoundError",this.runId=runId}}class WorkflowActionTraceWriter{inner;recordFailure;db;boundaries=new Map;constructor(inner,recordFailure,db2){this.inner=inner;this.recordFailure=recordFailure;this.db=db2}async saveActionStart(runId,node,kind,options){let outcome=await this.guard("action.start",{runId,node,kind},()=>this.inner.saveActionStart(runId,node,kind,options));if(!outcome.ok){let syntheticId=`${UNPERSISTED_PREFIX}${crypto.randomUUID()}`;return this.boundaries.set(syntheticId,{runId,node,kind}),this.lastStart={runId,node,kind},syntheticId}return this.boundaries.set(outcome.value,{runId,node,kind}),this.lastStart={runId,node,kind},outcome.value}lastStart;async saveActionFinalize(actionId,status,durationMs,ok,kind,result,redactor){let origin2=this.boundaries.get(actionId)??this.lastStart;await this.guard("action.finish",{runId:origin2?.runId??"",node:origin2?.node,kind},()=>this.inner.saveActionFinalize(actionId,status,durationMs,ok,kind,result,redactor)),this.boundaries.delete(actionId)}async finalizeRun(runId,status,completedAt,fence,reason){await this.inner.finalizeRun(runId,status,completedAt,fence,reason===void 0?void 0:classifyTerminalReason({status,engineReason:reason,errorText:reason}))}async claimRunOwnership(runId,owner,expectedStatuses){return this.inner.claimRunOwnership(runId,owner,expectedStatuses)}async interruptRun(runId,reason){return this.inner.interruptRun(runId,reason)}async recordAction(boundary2){let start=await this.guard("action.start",{runId:boundary2.runId,node:boundary2.node,kind:boundary2.kind},()=>this.inner.saveActionStart(boundary2.runId,boundary2.node,boundary2.kind));if(!start.ok)return start;let finish=await this.guard("action.finish",{runId:boundary2.runId,node:boundary2.node,kind:boundary2.kind},()=>this.inner.saveActionFinalize(start.value,boundary2.status,boundary2.durationMs,boundary2.ok,boundary2.kind,boundary2.result,boundary2.redactor));if(!finish.ok)return finish;return await this.backdateStart(start.value,boundary2),{ok:!0,actionId:start.value}}async backdateStart(actionId,boundary2){let db2=this.db;if(db2===void 0||boundary2.durationMs<=0)return;await this.guard("action.backdate",{runId:boundary2.runId,node:boundary2.node,kind:boundary2.kind},async()=>{let dao2=new ActionRunDao(db2),completedAt=await dao2.completedAtById(actionId);if(completedAt===null)return;let startedAt=new Date(new Date(completedAt).getTime()-boundary2.durationMs).toISOString();await dao2.setStartedAt(actionId,startedAt)})}async closeRun(runId,status,completedAt,reason){let existing=await this.inner.loadRun(runId);if(existing===void 0)throw new RunRowNotFoundError(runId);if(await this.inner.finalizeRun(runId,status,completedAt??new Date().toISOString(),void 0,reason===void 0?void 0:classifyTerminalReason({status,engineReason:reason,errorText:reason})),this.db===void 0)return{ok:!0,startedAt:existing.started_at};return{ok:!0,actionRows:(await new ActionRunDao(this.db).actionRowsByRunId(runId)).length,startedAt:existing.started_at}}async guard(operation,context4,emit){try{return{ok:!0,value:await emit()}}catch(error51){let failure={operation,runId:context4.runId,...context4.node!==void 0?{node:context4.node}:{},...context4.kind!==void 0?{kind:context4.kind}:{},error:error51 instanceof Error?error51.message:String(error51),at:new Date().toISOString()};try{this.recordFailure?.(failure)}catch{}return{ok:!1,failure}}}createRun(record3){return this.inner.createRun(record3)}savePhase(runId,phase,status){return this.inner.savePhase(runId,phase,status)}saveTransition(runId,from,to,trigger){return this.inner.saveTransition(runId,from,to,trigger)}saveWorkflowState(runId,state,data){return this.inner.saveWorkflowState(runId,state,data)}commitTransition(runId,from,to,trigger,state,data,phase){return this.inner.commitTransition(runId,from,to,trigger,state,data,phase)}loadRun(runId){return this.inner.loadRun(runId)}listRuns(){return this.inner.listRuns()}findRunByKey(workflowName,externalKey){return this.inner.findRunByKey(workflowName,externalKey)}createOrAttachRun(record3){return this.inner.createOrAttachRun(record3)}reseedRun(runId,newState){return this.inner.reseedRun(runId,newState)}loadCurrentState(runId){return this.inner.loadCurrentState(runId)}loadLatestStateSnapshot(runId){return this.inner.loadLatestStateSnapshot(runId)}listPausedRuns(options){return this.inner.listPausedRuns(options)}}function createWorkflowActionTraceWriter(db2,recordFailure){return new WorkflowActionTraceWriter(new DbWorkflowPersistenceAdapter(db2),recordFailure,db2)}init_zod();import{join as join5}from"node:path";init_dist9();import{createHash as createHash3}from"node:crypto";function evidencePayloadDigest(payload){return`sha256:${createHash3("sha256").update(canonicalJsonStringify(payload),"utf8").digest("hex")}`}async function defaultDecisionMaker(){return(await Promise.resolve().then(() => (init_dist9(),exports_dist3))).createDecisionMaker({timeoutMs:15000,maxRetries:0})}var DEFAULT_MIN_CONFIDENCE=0.8,NOUL_YES_THRESHOLD=0.5,DECIDE_EVIDENCE_MAX_CHARS=2000;async function runDecide(options,deps){let started=deps.now(),base2={schemaVersion:1,id:options.id,method:options.method},degraded=(reason,backend=null,confidence=null,evidenceDigest2=null)=>({...base2,value:options.default,backend,confidence,degraded:!0,reason,source:"default",evidenceDigest:evidenceDigest2,durationMs:deps.now()-started});if(!deps.enabled)return degraded("disabled");let maker;try{maker=deps.decisionMaker?await deps.decisionMaker():await defaultDecisionMaker()}catch{return degraded("no-backend")}let evidence=[],evidenceDigest=null;if(options.evidence!==void 0&&options.evidence.length>0)try{evidence=await Promise.all(options.evidence.map(async(path8)=>redactAndBound(await deps.readFile(path8),[],DECIDE_EVIDENCE_MAX_CHARS))),evidenceDigest=evidencePayloadDigest(evidence)}catch{return degraded("error")}let state={id:options.id,evidence},minConfidence=options.minConfidence??DEFAULT_MIN_CONFIDENCE;try{if(options.method==="choice"){let labels=Object.fromEntries((options.choices??[]).map((c3)=>[c3,c3])),answer2=await maker.choice(state,options.question,labels);if(!(answer2.label in labels))return degraded("error",maker.driver,answer2.confidence,evidenceDigest);if(answer2.confidence<minConfidence)return degraded("low-confidence",maker.driver,answer2.confidence,evidenceDigest);return{...base2,value:answer2.label,backend:maker.driver,confidence:answer2.confidence,degraded:!1,reason:"accepted",source:"model",evidenceDigest,durationMs:deps.now()-started}}let confidence=(await maker.noul(state,options.question)).probability;if(confidence<minConfidence)return degraded("low-confidence",maker.driver,confidence,evidenceDigest);return{...base2,value:confidence>=NOUL_YES_THRESHOLD?"yes":"no",backend:maker.driver,confidence,degraded:!1,reason:"accepted",source:"model",evidenceDigest,durationMs:deps.now()-started}}catch(error51){return degraded(error51 instanceof DecisionTimeoutError?"timeout":"error",maker.driver,null,evidenceDigest)}}var DECIDE_KIND="decide",DecideOptionsSchema=exports_external.object({id:exports_external.string().min(1),method:exports_external.enum(["choice","noul"]),question:exports_external.string().min(1),choices:exports_external.array(exports_external.string().min(1)).min(2).optional(),evidence:exports_external.array(exports_external.string().min(1)).optional(),default:exports_external.string().min(1),minConfidence:exports_external.number().min(0).max(1).optional(),resultFile:exports_external.string().min(1)}).strict().superRefine((options,ctx)=>{if(options.method==="choice"){if(options.choices===void 0)ctx.addIssue({code:"custom",message:"choices is required for method choice (at least 2 labels)"});else if(!options.choices.includes(options.default))ctx.addIssue({code:"custom",message:`default "${options.default}" is not one of choices [${options.choices.join(", ")}]`});return}if(options.choices!==void 0)ctx.addIssue({code:"custom",message:"choices is only valid for method choice; noul uses the engine yes/no outcomes"});if(options.default!=="yes"&&options.default!=="no")ctx.addIssue({code:"custom",message:'default must be "yes" or "no" for method noul'})});class DecideActionRunner{fileSystem;deps;kind=DECIDE_KIND;constructor(fileSystem,deps){this.fileSystem=fileSystem;this.deps=deps}async execute(rawOptions,context4){let parsed=DecideOptionsSchema.safeParse(rawOptions);if(!parsed.success)return{ok:!1,error:`${DECIDE_KIND}: invalid options — ${parsed.error.issues.map((i2)=>i2.message).join("; ")}`};let options=parsed.data,workdir=context4.workdir??".",result=await runDecide({...options,...options.evidence!==void 0?{evidence:options.evidence.map((path8)=>join5(workdir,path8))}:{},resultFile:join5(workdir,options.resultFile)},{enabled:this.deps.enabled,...this.deps.decisionMaker!==void 0?{decisionMaker:this.deps.decisionMaker}:{},readFile:async(path8)=>await this.fileSystem.readFile(path8),now:Date.now.bind(Date)});return await this.fileSystem.writeFile(join5(workdir,options.resultFile),`${JSON.stringify(result,null,2)}
|
|
1498
|
-
`),{ok:!0,data:{value:result.value,decision:result}}}}function parseWorkflowInventory(json3){if(typeof json3!=="object"||json3===null)return{ok:!1,error:"workflow inventory: projection is not an object"};let obj=json3,name=typeof obj.name==="string"?obj.name:"",kind=typeof obj.kind==="string"?obj.kind:"",format2=typeof obj.format==="string"?obj.format:"",version3=typeof obj.version==="string"||typeof obj.version==="number"?String(obj.version):"",definitionDigest=typeof obj.definitionDigest==="string"?obj.definitionDigest:"",source;if(obj.source!==void 0){if(typeof obj.source!=="object"||obj.source===null)return{ok:!1,error:"workflow inventory: invalid definition source"};let value=obj.source;if(typeof value.path!=="string"||value.path===""||typeof value.layer!=="string"||!["project","registered","shared"].includes(value.layer))return{ok:!1,error:"workflow inventory: invalid definition source path/layer"};source={path:value.path,layer:value.layer}}if(name==="")return{ok:!1,error:"workflow inventory: missing name"};if(kind==="")return{ok:!1,error:"workflow inventory: missing kind"};if(definitionDigest==="")return{ok:!1,error:"workflow inventory: missing definitionDigest"};if(!Array.isArray(obj.steps)||obj.steps.length===0)return{ok:!1,error:"workflow inventory: no declared steps"};let steps=[];for(let raw of obj.steps){if(typeof raw!=="object"||raw===null)return{ok:!1,error:"workflow inventory: a step is not an object"};let s2=raw;if(typeof s2.id!=="string"||s2.id==="")return{ok:!1,error:"workflow inventory: a step is missing its id"};steps.push({id:s2.id,initial:s2.initial===!0,terminal:s2.terminal===!0,failure:s2.failure===!0,pause:s2.pause===!0,loopBack:s2.loopBack===!0,conditional:s2.conditional===!0,...typeof s2.nodeType==="string"?{nodeType:s2.nodeType}:{},...typeof s2.description==="string"?{description:s2.description}:{}})}return{ok:!0,inventory:{name,kind,format:format2,version:version3,definitionDigest,steps,...source?{source}:{}}}}function assertInventoryIdentity(inventory,expectedDigest){if(expectedDigest==="")return{ok:!1,error:"workflow inventory: no expected definition digest to bind against"};if(inventory.definitionDigest!==expectedDigest)return{ok:!1,error:`workflow inventory: identity drift — projected ${inventory.definitionDigest} ≠ execution ${expectedDigest}`};return{ok:!0}}import{basename as basename3,isAbsolute as isAbsolute2,join as join8,resolve as resolve5}from"node:path";init_dist6();init_dist();init_dist2();init_zod();import{existsSync as existsSync4,statSync as statSync5}from"node:fs";import{homedir}from"node:os";import{dirname as dirname7,join as join7,resolve as resolve4}from"node:path";import{fileURLToPath as fileURLToPath3}from"node:url";import{existsSync as existsSync3,readdirSync as readdirSync3,statSync as statSync4}from"node:fs";import{dirname as dirname6,join as join6}from"node:path";var BUNDLED_CONFIG_DIRS=["config","spur-cli/config"],cachedRoot;function bundledConfigRoot(){if(cachedRoot!==void 0)return cachedRoot;let dir=import.meta.dirname;while(!0){for(let name of BUNDLED_CONFIG_DIRS){let candidate=join6(dir,name);if(isBundledConfigDir(candidate))return cachedRoot=candidate,cachedRoot}let parent=dirname6(dir);if(parent===dir)break;dir=parent}return cachedRoot=null,cachedRoot}function isBundledConfigDir(candidate){return existsSync3(candidate)&&statSync4(candidate).isDirectory()&&existsSync3(join6(candidate,"rules"))&&existsSync3(join6(candidate,"workflows"))}init_dist2();var SPUR_CONFIG_DIR=".spur",SPUR_CONFIG_FILE="config.yaml",GLOBAL_CONFIG_FILE=join7(homedir(),".config","spur","config.yaml"),LOADER_DIR=dirname7(fileURLToPath3(import.meta.url)),nextEmbeddedSchemasId=1,embeddedSchemasIds=new WeakMap,spurConfigCache=new Map;function embeddedSchemasId(embeddedSchemas){if(embeddedSchemas===void 0)return"disk";let id=embeddedSchemasIds.get(embeddedSchemas);if(id===void 0)id=nextEmbeddedSchemasId,nextEmbeddedSchemasId+=1,embeddedSchemasIds.set(embeddedSchemas,id);return`embedded:${id}`}function cacheKey(configPath,opts,validateJsonSchema2){return[configPath,validateJsonSchema2?"schema":"zod",opts?.schemaManifestSpecifier??"@gobing-ai/spur/package.json",embeddedSchemasId(opts?.embeddedSchemas)].join("\x00")}function resolveSchemaSpecifier(specifier,manifestSpecifier){if(specifier===manifestSpecifier){let workspaceManifest=join7(LOADER_DIR,"..","..","..","apps","cli","package.json");if(existsSync4(workspaceManifest))return workspaceManifest}try{let resolved=import.meta.resolve(specifier);return resolved.startsWith("file:")?fileURLToPath3(resolved):resolved}catch{return specifier}}function resolveConfigLayers(cwd){let layers={};if(!(cwd===void 0&&getEnvVar("SPUR_SKIP_PROJECT_CONFIG")==="true")){let projectConfig=join7(cwd??process.cwd(),SPUR_CONFIG_DIR,SPUR_CONFIG_FILE);if(existsSync4(projectConfig))layers.project=projectConfig}if(getEnvVar("SPUR_SKIP_GLOBAL_CONFIG")!=="true"&&existsSync4(GLOBAL_CONFIG_FILE))layers.global=GLOBAL_CONFIG_FILE;return layers}var EMBEDDED_PREFIX="\x00embedded-spur";function makeEmbeddedReader(embeddedSchemas){return async function(path8){if(path8.startsWith(EMBEDDED_PREFIX)){let subpath=path8.slice(EMBEDDED_PREFIX.length+1),embedded=embeddedSchemas.get(subpath);if(embedded===void 0)throw Error(`No embedded schema registered for "${subpath}".`);return embedded}return createNodeFileSystem2().readFile(path8)}}async function loadSpurConfig(cwd,opts){let layers=resolveConfigLayers(cwd),projectRoot=resolve4(cwd??process.cwd());if(assertNoLegacyFleetFile(projectRoot,layers.project),layers.global===void 0&&layers.project===void 0)return spurConfigSchema.parse({});let validateJsonSchema2=opts?.validateJsonSchema??getEnvVar("NODE_ENV")!=="test",mtimeOf=(path8)=>path8!==void 0?String(statSync5(path8).mtimeMs):"-",key=[cacheKey(layers.project??layers.global??"",opts,validateJsonSchema2),layers.global??"-",mtimeOf(layers.project),mtimeOf(layers.global)].join("\x00"),cached2=spurConfigCache.get(key);if(cached2!==void 0)return cached2;let promise2=loadMergedConfig(layers,opts,validateJsonSchema2);return spurConfigCache.set(key,promise2),promise2.catch(()=>spurConfigCache.delete(key)),promise2}async function resolveDecideDecisionMakerEnabled(cwd,opts){return(await loadSpurConfig(cwd,opts)).workflow?.decideDecisionMaker===!0}function assertNoRetiredTeamKey(parsed,layerPath,replacementFile){let agent=parsed.agent;if(!isPlainObject5(agent)||!("team"in agent))return;throw Error(`agent.team is no longer supported (${layerPath??"the merged config"}). Declare the project fleet under agent.fleet in ${replacementFile}.`)}function assertNoGlobalFleetSection(globalRaw,layerPath,projectFile){let agent=globalRaw.agent;if(!isPlainObject5(agent)||!("fleet"in agent))return;throw Error(`agent.fleet is not supported in the global config (${layerPath??SPUR_CONFIG_FILE}). Declare the project fleet under agent.fleet in ${projectFile} — the flock belongs to a project, not to the machine.`)}function assertNoLegacyFleetFile(projectRoot,projectConfigPath){let candidates=new Set([join7(projectRoot,SPUR_CONFIG_DIR,"fleet.json")]);if(projectConfigPath!==void 0)candidates.add(join7(dirname7(projectConfigPath),"fleet.json"));for(let legacyFile of candidates){if(!existsSync4(legacyFile))continue;throw Error(`The retired fleet declaration ${legacyFile} still exists. Move its members and orchestrator under agent.fleet in the project config, then delete the file.`)}}function projectConfigReplacement(layers){return layers.project??join7(SPUR_CONFIG_DIR,SPUR_CONFIG_FILE)}function schemaValidationContext(opts){let embeddedSchemas=opts?.embeddedSchemas,manifestSpecifier=opts?.schemaManifestSpecifier??"@gobing-ai/spur/package.json",resolve5=(specifier)=>{if(embeddedSchemas!==void 0&&specifier===manifestSpecifier)return`${EMBEDDED_PREFIX}/package.json`;return resolveSchemaSpecifier(specifier,manifestSpecifier)},fileSystem=embeddedSchemas?{readFile:makeEmbeddedReader(embeddedSchemas)}:void 0;return{resolve:resolve5,...fileSystem!==void 0?{fileSystem}:{}}}async function readRawYamlLayer(configPath,kind){let nodeFs=createNodeFileSystem2(),text3;try{text3=await nodeFs.readFile(nodeFs.resolve(configPath))}catch(error51){throw Error(`Failed to read ${kind} config ${configPath}: ${error51.message}`)}try{return $parse(text3)??{}}catch(error51){throw Error(`Failed to parse ${kind} config ${configPath}: ${error51.message}`)}}function isPlainObject5(value){return typeof value==="object"&&value!==null&&!Array.isArray(value)}function executorNameOf(item){return isPlainObject5(item)&&typeof item.name==="string"?item.name:void 0}function isConcatPath(segments){return segments.length===2&&segments[0]==="rules"&&segments[1]==="paths"||segments.length===2&&segments[0]==="workflows"&&segments[1]==="paths"}function byKeyIdentityFor(segments){if(segments.length===2&&segments[0]==="agent"&&segments[1]==="executors")return executorNameOf;return}function concatUnique(globalItems,projectItems){let out=[...globalItems];for(let item of projectItems)if(!out.includes(item))out.push(item);return out}function mergeByKeyIdentity(globalItems,projectItems,identityOf,segments){let merged=[],indexByIdentity=new Map;for(let item of globalItems){let identity5=identityOf(item);if(identity5!==void 0&&!indexByIdentity.has(identity5))indexByIdentity.set(identity5,merged.length);merged.push(item)}let matchedProjectIdentities=new Set;for(let item of projectItems){let identity5=identityOf(item),existing=identity5===void 0||matchedProjectIdentities.has(identity5)?void 0:indexByIdentity.get(identity5);if(existing===void 0){merged.push(item);continue}if(identity5!==void 0)matchedProjectIdentities.add(identity5);let base2=merged[existing];merged[existing]=isPlainObject5(base2)&&isPlainObject5(item)?mergeDeep(base2,item,[...segments,existing]):item}return merged}function mergeDeep(globalValue,projectValue,segments){if(isPlainObject5(globalValue)&&isPlainObject5(projectValue)){let out={...globalValue};for(let[key,projectItem]of Object.entries(projectValue))out[key]=key in out?mergeDeep(out[key],projectItem,[...segments,key]):projectItem;return out}if(Array.isArray(globalValue)&&Array.isArray(projectValue)){if(isConcatPath(segments))return concatUnique(globalValue,projectValue);let identityOf=byKeyIdentityFor(segments);if(identityOf!==void 0)return mergeByKeyIdentity(globalValue,projectValue,identityOf,segments);return projectValue}return projectValue}function mergeSpurConfigLayers(globalRaw,projectRaw){return mergeDeep(globalRaw,projectRaw,[])}function formatZodPath(path8){return path8.map((segment,index2)=>typeof segment==="number"?`[${segment}]`:index2===0?segment:`.${segment}`).join("")}function parseViolationPath(path8){let segments=[];for(let part of path8.split(".")){let bracket=part.indexOf("["),key=bracket===-1?part:part.slice(0,bracket);if(key!=="")segments.push(key);if(bracket!==-1)for(let match of part.slice(bracket).matchAll(/\[(\d+)\]/g))segments.push(Number(match[1]))}return segments}function findItemByIdentity(node,identityOf,identity5){return Array.isArray(node)?node.find((entry)=>identityOf(entry)===identity5):void 0}function describeIssueProvenance(issuePath,merged,globalRaw,projectRaw){let g2=globalRaw,p=projectRaw,m=merged,segments=[],parentG=globalRaw,parentP=projectRaw,identityPrefix="";for(let segment of issuePath){if(parentG=g2,parentP=p,segments=[...segments,segment],typeof segment==="number"){let mergedItem=Array.isArray(m)?m[segment]:void 0,identityOf=byKeyIdentityFor(segments.slice(0,-1));if(identityOf!==void 0&&mergedItem!==void 0){let identity5=identityOf(mergedItem);if(identity5!==void 0)identityPrefix=`executor "${identity5}" `,g2=findItemByIdentity(g2,identityOf,identity5),p=findItemByIdentity(p,identityOf,identity5)}else g2=Array.isArray(g2)&&segment<g2.length?g2[segment]:void 0,p=Array.isArray(p)&&segment<p.length?p[segment]:void 0;m=mergedItem;continue}g2=isPlainObject5(g2)?g2[segment]:void 0,p=isPlainObject5(p)?p[segment]:void 0,m=isPlainObject5(m)?m[segment]:void 0}let label;if(g2!==void 0&&p!==void 0)label="set in both layers (project value wins)";else if(g2!==void 0)label="from global layer";else if(p!==void 0)label="from project layer";else if(parentP!==void 0&&parentG===void 0)label="from project layer (key absent there)";else if(parentG!==void 0&&parentP===void 0)label="from global layer (key absent there)";else label="missing in both layers";return`${identityPrefix}${label}`}function parseMergedWithProvenance(merged,globalRaw,projectRaw,layers){try{return spurConfigSchema.parse(merged)}catch(error51){if(!(error51 instanceof ZodError))throw error51;let details=error51.issues.map((issue2)=>{let path8=issue2.path.filter((segment)=>typeof segment!=="symbol");return` ${formatZodPath(path8)}: ${issue2.message} (${describeIssueProvenance(path8,merged,globalRaw,projectRaw)})`}).join(`
|
|
1560
|
+
`,"utf8")}catch{}}var TERMINAL_REASONS=["done","paused-operator","failed-check","failed-agent","failed-timeout","failed-guard","cancelled","interrupted","retry-exhausted"];function isTerminalReason(value){return TERMINAL_REASONS.includes(value)}var BOOKKEEPING_WORKFLOWS=["task-lifecycle","feature-lifecycle"];function isBookkeepingWorkflow(workflowName){return BOOKKEEPING_WORKFLOWS.includes(workflowName)}function classifyTerminalReason({status,engineReason,actionKind,errorText}){if(engineReason!==void 0&&engineReason!==null&&isTerminalReason(engineReason))return engineReason;if(status==="interrupted")return"interrupted";if(status==="paused")return"paused-operator";if(status==="done")return"done";if(engineReason==="no-passing-transition"||engineReason==="no-passing-edge")return"failed-guard";if(engineReason==="iteration-bound-exceeded")return"retry-exhausted";if(errorText!==void 0&&errorText!==null&&/outcome[-_ ]?unknown/i.test(errorText))return"interrupted";if(errorText!==void 0&&errorText!==null&&/timeout/i.test(errorText))return"failed-timeout";if(actionKind==="agent.run")return"failed-agent";return"failed-check"}var UNPERSISTED_PREFIX="trace-unpersisted:";class RunRowNotFoundError extends Error{runId;constructor(runId){super(`run row not found: ${runId}`);this.name="RunRowNotFoundError",this.runId=runId}}class WorkflowActionTraceWriter{inner;recordFailure;db;boundaries=new Map;constructor(inner,recordFailure,db2){this.inner=inner;this.recordFailure=recordFailure;this.db=db2}async saveActionStart(runId,node,kind,options){let outcome=await this.guard("action.start",{runId,node,kind},()=>this.inner.saveActionStart(runId,node,kind,options));if(!outcome.ok){let syntheticId=`${UNPERSISTED_PREFIX}${crypto.randomUUID()}`;return this.boundaries.set(syntheticId,{runId,node,kind}),this.lastStart={runId,node,kind},syntheticId}return this.boundaries.set(outcome.value,{runId,node,kind}),this.lastStart={runId,node,kind},outcome.value}lastStart;async saveActionFinalize(actionId,status,durationMs,ok,kind,result,redactor){let origin2=this.boundaries.get(actionId)??this.lastStart;await this.guard("action.finish",{runId:origin2?.runId??"",node:origin2?.node,kind},()=>this.inner.saveActionFinalize(actionId,status,durationMs,ok,kind,result,redactor)),this.boundaries.delete(actionId)}async finalizeRun(runId,status,completedAt,fence,reason){await this.inner.finalizeRun(runId,status,completedAt,fence,reason===void 0?void 0:classifyTerminalReason({status,engineReason:reason,errorText:reason}))}async claimRunOwnership(runId,owner,expectedStatuses){return this.inner.claimRunOwnership(runId,owner,expectedStatuses)}async interruptRun(runId,reason){return this.inner.interruptRun(runId,reason)}async recordAction(boundary2){let start=await this.guard("action.start",{runId:boundary2.runId,node:boundary2.node,kind:boundary2.kind},()=>this.inner.saveActionStart(boundary2.runId,boundary2.node,boundary2.kind));if(!start.ok)return start;let finish=await this.guard("action.finish",{runId:boundary2.runId,node:boundary2.node,kind:boundary2.kind},()=>this.inner.saveActionFinalize(start.value,boundary2.status,boundary2.durationMs,boundary2.ok,boundary2.kind,boundary2.result,boundary2.redactor));if(!finish.ok)return finish;return await this.backdateStart(start.value,boundary2),{ok:!0,actionId:start.value}}async backdateStart(actionId,boundary2){let db2=this.db;if(db2===void 0||boundary2.durationMs<=0)return;await this.guard("action.backdate",{runId:boundary2.runId,node:boundary2.node,kind:boundary2.kind},async()=>{let dao2=new ActionRunDao(db2),completedAt=await dao2.completedAtById(actionId);if(completedAt===null)return;let startedAt=new Date(new Date(completedAt).getTime()-boundary2.durationMs).toISOString();await dao2.setStartedAt(actionId,startedAt)})}async closeRun(runId,status,completedAt,reason){let existing=await this.inner.loadRun(runId);if(existing===void 0)throw new RunRowNotFoundError(runId);if(await this.inner.finalizeRun(runId,status,completedAt??new Date().toISOString(),void 0,reason===void 0?void 0:classifyTerminalReason({status,engineReason:reason,errorText:reason})),this.db===void 0)return{ok:!0,startedAt:existing.started_at};return{ok:!0,actionRows:(await new ActionRunDao(this.db).actionRowsByRunId(runId)).length,startedAt:existing.started_at}}async guard(operation,context4,emit){try{return{ok:!0,value:await emit()}}catch(error51){let failure={operation,runId:context4.runId,...context4.node!==void 0?{node:context4.node}:{},...context4.kind!==void 0?{kind:context4.kind}:{},error:error51 instanceof Error?error51.message:String(error51),at:new Date().toISOString()};try{this.recordFailure?.(failure)}catch{}return{ok:!1,failure}}}createRun(record3){return this.inner.createRun(record3)}savePhase(runId,phase,status){return this.inner.savePhase(runId,phase,status)}saveTransition(runId,from,to,trigger){return this.inner.saveTransition(runId,from,to,trigger)}saveWorkflowState(runId,state,data){return this.inner.saveWorkflowState(runId,state,data)}commitTransition(runId,from,to,trigger,state,data,phase){return this.inner.commitTransition(runId,from,to,trigger,state,data,phase)}loadRun(runId){return this.inner.loadRun(runId)}listRuns(){return this.inner.listRuns()}findRunByKey(workflowName,externalKey){return this.inner.findRunByKey(workflowName,externalKey)}createOrAttachRun(record3){return this.inner.createOrAttachRun(record3)}reseedRun(runId,newState){return this.inner.reseedRun(runId,newState)}loadCurrentState(runId){return this.inner.loadCurrentState(runId)}loadLatestStateSnapshot(runId){return this.inner.loadLatestStateSnapshot(runId)}listPausedRuns(options){return this.inner.listPausedRuns(options)}saveBranchStart(runId,parallelNode,branchId,startNode){return this.inner.saveBranchStart(runId,parallelNode,branchId,startNode)}saveBranchFinalize(runId,branchId,status,durationMs,outputVars,error51){return this.inner.saveBranchFinalize(runId,branchId,status,durationMs,outputVars,error51)}listRunBranches(runId,parallelNode){return this.inner.listRunBranches(runId,parallelNode)}commitJoin(runId,parallelNode,joinNode,mergedVars,phase){return this.inner.commitJoin(runId,parallelNode,joinNode,mergedVars,phase)}}function createWorkflowActionTraceWriter(db2,recordFailure){return new WorkflowActionTraceWriter(new DbWorkflowPersistenceAdapter(db2),recordFailure,db2)}init_zod();import{join as join5}from"node:path";init_dist9();import{createHash as createHash3}from"node:crypto";function evidencePayloadDigest(payload){return`sha256:${createHash3("sha256").update(canonicalJsonStringify(payload),"utf8").digest("hex")}`}async function defaultDecisionMaker(){return(await Promise.resolve().then(() => (init_dist9(),exports_dist3))).createDecisionMaker({timeoutMs:15000,maxRetries:0})}var DEFAULT_MIN_CONFIDENCE=0.8,NOUL_YES_THRESHOLD=0.5,DECIDE_EVIDENCE_MAX_CHARS=2000;async function runDecide(options,deps){let started=deps.now(),base2={schemaVersion:1,id:options.id,method:options.method},degraded=(reason,backend=null,confidence=null,evidenceDigest2=null)=>({...base2,value:options.default,backend,confidence,degraded:!0,reason,source:"default",evidenceDigest:evidenceDigest2,durationMs:deps.now()-started});if(!deps.enabled)return degraded("disabled");let maker;try{maker=deps.decisionMaker?await deps.decisionMaker():await defaultDecisionMaker()}catch{return degraded("no-backend")}let evidence=[],evidenceDigest=null;if(options.evidence!==void 0&&options.evidence.length>0)try{evidence=await Promise.all(options.evidence.map(async(path8)=>redactAndBound(await deps.readFile(path8),[],DECIDE_EVIDENCE_MAX_CHARS))),evidenceDigest=evidencePayloadDigest(evidence)}catch{return degraded("error")}let state={id:options.id,evidence},minConfidence=options.minConfidence??DEFAULT_MIN_CONFIDENCE;try{if(options.method==="choice"){let labels=Object.fromEntries((options.choices??[]).map((c3)=>[c3,c3])),answer2=await maker.choice(state,options.question,labels);if(!(answer2.label in labels))return degraded("error",maker.driver,answer2.confidence,evidenceDigest);if(answer2.confidence<minConfidence)return degraded("low-confidence",maker.driver,answer2.confidence,evidenceDigest);return{...base2,value:answer2.label,backend:maker.driver,confidence:answer2.confidence,degraded:!1,reason:"accepted",source:"model",evidenceDigest,durationMs:deps.now()-started}}let confidence=(await maker.noul(state,options.question)).probability;if(confidence<minConfidence)return degraded("low-confidence",maker.driver,confidence,evidenceDigest);return{...base2,value:confidence>=NOUL_YES_THRESHOLD?"yes":"no",backend:maker.driver,confidence,degraded:!1,reason:"accepted",source:"model",evidenceDigest,durationMs:deps.now()-started}}catch(error51){return degraded(error51 instanceof DecisionTimeoutError?"timeout":"error",maker.driver,null,evidenceDigest)}}var DECIDE_KIND="decide",DecideOptionsSchema=exports_external.object({id:exports_external.string().min(1),method:exports_external.enum(["choice","noul"]),question:exports_external.string().min(1),choices:exports_external.array(exports_external.string().min(1)).min(2).optional(),evidence:exports_external.array(exports_external.string().min(1)).optional(),default:exports_external.string().min(1),minConfidence:exports_external.number().min(0).max(1).optional(),resultFile:exports_external.string().min(1)}).strict().superRefine((options,ctx)=>{if(options.method==="choice"){if(options.choices===void 0)ctx.addIssue({code:"custom",message:"choices is required for method choice (at least 2 labels)"});else if(!options.choices.includes(options.default))ctx.addIssue({code:"custom",message:`default "${options.default}" is not one of choices [${options.choices.join(", ")}]`});return}if(options.choices!==void 0)ctx.addIssue({code:"custom",message:"choices is only valid for method choice; noul uses the engine yes/no outcomes"});if(options.default!=="yes"&&options.default!=="no")ctx.addIssue({code:"custom",message:'default must be "yes" or "no" for method noul'})});class DecideActionRunner{fileSystem;deps;kind=DECIDE_KIND;constructor(fileSystem,deps){this.fileSystem=fileSystem;this.deps=deps}async execute(rawOptions,context4){let parsed=DecideOptionsSchema.safeParse(rawOptions);if(!parsed.success)return{ok:!1,error:`${DECIDE_KIND}: invalid options — ${parsed.error.issues.map((i2)=>i2.message).join("; ")}`};let options=parsed.data,workdir=context4.workdir??".",result=await runDecide({...options,...options.evidence!==void 0?{evidence:options.evidence.map((path8)=>join5(workdir,path8))}:{},resultFile:join5(workdir,options.resultFile)},{enabled:this.deps.enabled,...this.deps.decisionMaker!==void 0?{decisionMaker:this.deps.decisionMaker}:{},readFile:async(path8)=>await this.fileSystem.readFile(path8),now:Date.now.bind(Date)});return await this.fileSystem.writeFile(join5(workdir,options.resultFile),`${JSON.stringify(result,null,2)}
|
|
1561
|
+
`),{ok:!0,data:{value:result.value,decision:result}}}}var SHELL_METACHARACTERS=/[;&|<>$`(){}[\]!*?~#\n\r"']/;function splitLaunchCommand(value,label){if(SHELL_METACHARACTERS.test(value))return{error:`${label} must not contain shell metacharacters (got ${value})`};let tokens=value.trim().split(/\s+/).filter((t)=>t.length>0),command=tokens[0];if(command===void 0)return{error:`Action option ${label.slice(label.indexOf('"'))} must be a non-empty string`};return{command,leadingArgs:tokens.slice(1)}}function parseWorkflowInventory(json3){if(typeof json3!=="object"||json3===null)return{ok:!1,error:"workflow inventory: projection is not an object"};let obj=json3,name=typeof obj.name==="string"?obj.name:"",kind=typeof obj.kind==="string"?obj.kind:"",format2=typeof obj.format==="string"?obj.format:"",version3=typeof obj.version==="string"||typeof obj.version==="number"?String(obj.version):"",definitionDigest=typeof obj.definitionDigest==="string"?obj.definitionDigest:"",source;if(obj.source!==void 0){if(typeof obj.source!=="object"||obj.source===null)return{ok:!1,error:"workflow inventory: invalid definition source"};let value=obj.source;if(typeof value.path!=="string"||value.path===""||typeof value.layer!=="string"||!["project","registered","shared"].includes(value.layer))return{ok:!1,error:"workflow inventory: invalid definition source path/layer"};source={path:value.path,layer:value.layer}}if(name==="")return{ok:!1,error:"workflow inventory: missing name"};if(kind==="")return{ok:!1,error:"workflow inventory: missing kind"};if(definitionDigest==="")return{ok:!1,error:"workflow inventory: missing definitionDigest"};if(!Array.isArray(obj.steps)||obj.steps.length===0)return{ok:!1,error:"workflow inventory: no declared steps"};let steps=[];for(let raw of obj.steps){if(typeof raw!=="object"||raw===null)return{ok:!1,error:"workflow inventory: a step is not an object"};let s2=raw;if(typeof s2.id!=="string"||s2.id==="")return{ok:!1,error:"workflow inventory: a step is missing its id"};steps.push({id:s2.id,initial:s2.initial===!0,terminal:s2.terminal===!0,failure:s2.failure===!0,pause:s2.pause===!0,loopBack:s2.loopBack===!0,conditional:s2.conditional===!0,...typeof s2.nodeType==="string"?{nodeType:s2.nodeType}:{},...typeof s2.description==="string"?{description:s2.description}:{}})}return{ok:!0,inventory:{name,kind,format:format2,version:version3,definitionDigest,steps,...source?{source}:{}}}}function assertInventoryIdentity(inventory,expectedDigest){if(expectedDigest==="")return{ok:!1,error:"workflow inventory: no expected definition digest to bind against"};if(inventory.definitionDigest!==expectedDigest)return{ok:!1,error:`workflow inventory: identity drift — projected ${inventory.definitionDigest} ≠ execution ${expectedDigest}`};return{ok:!0}}import{basename as basename3,isAbsolute as isAbsolute2,join as join8,resolve as resolve5}from"node:path";init_dist6();init_dist();init_dist2();init_zod();import{existsSync as existsSync4,statSync as statSync5}from"node:fs";import{homedir}from"node:os";import{dirname as dirname7,join as join7,resolve as resolve4}from"node:path";import{fileURLToPath as fileURLToPath3}from"node:url";import{existsSync as existsSync3,readdirSync as readdirSync3,statSync as statSync4}from"node:fs";import{dirname as dirname6,join as join6}from"node:path";var BUNDLED_CONFIG_DIRS=["config","spur-cli/config"],cachedRoot;function bundledConfigRoot(){if(cachedRoot!==void 0)return cachedRoot;return cachedRoot=resolveBundledConfigRoot(import.meta.dirname,process.execPath),cachedRoot}function resolveBundledConfigRoot(moduleDir,execPath2){let dir=moduleDir;while(!0){for(let name of BUNDLED_CONFIG_DIRS){let candidate=join6(dir,name);if(isBundledConfigDir(candidate))return candidate}let parent=dirname6(dir);if(parent===dir)break;dir=parent}let executableConfig=join6(dirname6(execPath2),"config");return isBundledConfigDir(executableConfig)?executableConfig:null}function isBundledConfigDir(candidate){return existsSync3(candidate)&&statSync4(candidate).isDirectory()&&existsSync3(join6(candidate,"rules"))&&existsSync3(join6(candidate,"workflows"))}init_dist2();var SPUR_CONFIG_DIR=".spur",SPUR_CONFIG_FILE="config.yaml",GLOBAL_CONFIG_FILE=join7(homedir(),".config","spur","config.yaml"),LOADER_DIR=dirname7(fileURLToPath3(import.meta.url)),nextEmbeddedSchemasId=1,embeddedSchemasIds=new WeakMap,spurConfigCache=new Map;function embeddedSchemasId(embeddedSchemas){if(embeddedSchemas===void 0)return"disk";let id=embeddedSchemasIds.get(embeddedSchemas);if(id===void 0)id=nextEmbeddedSchemasId,nextEmbeddedSchemasId+=1,embeddedSchemasIds.set(embeddedSchemas,id);return`embedded:${id}`}function cacheKey(configPath,opts,validateJsonSchema2){return[configPath,validateJsonSchema2?"schema":"zod",opts?.schemaManifestSpecifier??"@gobing-ai/spur/package.json",embeddedSchemasId(opts?.embeddedSchemas)].join("\x00")}function resolveSchemaSpecifier(specifier,manifestSpecifier){if(specifier===manifestSpecifier){let workspaceManifest=join7(LOADER_DIR,"..","..","..","apps","cli","package.json");if(existsSync4(workspaceManifest))return workspaceManifest}try{let resolved=import.meta.resolve(specifier);return resolved.startsWith("file:")?fileURLToPath3(resolved):resolved}catch{if(specifier===manifestSpecifier&&manifestSpecifier==="@gobing-ai/spur/package.json"){let manifest=join7(dirname7(process.execPath),"package.json");if(existsSync4(manifest)&&existsSync4(join7(dirname7(manifest),"schemas")))return manifest}return specifier}}function resolveConfigLayers(cwd){let layers={};if(!(cwd===void 0&&getEnvVar("SPUR_SKIP_PROJECT_CONFIG")==="true")){let projectConfig=join7(cwd??process.cwd(),SPUR_CONFIG_DIR,SPUR_CONFIG_FILE);if(existsSync4(projectConfig))layers.project=projectConfig}if(getEnvVar("SPUR_SKIP_GLOBAL_CONFIG")!=="true"&&existsSync4(GLOBAL_CONFIG_FILE))layers.global=GLOBAL_CONFIG_FILE;return layers}var EMBEDDED_PREFIX="\x00embedded-spur";function makeEmbeddedReader(embeddedSchemas){return async function(path8){if(path8.startsWith(EMBEDDED_PREFIX)){let subpath=path8.slice(EMBEDDED_PREFIX.length+1),embedded=embeddedSchemas.get(subpath);if(embedded===void 0)throw Error(`No embedded schema registered for "${subpath}".`);return embedded}return createNodeFileSystem2().readFile(path8)}}async function loadSpurConfig(cwd,opts){let layers=resolveConfigLayers(cwd),projectRoot=resolve4(cwd??process.cwd());if(assertNoLegacyFleetFile(projectRoot,layers.project),layers.global===void 0&&layers.project===void 0)return spurConfigSchema.parse({});let validateJsonSchema2=opts?.validateJsonSchema??getEnvVar("NODE_ENV")!=="test",mtimeOf=(path8)=>path8!==void 0?String(statSync5(path8).mtimeMs):"-",key=[cacheKey(layers.project??layers.global??"",opts,validateJsonSchema2),layers.global??"-",mtimeOf(layers.project),mtimeOf(layers.global)].join("\x00"),cached2=spurConfigCache.get(key);if(cached2!==void 0)return cached2;let promise2=loadMergedConfig(layers,opts,validateJsonSchema2);return spurConfigCache.set(key,promise2),promise2.catch(()=>spurConfigCache.delete(key)),promise2}async function resolveDecideDecisionMakerEnabled(cwd,opts){return(await loadSpurConfig(cwd,opts)).workflow?.decideDecisionMaker===!0}function assertNoRetiredTeamKey(parsed,layerPath,replacementFile){let agent=parsed.agent;if(!isPlainObject5(agent)||!("team"in agent))return;throw Error(`agent.team is no longer supported (${layerPath??"the merged config"}). Declare the project fleet under agent.fleet in ${replacementFile}.`)}function assertNoGlobalFleetSection(globalRaw,layerPath,projectFile){let agent=globalRaw.agent;if(!isPlainObject5(agent)||!("fleet"in agent))return;throw Error(`agent.fleet is not supported in the global config (${layerPath??SPUR_CONFIG_FILE}). Declare the project fleet under agent.fleet in ${projectFile} — the flock belongs to a project, not to the machine.`)}function assertNoLegacyFleetFile(projectRoot,projectConfigPath){let candidates=new Set([join7(projectRoot,SPUR_CONFIG_DIR,"fleet.json")]);if(projectConfigPath!==void 0)candidates.add(join7(dirname7(projectConfigPath),"fleet.json"));for(let legacyFile of candidates){if(!existsSync4(legacyFile))continue;throw Error(`The retired fleet declaration ${legacyFile} still exists. Move its members and orchestrator under agent.fleet in the project config, then delete the file.`)}}function projectConfigReplacement(layers){return layers.project??join7(SPUR_CONFIG_DIR,SPUR_CONFIG_FILE)}function schemaValidationContext(opts){let embeddedSchemas=opts?.embeddedSchemas,manifestSpecifier=opts?.schemaManifestSpecifier??"@gobing-ai/spur/package.json",resolve5=(specifier)=>{if(embeddedSchemas!==void 0&&specifier===manifestSpecifier)return`${EMBEDDED_PREFIX}/package.json`;return resolveSchemaSpecifier(specifier,manifestSpecifier)},fileSystem=embeddedSchemas?{readFile:makeEmbeddedReader(embeddedSchemas)}:void 0;return{resolve:resolve5,...fileSystem!==void 0?{fileSystem}:{}}}async function readRawYamlLayer(configPath,kind){let nodeFs=createNodeFileSystem2(),text3;try{text3=await nodeFs.readFile(nodeFs.resolve(configPath))}catch(error51){throw Error(`Failed to read ${kind} config ${configPath}: ${error51.message}`)}try{return $parse(text3)??{}}catch(error51){throw Error(`Failed to parse ${kind} config ${configPath}: ${error51.message}`)}}function isPlainObject5(value){return typeof value==="object"&&value!==null&&!Array.isArray(value)}function executorNameOf(item){return isPlainObject5(item)&&typeof item.name==="string"?item.name:void 0}function isConcatPath(segments){return segments.length===2&&segments[0]==="rules"&&segments[1]==="paths"||segments.length===2&&segments[0]==="workflows"&&segments[1]==="paths"}function byKeyIdentityFor(segments){if(segments.length===2&&segments[0]==="agent"&&segments[1]==="executors")return executorNameOf;return}function concatUnique(globalItems,projectItems){let out=[...globalItems];for(let item of projectItems)if(!out.includes(item))out.push(item);return out}function mergeByKeyIdentity(globalItems,projectItems,identityOf,segments){let merged=[],indexByIdentity=new Map;for(let item of globalItems){let identity5=identityOf(item);if(identity5!==void 0&&!indexByIdentity.has(identity5))indexByIdentity.set(identity5,merged.length);merged.push(item)}let matchedProjectIdentities=new Set;for(let item of projectItems){let identity5=identityOf(item),existing=identity5===void 0||matchedProjectIdentities.has(identity5)?void 0:indexByIdentity.get(identity5);if(existing===void 0){merged.push(item);continue}if(identity5!==void 0)matchedProjectIdentities.add(identity5);let base2=merged[existing];merged[existing]=isPlainObject5(base2)&&isPlainObject5(item)?mergeDeep(base2,item,[...segments,existing]):item}return merged}function mergeDeep(globalValue,projectValue,segments){if(isPlainObject5(globalValue)&&isPlainObject5(projectValue)){let out={...globalValue};for(let[key,projectItem]of Object.entries(projectValue))out[key]=key in out?mergeDeep(out[key],projectItem,[...segments,key]):projectItem;return out}if(Array.isArray(globalValue)&&Array.isArray(projectValue)){if(isConcatPath(segments))return concatUnique(globalValue,projectValue);let identityOf=byKeyIdentityFor(segments);if(identityOf!==void 0)return mergeByKeyIdentity(globalValue,projectValue,identityOf,segments);return projectValue}return projectValue}function mergeSpurConfigLayers(globalRaw,projectRaw){return mergeDeep(globalRaw,projectRaw,[])}function formatZodPath(path8){return path8.map((segment,index2)=>typeof segment==="number"?`[${segment}]`:index2===0?segment:`.${segment}`).join("")}function parseViolationPath(path8){let segments=[];for(let part of path8.split(".")){let bracket=part.indexOf("["),key=bracket===-1?part:part.slice(0,bracket);if(key!=="")segments.push(key);if(bracket!==-1)for(let match of part.slice(bracket).matchAll(/\[(\d+)\]/g))segments.push(Number(match[1]))}return segments}function findItemByIdentity(node,identityOf,identity5){return Array.isArray(node)?node.find((entry)=>identityOf(entry)===identity5):void 0}function describeIssueProvenance(issuePath,merged,globalRaw,projectRaw){let g2=globalRaw,p=projectRaw,m=merged,segments=[],parentG=globalRaw,parentP=projectRaw,identityPrefix="";for(let segment of issuePath){if(parentG=g2,parentP=p,segments=[...segments,segment],typeof segment==="number"){let mergedItem=Array.isArray(m)?m[segment]:void 0,identityOf=byKeyIdentityFor(segments.slice(0,-1));if(identityOf!==void 0&&mergedItem!==void 0){let identity5=identityOf(mergedItem);if(identity5!==void 0)identityPrefix=`executor "${identity5}" `,g2=findItemByIdentity(g2,identityOf,identity5),p=findItemByIdentity(p,identityOf,identity5)}else g2=Array.isArray(g2)&&segment<g2.length?g2[segment]:void 0,p=Array.isArray(p)&&segment<p.length?p[segment]:void 0;m=mergedItem;continue}g2=isPlainObject5(g2)?g2[segment]:void 0,p=isPlainObject5(p)?p[segment]:void 0,m=isPlainObject5(m)?m[segment]:void 0}let label;if(g2!==void 0&&p!==void 0)label="set in both layers (project value wins)";else if(g2!==void 0)label="from global layer";else if(p!==void 0)label="from project layer";else if(parentP!==void 0&&parentG===void 0)label="from project layer (key absent there)";else if(parentG!==void 0&&parentP===void 0)label="from global layer (key absent there)";else label="missing in both layers";return`${identityPrefix}${label}`}function parseMergedWithProvenance(merged,globalRaw,projectRaw,layers){try{return spurConfigSchema.parse(merged)}catch(error51){if(!(error51 instanceof ZodError))throw error51;let details=error51.issues.map((issue2)=>{let path8=issue2.path.filter((segment)=>typeof segment!=="symbol");return` ${formatZodPath(path8)}: ${issue2.message} (${describeIssueProvenance(path8,merged,globalRaw,projectRaw)})`}).join(`
|
|
1499
1562
|
`);throw Error(`Spur config validation failed after merging global ${layers.global??"(absent)"} with project ${layers.project??"(absent)"}:
|
|
1500
1563
|
${details}`)}}function enrichSchemaViolationError(error51,merged,globalRaw,projectRaw,layers){let violations=error51.violations;if(!Array.isArray(violations))return error51;let details=violations.map((violation)=>{let v=violation,path8=typeof v.path==="string"?v.path:"(root)",message=typeof v.message==="string"?v.message:"schema violation",label=describeIssueProvenance(parseViolationPath(path8),merged,globalRaw,projectRaw);return` ${path8}: ${message} (${label})`}).join(`
|
|
1501
1564
|
`);return Error(`Merged Spur config failed JSON Schema validation (global ${layers.global??"(absent)"} + project ${layers.project??"(absent)"}):
|
|
1502
|
-
${details}`)}async function loadMergedConfig(layers,opts,validateJsonSchema2){let globalRaw=layers.global!==void 0?await readRawYamlLayer(layers.global,"global"):{},projectRaw=layers.project!==void 0?await readRawYamlLayer(layers.project,"project"):{},replacementFile=projectConfigReplacement(layers);if(layers.global!==void 0)assertNoRetiredTeamKey(globalRaw,layers.global,replacementFile),assertNoGlobalFleetSection(globalRaw,layers.global,replacementFile);if(layers.project!==void 0)assertNoRetiredTeamKey(projectRaw,layers.project,replacementFile);let merged=mergeSpurConfigLayers(globalRaw,projectRaw);if(validateJsonSchema2){let source=layers.project??layers.global??"";try{await validateDeclaredJsonSchema(merged,source,schemaValidationContext(opts))}catch(error51){throw enrichSchemaViolationError(error51,merged,globalRaw,projectRaw,layers)}}return parseMergedWithProvenance(merged,globalRaw,projectRaw,layers)}init_dist6();init_dist2();var EMBEDDED_SCHEMA_PREFIX="\x00embedded-spur",SPUR_SCHEMA_MANIFEST="@gobing-ai/spur/package.json";function normalizeLayerPath(cwd,path8){return resolve5(cwd,path8)}function workflowLayers(opts){let sharedRoot=opts.sharedRoot!==void 0?opts.sharedRoot:bundledConfigRoot(),sharedPath=sharedRoot!==null?normalizeLayerPath(opts.cwd,join8(sharedRoot,"workflows")):null,layers=[],seen=new Set,add=(id,path8)=>{if(seen.has(path8))return;seen.add(path8),layers.push({id,path:path8})};add("project",normalizeLayerPath(opts.cwd,join8(opts.cwd,".spur","workflows")));for(let entry of opts.registered){if(sharedPath!==null&&normalizeLayerPath(opts.cwd,entry)===sharedPath)continue;add("registered",normalizeLayerPath(opts.cwd,entry))}if(sharedPath!==null)add("shared",sharedPath);return layers}function createEmbeddedSchemaOptions(embedded){if(embedded===void 0||embedded.size===0)return;let nodeFs=createNodeFileSystem2();return{resolve:(specifier)=>specifier===SPUR_SCHEMA_MANIFEST?`${EMBEDDED_SCHEMA_PREFIX}/package.json`:specifier,fileSystem:{readFile:async(path8)=>{if(!path8.startsWith(EMBEDDED_SCHEMA_PREFIX))return nodeFs.readFile(path8);let subpath=path8.slice(EMBEDDED_SCHEMA_PREFIX.length+1),text3=embedded.get(subpath);if(text3===void 0)throw Error(`No embedded schema registered for "${subpath}".`);return text3}}}}async function readWorkflowNameFast(fs2,filePath){try{let text3=await fs2.readFile(filePath),parsed=$parse(text3);return typeof parsed?.name==="string"?parsed.name:null}catch{return null}}async function scanWorkflowByName(cwd,name,registered){let fs2=createNodeFileSystem2();for(let layer of workflowLayers({cwd,registered}))try{let files=(await fs2.readDir(layer.path)).filter((f)=>f.endsWith(".yaml")||f.endsWith(".yml"));for(let f of files){let abs=join8(layer.path,f);if(await readWorkflowNameFast(fs2,abs)===name)return{path:abs,source:layer.id}}}catch{}return null}function resolveWorkflowFile(cwd,file2){let fs2=createNodeFileSystem2(),projectPath=resolve5(cwd,file2);if(fs2.exists(projectPath))return{path:projectPath,source:"project"};let isYaml=file2.endsWith(".yaml")||file2.endsWith(".yml"),base2=basename3(file2);if(!isAbsolute2(file2)){let withYaml=isYaml?file2:`${file2}.yaml`,projectSpur=resolve5(cwd,".spur","workflows",withYaml);if(fs2.exists(projectSpur))return{path:projectSpur,source:"project"};if(!isYaml){let projectDirect=resolve5(cwd,`${file2}.yaml`);if(fs2.exists(projectDirect))return{path:projectDirect,source:"project"};let projectSpurPipeline=resolve5(cwd,".spur","workflows",`${file2}-pipeline.yaml`);if(fs2.exists(projectSpurPipeline))return{path:projectSpurPipeline,source:"project"};let projectDirectPipeline=resolve5(cwd,`${file2}-pipeline.yaml`);if(fs2.exists(projectDirectPipeline))return{path:projectDirectPipeline,source:"project"}}}let bundledRoot=bundledConfigRoot();if(bundledRoot!==null){let sharedName=isYaml?base2:`${base2}.yaml`,sharedPath=join8(bundledRoot,"workflows",sharedName);if(fs2.exists(sharedPath))return{path:sharedPath,source:"shared"};if(!isYaml){let sharedPipeline=join8(bundledRoot,"workflows",`${base2}-pipeline.yaml`);if(fs2.exists(sharedPipeline))return{path:sharedPipeline,source:"shared"};let sharedLiteral=join8(bundledRoot,"workflows",base2);if(fs2.exists(sharedLiteral))return{path:sharedLiteral,source:"shared"}}return{path:null,probed:[projectPath,sharedPath]}}return{path:null,probed:[projectPath,null]}}async function resolveWorkflowDefinition(cwd,fileOrName,options={}){let registered=options.registered??[],resolved=(basename3(fileOrName)===fileOrName&&!/\.ya?ml$/.test(fileOrName)&&!createNodeFileSystem2().exists(resolve5(cwd,fileOrName))?await scanWorkflowByName(cwd,fileOrName,registered):null)??resolveWorkflowFile(cwd,fileOrName);if(resolved.path===null){let scanned=await scanWorkflowByName(cwd,fileOrName,registered);if(scanned!==null)resolved=scanned;else{let[probedProject,probedShared]=resolved.probed;throw Error(`Workflow not found: ${probedProject}${probedShared!==null?` (shared: ${probedShared})`:""}`)}}let embedded=createEmbeddedSchemaOptions(options.embeddedSchemas),workflow=await loadWorkflowDef(resolved.path,{validateSchema:options.validateSchema!==!1,...embedded!==void 0?embedded:{}});if(workflow.version==="")throw Error(`Invalid workflow definition ${resolved.path}: root "version" is an empty string. Omit the field for an unversioned definition, or give it a non-empty literal.`);let digest=computeDefinitionDigest(workflow);return{path:resolved.path,workflow,digest,layer:resolved.source}}var TRIPWIRE_CATALOG=Object.freeze({"retry-exhausted":{id:"retry-exhausted",version:1,response:"fail",nextDecision:"Retries are exhausted; an operator must decide to escalate, extend the retry policy, or fail the stage. No further automatic retry is permitted."},"hard-budget":{id:"hard-budget",version:1,response:"fail",nextDecision:"An operator must raise the declared budget or trim the stage scope, then re-run the action; the run stays failed until then."},"capability-denied":{id:"capability-denied",version:1,response:"fail",nextDecision:"An operator must attest the executor capabilities in agent config or lower the stage requiresCapabilities, then re-run the action."},"proof-invalidated":{id:"proof-invalidated",version:1,response:"fail",nextDecision:"An operator must restore the proof inputs or re-establish the verdict (re-verify) before record; recording against a changed tree is blocked."},"output-drop":{id:"output-drop",version:1,response:"continue",nextDecision:"The dispatch completed but its captured evidence is incomplete (bounded relay dropped chunks). Inspect the session/trace for full output if the result is contested."}});var SHELL_METACHARACTERS=/[;&|<>$`(){}[\]!*?~#\n\r"']/;function splitLaunchCommand(value,label){if(SHELL_METACHARACTERS.test(value))return{error:`${label} must not contain shell metacharacters (got ${value})`};let tokens=value.trim().split(/\s+/).filter((t)=>t.length>0),command=tokens[0];if(command===void 0)return{error:`Action option ${label.slice(label.indexOf('"'))} must be a non-empty string`};return{command,leadingArgs:tokens.slice(1)}}var{copyFile,link,mkdir,readFile,unlink,writeFile}=await import("node:fs/promises");var field=(path8,label)=>({path:path8,label}),SOURCE_PROFILES={planning:{producerPackage:"spur",subsystem:"planning",remediationKind:"prefix-filter"},queue:{producerPackage:"@gobing-ai/ts-infra",subsystem:"job-queue",remediationKind:"prefix-filter"},scheduler:{producerPackage:"@gobing-ai/ts-infra",subsystem:"scheduler",remediationKind:"prefix-filter"},message:{producerPackage:"spur",subsystem:"coordination-messaging",remediationKind:"prefix-filter"},process:{producerPackage:"@gobing-ai/ts-runtime",subsystem:"process-executor",remediationKind:"prefix-filter"},workflow:{producerPackage:"@gobing-ai/ts-dual-workflow-engine",subsystem:"workflow",remediationKind:"workflow-trace"},rule:{producerPackage:"@gobing-ai/ts-rule-engine",subsystem:"rule-engine",remediationKind:"rule-trace"},agent:{producerPackage:"@gobing-ai/ts-ai-runner",subsystem:"agent-runner",remediationKind:"prefix-filter"},history:{producerPackage:"spur",subsystem:"history",remediationKind:"prefix-filter"},bus:{producerPackage:"@gobing-ai/ts-infra",subsystem:"event-bus",remediationKind:"prefix-filter"},api:{producerPackage:"spur",subsystem:"http-api",remediationKind:"prefix-filter"}};function at(data,path8){if(data===null)return;let current=data;for(let segment of path8.split(".")){if(current===null||typeof current!=="object"||Array.isArray(current))return;current=current[segment]}return current}function s2(data,...paths){for(let path8 of paths){let value=at(data,path8);if(typeof value==="string"&&value.length>0)return value}return}function n2(data,...paths){for(let path8 of paths){let value=at(data,path8);if(typeof value==="number"&&Number.isFinite(value))return String(value);if(typeof value==="boolean")return String(value)}return}function entityId(input){return s2(input.data,"entity.id")??input.correlation.entityId??""}function looksLikeOpaqueId(value){if(typeof value!=="string")return!1;let v=value.trim();if(v==="")return!1;if(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(v))return!0;if(/^live[-_][a-z0-9._-]+$/i.test(v))return!0;if(/^(?:eventId|rowId|runId|executionId|actionId)$/i.test(v))return!0;return!1}function humanWorkflowTitle(input){let raw=s2(input.data,"workflowName")??s2(input.data,"workflow");if(raw!==void 0&&!looksLikeOpaqueId(raw))return(raw.split("/").pop()?.replace(/\.(?:ya?ml|json)$/i,"")??raw).replace(/[._-]+$/,"");return""}function humanStepLabel(data){let label=s2(data,"nodeLabel")??s2(data,"stepName")??s2(data,"step");if(label!==void 0&&!looksLikeOpaqueId(label))return label;let node=s2(data,"node");if(node!==void 0&&!looksLikeOpaqueId(node))return node;return}function derivedFrom(...paths){return{support:"derived",derive:({data})=>s2(data,...paths)}}function derivedFromValue(...paths){return{support:"derived",derive:({data})=>n2(data,...paths)??s2(data,...paths)}}var unsupported={support:"unsupported"};function baseEvent(name,source,renderer,payloadPolicy="metadata-only",tier="default",producer){return{name,source,tier,payloadPolicy,renderer,...producer!==void 0?{producer}:{}}}var BASE_CATALOG=[baseEvent("task.created","planning","planning"),baseEvent("task.updated","planning","planning"),baseEvent("task.transitioned","planning","planning"),baseEvent("feature.created","planning","planning"),baseEvent("feature.updated","planning","planning"),baseEvent("feature.transitioned","planning","planning"),baseEvent("queue.consumer.started","queue","queue"),baseEvent("queue.consumer.stopped","queue","queue"),baseEvent("queue.job.enqueued","queue","queue"),baseEvent("queue.job.started","queue","queue"),baseEvent("queue.job.completed","queue","queue"),baseEvent("queue.job.failed","queue","queue"),baseEvent("queue.job.retrying","queue","queue"),baseEvent("queue.stats","queue","queue"),baseEvent("scheduler.job.executed","scheduler","scheduler"),baseEvent("message.sent","message","message"),baseEvent("message.replied","message","message"),baseEvent("process.spawned","process","process"),baseEvent("process.exited","process","process"),baseEvent("process.stopped","process","process"),baseEvent("process.started","process","process"),baseEvent("agent.invoke.start","agent","agent"),baseEvent("agent.invoke.exit","agent","agent"),baseEvent("agent.invoke.escalated","agent","agent","metadata-only","default",{package:"spur",subsystem:"agent-runner"}),baseEvent("agent.invoke.exhausted","agent","agent","metadata-only","default",{package:"spur",subsystem:"agent-runner"}),baseEvent("agent.started","agent","agent"),baseEvent("agent.stopped","agent","agent"),baseEvent("agent.message.sent","agent","agent"),baseEvent("strategy.changed","agent","agent","metadata-only","default",{package:"spur",subsystem:"fleet-strategy"}),baseEvent("fleet.capacity.changed","agent","agent","metadata-only","default",{package:"spur",subsystem:"write-slot"}),baseEvent("task.assigned","planning","planning"),baseEvent("history.import.completed","history","history-import"),baseEvent("history.analyze.completed","history","history-analyze"),baseEvent("history.daily.failed","history","history-daily"),baseEvent("history.refresh.enqueued","history","history-refresh"),baseEvent("rule.run.start","rule","rule"),baseEvent("rule.eval.start","rule","rule"),baseEvent("rule.eval.done","rule","rule"),baseEvent("rule.eval.error","rule","rule"),baseEvent("rule.run.done","rule","rule"),baseEvent("workflow.run.started","workflow","workflow-run"),baseEvent("workflow.run.done","workflow","workflow-run"),baseEvent("workflow.run.failed","workflow","workflow-run"),baseEvent("workflow.run.finalized","workflow","workflow-run"),baseEvent("workflow.escalation.created","workflow","workflow-run","redacted"),baseEvent("workflow.escalation.projection_failed","workflow","workflow-run","metadata-only"),baseEvent("workflow.run.paused","workflow","workflow-run"),baseEvent("workflow.run.resumed","workflow","workflow-run"),baseEvent("workflow.run.reseeded","workflow","workflow-run"),baseEvent("workflow.node.enter","workflow","workflow-phase"),baseEvent("workflow.phase","workflow","workflow-phase"),baseEvent("workflow.node.transition","workflow","workflow-transition"),baseEvent("workflow.transition","workflow","workflow-transition"),baseEvent("workflow.transition.requested","workflow","workflow-transition","metadata-only","diagnostic"),baseEvent("workflow.transition.denied","workflow","workflow-transition","metadata-only","diagnostic"),baseEvent("workflow.action.started","workflow","workflow-action"),baseEvent("workflow.action.finished","workflow","workflow-action"),baseEvent("workflow.action.failed_continue","workflow","workflow-action"),baseEvent("workflow.guard.evaluated","workflow","workflow-guard","metadata-only","diagnostic"),baseEvent("workflow.hitl.ask","workflow","workflow-hitl","redacted"),baseEvent("workflow.hitl.response","workflow","workflow-hitl","redacted"),baseEvent("workflow.hitl.note","workflow","workflow-hitl","redacted"),baseEvent("workflow.custom","workflow","workflow-custom"),baseEvent("workflow.agent","workflow","workflow-agent","redacted","diagnostic"),baseEvent("workflow.steering","workflow","workflow-steering","redacted"),baseEvent("api.request.error","api","api"),baseEvent("bus.emit.done","bus","bus","metadata-only","diagnostic"),baseEvent("bus.emit.noop","bus","bus","metadata-only","diagnostic"),baseEvent("bus.handler.error","bus","bus","metadata-only","diagnostic"),baseEvent("bus.handler.async.enqueued","bus","bus","metadata-only","diagnostic")],SYSTEM_EVENT_PRESENTERS={"task.created":{description:"A task file was created with a new WBS id.",fields:[field("entity.kind","Entity kind"),field("entity.id","Entity")],summary:({data,correlation})=>`[task] ${entityId({data,correlation})} created`,outcome:unsupported},"task.updated":{description:"An existing task file was updated in place, naming the section that changed.",fields:[field("entity.kind","Entity kind"),field("entity.id","Entity"),field("field","Field"),field("data.mutation.name","Section"),field("data.after","After"),field("data.diff","Diff")],summary:({data,correlation})=>{let section=s2(data,"data.mutation.name"),id=entityId({data,correlation});return section!==void 0?`[task] ${section}`:`[task] ${id||"updated"}`},outcome:unsupported},"task.transitioned":{description:"A task moved between lifecycle states, naming both the previous and new status.",fields:[field("entity.kind","Entity kind"),field("entity.id","Entity"),field("from","From"),field("to","To")],summary:({data,correlation})=>{let id=entityId({data,correlation}),from=s2(data,"from"),to=s2(data,"to");return from!==void 0&&to!==void 0?`[task] ${id} : ${from} -> ${to}`:`[task] ${id} transitioned`},outcome:{support:"derived",derive:({data})=>s2(data,"to")}},"feature.created":{description:"A feature file was created with a new feature id.",fields:[field("entity.kind","Entity kind"),field("entity.id","Entity")],summary:({data,correlation})=>`[feature] ${entityId({data,correlation})} created`,outcome:unsupported},"feature.updated":{description:"An existing feature file was updated in place, naming the section that changed.",fields:[field("entity.kind","Entity kind"),field("entity.id","Entity"),field("field","Field"),field("data.mutation.name","Section"),field("data.after","After"),field("data.diff","Diff")],summary:({data,correlation})=>{let section=s2(data,"data.mutation.name"),id=entityId({data,correlation});return section!==void 0?`[feature] ${section}`:`[feature] ${id||"updated"}`},outcome:unsupported},"feature.transitioned":{description:"A feature moved between lifecycle states, naming both the previous and new status.",fields:[field("entity.kind","Entity kind"),field("entity.id","Entity"),field("from","From"),field("to","To")],summary:({data,correlation})=>{let id=entityId({data,correlation}),from=s2(data,"from"),to=s2(data,"to");return from!==void 0&&to!==void 0?`[feature] ${id} : ${from} -> ${to}`:`[feature] ${id} transitioned`},outcome:{support:"derived",derive:({data})=>s2(data,"to")}},"queue.consumer.started":{description:"The configured queue consumer began polling its named queue.",fields:[field("queueName","Queue"),field("startedAt","Started"),field("pollInterval","Poll interval"),field("batchSize","Batch size"),field("maxConcurrency","Max concurrency"),field("visibilityTimeout","Visibility timeout")],summary:({data})=>{let name=s2(data,"queueName");return name!==void 0?`[queue] ${name} : consumer started`:"[queue] consumer started"},outcome:{support:"derived",derive:({data})=>at(data,"startedAt")!==void 0?"running":void 0}},"queue.consumer.stopped":{description:"The queue consumer stopped, reporting whether it drained in-flight work.",fields:[field("queueName","Queue"),field("stoppedAt","Stopped"),field("drainTimeoutMs","Drain timeout"),field("inFlightAtStop","In flight"),field("drained","Drained")],summary:({data})=>{let name=s2(data,"queueName");return name!==void 0?`[queue] ${name} : consumer stopped`:"[queue] consumer stopped"},outcome:{support:"derived",derive:({data})=>{let drained=at(data,"drained");if(drained===!0)return"drained";if(drained===!1)return"timeout";return}}},"queue.job.enqueued":{description:"A job was enqueued onto the job queue for later processing.",fields:[field("jobId","Job"),field("type","Type"),field("nextRetryAt","Next retry")],summary:({data})=>{let type=s2(data,"type"),jobId=s2(data,"jobId");return type!==void 0&&jobId!==void 0?`[queue] ${type} · job ${jobId} enqueued`:"[queue] job enqueued"},outcome:unsupported},"queue.job.started":{description:"A queued job handler began executing (job identity and phase anchor).",fields:[field("jobId","Job"),field("type","Type"),field("name","Name")],summary:({data})=>{let type=s2(data,"type"),jobId=s2(data,"jobId");return type!==void 0&&jobId!==void 0?`[queue] ${type} · job ${jobId} started`:"[queue] job started"},outcome:unsupported},"queue.job.completed":{description:"A queued job finished successfully with its attempt and duration.",fields:[field("jobId","Job"),field("type","Type"),field("attempt","Attempt"),field("durationMs","Duration (ms)")],summary:({data})=>{let type=s2(data,"type"),jobId=s2(data,"jobId");return type!==void 0&&jobId!==void 0?`[queue] ${type} · job ${jobId} completed`:"[queue] job completed"},outcome:unsupported},"queue.job.failed":{description:"A queued job exhausted its attempts and failed with an error.",fields:[field("jobId","Job"),field("type","Type"),field("attempt","Attempt"),field("maxRetries","Max retries"),field("durationMs","Duration (ms)"),field("error","Error")],summary:({data})=>{let type=s2(data,"type"),jobId=s2(data,"jobId");return type!==void 0&&jobId!==void 0?`[queue] ${type} · job ${jobId} failed`:"[queue] job failed"},outcome:derivedFrom("error")},"queue.job.retrying":{description:"A queued job failed once and is scheduled for another attempt.",fields:[field("jobId","Job"),field("type","Type"),field("attempt","Attempt"),field("maxRetries","Max retries"),field("nextRetryAt","Next retry"),field("error","Error")],summary:({data})=>{let type=s2(data,"type"),jobId=s2(data,"jobId");return type!==void 0&&jobId!==void 0?`[queue] ${type} · job ${jobId} retrying`:"[queue] job retrying"},outcome:{support:"derived",derive:({data})=>{let attempt=at(data,"attempt"),max=at(data,"maxRetries");if(typeof attempt==="number"&&typeof max==="number"&&Number.isFinite(attempt)&&Number.isFinite(max))return`retrying ${attempt}/${max}`;return s2(data,"error")}}},"queue.stats":{description:"Periodic job-queue statistics across ready, running, completed, and failed counts.",fields:[field("ready","Ready"),field("running","Running"),field("completed","Completed"),field("failed","Failed")],summary:()=>"[queue] stats",outcome:unsupported},"scheduler.job.executed":{description:"A scheduler job ran to completion or failed, with its duration.",fields:[field("name","Job"),field("action","Action"),field("durationMs","Duration (ms)"),field("error","Error")],summary:({data})=>{let name=s2(data,"name");return name!==void 0?`[scheduler] ${name}`:"[scheduler] job executed"},outcome:{support:"derived",derive:({data})=>s2(data,"error")??(at(data,"error")===null?"completed":void 0)}},"message.sent":{description:"A team message was sent from one member to another.",fields:[field("msgId","Message"),field("fromId","From"),field("toId","To"),field("threadId","Thread")],summary:({data})=>{let from=s2(data,"fromId"),to=s2(data,"toId");return from!==void 0&&to!==void 0?`[message] ${from} -> ${to}`:"[message] sent"},outcome:unsupported},"message.replied":{description:"A member replied to an existing message thread.",fields:[field("msgId","Message"),field("fromId","From"),field("toId","To"),field("threadId","Thread")],summary:({data})=>{let from=s2(data,"fromId"),thread=s2(data,"threadId");return from!==void 0&&thread!==void 0?`[message] ${from} replied in ${thread}`:"[message] replied"},outcome:unsupported},"process.spawned":{description:"A supervised process was spawned with a new pid.",fields:[field("label","Label"),field("pid","PID"),field("agentId","Agent")],summary:({data})=>{let label=s2(data,"label")??n2(data,"pid");return label!==void 0?`[process] ${label} spawned`:"[process] spawned"},outcome:unsupported},"process.exited":{description:"A supervised process exited, carrying its exit code, signal, or failure reason.",fields:[field("label","Label"),field("pid","PID"),field("exitCode","Exit code"),field("signal","Signal"),field("durationMs","Duration (ms)"),field("reason","Reason")],summary:({data})=>{let label=s2(data,"label")??n2(data,"pid");return label!==void 0?`[process] ${label} exited`:"[process] exited"},outcome:{support:"derived",derive:({data})=>{let reason=s2(data,"reason");if(reason!==void 0)return reason;let signal=s2(data,"signal");if(signal!==void 0)return`signal ${signal}`;let code=at(data,"exitCode");if(typeof code==="number"&&Number.isFinite(code))return code===0?"ok":`exit ${code}`;return}}},"process.stopped":{description:"A supervised process was stopped, naming the stopping reason.",fields:[field("label","Label"),field("pid","PID"),field("signal","Signal"),field("reason","Reason")],summary:({data})=>{let label=s2(data,"label")??n2(data,"pid");return label!==void 0?`[process] ${label} stopped`:"[process] stopped"},outcome:derivedFrom("reason")},"process.started":{description:"A process executor started a process with a new pid.",fields:[field("label","Label"),field("pid","PID")],summary:({data})=>{let label=s2(data,"label")??n2(data,"pid");return label!==void 0?`[process] ${label} started`:"[process] started"},outcome:unsupported},"agent.invoke.start":{description:"An agent invocation began, naming the agent and its operation.",fields:[field("agent","Agent"),field("operation","Operation"),field("routing.role","Role"),field("routing.tier","Tier"),field("routing.executor","Executor"),field("routing.source","Selection source")],summary:({data})=>{let agent=s2(data,"agent"),operation=s2(data,"operation");return agent!==void 0&&operation!==void 0?`[agent] ${agent} · ${operation}`:"[agent] invocation started"},outcome:unsupported},"agent.invoke.exit":{description:"An agent invocation exited, reporting its exit code or signal.",fields:[field("agent","Agent"),field("operation","Operation"),field("exitCode","Exit code"),field("signal","Signal"),field("routing.role","Role"),field("routing.tier","Tier"),field("routing.executor","Executor"),field("routing.source","Selection source")],summary:({data})=>{let agent=s2(data,"agent"),operation=s2(data,"operation");return agent!==void 0&&operation!==void 0?`[agent] ${agent} · ${operation} exited`:"[agent] invocation exited"},outcome:{support:"derived",derive:({data})=>{let signal=s2(data,"signal");if(signal!==void 0)return`signal ${signal}`;let code=at(data,"exitCode");if(typeof code==="number"&&Number.isFinite(code))return code===0?"ok":`exit ${code}`;return}}},"agent.invoke.escalated":{description:"An agent invocation escalated from one executor tier to another.",fields:[field("fromExecutor","From executor"),field("fromTier","From tier"),field("toExecutor","To executor"),field("toTier","To tier"),field("trigger","Trigger")],summary:({data})=>{let from=s2(data,"fromExecutor"),to=s2(data,"toExecutor");return from!==void 0&&to!==void 0?`[agent] ${from} -> ${to}`:"[agent] escalation"},outcome:{support:"derived",derive:({data})=>s2(data,"toTier")??s2(data,"trigger")}},"agent.invoke.exhausted":{description:"An agent invocation exhausted every eligible executor tier without success.",fields:[field("stage","Stage"),field("attempts","Attempts"),field("fromTier","From tier"),field("toTier","To tier"),field("fromExecutor","From executor"),field("toExecutor","To executor")],summary:({data})=>{let stage=s2(data,"stage");return stage!==void 0?`[agent] ${stage} escalation exhausted`:"[agent] escalation exhausted"},outcome:derivedFromValue("attempts")},"agent.started":{description:"An agent started, carrying its id and type.",fields:[field("agentId","Agent"),field("agentType","Agent type"),field("pid","PID")],summary:({data})=>{let id=s2(data,"agentId");return id!==void 0?`[agent] ${id} started`:"[agent] started"},outcome:unsupported},"agent.stopped":{description:"An agent stopped, reporting its exit code.",fields:[field("agentId","Agent"),field("exitCode","Exit code")],summary:({data})=>{let id=s2(data,"agentId");return id!==void 0?`[agent] ${id} stopped`:"[agent] stopped"},outcome:derivedFromValue("exitCode")},"strategy.changed":{description:"A project strategy changed (0838), minting a new strategy version for dispatch fencing.",fields:[field("data.projectPath","Project"),field("data.strategy","Strategy"),field("data.version","Version")],summary:({data})=>{let strategy=s2(data,"data.strategy"),version3=s2(data,"data.version");return strategy!==void 0?`[strategy] ${strategy}${version3!==void 0?` (v${version3})`:""}`:"[strategy] changed"},outcome:unsupported},"fleet.capacity.changed":{description:"The project write slot was claimed or released (0837), changing dispatch capacity.",fields:[field("data.projectPath","Project"),field("data.change","Change"),field("data.holderId","Holder")],summary:({data})=>{let change=s2(data,"data.change"),holder=s2(data,"data.holderId");return`[fleet] write slot ${change??"changed"}${holder!==void 0?` — ${holder}`:""}`},outcome:unsupported},"agent.message.sent":{description:"A message was sent to an agent, reporting delivery success.",fields:[field("agentId","Agent"),field("ok","Delivered")],summary:({data})=>{let id=s2(data,"agentId");return id!==void 0?`[agent] message -> ${id}`:"[agent] message sent"},outcome:derivedFromValue("ok")},"task.assigned":{description:"A task was assigned to an agent, naming the agent when resolved.",fields:[field("memberId","Member"),field("agentType","Agent type"),field("taskId","Task"),field("outcome","Outcome")],summary:({data})=>{let member=s2(data,"memberId"),task=s2(data,"taskId");return task!==void 0&&member!==void 0?`[task] ${task} assigned to ${member}`:"[task] assignment recorded"},outcome:derivedFrom("outcome")},"history.import.completed":{description:"A history import finished, reporting files, messages, and exit code.",fields:[field("source","Source"),field("sources","Sources"),field("files","Files"),field("messages","Messages"),field("durationMs","Duration (ms)"),field("exitCode","Exit code"),field("artifactPath","Artifact"),field("cwd","Project root")],retain:[field("trigger","Refresh trigger"),field("windowStart","Refresh window start"),field("windowEnd","Refresh window end"),field("importMode","Import mode"),field("coverage","Refresh coverage")],summary:({data})=>{let source=s2(data,"source")??s2(data,"sources");return source!==void 0?`[history] import · ${source}`:"[history] import completed"},outcome:derivedFromValue("exitCode")},"history.analyze.completed":{description:"A history analyze pass finished, reporting sources, duration, and exit code.",fields:[field("source","Source"),field("sources","Sources"),field("durationMs","Duration (ms)"),field("exitCode","Exit code"),field("artifactPath","Artifact")],retain:[field("trigger","Refresh trigger"),field("windowStart","Refresh window start"),field("windowEnd","Refresh window end"),field("importMode","Import mode")],summary:({data})=>{let source=s2(data,"source")??s2(data,"sources");return source!==void 0?`[history] analyze · ${source}`:"[history] analyze completed"},outcome:derivedFromValue("exitCode")},"history.daily.failed":{description:"The daily history refresh failed, carrying the detail, reason, and exit code.",fields:[field("source","Source"),field("sources","Sources"),field("detail","Detail"),field("reason","Reason"),field("exitCode","Exit code")],retain:[field("trigger","Refresh trigger"),field("windowStart","Refresh window start"),field("windowEnd","Refresh window end"),field("importMode","Import mode")],summary:()=>"[history] daily failed",outcome:{support:"derived",derive:({data})=>s2(data,"reason")??s2(data,"detail")??n2(data,"exitCode")}},"history.refresh.enqueued":{description:"A completion-triggered history refresh was enqueued, naming its window.",fields:[field("trigger","Trigger"),field("triggerId","Trigger id"),field("jobId","Queue job"),field("windowStart","Window start"),field("windowEnd","Window end"),field("coalesced","Coalesced"),field("outcome","Outcome")],summary:({data})=>{let start=s2(data,"windowStart"),end=s2(data,"windowEnd");return start!==void 0&&end!==void 0?`[history] refresh · ${start} -> ${end}`:"[history] refresh enqueued"},outcome:{support:"derived",derive:({data})=>{let status=s2(data,"outcome");return status!==void 0&&status!=="enqueued"?status:void 0}}},"rule.run.start":{description:"A rule run began with the rule count it will evaluate.",fields:[field("runId","Run"),field("ruleCount","Rules"),field("evaluator","Evaluator")],summary:({data,correlation})=>{let run=s2(data,"runId")??correlation.runId;return run!==void 0?`[rule] run ${run} started`:"[rule] run started"},outcome:unsupported},"rule.eval.start":{description:"A single rule began evaluating.",fields:[field("runId","Run"),field("ruleId","Rule"),field("evaluator","Evaluator"),field("index","Index"),field("total","Total")],summary:({data})=>{let id=s2(data,"ruleId");return id!==void 0?`[rule] ${id} evaluating`:"[rule] evaluating"},outcome:unsupported},"rule.eval.done":{description:"A rule finished evaluating, reporting its findings count and severity.",fields:[field("runId","Run"),field("ruleId","Rule"),field("evaluator","Evaluator"),field("findings","Findings"),field("durationMs","Duration (ms)"),field("severity","Severity")],summary:({data})=>{let id=s2(data,"ruleId");return id!==void 0?`[rule] ${id} evaluated`:"[rule] evaluated"},outcome:derivedFromValue("findings")},"rule.eval.error":{description:"A rule evaluation failed with an error.",fields:[field("runId","Run"),field("ruleId","Rule"),field("evaluator","Evaluator"),field("error","Error")],summary:({data})=>{let id=s2(data,"ruleId");return id!==void 0?`[rule] ${id} error`:"[rule] error"},outcome:derivedFrom("error")},"rule.run.done":{description:"A rule run finished, reporting findings and whether it stopped early.",fields:[field("runId","Run"),field("findings","Findings"),field("durationMs","Duration (ms)"),field("stoppedEarly","Stopped early"),field("severity","Severity")],summary:({data,correlation})=>{let run=s2(data,"runId")??correlation.runId;return run!==void 0?`[rule] run ${run} done`:"[rule] run done"},outcome:{support:"derived",derive:({data})=>n2(data,"findings")??s2(data,"stoppedEarly")}},"workflow.run.started":{description:"A workflow run started, naming the workflow definition.",fields:[field("runId","Run"),field("workflowName","Workflow"),field("mode","Mode"),field("dryRun","Dry run")],summary:(input)=>{let name=humanWorkflowTitle(input);return name!==""?`[workflow] ${name} started`:"[workflow] started"},outcome:unsupported},"workflow.run.done":{description:"A workflow run reached a done terminal state.",fields:[field("runId","Run"),field("workflowName","Workflow"),field("finalState","Final state"),field("transitionsTaken","Transitions")],summary:(input)=>{let name=humanWorkflowTitle(input);return name!==""?`[workflow] ${name} done`:"[workflow] done"},outcome:derivedFrom("finalState")},"workflow.run.failed":{description:"A workflow run failed with a terminal failure reason.",fields:[field("runId","Run"),field("workflowName","Workflow"),field("finalState","Final state"),field("reason","Reason")],summary:(input)=>{let name=humanWorkflowTitle(input);return name!==""?`[workflow] ${name} failed`:"[workflow] failed"},outcome:derivedFrom("reason")},"workflow.run.finalized":{description:"A workflow run settled on a terminal status.",fields:[field("runId","Run"),field("workflowName","Workflow"),field("status","Status")],summary:(input)=>{let name=humanWorkflowTitle(input);return name!==""?`[workflow] ${name} finalized`:"[workflow] finalized"},outcome:derivedFrom("status")},"workflow.escalation.created":{description:"A canonical escalation packet was projected from existing run evidence.",fields:[field("runId","Run"),field("workflowName","Workflow"),field("fingerprint","Fingerprint"),field("artifactPath","Artifact"),field("decision","Decision")],summary:(input)=>{let name=humanWorkflowTitle(input),decision=typeof at(input.data,"decision")==="string"?` — ${String(at(input.data,"decision"))}`:"";return name!==""?`[workflow] escalation packet created (${name}${decision})`:`[workflow] escalation packet created${decision}`},outcome:derivedFrom("decision")},"workflow.escalation.projection_failed":{description:"Escalation packet projection failed; the original failure is preserved untouched.",fields:[field("runId","Run"),field("workflowName","Workflow"),field("error","Error")],summary:()=>"[workflow] escalation packet projection failed",outcome:derivedFrom("error")},"workflow.run.paused":{description:"A workflow run paused at a step, naming the step when available.",fields:[field("runId","Run"),field("workflowName","Workflow"),field("nodeLabel","Step"),field("node","Node"),field("transitionsTaken","Transitions")],summary:(input)=>{let name=humanWorkflowTitle(input),step=humanStepLabel(input.data),parts=[name,step].filter((part)=>typeof part==="string"&&part!=="");return parts.length>0?`[workflow] ${parts.join(" · ")} paused`:"[workflow] paused"},outcome:unsupported},"workflow.run.resumed":{description:"A paused workflow run resumed at a step, naming the step when available.",fields:[field("runId","Run"),field("workflowName","Workflow"),field("nodeLabel","Step"),field("node","Node")],summary:(input)=>{let name=humanWorkflowTitle(input),step=humanStepLabel(input.data),parts=[name,step].filter((part)=>typeof part==="string"&&part!=="");return parts.length>0?`[workflow] ${parts.join(" · ")} resumed`:"[workflow] resumed"},outcome:unsupported},"workflow.run.reseeded":{description:"A workflow run was reseeded to a new state, naming the transition.",fields:[field("runId","Run"),field("workflowName","Workflow"),field("fromState","From"),field("toState","To")],summary:(input)=>{let name=humanWorkflowTitle(input),from=s2(input.data,"fromState"),to=s2(input.data,"toState");if(from!==void 0&&to!==void 0)return name!==""?`[workflow] ${name} : ${from} -> ${to}`:`[workflow] : ${from} -> ${to}`;return name!==""?`[workflow] ${name} reseeded`:"[workflow] reseeded"},outcome:derivedFrom("toState")},"workflow.node.enter":{description:"The engine entered a workflow node, naming the step when available.",fields:[field("runId","Run"),field("workflowName","Workflow"),field("nodeLabel","Step"),field("node","Node"),field("transitionsTaken","Transitions")],summary:(input)=>{let name=humanWorkflowTitle(input),step=humanStepLabel(input.data),parts=[name,step].filter((part)=>typeof part==="string"&&part!=="");return parts.length>0?`[workflow] ${parts.join(" · ")}`:"[workflow] node entered"},outcome:unsupported},"workflow.phase":{description:"A workflow phase changed status, naming the phase.",fields:[field("runId","Run"),field("workflowName","Workflow"),field("phase","Phase"),field("status","Status")],summary:(input)=>{let name=humanWorkflowTitle(input),phase=s2(input.data,"phase"),parts=[name,phase].filter((part)=>typeof part==="string"&&part!=="");return parts.length>0?`[workflow] ${parts.join(" · ")}`:"[workflow] phase"},outcome:derivedFrom("status")},"workflow.node.transition":{description:"A workflow transitioned between nodes, naming the from and to states.",fields:[field("runId","Run"),field("workflowName","Workflow"),field("from","From"),field("to","To"),field("trigger","Trigger")],summary:(input)=>{let name=humanWorkflowTitle(input),from=s2(input.data,"from"),to=s2(input.data,"to");if(from!==void 0&&to!==void 0)return name!==""?`[workflow] ${name} : ${from} -> ${to}`:`[workflow] : ${from} -> ${to}`;return name!==""?`[workflow] ${name} transitioned`:"[workflow] transitioned"},outcome:derivedFrom("to")},"workflow.transition":{description:"A workflow state transition was committed.",fields:[field("runId","Run"),field("workflowName","Workflow"),field("from","From"),field("to","To"),field("trigger","Trigger")],summary:(input)=>{let name=humanWorkflowTitle(input),from=s2(input.data,"from"),to=s2(input.data,"to");if(from!==void 0&&to!==void 0)return name!==""?`[workflow] ${name} : ${from} -> ${to}`:`[workflow] : ${from} -> ${to}`;return name!==""?`[workflow] ${name} transitioned`:"[workflow] transitioned"},outcome:derivedFrom("to")},"workflow.transition.requested":{description:"A workflow transition was requested and accepted for evaluation.",fields:[field("runId","Run"),field("workflowName","Workflow"),field("from","From"),field("to","To"),field("trigger","Trigger")],summary:(input)=>{let name=humanWorkflowTitle(input),from=s2(input.data,"from"),to=s2(input.data,"to");if(from!==void 0&&to!==void 0)return name!==""?`[workflow] ${name} requested ${from} -> ${to}`:`[workflow] requested ${from} -> ${to}`;return name!==""?`[workflow] ${name} transition requested`:"[workflow] transition requested"},outcome:unsupported},"workflow.transition.denied":{description:"A workflow transition was denied with a reason.",fields:[field("runId","Run"),field("workflowName","Workflow"),field("from","From"),field("to","To"),field("reason","Reason")],summary:(input)=>{let name=humanWorkflowTitle(input),from=s2(input.data,"from"),to=s2(input.data,"to");if(from!==void 0&&to!==void 0)return name!==""?`[workflow] ${name} denied ${from} -> ${to}`:`[workflow] denied ${from} -> ${to}`;return name!==""?`[workflow] ${name} transition denied`:"[workflow] transition denied"},outcome:derivedFrom("reason")},"workflow.action.started":{description:"A workflow action began executing, naming the step and kind.",fields:[field("runId","Run"),field("workflowName","Workflow"),field("nodeLabel","Step"),field("node","Node"),field("actionId","Action"),field("kind","Kind")],retain:[field("metadata.agent","Agent"),field("metadata.role","Role"),field("routing.executor","Executor")],summary:(input)=>{let name=humanWorkflowTitle(input),step=humanStepLabel(input.data),parts=[name,step].filter((part)=>typeof part==="string"&&part!=="");return parts.length>0?`[workflow] ${parts.join(" · ")} started`:"[workflow] action started"},outcome:unsupported},"workflow.action.finished":{description:"A workflow action finished, reporting its status and success.",fields:[field("runId","Run"),field("workflowName","Workflow"),field("nodeLabel","Step"),field("node","Node"),field("actionId","Action"),field("kind","Kind"),field("durationMs","Duration (ms)"),field("status","Status")],retain:[field("metadata.agent","Agent"),field("metadata.role","Role"),field("routing.executor","Executor")],summary:(input)=>{let name=humanWorkflowTitle(input),step=humanStepLabel(input.data),parts=[name,step].filter((part)=>typeof part==="string"&&part!=="");return parts.length>0?`[workflow] ${parts.join(" · ")} finished`:"[workflow] action finished"},outcome:{support:"derived",derive:({data})=>s2(data,"status")??n2(data,"ok")}},"workflow.action.failed_continue":{description:"A workflow action failed but the workflow continued, carrying the error.",fields:[field("runId","Run"),field("workflowName","Workflow"),field("nodeLabel","Step"),field("node","Node"),field("transitionsTaken","Transitions"),field("error","Error")],retain:[field("metadata.agent","Agent"),field("metadata.role","Role"),field("routing.executor","Executor")],summary:(input)=>{let name=humanWorkflowTitle(input),step=humanStepLabel(input.data),parts=[name,step].filter((part)=>typeof part==="string"&&part!=="");return parts.length>0?`[workflow] ${parts.join(" · ")} failed; continuing`:"[workflow] action failed; continuing"},outcome:derivedFrom("error")},"workflow.guard.evaluated":{description:"A workflow guard was evaluated for a transition, reporting whether it passed.",fields:[field("runId","Run"),field("workflowName","Workflow"),field("from","From"),field("to","To"),field("kind","Kind"),field("passed","Passed")],summary:(input)=>{let name=humanWorkflowTitle(input),from=s2(input.data,"from"),to=s2(input.data,"to");if(from!==void 0&&to!==void 0)return name!==""?`[workflow] ${name} guard ${from} -> ${to}`:`[workflow] guard ${from} -> ${to}`;return name!==""?`[workflow] ${name} guard evaluated`:"[workflow] guard evaluated"},outcome:derivedFromValue("passed")},"workflow.hitl.ask":{description:"A workflow paused for human input, naming the step and kind.",fields:[field("runId","Run"),field("workflowName","Workflow"),field("nodeLabel","Step"),field("node","Node"),field("kind","Kind")],summary:(input)=>{let name=humanWorkflowTitle(input),step=humanStepLabel(input.data),parts=[name,step].filter((part)=>typeof part==="string"&&part!=="");return parts.length>0?`[workflow] ${parts.join(" · ")} awaiting input`:"[workflow] awaiting input"},outcome:unsupported},"workflow.hitl.response":{description:"Human input was received for a paused workflow step.",fields:[field("runId","Run"),field("workflowName","Workflow"),field("nodeLabel","Step"),field("node","Node"),field("ok","Accepted")],summary:(input)=>{let name=humanWorkflowTitle(input),step=humanStepLabel(input.data),parts=[name,step].filter((part)=>typeof part==="string"&&part!=="");return parts.length>0?`[workflow] ${parts.join(" · ")} input received`:"[workflow] input received"},outcome:derivedFromValue("ok")},"workflow.hitl.note":{description:"A note was recorded on a paused workflow step.",fields:[field("runId","Run"),field("workflowName","Workflow"),field("nodeLabel","Step"),field("node","Node")],summary:(input)=>{let name=humanWorkflowTitle(input),step=humanStepLabel(input.data),parts=[name,step].filter((part)=>typeof part==="string"&&part!=="");return parts.length>0?`[workflow] ${parts.join(" · ")} note`:"[workflow] note"},outcome:unsupported},"workflow.custom":{description:"A custom workflow event was emitted, naming the custom event.",fields:[field("runId","Run"),field("workflowName","Workflow"),field("name","Event")],summary:(input)=>{let name=humanWorkflowTitle(input),custom3=s2(input.data,"name"),parts=[name,custom3].filter((part)=>typeof part==="string"&&part!=="");return parts.length>0?`[workflow] ${parts.join(" · ")}`:"[workflow] custom"},outcome:unsupported},"workflow.agent":{description:"A workflow-dispatched agent execution lifecycle event, discriminated by kind.",fields:[field("runId","Run"),field("executionId","Execution"),field("actionId","Action"),field("kind","Kind"),field("agent","Agent"),field("model","Model")],retain:[field("metadata.agent","Agent"),field("metadata.role","Role"),field("routing.executor","Executor")],summary:(input)=>{let name=humanWorkflowTitle(input),kind=s2(input.data,"kind"),parts=[name,kind!==void 0?`agent ${kind}`:"agent"].filter((part)=>typeof part==="string"&&part!=="");return parts.length>0?`[workflow] ${parts.join(" · ")}`:"[workflow] agent"},outcome:{support:"derived",derive:({data})=>s2(data,"kind")==="finished"?s2(data,"outcome"):void 0}},"workflow.steering":{description:"A steering command was acknowledged for a workflow action boundary.",fields:[field("runId","Run"),field("actionId","Action"),field("operation","Operation"),field("actor","Actor"),field("accepted","Accepted"),field("state","State"),field("reason","Reason")],summary:(input)=>{let name=humanWorkflowTitle(input),operation=s2(input.data,"operation"),parts=[name,operation!==void 0?`steering ${operation}`:"steering"].filter((part)=>typeof part==="string"&&part!=="");return parts.length>0?`[workflow] ${parts.join(" · ")}`:"[workflow] steering"},outcome:{support:"derived",derive:({data})=>{let reason=s2(data,"reason");if(reason!==void 0)return reason;let accepted=at(data,"accepted");if(accepted===!0)return"accepted";if(accepted===!1)return"rejected";return s2(data,"state")}}},"api.request.error":{description:"An API request failed, naming the method, path, and status or error code.",fields:[field("method","Method"),field("path","Path"),field("status","Status"),field("code","Code"),field("requestId","Request"),field("error","Error")],summary:({data})=>{let method=s2(data,"method"),path8=s2(data,"path");return method!==void 0&&path8!==void 0?`[api] ${method} ${path8}`:"[api] request error"},outcome:{support:"derived",derive:({data})=>s2(data,"error")??s2(data,"code")??n2(data,"status")}},"bus.emit.done":{description:"An event was emitted to its handlers on the event bus.",fields:[field("event","Event"),field("handlers","Handlers"),field("durationMs","Duration (ms)")],summary:({data})=>{let event=s2(data,"event");return event!==void 0?`[bus] ${event} emitted`:"[bus] event emitted"},outcome:derivedFromValue("handlers")},"bus.emit.noop":{description:"An event was emitted but had no registered handlers.",fields:[field("event","Event"),field("handlers","Handlers"),field("durationMs","Duration (ms)")],summary:({data})=>{let event=s2(data,"event");return event!==void 0?`[bus] ${event} had no handlers`:"[bus] event had no handlers"},outcome:derivedFromValue("handlers")},"bus.handler.error":{description:"An event-bus handler threw an error while processing an event.",fields:[field("event","Event"),field("handlers","Handlers"),field("durationMs","Duration (ms)"),field("error","Error")],summary:({data})=>{let event=s2(data,"event");return event!==void 0?`[bus] ${event} handler error`:"[bus] handler error"},outcome:derivedFrom("error")},"bus.handler.async.enqueued":{description:"An event-bus handler was enqueued for asynchronous processing.",fields:[field("event","Event"),field("handlers","Handlers")],summary:({data})=>{let event=s2(data,"event");return event!==void 0?`[bus] ${event} handlers enqueued`:"[bus] handlers enqueued"},outcome:derivedFromValue("handlers")}};function inferSeverity(name){if(/(?:failed|error|denied)$/.test(name))return"error";if(/(?:retrying|paused|dropped)$/.test(name))return"warning";return"info"}function resolveCatalogEntry(base2){let profile=SOURCE_PROFILES[base2.source],presenter=SYSTEM_EVENT_PRESENTERS[base2.name];return{name:base2.name,prefix:base2.name.split(".")[0]??base2.name,source:base2.source,tier:base2.tier,persisted:!0,streamed:!0,payloadPolicy:base2.payloadPolicy,renderer:base2.renderer,...profile,...base2.producer!==void 0?{producerPackage:base2.producer.package,subsystem:base2.producer.subsystem}:{},severity:inferSeverity(base2.name),description:presenter.description,metadataFields:presenter.retain?[...presenter.fields,...presenter.retain.filter((r)=>!presenter.fields.some((f)=>f.path===r.path))]:presenter.fields,remediationKind:profile.remediationKind}}var SYSTEM_EVENT_CATALOG=BASE_CATALOG.map(resolveCatalogEntry),SYSTEM_EVENT_NAMES=SYSTEM_EVENT_CATALOG.map((entry)=>entry.name),SYSTEM_EVENT_PERSISTED_NAMES=SYSTEM_EVENT_CATALOG.filter((entry)=>entry.tier==="default").map((entry)=>entry.name),SYSTEM_EVENT_STREAMED_NAMES=SYSTEM_EVENT_CATALOG.filter((entry)=>entry.tier==="default").map((entry)=>entry.name),SYSTEM_EVENT_PREFIXES=Array.from(new Set(SYSTEM_EVENT_CATALOG.map((entry)=>entry.prefix))),SYSTEM_EVENT_DEFAULT_NAMES=SYSTEM_EVENT_CATALOG.filter((entry)=>entry.tier==="default").map((entry)=>entry.name),SYSTEM_EVENT_DIAGNOSTIC_NAMES=SYSTEM_EVENT_CATALOG.filter((entry)=>entry.tier==="diagnostic").map((entry)=>entry.name);var SYSTEM_EVENT_CATALOG_METADATA=SYSTEM_EVENT_CATALOG.map(({name,prefix,source,tier,renderer,producerPackage,subsystem,severity,description,metadataFields,remediationKind})=>({name,prefix,source,tier,renderer,producerPackage,subsystem,severity,description,metadataFields,remediationKind}));function workflowVersionLiteral(workflow){return typeof workflow.version==="string"&&workflow.version!==""?workflow.version:null}var{appendFileSync:appendFileSync4,closeSync,existsSync:existsSync5,mkdirSync:mkdirSync3,openSync,readFileSync:readFileSync5,renameSync:renameSync3,unlinkSync:unlinkSync2,writeFileSync:writeFileSync4,writeSync}=await import("node:fs"),{lstat,mkdir:mkdir2,readdir,readFile:readFile2}=await import("node:fs/promises");function parseIdentityMetadata(raw){if(raw.trim()==="")return{};try{let parsed=JSON.parse(raw);if(parsed===null||typeof parsed!=="object"||Array.isArray(parsed))return null;return parsed}catch{return null}}async function openInlineRunProjectDb(workdir){let url2=join9(resolve6(workdir),".spur","spur.db");mkdirSync3(join9(url2,".."),{recursive:!0});let adapter=await createMigratedDb({url:url2});return{adapter,close:()=>adapter.close()}}var SAFE_RUN_ID_RE=/^[A-Za-z0-9][A-Za-z0-9._-]*$/,MAX_CITED_RUN_FILES=64,RUN_CITATION_RE=/(?<![\w~:-]|[\w~:-]\/)\.spur\/run\/([A-Za-z0-9][A-Za-z0-9._*?<>{}|,\u2026-]*)(\/[^\s`]*)?/g;function asLiteralRunFileName(citation){let name=citation.replace(/[.,]+$/,"");if(!SAFE_RUN_ID_RE.test(name)||name.includes(".."))return;return name}async function readExistingRunFile(path8){let stat=await lstat(path8).catch((error51)=>{if(error51.code==="ENOENT")return;throw error51});if(stat===void 0)return;if(!stat.isFile())throw Error(`persist-out: destination ${path8} is not a regular file — refusing to follow it`);return readFile2(path8)}async function persistWorktreeRuns(input){let fromDir=resolve6(input.fromWorkdir),toDir=resolve6(input.toWorkdir),fromRunDir=join9(fromDir,".spur","run"),toRunDir=join9(toDir,".spur","run"),fromRecordsDir=runStoragePaths(fromDir).recordsDir,toRecordsDir=runStoragePaths(toDir).recordsDir,fs2=createNodeFileSystem2(),fromEvidence=runStoragePaths(fromDir).evidenceDir,toEvidence=runStoragePaths(toDir).evidenceDir,evidenceCopies=[];await resolveDurableArtifactPath(fs2,fromDir,join9(fromEvidence,"probe.json"),"evidence");let evidenceNames=await readdir(fromEvidence).catch((error51)=>{if(error51.code==="ENOENT")return[];throw error51});for(let name of evidenceNames.sort()){let source2=await resolveDurableArtifactPath(fs2,fromDir,join9(fromEvidence,name),"evidence"),target=await resolveDurableArtifactPath(fs2,toDir,join9(toEvidence,name),"evidence");if(!(await lstat(source2)).isFile())throw Error(`persist-out: durable evidence is not a regular file: ${name}`);let bytes=await readFile2(source2),verdictWbs=/^(\d{4})-verdict\.json$/.exec(name)?.[1];if(verdictWbs!==void 0){let parsed=parseVerifyVerdict(bytes.toString(),verdictWbs),raw=JSON.parse(bytes.toString());if(!parsed||parsed.wbs!==verdictWbs||raw.wbs!==void 0&&raw.wbs!==verdictWbs)throw Error(`persist-out: malformed durable verdict identity: ${name}`)}else if(name.endsWith("-feature-verification.json")){let receipt=parseFeatureVerificationReceipt(bytes.toString()),owner=name.slice(0,-26);if(owner!==receipt.runId&&owner!==receipt.featureId)throw Error(`persist-out: malformed durable receipt identity: ${name}`)}else throw Error(`persist-out: unclassified durable evidence: ${name}`);let existing=await readExistingRunFile(target);if(existing!==void 0&&!existing.equals(bytes))throw Error(`persist-out: durable evidence conflicts: ${name}`);evidenceCopies.push({source:source2,target,bytes})}let citedNames=new Set,citedDirSkips=new Set;for(let taskFile of input.taskFiles??[]){let content;try{content=await readFile2(resolve6(toDir,taskFile),"utf8")}catch(error51){throw Error(`persist-out: merged task file ${taskFile} is unreadable: ${String(error51)}`)}for(let match of content.matchAll(RUN_CITATION_RE)){let name=asLiteralRunFileName(match[1]??"");if(name===void 0)continue;if(match[2]!==void 0){citedDirSkips.add(name);continue}if(citedNames.has(name))continue;if(citedNames.size>=MAX_CITED_RUN_FILES)throw Error(`persist-out: merged task files cite more than ${MAX_CITED_RUN_FILES} distinct `+".spur/run/ files — over the fixed citation cap (0984 R3); split the batch or prune the citations");citedNames.add(name)}}if((input.taskFiles??[]).length>0){let prefixes=(input.taskFiles??[]).flatMap((taskFile)=>{let wbs=/^(\d{4})_/.exec(basename4(taskFile))?.[1];return wbs===void 0?[]:[`${wbs}-`]}),recordNames=new Set,owner=await openInlineRunProjectDb(fromDir);try{for(let row of await listRunIdRows(owner.adapter)){if(!SAFE_RUN_ID_RE.test(row.id))throw new InvalidWorkflowRunIdError(row.id);prefixes.push(`${row.id}-`),recordNames.add(`${row.id}.md`).add(`${row.id}.state.json`)}}finally{owner.close()}let entries=await readdir(fromRunDir).catch((error51)=>{if(error51.code==="ENOENT")return[];throw error51}),ownedCounts=new Map;for(let name of entries.sort()){if(recordNames.has(name))continue;let owner2=prefixes.find((prefix)=>name.startsWith(prefix));if(owner2===void 0)continue;let count3=(ownedCounts.get(owner2)??0)+1;if(count3>MAX_CITED_RUN_FILES)throw Error(`persist-out: owner ${owner2} owns more than ${MAX_CITED_RUN_FILES} .spur/run/ files `+"— over the per-owner evidence cap (1012 R1, 1034 R1); split the batch or prune the evidence");ownedCounts.set(owner2,count3),citedNames.add(name)}}let citedCopies=[],citedSkips=[];for(let name of citedDirSkips)citedSkips.push({id:name,reason:`cited-directory:${name}`});for(let name of citedNames){let scratchPath=join9(fromRunDir,name),durablePath=join9(fromRecordsDir,name),scratchStat=await lstat(scratchPath).catch(()=>{return}),sourceIsDurable=scratchStat===void 0,sourcePath=sourceIsDurable?durablePath:scratchPath,targetPath=sourceIsDurable?join9(toRecordsDir,name):join9(toRunDir,name),sourceStat=sourceIsDurable?await lstat(durablePath).catch(()=>{return}):scratchStat,targetBytes=await readExistingRunFile(targetPath);if(sourceStat===void 0){if(targetBytes===void 0)throw Error(`persist-out: cited run evidence .spur/run/${name} is missing in both the worktree and `+"the invoking tree — resolve or drop the citation before teardown (0984 R1)");continue}if(!sourceStat.isFile()){let kind=sourceStat.isDirectory()?"directory":sourceStat.isSymbolicLink()?"symlink":"non-file";citedSkips.push({id:name,reason:`cited-${kind}:${name}`});continue}if(targetBytes!==void 0){let sourceBytes=await readFile2(sourcePath);if(!targetBytes.equals(sourceBytes))throw Error(`persist-out: cited run evidence .spur/run/${name} diverges from the invoking tree's `+"existing file — refusing to overwrite; reconcile the two copies by hand (0984 R4)");continue}citedCopies.push({name,sourcePath,targetPath})}let source=await openInlineRunProjectDb(fromDir);try{let runRows=await listRunIdRows(source.adapter);for(let row of runRows)if(!SAFE_RUN_ID_RE.test(row.id))throw new InvalidWorkflowRunIdError(row.id);let recordBytes=new Map;for(let row of runRows){let bookkeeping=row.workflowName!==null&&row.workflowName!==void 0&&isBookkeepingWorkflow(row.workflowName);for(let fileName of[`${row.id}.md`,`${row.id}.state.json`])try{recordBytes.set(fileName,await readFile2(join9(fromRecordsDir,fileName)))}catch(error51){if(error51.code==="ENOENT"){if(bookkeeping)continue;throw Error(`persist-out: ${row.workflowName??"unknown"} run ${row.id} is missing its run record \`${fileName}\` in the worktree — failing closed before any row transfer `+"(green-run evidence guarantee, 0984 R5 / 1043 R1)")}throw error51}}let target=await openInlineRunProjectDb(toDir);try{let{persistedIds,skipped}=await transferRunTables(source.adapter,target.adapter),recordIds=[...persistedIds,...skipped.filter((s3)=>s3.reason==="id-exists").map((s3)=>s3.id)],recordSkips=[],referenceMoves=[];if(evidenceCopies.length>0){ensureDurablePlaneIgnored(toDir);for(let copy of evidenceCopies){await mkdir2(join9(copy.target,".."),{recursive:!0});let existing=await readExistingRunFile(copy.target);if(existing!==void 0&&!existing.equals(copy.bytes))throw Error(`persist-out: durable evidence conflicts: ${copy.target}`);if(existing===void 0)writeFileSync4(copy.target,copy.bytes,{flag:"wx"});referenceMoves.push({source:copy.source,target:fs2.realPath?.(copy.target)??copy.target})}}if(recordIds.length>0||citedCopies.length>0){mkdirSync3(toRunDir,{recursive:!0}),mkdirSync3(toRecordsDir,{recursive:!0}),ensureDurablePlaneIgnored(toDir);for(let id of recordIds)for(let fileName of[`${id}.md`,`${id}.state.json`]){let sourceBytes=recordBytes.get(fileName);if(sourceBytes===void 0){recordSkips.push({id,reason:`record-missing:${fileName}`});continue}let targetPath=join9(toRecordsDir,fileName),existing=await readExistingRunFile(targetPath);if(existing!==void 0){if(existing.equals(sourceBytes))continue;recordSkips.push({id,reason:`record-conflict:${fileName}`});continue}writeFileSync4(targetPath,sourceBytes,{flag:"wx"})}for(let cited of citedCopies){let sourceBytes=await readFile2(cited.sourcePath),existing=await readExistingRunFile(cited.targetPath);if(existing!==void 0){if(!existing.equals(sourceBytes))throw Error(`persist-out: cited run evidence .spur/run/${cited.name} diverges from the invoking `+"tree's existing file — refusing to overwrite; reconcile the two copies by hand (0984 R4)");continue}writeFileSync4(cited.targetPath,sourceBytes,{flag:"wx"})}for(let id of recordIds)await carryRunRecordDir(fromRecordsDir,toRecordsDir,"",id,recordSkips,referenceMoves)}return await redirectRunStorageReferences(target.adapter,referenceMoves),{ok:!0,persisted:persistedIds.length,skipped:[...skipped,...recordSkips,...citedSkips]}}finally{target.close()}}finally{source.close()}}async function createOrAttachInlineRun(input){let runId=input.runId.trim();if(runId==="")return{ok:!1,error:"inline run setup requires a non-empty runId (driver Run setup step 2)"};let workdir=resolve6(input.workdir),resolved;try{let projection=input.inventory===void 0?void 0:parseWorkflowInventory(input.inventory);if(projection&&!projection.ok)return projection;let inventory=projection?.ok?projection.inventory:void 0;if(inventory&&(!inventory.source||inventory.kind!=="state-machine"))return{ok:!1,error:"inline run setup requires a state-machine inventory with definition source"};if(resolved=await resolveWorkflowDefinition(workdir,inventory?.source?.path??input.file,{validateSchema:!0,...input.embeddedSchemas!==void 0?{embeddedSchemas:input.embeddedSchemas}:{},...!inventory?{registered:input.registered}:{}}),(resolved.workflow.kind??"state-machine")!=="state-machine")return{ok:!1,error:"inline run setup requires a state-machine definition"};if(inventory?.source){let identity5=assertInventoryIdentity(inventory,resolved.digest);if(!identity5.ok)return identity5;if(inventory.name!==resolved.workflow.name)return{ok:!1,error:"inline run setup: inventory workflow name does not match its definition"};resolved={...resolved,layer:inventory.source.layer}}}catch(error51){return{ok:!1,error:`inline run setup could not resolve the workflow definition: ${error51.message}`}}let digest=resolved.digest,version3=workflowVersionLiteral(resolved.workflow),source={path:resolved.path,layer:resolved.layer,workdir},db2=await input.getDb(),existing=await new RunDao(db2).traceRowById(runId);if(existing!==void 0){let metadata=parseIdentityMetadata(existing.metadata_json);if(metadata===null)return{ok:!1,error:`inline run setup refuses run ${runId}: its existing row has malformed metadata_json, `+"so its identity cannot be verified — delete the stale run row or allocate a new run id"};let resumeDigest=typeof metadata.resumeDefinitionDigest==="string"?metadata.resumeDefinitionDigest:void 0,launchDigest=typeof metadata.definitionDigest==="string"?metadata.definitionDigest:void 0,effectiveDigest=resumeDigest??launchDigest;if(effectiveDigest===void 0)return{ok:!1,error:`inline run setup refuses run ${runId}: its existing row carries no definition digest `+"(pre-identity legacy row) — allocate a new run id instead of attaching an unverifiable identity"};if(effectiveDigest!==digest)return{ok:!1,error:`inline run setup refuses run ${runId}: the resolved definition digest (${digest}) does not match the run's recorded ${resumeDigest!==void 0?"resume":""} digest (${effectiveDigest}) — `+"a changed definition must resume through the explicit resume rules, not silently re-attach"};if(existing.workflow_name!==resolved.workflow.name)return{ok:!1,error:`inline run setup refuses run ${runId}: the run row records workflow "${existing.workflow_name}" but the resolved definition is "${resolved.workflow.name}" — conflicting run identity`};if(typeof metadata.definitionSource!=="object"||metadata.definitionSource===null||Array.isArray(metadata.definitionSource))return{ok:!1,error:`inline run setup refuses run ${runId}: its existing row carries no definition source `+"(path/layer/workdir) — allocate a new run id instead of attaching an unverifiable launch source"};let existingSource=metadata.definitionSource;if(!(typeof existingSource.path==="string"&&resolve6(existingSource.path)===resolved.path&&normalizePersistedWorkflowLayer(existingSource.layer)===resolved.layer&&typeof existingSource.workdir==="string"&&resolve6(existingSource.workdir)===workdir))return{ok:!1,error:`inline run setup refuses run ${runId}: the recorded definition source (${JSON.stringify(existingSource)}) does not match the resolved launch source (${JSON.stringify(source)}) — conflicting project/workdir identity`};return{ok:!0,attached:!0,runId,workflowName:resolved.workflow.name,definitionDigest:digest,workflowVersion:version3,resolvedPath:resolved.path,layer:resolved.layer,workdir,status:existing.status}}return await new WorkflowService(createDefaultWorkflowEngineHost(),new DbWorkflowPersistenceAdapter(db2)).createOrAttachRun({id:runId,workflow_name:resolved.workflow.name,mode:"state-machine",status:"running",started_at:new Date().toISOString(),completed_at:null,metadata_json:JSON.stringify({definitionDigest:digest,workflowVersion:version3,definitionSource:source})}),{ok:!0,attached:!1,runId,workflowName:resolved.workflow.name,definitionDigest:digest,workflowVersion:version3,resolvedPath:resolved.path,layer:resolved.layer,workdir,status:"running"}}async function runDecideForInlineRun(input){let optionsFile=join9(resolve6(input.workdir),input.optionsFile),raw;try{raw=JSON.parse(await readFile2(optionsFile,"utf8"))}catch(error51){return{ok:!1,error:`decide: unreadable options file ${input.optionsFile}: ${String(error51)}`}}let parsed=DecideOptionsSchema.safeParse(raw);if(!parsed.success)return{ok:!1,error:`decide: invalid options — ${parsed.error.issues.map((i2)=>i2.message).join("; ")}`};let result=await new DecideActionRunner(createNodeFileSystem2(),{enabled:input.enabled}).execute(raw,{runId:"inline-decide",stateOrNodeId:"decide",workdir:resolve6(input.workdir),vars:{},env:{}});if(!result.ok||result.data===void 0)return{ok:!1,error:result.error??"decide: action failed without an error message"};let decision=result.data.decision;return{ok:!0,value:decision.value,degraded:decision.degraded,reason:decision.reason,source:decision.source,backend:decision.backend,confidence:decision.confidence,resultFile:join9(resolve6(input.workdir),parsed.data.resultFile),durationMs:decision.durationMs}}async function carryRunRecordDir(srcRoot,destRoot,rel,runId,skips,moves){let fs2=createNodeFileSystem2();await resolveDurableArtifactPath(fs2,resolve6(srcRoot,"../../.."),join9(srcRoot,rel,"probe"),"runs"),await resolveDurableArtifactPath(fs2,resolve6(destRoot,"../../.."),join9(destRoot,rel,"probe"),"runs");let entries;try{entries=await readdir(join9(srcRoot,rel),{withFileTypes:!0})}catch(error51){if(error51.code==="ENOENT")return;throw error51}for(let entry of entries){if(rel===""&&![runId,`${runId}.md`,`${runId}.state.json`,`${runId}.log`].includes(entry.name))continue;let relNext=rel===""?entry.name:`${rel}/${entry.name}`;if(entry.isDirectory()){await carryRunRecordDir(srcRoot,destRoot,relNext,runId,skips,moves);let target=join9(destRoot,relNext);if(existsSync5(target))moves.push({source:join9(srcRoot,relNext),target:fs2.realPath?.(target)??target});continue}let source=await resolveDurableArtifactPath(fs2,resolve6(srcRoot,"../../.."),join9(srcRoot,relNext),"runs"),dest=await resolveDurableArtifactPath(fs2,resolve6(destRoot,"../../.."),join9(destRoot,relNext),"runs");if(!(await lstat(source)).isFile())throw Error(`persist-out: retained item is not a regular file: ${source}`);let sourceBytes=await readFile2(source),existing=await readExistingRunFile(dest);if(existing!==void 0){if(!existing.equals(sourceBytes)){if(rel!=="")throw Error(`persist-out: retained data conflicts: ${relNext}`);skips.push({id:`${runId}/${relNext}`,reason:`record-conflict:${relNext}`});continue}}else await mkdir2(join9(dest,".."),{recursive:!0}),writeFileSync4(dest,sourceBytes,{flag:"wx"});if(moves.push({source,target:fs2.realPath?.(dest)??dest}),moves.push({source:join9(srcRoot,relNext),target:fs2.realPath?.(dest)??dest}),rel!=="")moves.push({source:join9(srcRoot,rel),target:fs2.realPath?.(join9(destRoot,rel))??join9(destRoot,rel)})}}function writeInlineRunOutcome(runId,outcome){let runDir=runStoragePaths(process.cwd()).recordsDir;if(!existsSync5(runDir))mkdirSync3(runDir,{recursive:!0});let statePath=join9(runDir,`${runId}.state.json`),markdownPath=join9(runDir,`${runId}.md`),prior={};try{let parsed=JSON.parse(readFileSync5(statePath,"utf8"));if(parsed!==null&&typeof parsed==="object"&&!Array.isArray(parsed))prior=parsed}catch{}let at2=new Date().toISOString(),state={schemaVersion:1,runId,...outcome.workflowName!==void 0?{workflowName:outcome.workflowName}:{},...outcome.status!==void 0?{status:outcome.status}:{},startedAt:typeof prior.startedAt==="string"?prior.startedAt:at2,updatedAt:at2,...outcome.attached!==void 0?{attached:outcome.attached}:{},...outcome.definitionDigest!==void 0?{definitionDigest:outcome.definitionDigest}:{},...outcome.workflowVersion!==void 0?{workflowVersion:outcome.workflowVersion}:{},...outcome.resolvedPath!==void 0?{resolvedPath:outcome.resolvedPath}:{},...outcome.layer!==void 0?{layer:outcome.layer}:{},...outcome.workdir!==void 0?{workdir:outcome.workdir}:{},ok:outcome.ok,...outcome.ok===!1&&outcome.error!==void 0?{error:outcome.error}:{}},temp=`${statePath}.tmp`;try{writeFileSync4(temp,`${JSON.stringify(state,null,4)}
|
|
1565
|
+
${details}`)}async function loadMergedConfig(layers,opts,validateJsonSchema2){let globalRaw=layers.global!==void 0?await readRawYamlLayer(layers.global,"global"):{},projectRaw=layers.project!==void 0?await readRawYamlLayer(layers.project,"project"):{},replacementFile=projectConfigReplacement(layers);if(layers.global!==void 0)assertNoRetiredTeamKey(globalRaw,layers.global,replacementFile),assertNoGlobalFleetSection(globalRaw,layers.global,replacementFile);if(layers.project!==void 0)assertNoRetiredTeamKey(projectRaw,layers.project,replacementFile);let merged=mergeSpurConfigLayers(globalRaw,projectRaw);if(validateJsonSchema2){let source=layers.project??layers.global??"";try{await validateDeclaredJsonSchema(merged,source,schemaValidationContext(opts))}catch(error51){throw enrichSchemaViolationError(error51,merged,globalRaw,projectRaw,layers)}}return parseMergedWithProvenance(merged,globalRaw,projectRaw,layers)}init_dist6();init_dist2();var EMBEDDED_SCHEMA_PREFIX="\x00embedded-spur",SPUR_SCHEMA_MANIFEST="@gobing-ai/spur/package.json";function normalizeLayerPath(cwd,path8){return resolve5(cwd,path8)}function workflowLayers(opts){let sharedRoot=opts.sharedRoot!==void 0?opts.sharedRoot:bundledConfigRoot(),sharedPath=sharedRoot!==null?normalizeLayerPath(opts.cwd,join8(sharedRoot,"workflows")):null,layers=[],seen=new Set,add=(id,path8)=>{if(seen.has(path8))return;seen.add(path8),layers.push({id,path:path8})};add("project",normalizeLayerPath(opts.cwd,join8(opts.cwd,".spur","workflows")));for(let entry of opts.registered){if(sharedPath!==null&&normalizeLayerPath(opts.cwd,entry)===sharedPath)continue;add("registered",normalizeLayerPath(opts.cwd,entry))}if(sharedPath!==null)add("shared",sharedPath);return layers}function createEmbeddedSchemaOptions(embedded){if(embedded===void 0||embedded.size===0)return;let nodeFs=createNodeFileSystem2();return{resolve:(specifier)=>specifier===SPUR_SCHEMA_MANIFEST?`${EMBEDDED_SCHEMA_PREFIX}/package.json`:specifier,fileSystem:{readFile:async(path8)=>{if(!path8.startsWith(EMBEDDED_SCHEMA_PREFIX))return nodeFs.readFile(path8);let subpath=path8.slice(EMBEDDED_SCHEMA_PREFIX.length+1),text3=embedded.get(subpath);if(text3===void 0)throw Error(`No embedded schema registered for "${subpath}".`);return text3}}}}async function readWorkflowNameFast(fs2,filePath){try{let text3=await fs2.readFile(filePath),parsed=$parse(text3);return typeof parsed?.name==="string"?parsed.name:null}catch{return null}}async function scanWorkflowByName(cwd,name,registered){let fs2=createNodeFileSystem2();for(let layer of workflowLayers({cwd,registered}))try{let files=(await fs2.readDir(layer.path)).filter((f)=>f.endsWith(".yaml")||f.endsWith(".yml"));for(let f of files){let abs=join8(layer.path,f);if(await readWorkflowNameFast(fs2,abs)===name)return{path:abs,source:layer.id}}}catch{}return null}function resolveWorkflowFile(cwd,file2){let fs2=createNodeFileSystem2(),projectPath=resolve5(cwd,file2);if(fs2.exists(projectPath))return{path:projectPath,source:"project"};let isYaml=file2.endsWith(".yaml")||file2.endsWith(".yml"),base2=basename3(file2);if(!isAbsolute2(file2)){let withYaml=isYaml?file2:`${file2}.yaml`,projectSpur=resolve5(cwd,".spur","workflows",withYaml);if(fs2.exists(projectSpur))return{path:projectSpur,source:"project"};if(!isYaml){let projectDirect=resolve5(cwd,`${file2}.yaml`);if(fs2.exists(projectDirect))return{path:projectDirect,source:"project"};let projectSpurPipeline=resolve5(cwd,".spur","workflows",`${file2}-pipeline.yaml`);if(fs2.exists(projectSpurPipeline))return{path:projectSpurPipeline,source:"project"};let projectDirectPipeline=resolve5(cwd,`${file2}-pipeline.yaml`);if(fs2.exists(projectDirectPipeline))return{path:projectDirectPipeline,source:"project"}}}let bundledRoot=bundledConfigRoot();if(bundledRoot!==null){let sharedName=isYaml?base2:`${base2}.yaml`,sharedPath=join8(bundledRoot,"workflows",sharedName);if(fs2.exists(sharedPath))return{path:sharedPath,source:"shared"};if(!isYaml){let sharedPipeline=join8(bundledRoot,"workflows",`${base2}-pipeline.yaml`);if(fs2.exists(sharedPipeline))return{path:sharedPipeline,source:"shared"};let sharedLiteral=join8(bundledRoot,"workflows",base2);if(fs2.exists(sharedLiteral))return{path:sharedLiteral,source:"shared"}}return{path:null,probed:[projectPath,sharedPath]}}return{path:null,probed:[projectPath,null]}}async function resolveWorkflowDefinition(cwd,fileOrName,options={}){let registered=options.registered??[],resolved=(basename3(fileOrName)===fileOrName&&!/\.ya?ml$/.test(fileOrName)&&!createNodeFileSystem2().exists(resolve5(cwd,fileOrName))?await scanWorkflowByName(cwd,fileOrName,registered):null)??resolveWorkflowFile(cwd,fileOrName);if(resolved.path===null){let scanned=await scanWorkflowByName(cwd,fileOrName,registered);if(scanned!==null)resolved=scanned;else{let[probedProject,probedShared]=resolved.probed;throw Error(`Workflow not found: ${probedProject}${probedShared!==null?` (shared: ${probedShared})`:""}`)}}let embedded=createEmbeddedSchemaOptions(options.embeddedSchemas),workflow=await loadWorkflowDef(resolved.path,{validateSchema:options.validateSchema!==!1,...embedded!==void 0?embedded:{}});if(workflow.version==="")throw Error(`Invalid workflow definition ${resolved.path}: root "version" is an empty string. Omit the field for an unversioned definition, or give it a non-empty literal.`);let digest=computeDefinitionDigest(workflow);return{path:resolved.path,workflow,digest,layer:resolved.source}}var TRIPWIRE_CATALOG=Object.freeze({"retry-exhausted":{id:"retry-exhausted",version:1,response:"fail",nextDecision:"Retries are exhausted; an operator must decide to escalate, extend the retry policy, or fail the stage. No further automatic retry is permitted."},"hard-budget":{id:"hard-budget",version:1,response:"fail",nextDecision:"An operator must raise the declared budget or trim the stage scope, then re-run the action; the run stays failed until then."},"capability-denied":{id:"capability-denied",version:1,response:"fail",nextDecision:"An operator must attest the executor capabilities in agent config or lower the stage requiresCapabilities, then re-run the action."},"proof-invalidated":{id:"proof-invalidated",version:1,response:"fail",nextDecision:"An operator must restore the proof inputs or re-establish the verdict (re-verify) before record; recording against a changed tree is blocked."},"output-drop":{id:"output-drop",version:1,response:"continue",nextDecision:"The dispatch completed but its captured evidence is incomplete (bounded relay dropped chunks). Inspect the session/trace for full output if the result is contested."}});var{copyFile,link,mkdir,readFile,unlink,writeFile}=await import("node:fs/promises");var field=(path8,label)=>({path:path8,label}),SOURCE_PROFILES={planning:{producerPackage:"spur",subsystem:"planning",remediationKind:"prefix-filter"},queue:{producerPackage:"@gobing-ai/ts-infra",subsystem:"job-queue",remediationKind:"prefix-filter"},scheduler:{producerPackage:"@gobing-ai/ts-infra",subsystem:"scheduler",remediationKind:"prefix-filter"},message:{producerPackage:"spur",subsystem:"coordination-messaging",remediationKind:"prefix-filter"},process:{producerPackage:"@gobing-ai/ts-runtime",subsystem:"process-executor",remediationKind:"prefix-filter"},workflow:{producerPackage:"@gobing-ai/ts-dual-workflow-engine",subsystem:"workflow",remediationKind:"workflow-trace"},rule:{producerPackage:"@gobing-ai/ts-rule-engine",subsystem:"rule-engine",remediationKind:"rule-trace"},agent:{producerPackage:"@gobing-ai/ts-ai-runner",subsystem:"agent-runner",remediationKind:"prefix-filter"},history:{producerPackage:"spur",subsystem:"history",remediationKind:"prefix-filter"},bus:{producerPackage:"@gobing-ai/ts-infra",subsystem:"event-bus",remediationKind:"prefix-filter"},api:{producerPackage:"spur",subsystem:"http-api",remediationKind:"prefix-filter"}};function at(data,path8){if(data===null)return;let current=data;for(let segment of path8.split(".")){if(current===null||typeof current!=="object"||Array.isArray(current))return;current=current[segment]}return current}function s2(data,...paths){for(let path8 of paths){let value=at(data,path8);if(typeof value==="string"&&value.length>0)return value}return}function n2(data,...paths){for(let path8 of paths){let value=at(data,path8);if(typeof value==="number"&&Number.isFinite(value))return String(value);if(typeof value==="boolean")return String(value)}return}function entityId(input){return s2(input.data,"entity.id")??input.correlation.entityId??""}function looksLikeOpaqueId(value){if(typeof value!=="string")return!1;let v=value.trim();if(v==="")return!1;if(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(v))return!0;if(/^live[-_][a-z0-9._-]+$/i.test(v))return!0;if(/^(?:eventId|rowId|runId|executionId|actionId)$/i.test(v))return!0;return!1}function humanWorkflowTitle(input){let raw=s2(input.data,"workflowName")??s2(input.data,"workflow");if(raw!==void 0&&!looksLikeOpaqueId(raw))return(raw.split("/").pop()?.replace(/\.(?:ya?ml|json)$/i,"")??raw).replace(/[._-]+$/,"");return""}function humanStepLabel(data){let label=s2(data,"nodeLabel")??s2(data,"stepName")??s2(data,"step");if(label!==void 0&&!looksLikeOpaqueId(label))return label;let node=s2(data,"node");if(node!==void 0&&!looksLikeOpaqueId(node))return node;return}function derivedFrom(...paths){return{support:"derived",derive:({data})=>s2(data,...paths)}}function derivedFromValue(...paths){return{support:"derived",derive:({data})=>n2(data,...paths)??s2(data,...paths)}}var unsupported={support:"unsupported"};function baseEvent(name,source,renderer,payloadPolicy="metadata-only",tier="default",producer){return{name,source,tier,payloadPolicy,renderer,...producer!==void 0?{producer}:{}}}var BASE_CATALOG=[baseEvent("task.created","planning","planning"),baseEvent("task.updated","planning","planning"),baseEvent("task.transitioned","planning","planning"),baseEvent("feature.created","planning","planning"),baseEvent("feature.updated","planning","planning"),baseEvent("feature.transitioned","planning","planning"),baseEvent("queue.consumer.started","queue","queue"),baseEvent("queue.consumer.stopped","queue","queue"),baseEvent("queue.job.enqueued","queue","queue"),baseEvent("queue.job.started","queue","queue"),baseEvent("queue.job.completed","queue","queue"),baseEvent("queue.job.failed","queue","queue"),baseEvent("queue.job.retrying","queue","queue"),baseEvent("queue.stats","queue","queue"),baseEvent("scheduler.job.executed","scheduler","scheduler"),baseEvent("message.sent","message","message"),baseEvent("message.replied","message","message"),baseEvent("process.spawned","process","process"),baseEvent("process.exited","process","process"),baseEvent("process.stopped","process","process"),baseEvent("process.started","process","process"),baseEvent("agent.invoke.start","agent","agent"),baseEvent("agent.invoke.exit","agent","agent"),baseEvent("agent.invoke.escalated","agent","agent","metadata-only","default",{package:"spur",subsystem:"agent-runner"}),baseEvent("agent.invoke.exhausted","agent","agent","metadata-only","default",{package:"spur",subsystem:"agent-runner"}),baseEvent("agent.started","agent","agent"),baseEvent("agent.stopped","agent","agent"),baseEvent("agent.message.sent","agent","agent"),baseEvent("agent.lifecycle.changed","agent","agent"),baseEvent("strategy.changed","agent","agent","metadata-only","default",{package:"spur",subsystem:"fleet-strategy"}),baseEvent("fleet.capacity.changed","agent","agent","metadata-only","default",{package:"spur",subsystem:"write-slot"}),baseEvent("task.assigned","planning","planning"),baseEvent("history.import.completed","history","history-import"),baseEvent("history.analyze.completed","history","history-analyze"),baseEvent("history.daily.failed","history","history-daily"),baseEvent("history.refresh.enqueued","history","history-refresh"),baseEvent("rule.run.start","rule","rule"),baseEvent("rule.eval.start","rule","rule"),baseEvent("rule.eval.done","rule","rule"),baseEvent("rule.eval.error","rule","rule"),baseEvent("rule.run.done","rule","rule"),baseEvent("workflow.run.started","workflow","workflow-run"),baseEvent("workflow.run.done","workflow","workflow-run"),baseEvent("workflow.run.failed","workflow","workflow-run"),baseEvent("workflow.run.finalized","workflow","workflow-run"),baseEvent("workflow.escalation.created","workflow","workflow-run","redacted"),baseEvent("workflow.escalation.projection_failed","workflow","workflow-run","metadata-only"),baseEvent("workflow.run.paused","workflow","workflow-run"),baseEvent("workflow.run.resumed","workflow","workflow-run"),baseEvent("workflow.run.reseeded","workflow","workflow-run"),baseEvent("workflow.node.enter","workflow","workflow-phase"),baseEvent("workflow.phase","workflow","workflow-phase"),baseEvent("workflow.node.transition","workflow","workflow-transition"),baseEvent("workflow.transition","workflow","workflow-transition"),baseEvent("workflow.transition.requested","workflow","workflow-transition","metadata-only","diagnostic"),baseEvent("workflow.transition.denied","workflow","workflow-transition","metadata-only","diagnostic"),baseEvent("workflow.action.started","workflow","workflow-action"),baseEvent("workflow.action.finished","workflow","workflow-action"),baseEvent("workflow.action.failed_continue","workflow","workflow-action"),baseEvent("workflow.guard.evaluated","workflow","workflow-guard","metadata-only","diagnostic"),baseEvent("workflow.hitl.ask","workflow","workflow-hitl","redacted"),baseEvent("workflow.hitl.response","workflow","workflow-hitl","redacted"),baseEvent("workflow.hitl.note","workflow","workflow-hitl","redacted"),baseEvent("workflow.custom","workflow","workflow-custom"),baseEvent("workflow.agent","workflow","workflow-agent","redacted","diagnostic"),baseEvent("workflow.steering","workflow","workflow-steering","redacted"),baseEvent("api.request.error","api","api"),baseEvent("bus.emit.done","bus","bus","metadata-only","diagnostic"),baseEvent("bus.emit.noop","bus","bus","metadata-only","diagnostic"),baseEvent("bus.handler.error","bus","bus","metadata-only","diagnostic"),baseEvent("bus.handler.async.enqueued","bus","bus","metadata-only","diagnostic")],SYSTEM_EVENT_PRESENTERS={"task.created":{description:"A task file was created with a new WBS id.",fields:[field("entity.kind","Entity kind"),field("entity.id","Entity")],summary:({data,correlation})=>`[task] ${entityId({data,correlation})} created`,outcome:unsupported},"task.updated":{description:"An existing task file was updated in place, naming the section that changed.",fields:[field("entity.kind","Entity kind"),field("entity.id","Entity"),field("field","Field"),field("data.mutation.name","Section"),field("data.after","After"),field("data.diff","Diff")],summary:({data,correlation})=>{let section=s2(data,"data.mutation.name"),id=entityId({data,correlation});return section!==void 0?`[task] ${section}`:`[task] ${id||"updated"}`},outcome:unsupported},"task.transitioned":{description:"A task moved between lifecycle states, naming both the previous and new status.",fields:[field("entity.kind","Entity kind"),field("entity.id","Entity"),field("from","From"),field("to","To")],summary:({data,correlation})=>{let id=entityId({data,correlation}),from=s2(data,"from"),to=s2(data,"to");return from!==void 0&&to!==void 0?`[task] ${id} : ${from} -> ${to}`:`[task] ${id} transitioned`},outcome:{support:"derived",derive:({data})=>s2(data,"to")}},"feature.created":{description:"A feature file was created with a new feature id.",fields:[field("entity.kind","Entity kind"),field("entity.id","Entity")],summary:({data,correlation})=>`[feature] ${entityId({data,correlation})} created`,outcome:unsupported},"feature.updated":{description:"An existing feature file was updated in place, naming the section that changed.",fields:[field("entity.kind","Entity kind"),field("entity.id","Entity"),field("field","Field"),field("data.mutation.name","Section"),field("data.after","After"),field("data.diff","Diff")],summary:({data,correlation})=>{let section=s2(data,"data.mutation.name"),id=entityId({data,correlation});return section!==void 0?`[feature] ${section}`:`[feature] ${id||"updated"}`},outcome:unsupported},"feature.transitioned":{description:"A feature moved between lifecycle states, naming both the previous and new status.",fields:[field("entity.kind","Entity kind"),field("entity.id","Entity"),field("from","From"),field("to","To")],summary:({data,correlation})=>{let id=entityId({data,correlation}),from=s2(data,"from"),to=s2(data,"to");return from!==void 0&&to!==void 0?`[feature] ${id} : ${from} -> ${to}`:`[feature] ${id} transitioned`},outcome:{support:"derived",derive:({data})=>s2(data,"to")}},"queue.consumer.started":{description:"The configured queue consumer began polling its named queue.",fields:[field("queueName","Queue"),field("startedAt","Started"),field("pollInterval","Poll interval"),field("batchSize","Batch size"),field("maxConcurrency","Max concurrency"),field("visibilityTimeout","Visibility timeout")],summary:({data})=>{let name=s2(data,"queueName");return name!==void 0?`[queue] ${name} : consumer started`:"[queue] consumer started"},outcome:{support:"derived",derive:({data})=>at(data,"startedAt")!==void 0?"running":void 0}},"queue.consumer.stopped":{description:"The queue consumer stopped, reporting whether it drained in-flight work.",fields:[field("queueName","Queue"),field("stoppedAt","Stopped"),field("drainTimeoutMs","Drain timeout"),field("inFlightAtStop","In flight"),field("drained","Drained")],summary:({data})=>{let name=s2(data,"queueName");return name!==void 0?`[queue] ${name} : consumer stopped`:"[queue] consumer stopped"},outcome:{support:"derived",derive:({data})=>{let drained=at(data,"drained");if(drained===!0)return"drained";if(drained===!1)return"timeout";return}}},"queue.job.enqueued":{description:"A job was enqueued onto the job queue for later processing.",fields:[field("jobId","Job"),field("type","Type"),field("nextRetryAt","Next retry")],summary:({data})=>{let type=s2(data,"type"),jobId=s2(data,"jobId");return type!==void 0&&jobId!==void 0?`[queue] ${type} · job ${jobId} enqueued`:"[queue] job enqueued"},outcome:unsupported},"queue.job.started":{description:"A queued job handler began executing (job identity and phase anchor).",fields:[field("jobId","Job"),field("type","Type"),field("name","Name")],summary:({data})=>{let type=s2(data,"type"),jobId=s2(data,"jobId");return type!==void 0&&jobId!==void 0?`[queue] ${type} · job ${jobId} started`:"[queue] job started"},outcome:unsupported},"queue.job.completed":{description:"A queued job finished successfully with its attempt and duration.",fields:[field("jobId","Job"),field("type","Type"),field("attempt","Attempt"),field("durationMs","Duration (ms)")],summary:({data})=>{let type=s2(data,"type"),jobId=s2(data,"jobId");return type!==void 0&&jobId!==void 0?`[queue] ${type} · job ${jobId} completed`:"[queue] job completed"},outcome:unsupported},"queue.job.failed":{description:"A queued job exhausted its attempts and failed with an error.",fields:[field("jobId","Job"),field("type","Type"),field("attempt","Attempt"),field("maxRetries","Max retries"),field("durationMs","Duration (ms)"),field("error","Error")],summary:({data})=>{let type=s2(data,"type"),jobId=s2(data,"jobId");return type!==void 0&&jobId!==void 0?`[queue] ${type} · job ${jobId} failed`:"[queue] job failed"},outcome:derivedFrom("error")},"queue.job.retrying":{description:"A queued job failed once and is scheduled for another attempt.",fields:[field("jobId","Job"),field("type","Type"),field("attempt","Attempt"),field("maxRetries","Max retries"),field("nextRetryAt","Next retry"),field("error","Error")],summary:({data})=>{let type=s2(data,"type"),jobId=s2(data,"jobId");return type!==void 0&&jobId!==void 0?`[queue] ${type} · job ${jobId} retrying`:"[queue] job retrying"},outcome:{support:"derived",derive:({data})=>{let attempt=at(data,"attempt"),max=at(data,"maxRetries");if(typeof attempt==="number"&&typeof max==="number"&&Number.isFinite(attempt)&&Number.isFinite(max))return`retrying ${attempt}/${max}`;return s2(data,"error")}}},"queue.stats":{description:"Periodic job-queue statistics across ready, running, completed, and failed counts.",fields:[field("ready","Ready"),field("running","Running"),field("completed","Completed"),field("failed","Failed")],summary:()=>"[queue] stats",outcome:unsupported},"scheduler.job.executed":{description:"A scheduler job ran to completion or failed, with its duration.",fields:[field("name","Job"),field("action","Action"),field("durationMs","Duration (ms)"),field("error","Error")],summary:({data})=>{let name=s2(data,"name");return name!==void 0?`[scheduler] ${name}`:"[scheduler] job executed"},outcome:{support:"derived",derive:({data})=>s2(data,"error")??(at(data,"error")===null?"completed":void 0)}},"message.sent":{description:"A team message was sent from one member to another.",fields:[field("msgId","Message"),field("fromId","From"),field("toId","To"),field("threadId","Thread")],summary:({data})=>{let from=s2(data,"fromId"),to=s2(data,"toId");return from!==void 0&&to!==void 0?`[message] ${from} -> ${to}`:"[message] sent"},outcome:unsupported},"message.replied":{description:"A member replied to an existing message thread.",fields:[field("msgId","Message"),field("fromId","From"),field("toId","To"),field("threadId","Thread")],summary:({data})=>{let from=s2(data,"fromId"),thread=s2(data,"threadId");return from!==void 0&&thread!==void 0?`[message] ${from} replied in ${thread}`:"[message] replied"},outcome:unsupported},"process.spawned":{description:"A supervised process was spawned with a new pid.",fields:[field("label","Label"),field("pid","PID"),field("agentId","Agent")],summary:({data})=>{let label=s2(data,"label")??n2(data,"pid");return label!==void 0?`[process] ${label} spawned`:"[process] spawned"},outcome:unsupported},"process.exited":{description:"A supervised process exited, carrying its exit code, signal, or failure reason.",fields:[field("label","Label"),field("pid","PID"),field("exitCode","Exit code"),field("signal","Signal"),field("durationMs","Duration (ms)"),field("reason","Reason")],summary:({data})=>{let label=s2(data,"label")??n2(data,"pid");return label!==void 0?`[process] ${label} exited`:"[process] exited"},outcome:{support:"derived",derive:({data})=>{let reason=s2(data,"reason");if(reason!==void 0)return reason;let signal=s2(data,"signal");if(signal!==void 0)return`signal ${signal}`;let code=at(data,"exitCode");if(typeof code==="number"&&Number.isFinite(code))return code===0?"ok":`exit ${code}`;return}}},"process.stopped":{description:"A supervised process was stopped, naming the stopping reason.",fields:[field("label","Label"),field("pid","PID"),field("signal","Signal"),field("reason","Reason")],summary:({data})=>{let label=s2(data,"label")??n2(data,"pid");return label!==void 0?`[process] ${label} stopped`:"[process] stopped"},outcome:derivedFrom("reason")},"process.started":{description:"A process executor started a process with a new pid.",fields:[field("label","Label"),field("pid","PID")],summary:({data})=>{let label=s2(data,"label")??n2(data,"pid");return label!==void 0?`[process] ${label} started`:"[process] started"},outcome:unsupported},"agent.invoke.start":{description:"An agent invocation began, naming the agent and its operation.",fields:[field("agent","Agent"),field("operation","Operation"),field("routing.role","Role"),field("routing.tier","Tier"),field("routing.executor","Executor"),field("routing.source","Selection source")],summary:({data})=>{let agent=s2(data,"agent"),operation=s2(data,"operation");return agent!==void 0&&operation!==void 0?`[agent] ${agent} · ${operation}`:"[agent] invocation started"},outcome:unsupported},"agent.invoke.exit":{description:"An agent invocation exited, reporting its exit code or signal.",fields:[field("agent","Agent"),field("operation","Operation"),field("exitCode","Exit code"),field("signal","Signal"),field("routing.role","Role"),field("routing.tier","Tier"),field("routing.executor","Executor"),field("routing.source","Selection source")],summary:({data})=>{let agent=s2(data,"agent"),operation=s2(data,"operation");return agent!==void 0&&operation!==void 0?`[agent] ${agent} · ${operation} exited`:"[agent] invocation exited"},outcome:{support:"derived",derive:({data})=>{let signal=s2(data,"signal");if(signal!==void 0)return`signal ${signal}`;let code=at(data,"exitCode");if(typeof code==="number"&&Number.isFinite(code))return code===0?"ok":`exit ${code}`;return}}},"agent.invoke.escalated":{description:"An agent invocation escalated from one executor tier to another.",fields:[field("fromExecutor","From executor"),field("fromTier","From tier"),field("toExecutor","To executor"),field("toTier","To tier"),field("trigger","Trigger")],summary:({data})=>{let from=s2(data,"fromExecutor"),to=s2(data,"toExecutor");return from!==void 0&&to!==void 0?`[agent] ${from} -> ${to}`:"[agent] escalation"},outcome:{support:"derived",derive:({data})=>s2(data,"toTier")??s2(data,"trigger")}},"agent.invoke.exhausted":{description:"An agent invocation exhausted every eligible executor tier without success.",fields:[field("stage","Stage"),field("attempts","Attempts"),field("fromTier","From tier"),field("toTier","To tier"),field("fromExecutor","From executor"),field("toExecutor","To executor")],summary:({data})=>{let stage=s2(data,"stage");return stage!==void 0?`[agent] ${stage} escalation exhausted`:"[agent] escalation exhausted"},outcome:derivedFromValue("attempts")},"agent.started":{description:"An agent started, carrying its id and type.",fields:[field("agentId","Agent"),field("agentType","Agent type"),field("pid","PID")],summary:({data})=>{let id=s2(data,"agentId");return id!==void 0?`[agent] ${id} started`:"[agent] started"},outcome:unsupported},"agent.stopped":{description:"An agent stopped, reporting its exit code.",fields:[field("agentId","Agent"),field("exitCode","Exit code")],summary:({data})=>{let id=s2(data,"agentId");return id!==void 0?`[agent] ${id} stopped`:"[agent] stopped"},outcome:derivedFromValue("exitCode")},"strategy.changed":{description:"A project strategy changed (0838), minting a new strategy version for dispatch fencing.",fields:[field("data.projectPath","Project"),field("data.strategy","Strategy"),field("data.version","Version")],summary:({data})=>{let strategy=s2(data,"data.strategy"),version3=s2(data,"data.version");return strategy!==void 0?`[strategy] ${strategy}${version3!==void 0?` (v${version3})`:""}`:"[strategy] changed"},outcome:unsupported},"fleet.capacity.changed":{description:"The project write slot was claimed or released (0837), changing dispatch capacity.",fields:[field("data.projectPath","Project"),field("data.change","Change"),field("data.holderId","Holder")],summary:({data})=>{let change=s2(data,"data.change"),holder=s2(data,"data.holderId");return`[fleet] write slot ${change??"changed"}${holder!==void 0?` — ${holder}`:""}`},outcome:unsupported},"agent.lifecycle.changed":{description:"A fleet member reported its lifecycle state through a host hook (G73): working, idle, or blocked on a human (a permission prompt).",fields:[field("member","Member"),field("state","State"),field("seq","Sequence")],summary:({data})=>{let member=s2(data,"member"),state=s2(data,"state");return member!==void 0?`[agent] ${member} · ${state??"state"}`:"[agent] lifecycle changed"},outcome:{support:"derived",derive:({data})=>s2(data,"state")}},"agent.message.sent":{description:"A message was sent to an agent, reporting delivery success.",fields:[field("agentId","Agent"),field("ok","Delivered")],summary:({data})=>{let id=s2(data,"agentId");return id!==void 0?`[agent] message -> ${id}`:"[agent] message sent"},outcome:derivedFromValue("ok")},"task.assigned":{description:"A task was assigned to an agent, naming the agent when resolved.",fields:[field("memberId","Member"),field("agentType","Agent type"),field("taskId","Task"),field("outcome","Outcome")],summary:({data})=>{let member=s2(data,"memberId"),task=s2(data,"taskId");return task!==void 0&&member!==void 0?`[task] ${task} assigned to ${member}`:"[task] assignment recorded"},outcome:derivedFrom("outcome")},"history.import.completed":{description:"A history import finished, reporting files, messages, and exit code.",fields:[field("source","Source"),field("sources","Sources"),field("files","Files"),field("messages","Messages"),field("durationMs","Duration (ms)"),field("exitCode","Exit code"),field("artifactPath","Artifact"),field("cwd","Project root")],retain:[field("trigger","Refresh trigger"),field("windowStart","Refresh window start"),field("windowEnd","Refresh window end"),field("importMode","Import mode"),field("coverage","Refresh coverage")],summary:({data})=>{let source=s2(data,"source")??s2(data,"sources");return source!==void 0?`[history] import · ${source}`:"[history] import completed"},outcome:derivedFromValue("exitCode")},"history.analyze.completed":{description:"A history analyze pass finished, reporting sources, duration, and exit code.",fields:[field("source","Source"),field("sources","Sources"),field("durationMs","Duration (ms)"),field("exitCode","Exit code"),field("artifactPath","Artifact")],retain:[field("trigger","Refresh trigger"),field("windowStart","Refresh window start"),field("windowEnd","Refresh window end"),field("importMode","Import mode")],summary:({data})=>{let source=s2(data,"source")??s2(data,"sources");return source!==void 0?`[history] analyze · ${source}`:"[history] analyze completed"},outcome:derivedFromValue("exitCode")},"history.daily.failed":{description:"The daily history refresh failed, carrying the detail, reason, and exit code.",fields:[field("source","Source"),field("sources","Sources"),field("detail","Detail"),field("reason","Reason"),field("exitCode","Exit code")],retain:[field("trigger","Refresh trigger"),field("windowStart","Refresh window start"),field("windowEnd","Refresh window end"),field("importMode","Import mode")],summary:()=>"[history] daily failed",outcome:{support:"derived",derive:({data})=>s2(data,"reason")??s2(data,"detail")??n2(data,"exitCode")}},"history.refresh.enqueued":{description:"A completion-triggered history refresh was enqueued, naming its window.",fields:[field("trigger","Trigger"),field("triggerId","Trigger id"),field("jobId","Queue job"),field("windowStart","Window start"),field("windowEnd","Window end"),field("coalesced","Coalesced"),field("outcome","Outcome")],summary:({data})=>{let start=s2(data,"windowStart"),end=s2(data,"windowEnd");return start!==void 0&&end!==void 0?`[history] refresh · ${start} -> ${end}`:"[history] refresh enqueued"},outcome:{support:"derived",derive:({data})=>{let status=s2(data,"outcome");return status!==void 0&&status!=="enqueued"?status:void 0}}},"rule.run.start":{description:"A rule run began with the rule count it will evaluate.",fields:[field("runId","Run"),field("ruleCount","Rules"),field("evaluator","Evaluator")],summary:({data,correlation})=>{let run=s2(data,"runId")??correlation.runId;return run!==void 0?`[rule] run ${run} started`:"[rule] run started"},outcome:unsupported},"rule.eval.start":{description:"A single rule began evaluating.",fields:[field("runId","Run"),field("ruleId","Rule"),field("evaluator","Evaluator"),field("index","Index"),field("total","Total")],summary:({data})=>{let id=s2(data,"ruleId");return id!==void 0?`[rule] ${id} evaluating`:"[rule] evaluating"},outcome:unsupported},"rule.eval.done":{description:"A rule finished evaluating, reporting its findings count and severity.",fields:[field("runId","Run"),field("ruleId","Rule"),field("evaluator","Evaluator"),field("findings","Findings"),field("durationMs","Duration (ms)"),field("severity","Severity")],summary:({data})=>{let id=s2(data,"ruleId");return id!==void 0?`[rule] ${id} evaluated`:"[rule] evaluated"},outcome:derivedFromValue("findings")},"rule.eval.error":{description:"A rule evaluation failed with an error.",fields:[field("runId","Run"),field("ruleId","Rule"),field("evaluator","Evaluator"),field("error","Error")],summary:({data})=>{let id=s2(data,"ruleId");return id!==void 0?`[rule] ${id} error`:"[rule] error"},outcome:derivedFrom("error")},"rule.run.done":{description:"A rule run finished, reporting findings and whether it stopped early.",fields:[field("runId","Run"),field("findings","Findings"),field("durationMs","Duration (ms)"),field("stoppedEarly","Stopped early"),field("severity","Severity")],summary:({data,correlation})=>{let run=s2(data,"runId")??correlation.runId;return run!==void 0?`[rule] run ${run} done`:"[rule] run done"},outcome:{support:"derived",derive:({data})=>n2(data,"findings")??s2(data,"stoppedEarly")}},"workflow.run.started":{description:"A workflow run started, naming the workflow definition.",fields:[field("runId","Run"),field("workflowName","Workflow"),field("mode","Mode"),field("dryRun","Dry run")],summary:(input)=>{let name=humanWorkflowTitle(input);return name!==""?`[workflow] ${name} started`:"[workflow] started"},outcome:unsupported},"workflow.run.done":{description:"A workflow run reached a done terminal state.",fields:[field("runId","Run"),field("workflowName","Workflow"),field("finalState","Final state"),field("transitionsTaken","Transitions")],summary:(input)=>{let name=humanWorkflowTitle(input);return name!==""?`[workflow] ${name} done`:"[workflow] done"},outcome:derivedFrom("finalState")},"workflow.run.failed":{description:"A workflow run failed with a terminal failure reason.",fields:[field("runId","Run"),field("workflowName","Workflow"),field("finalState","Final state"),field("reason","Reason")],summary:(input)=>{let name=humanWorkflowTitle(input);return name!==""?`[workflow] ${name} failed`:"[workflow] failed"},outcome:derivedFrom("reason")},"workflow.run.finalized":{description:"A workflow run settled on a terminal status.",fields:[field("runId","Run"),field("workflowName","Workflow"),field("status","Status")],summary:(input)=>{let name=humanWorkflowTitle(input);return name!==""?`[workflow] ${name} finalized`:"[workflow] finalized"},outcome:derivedFrom("status")},"workflow.escalation.created":{description:"A canonical escalation packet was projected from existing run evidence.",fields:[field("runId","Run"),field("workflowName","Workflow"),field("fingerprint","Fingerprint"),field("artifactPath","Artifact"),field("decision","Decision")],summary:(input)=>{let name=humanWorkflowTitle(input),decision=typeof at(input.data,"decision")==="string"?` — ${String(at(input.data,"decision"))}`:"";return name!==""?`[workflow] escalation packet created (${name}${decision})`:`[workflow] escalation packet created${decision}`},outcome:derivedFrom("decision")},"workflow.escalation.projection_failed":{description:"Escalation packet projection failed; the original failure is preserved untouched.",fields:[field("runId","Run"),field("workflowName","Workflow"),field("error","Error")],summary:()=>"[workflow] escalation packet projection failed",outcome:derivedFrom("error")},"workflow.run.paused":{description:"A workflow run paused at a step, naming the step when available.",fields:[field("runId","Run"),field("workflowName","Workflow"),field("nodeLabel","Step"),field("node","Node"),field("transitionsTaken","Transitions")],summary:(input)=>{let name=humanWorkflowTitle(input),step=humanStepLabel(input.data),parts=[name,step].filter((part)=>typeof part==="string"&&part!=="");return parts.length>0?`[workflow] ${parts.join(" · ")} paused`:"[workflow] paused"},outcome:unsupported},"workflow.run.resumed":{description:"A paused workflow run resumed at a step, naming the step when available.",fields:[field("runId","Run"),field("workflowName","Workflow"),field("nodeLabel","Step"),field("node","Node")],summary:(input)=>{let name=humanWorkflowTitle(input),step=humanStepLabel(input.data),parts=[name,step].filter((part)=>typeof part==="string"&&part!=="");return parts.length>0?`[workflow] ${parts.join(" · ")} resumed`:"[workflow] resumed"},outcome:unsupported},"workflow.run.reseeded":{description:"A workflow run was reseeded to a new state, naming the transition.",fields:[field("runId","Run"),field("workflowName","Workflow"),field("fromState","From"),field("toState","To")],summary:(input)=>{let name=humanWorkflowTitle(input),from=s2(input.data,"fromState"),to=s2(input.data,"toState");if(from!==void 0&&to!==void 0)return name!==""?`[workflow] ${name} : ${from} -> ${to}`:`[workflow] : ${from} -> ${to}`;return name!==""?`[workflow] ${name} reseeded`:"[workflow] reseeded"},outcome:derivedFrom("toState")},"workflow.node.enter":{description:"The engine entered a workflow node, naming the step when available.",fields:[field("runId","Run"),field("workflowName","Workflow"),field("nodeLabel","Step"),field("node","Node"),field("transitionsTaken","Transitions")],summary:(input)=>{let name=humanWorkflowTitle(input),step=humanStepLabel(input.data),parts=[name,step].filter((part)=>typeof part==="string"&&part!=="");return parts.length>0?`[workflow] ${parts.join(" · ")}`:"[workflow] node entered"},outcome:unsupported},"workflow.phase":{description:"A workflow phase changed status, naming the phase.",fields:[field("runId","Run"),field("workflowName","Workflow"),field("phase","Phase"),field("status","Status")],summary:(input)=>{let name=humanWorkflowTitle(input),phase=s2(input.data,"phase"),parts=[name,phase].filter((part)=>typeof part==="string"&&part!=="");return parts.length>0?`[workflow] ${parts.join(" · ")}`:"[workflow] phase"},outcome:derivedFrom("status")},"workflow.node.transition":{description:"A workflow transitioned between nodes, naming the from and to states.",fields:[field("runId","Run"),field("workflowName","Workflow"),field("from","From"),field("to","To"),field("trigger","Trigger")],summary:(input)=>{let name=humanWorkflowTitle(input),from=s2(input.data,"from"),to=s2(input.data,"to");if(from!==void 0&&to!==void 0)return name!==""?`[workflow] ${name} : ${from} -> ${to}`:`[workflow] : ${from} -> ${to}`;return name!==""?`[workflow] ${name} transitioned`:"[workflow] transitioned"},outcome:derivedFrom("to")},"workflow.transition":{description:"A workflow state transition was committed.",fields:[field("runId","Run"),field("workflowName","Workflow"),field("from","From"),field("to","To"),field("trigger","Trigger")],summary:(input)=>{let name=humanWorkflowTitle(input),from=s2(input.data,"from"),to=s2(input.data,"to");if(from!==void 0&&to!==void 0)return name!==""?`[workflow] ${name} : ${from} -> ${to}`:`[workflow] : ${from} -> ${to}`;return name!==""?`[workflow] ${name} transitioned`:"[workflow] transitioned"},outcome:derivedFrom("to")},"workflow.transition.requested":{description:"A workflow transition was requested and accepted for evaluation.",fields:[field("runId","Run"),field("workflowName","Workflow"),field("from","From"),field("to","To"),field("trigger","Trigger")],summary:(input)=>{let name=humanWorkflowTitle(input),from=s2(input.data,"from"),to=s2(input.data,"to");if(from!==void 0&&to!==void 0)return name!==""?`[workflow] ${name} requested ${from} -> ${to}`:`[workflow] requested ${from} -> ${to}`;return name!==""?`[workflow] ${name} transition requested`:"[workflow] transition requested"},outcome:unsupported},"workflow.transition.denied":{description:"A workflow transition was denied with a reason.",fields:[field("runId","Run"),field("workflowName","Workflow"),field("from","From"),field("to","To"),field("reason","Reason")],summary:(input)=>{let name=humanWorkflowTitle(input),from=s2(input.data,"from"),to=s2(input.data,"to");if(from!==void 0&&to!==void 0)return name!==""?`[workflow] ${name} denied ${from} -> ${to}`:`[workflow] denied ${from} -> ${to}`;return name!==""?`[workflow] ${name} transition denied`:"[workflow] transition denied"},outcome:derivedFrom("reason")},"workflow.action.started":{description:"A workflow action began executing, naming the step and kind.",fields:[field("runId","Run"),field("workflowName","Workflow"),field("nodeLabel","Step"),field("node","Node"),field("actionId","Action"),field("kind","Kind")],retain:[field("metadata.agent","Agent"),field("metadata.role","Role"),field("routing.executor","Executor")],summary:(input)=>{let name=humanWorkflowTitle(input),step=humanStepLabel(input.data),parts=[name,step].filter((part)=>typeof part==="string"&&part!=="");return parts.length>0?`[workflow] ${parts.join(" · ")} started`:"[workflow] action started"},outcome:unsupported},"workflow.action.finished":{description:"A workflow action finished, reporting its status and success.",fields:[field("runId","Run"),field("workflowName","Workflow"),field("nodeLabel","Step"),field("node","Node"),field("actionId","Action"),field("kind","Kind"),field("durationMs","Duration (ms)"),field("status","Status")],retain:[field("metadata.agent","Agent"),field("metadata.role","Role"),field("routing.executor","Executor")],summary:(input)=>{let name=humanWorkflowTitle(input),step=humanStepLabel(input.data),parts=[name,step].filter((part)=>typeof part==="string"&&part!=="");return parts.length>0?`[workflow] ${parts.join(" · ")} finished`:"[workflow] action finished"},outcome:{support:"derived",derive:({data})=>s2(data,"status")??n2(data,"ok")}},"workflow.action.failed_continue":{description:"A workflow action failed but the workflow continued, carrying the error.",fields:[field("runId","Run"),field("workflowName","Workflow"),field("nodeLabel","Step"),field("node","Node"),field("transitionsTaken","Transitions"),field("error","Error")],retain:[field("metadata.agent","Agent"),field("metadata.role","Role"),field("routing.executor","Executor")],summary:(input)=>{let name=humanWorkflowTitle(input),step=humanStepLabel(input.data),parts=[name,step].filter((part)=>typeof part==="string"&&part!=="");return parts.length>0?`[workflow] ${parts.join(" · ")} failed; continuing`:"[workflow] action failed; continuing"},outcome:derivedFrom("error")},"workflow.guard.evaluated":{description:"A workflow guard was evaluated for a transition, reporting whether it passed.",fields:[field("runId","Run"),field("workflowName","Workflow"),field("from","From"),field("to","To"),field("kind","Kind"),field("passed","Passed")],summary:(input)=>{let name=humanWorkflowTitle(input),from=s2(input.data,"from"),to=s2(input.data,"to");if(from!==void 0&&to!==void 0)return name!==""?`[workflow] ${name} guard ${from} -> ${to}`:`[workflow] guard ${from} -> ${to}`;return name!==""?`[workflow] ${name} guard evaluated`:"[workflow] guard evaluated"},outcome:derivedFromValue("passed")},"workflow.hitl.ask":{description:"A workflow paused for human input, naming the step and kind.",fields:[field("runId","Run"),field("workflowName","Workflow"),field("nodeLabel","Step"),field("node","Node"),field("kind","Kind")],summary:(input)=>{let name=humanWorkflowTitle(input),step=humanStepLabel(input.data),parts=[name,step].filter((part)=>typeof part==="string"&&part!=="");return parts.length>0?`[workflow] ${parts.join(" · ")} awaiting input`:"[workflow] awaiting input"},outcome:unsupported},"workflow.hitl.response":{description:"Human input was received for a paused workflow step.",fields:[field("runId","Run"),field("workflowName","Workflow"),field("nodeLabel","Step"),field("node","Node"),field("ok","Accepted")],summary:(input)=>{let name=humanWorkflowTitle(input),step=humanStepLabel(input.data),parts=[name,step].filter((part)=>typeof part==="string"&&part!=="");return parts.length>0?`[workflow] ${parts.join(" · ")} input received`:"[workflow] input received"},outcome:derivedFromValue("ok")},"workflow.hitl.note":{description:"A note was recorded on a paused workflow step.",fields:[field("runId","Run"),field("workflowName","Workflow"),field("nodeLabel","Step"),field("node","Node")],summary:(input)=>{let name=humanWorkflowTitle(input),step=humanStepLabel(input.data),parts=[name,step].filter((part)=>typeof part==="string"&&part!=="");return parts.length>0?`[workflow] ${parts.join(" · ")} note`:"[workflow] note"},outcome:unsupported},"workflow.custom":{description:"A custom workflow event was emitted, naming the custom event.",fields:[field("runId","Run"),field("workflowName","Workflow"),field("name","Event")],summary:(input)=>{let name=humanWorkflowTitle(input),custom3=s2(input.data,"name"),parts=[name,custom3].filter((part)=>typeof part==="string"&&part!=="");return parts.length>0?`[workflow] ${parts.join(" · ")}`:"[workflow] custom"},outcome:unsupported},"workflow.agent":{description:"A workflow-dispatched agent execution lifecycle event, discriminated by kind.",fields:[field("runId","Run"),field("executionId","Execution"),field("actionId","Action"),field("kind","Kind"),field("agent","Agent"),field("model","Model")],retain:[field("metadata.agent","Agent"),field("metadata.role","Role"),field("routing.executor","Executor")],summary:(input)=>{let name=humanWorkflowTitle(input),kind=s2(input.data,"kind"),parts=[name,kind!==void 0?`agent ${kind}`:"agent"].filter((part)=>typeof part==="string"&&part!=="");return parts.length>0?`[workflow] ${parts.join(" · ")}`:"[workflow] agent"},outcome:{support:"derived",derive:({data})=>s2(data,"kind")==="finished"?s2(data,"outcome"):void 0}},"workflow.steering":{description:"A steering command was acknowledged for a workflow action boundary.",fields:[field("runId","Run"),field("actionId","Action"),field("operation","Operation"),field("actor","Actor"),field("accepted","Accepted"),field("state","State"),field("reason","Reason")],summary:(input)=>{let name=humanWorkflowTitle(input),operation=s2(input.data,"operation"),parts=[name,operation!==void 0?`steering ${operation}`:"steering"].filter((part)=>typeof part==="string"&&part!=="");return parts.length>0?`[workflow] ${parts.join(" · ")}`:"[workflow] steering"},outcome:{support:"derived",derive:({data})=>{let reason=s2(data,"reason");if(reason!==void 0)return reason;let accepted=at(data,"accepted");if(accepted===!0)return"accepted";if(accepted===!1)return"rejected";return s2(data,"state")}}},"api.request.error":{description:"An API request failed, naming the method, path, and status or error code.",fields:[field("method","Method"),field("path","Path"),field("status","Status"),field("code","Code"),field("requestId","Request"),field("error","Error")],summary:({data})=>{let method=s2(data,"method"),path8=s2(data,"path");return method!==void 0&&path8!==void 0?`[api] ${method} ${path8}`:"[api] request error"},outcome:{support:"derived",derive:({data})=>s2(data,"error")??s2(data,"code")??n2(data,"status")}},"bus.emit.done":{description:"An event was emitted to its handlers on the event bus.",fields:[field("event","Event"),field("handlers","Handlers"),field("durationMs","Duration (ms)")],summary:({data})=>{let event=s2(data,"event");return event!==void 0?`[bus] ${event} emitted`:"[bus] event emitted"},outcome:derivedFromValue("handlers")},"bus.emit.noop":{description:"An event was emitted but had no registered handlers.",fields:[field("event","Event"),field("handlers","Handlers"),field("durationMs","Duration (ms)")],summary:({data})=>{let event=s2(data,"event");return event!==void 0?`[bus] ${event} had no handlers`:"[bus] event had no handlers"},outcome:derivedFromValue("handlers")},"bus.handler.error":{description:"An event-bus handler threw an error while processing an event.",fields:[field("event","Event"),field("handlers","Handlers"),field("durationMs","Duration (ms)"),field("error","Error")],summary:({data})=>{let event=s2(data,"event");return event!==void 0?`[bus] ${event} handler error`:"[bus] handler error"},outcome:derivedFrom("error")},"bus.handler.async.enqueued":{description:"An event-bus handler was enqueued for asynchronous processing.",fields:[field("event","Event"),field("handlers","Handlers")],summary:({data})=>{let event=s2(data,"event");return event!==void 0?`[bus] ${event} handlers enqueued`:"[bus] handlers enqueued"},outcome:derivedFromValue("handlers")}};function inferSeverity(name){if(/(?:failed|error|denied)$/.test(name))return"error";if(/(?:retrying|paused|dropped)$/.test(name))return"warning";return"info"}function resolveCatalogEntry(base2){let profile=SOURCE_PROFILES[base2.source],presenter=SYSTEM_EVENT_PRESENTERS[base2.name];return{name:base2.name,prefix:base2.name.split(".")[0]??base2.name,source:base2.source,tier:base2.tier,persisted:!0,streamed:!0,payloadPolicy:base2.payloadPolicy,renderer:base2.renderer,...profile,...base2.producer!==void 0?{producerPackage:base2.producer.package,subsystem:base2.producer.subsystem}:{},severity:inferSeverity(base2.name),description:presenter.description,metadataFields:presenter.retain?[...presenter.fields,...presenter.retain.filter((r)=>!presenter.fields.some((f)=>f.path===r.path))]:presenter.fields,remediationKind:profile.remediationKind}}var SYSTEM_EVENT_CATALOG=BASE_CATALOG.map(resolveCatalogEntry),SYSTEM_EVENT_NAMES=SYSTEM_EVENT_CATALOG.map((entry)=>entry.name),SYSTEM_EVENT_PERSISTED_NAMES=SYSTEM_EVENT_CATALOG.filter((entry)=>entry.tier==="default").map((entry)=>entry.name),SYSTEM_EVENT_STREAMED_NAMES=SYSTEM_EVENT_CATALOG.filter((entry)=>entry.tier==="default").map((entry)=>entry.name),SYSTEM_EVENT_PREFIXES=Array.from(new Set(SYSTEM_EVENT_CATALOG.map((entry)=>entry.prefix))),SYSTEM_EVENT_DEFAULT_NAMES=SYSTEM_EVENT_CATALOG.filter((entry)=>entry.tier==="default").map((entry)=>entry.name),SYSTEM_EVENT_DIAGNOSTIC_NAMES=SYSTEM_EVENT_CATALOG.filter((entry)=>entry.tier==="diagnostic").map((entry)=>entry.name);var SYSTEM_EVENT_CATALOG_METADATA=SYSTEM_EVENT_CATALOG.map(({name,prefix,source,tier,renderer,producerPackage,subsystem,severity,description,metadataFields,remediationKind})=>({name,prefix,source,tier,renderer,producerPackage,subsystem,severity,description,metadataFields,remediationKind}));function workflowVersionLiteral(workflow){return typeof workflow.version==="string"&&workflow.version!==""?workflow.version:null}var{appendFileSync:appendFileSync4,closeSync,existsSync:existsSync5,mkdirSync:mkdirSync3,openSync,readFileSync:readFileSync5,renameSync:renameSync3,unlinkSync:unlinkSync2,writeFileSync:writeFileSync4,writeSync}=await import("node:fs"),{lstat,mkdir:mkdir2,readdir,readFile:readFile2}=await import("node:fs/promises");function parseIdentityMetadata(raw){if(raw.trim()==="")return{};try{let parsed=JSON.parse(raw);if(parsed===null||typeof parsed!=="object"||Array.isArray(parsed))return null;return parsed}catch{return null}}async function openInlineRunProjectDb(workdir){let url2=join9(resolve6(workdir),".spur","spur.db");mkdirSync3(join9(url2,".."),{recursive:!0});let adapter=await createMigratedDb({url:url2});return{adapter,close:()=>adapter.close()}}async function readInstalledInventory(input){let launch=input.spurBin?splitLaunchCommand(input.spurBin,'inline-run-setup "spurBin"'):existsSync5(input.localCli)?{command:"bun",leadingArgs:[input.localCli]}:{command:"spur",leadingArgs:[]};if("error"in launch)throw Error(launch.error);let res=await new NodeProcessExecutor2().run({command:launch.command,args:[...launch.leadingArgs,"workflow","show",input.file,"--format","todo","--json"],cwd:input.workdir??process.cwd(),forceBuffered:!0,rejectOnError:!1,timeout:30000});if(res.exitCode!==0){let detail=res.stderr.trim()!==""?res.stderr.trim():`exit ${res.exitCode??-1}`;throw Error(`could not resolve the workflow definition with the installed CLI: ${detail}`)}let value=JSON.parse(res.stdout);if(value&&typeof value==="object"&&"ok"in value&&"data"in value&&value.ok===!0)return value.data;return value}var SAFE_RUN_ID_RE=/^[A-Za-z0-9][A-Za-z0-9._-]*$/,MAX_CITED_RUN_FILES=64,RUN_CITATION_RE=/(?<![\w~:-]|[\w~:-]\/)\.spur\/run\/([A-Za-z0-9][A-Za-z0-9._*?<>{}|,\u2026-]*)(\/[^\s`]*)?/g;function asLiteralRunFileName(citation){let name=citation.replace(/[.,]+$/,"");if(!SAFE_RUN_ID_RE.test(name)||name.includes(".."))return;return name}async function readExistingRunFile(path8){let stat=await lstat(path8).catch((error51)=>{if(error51.code==="ENOENT")return;throw error51});if(stat===void 0)return;if(!stat.isFile())throw Error(`persist-out: destination ${path8} is not a regular file — refusing to follow it`);return readFile2(path8)}async function persistWorktreeRuns(input){let fromDir=resolve6(input.fromWorkdir),toDir=resolve6(input.toWorkdir),fromRunDir=join9(fromDir,".spur","run"),toRunDir=join9(toDir,".spur","run"),fromRecordsDir=runStoragePaths(fromDir).recordsDir,toRecordsDir=runStoragePaths(toDir).recordsDir,fs2=createNodeFileSystem2(),fromEvidence=runStoragePaths(fromDir).evidenceDir,toEvidence=runStoragePaths(toDir).evidenceDir,evidenceCopies=[];await resolveDurableArtifactPath(fs2,fromDir,join9(fromEvidence,"probe.json"),"evidence");let evidenceNames=await readdir(fromEvidence).catch((error51)=>{if(error51.code==="ENOENT")return[];throw error51});for(let name of evidenceNames.sort()){let source2=await resolveDurableArtifactPath(fs2,fromDir,join9(fromEvidence,name),"evidence"),target=await resolveDurableArtifactPath(fs2,toDir,join9(toEvidence,name),"evidence");if(!(await lstat(source2)).isFile())throw Error(`persist-out: durable evidence is not a regular file: ${name}`);let bytes=await readFile2(source2),verdictWbs=/^(\d{4})-verdict\.json$/.exec(name)?.[1];if(verdictWbs!==void 0){let parsed=parseVerifyVerdict(bytes.toString(),verdictWbs),raw=JSON.parse(bytes.toString());if(!parsed||parsed.wbs!==verdictWbs||raw.wbs!==void 0&&raw.wbs!==verdictWbs)throw Error(`persist-out: malformed durable verdict identity: ${name}`)}else if(name.endsWith("-feature-verification.json")){let receipt=parseFeatureVerificationReceipt(bytes.toString()),owner=name.slice(0,-26);if(owner!==receipt.runId&&owner!==receipt.featureId)throw Error(`persist-out: malformed durable receipt identity: ${name}`)}else throw Error(`persist-out: unclassified durable evidence: ${name}`);let existing=await readExistingRunFile(target);if(existing!==void 0&&!existing.equals(bytes))throw Error(`persist-out: durable evidence conflicts: ${name}`);evidenceCopies.push({source:source2,target,bytes})}let citedNames=new Set,citedDirSkips=new Set;for(let taskFile of input.taskFiles??[]){let content;try{content=await readFile2(resolve6(toDir,taskFile),"utf8")}catch(error51){throw Error(`persist-out: merged task file ${taskFile} is unreadable: ${String(error51)}`)}for(let match of content.matchAll(RUN_CITATION_RE)){let name=asLiteralRunFileName(match[1]??"");if(name===void 0)continue;if(match[2]!==void 0){citedDirSkips.add(name);continue}if(citedNames.has(name))continue;if(citedNames.size>=MAX_CITED_RUN_FILES)throw Error(`persist-out: merged task files cite more than ${MAX_CITED_RUN_FILES} distinct `+".spur/run/ files — over the fixed citation cap (0984 R3); split the batch or prune the citations");citedNames.add(name)}}if((input.taskFiles??[]).length>0){let prefixes=(input.taskFiles??[]).flatMap((taskFile)=>{let wbs=/^(\d{4})_/.exec(basename4(taskFile))?.[1];return wbs===void 0?[]:[`${wbs}-`]}),recordNames=new Set,owner=await openInlineRunProjectDb(fromDir);try{for(let row of await listRunIdRows(owner.adapter)){if(!SAFE_RUN_ID_RE.test(row.id))throw new InvalidWorkflowRunIdError(row.id);prefixes.push(`${row.id}-`),recordNames.add(`${row.id}.md`).add(`${row.id}.state.json`)}}finally{owner.close()}let entries=await readdir(fromRunDir).catch((error51)=>{if(error51.code==="ENOENT")return[];throw error51}),ownedCounts=new Map;for(let name of entries.sort()){if(recordNames.has(name))continue;let owner2=prefixes.find((prefix)=>name.startsWith(prefix));if(owner2===void 0)continue;let count3=(ownedCounts.get(owner2)??0)+1;if(count3>MAX_CITED_RUN_FILES)throw Error(`persist-out: owner ${owner2} owns more than ${MAX_CITED_RUN_FILES} .spur/run/ files `+"— over the per-owner evidence cap (1012 R1, 1034 R1); split the batch or prune the evidence");ownedCounts.set(owner2,count3),citedNames.add(name)}}let citedCopies=[],citedSkips=[];for(let name of citedDirSkips)citedSkips.push({id:name,reason:`cited-directory:${name}`});for(let name of citedNames){let scratchPath=join9(fromRunDir,name),durablePath=join9(fromRecordsDir,name),scratchStat=await lstat(scratchPath).catch(()=>{return}),sourceIsDurable=scratchStat===void 0,sourcePath=sourceIsDurable?durablePath:scratchPath,targetPath=sourceIsDurable?join9(toRecordsDir,name):join9(toRunDir,name),sourceStat=sourceIsDurable?await lstat(durablePath).catch(()=>{return}):scratchStat,targetBytes=await readExistingRunFile(targetPath);if(sourceStat===void 0){if(targetBytes===void 0)throw Error(`persist-out: cited run evidence .spur/run/${name} is missing in both the worktree and `+"the invoking tree — resolve or drop the citation before teardown (0984 R1)");continue}if(!sourceStat.isFile()){let kind=sourceStat.isDirectory()?"directory":sourceStat.isSymbolicLink()?"symlink":"non-file";citedSkips.push({id:name,reason:`cited-${kind}:${name}`});continue}if(targetBytes!==void 0){let sourceBytes=await readFile2(sourcePath);if(!targetBytes.equals(sourceBytes))throw Error(`persist-out: cited run evidence .spur/run/${name} diverges from the invoking tree's `+"existing file — refusing to overwrite; reconcile the two copies by hand (0984 R4)");continue}citedCopies.push({name,sourcePath,targetPath})}let source=await openInlineRunProjectDb(fromDir);try{let runRows=await listRunIdRows(source.adapter);for(let row of runRows)if(!SAFE_RUN_ID_RE.test(row.id))throw new InvalidWorkflowRunIdError(row.id);let recordBytes=new Map;for(let row of runRows){let bookkeeping=row.workflowName!==null&&row.workflowName!==void 0&&isBookkeepingWorkflow(row.workflowName);for(let fileName of[`${row.id}.md`,`${row.id}.state.json`])try{recordBytes.set(fileName,await readFile2(join9(fromRecordsDir,fileName)))}catch(error51){if(error51.code==="ENOENT"){if(bookkeeping)continue;throw Error(`persist-out: ${row.workflowName??"unknown"} run ${row.id} is missing its run record \`${fileName}\` in the worktree — failing closed before any row transfer `+"(green-run evidence guarantee, 0984 R5 / 1043 R1)")}throw error51}}let target=await openInlineRunProjectDb(toDir);try{let{persistedIds,skipped}=await transferRunTables(source.adapter,target.adapter),recordIds=[...persistedIds,...skipped.filter((s3)=>s3.reason==="id-exists").map((s3)=>s3.id)],recordSkips=[],referenceMoves=[];if(evidenceCopies.length>0){ensureDurablePlaneIgnored(toDir);for(let copy of evidenceCopies){await mkdir2(join9(copy.target,".."),{recursive:!0});let existing=await readExistingRunFile(copy.target);if(existing!==void 0&&!existing.equals(copy.bytes))throw Error(`persist-out: durable evidence conflicts: ${copy.target}`);if(existing===void 0)writeFileSync4(copy.target,copy.bytes,{flag:"wx"});referenceMoves.push({source:copy.source,target:fs2.realPath?.(copy.target)??copy.target})}}if(recordIds.length>0||citedCopies.length>0){mkdirSync3(toRunDir,{recursive:!0}),mkdirSync3(toRecordsDir,{recursive:!0}),ensureDurablePlaneIgnored(toDir);for(let id of recordIds)for(let fileName of[`${id}.md`,`${id}.state.json`]){let sourceBytes=recordBytes.get(fileName);if(sourceBytes===void 0){recordSkips.push({id,reason:`record-missing:${fileName}`});continue}let targetPath=join9(toRecordsDir,fileName),existing=await readExistingRunFile(targetPath);if(existing!==void 0){if(existing.equals(sourceBytes))continue;recordSkips.push({id,reason:`record-conflict:${fileName}`});continue}writeFileSync4(targetPath,sourceBytes,{flag:"wx"})}for(let cited of citedCopies){let sourceBytes=await readFile2(cited.sourcePath),existing=await readExistingRunFile(cited.targetPath);if(existing!==void 0){if(!existing.equals(sourceBytes))throw Error(`persist-out: cited run evidence .spur/run/${cited.name} diverges from the invoking `+"tree's existing file — refusing to overwrite; reconcile the two copies by hand (0984 R4)");continue}writeFileSync4(cited.targetPath,sourceBytes,{flag:"wx"})}for(let id of recordIds)await carryRunRecordDir(fromRecordsDir,toRecordsDir,"",id,recordSkips,referenceMoves)}return await redirectRunStorageReferences(target.adapter,referenceMoves),{ok:!0,persisted:persistedIds.length,skipped:[...skipped,...recordSkips,...citedSkips]}}finally{target.close()}}finally{source.close()}}async function createOrAttachInlineRun(input){let runId=input.runId.trim();if(runId==="")return{ok:!1,error:"inline run setup requires a non-empty runId (driver Run setup step 2)"};let workdir=resolve6(input.workdir),resolved;try{let projection=input.inventory===void 0?void 0:parseWorkflowInventory(input.inventory);if(projection&&!projection.ok)return projection;let inventory=projection?.ok?projection.inventory:void 0;if(inventory&&(!inventory.source||inventory.kind!=="state-machine"))return{ok:!1,error:"inline run setup requires a state-machine inventory with definition source"};if(resolved=await resolveWorkflowDefinition(workdir,inventory?.source?.path??input.file,{validateSchema:!0,...input.embeddedSchemas!==void 0?{embeddedSchemas:input.embeddedSchemas}:{},...!inventory?{registered:input.registered}:{}}),(resolved.workflow.kind??"state-machine")!=="state-machine")return{ok:!1,error:"inline run setup requires a state-machine definition"};if(inventory?.source){let identity5=assertInventoryIdentity(inventory,resolved.digest);if(!identity5.ok)return identity5;if(inventory.name!==resolved.workflow.name)return{ok:!1,error:"inline run setup: inventory workflow name does not match its definition"};resolved={...resolved,layer:inventory.source.layer}}}catch(error51){return{ok:!1,error:`inline run setup could not resolve the workflow definition: ${error51.message}`}}let digest=resolved.digest,version3=workflowVersionLiteral(resolved.workflow),source={path:resolved.path,layer:resolved.layer,workdir},db2=await input.getDb(),existing=await new RunDao(db2).traceRowById(runId);if(existing!==void 0){let metadata=parseIdentityMetadata(existing.metadata_json);if(metadata===null)return{ok:!1,error:`inline run setup refuses run ${runId}: its existing row has malformed metadata_json, `+"so its identity cannot be verified — delete the stale run row or allocate a new run id"};let resumeDigest=typeof metadata.resumeDefinitionDigest==="string"?metadata.resumeDefinitionDigest:void 0,launchDigest=typeof metadata.definitionDigest==="string"?metadata.definitionDigest:void 0,effectiveDigest=resumeDigest??launchDigest;if(effectiveDigest===void 0)return{ok:!1,error:`inline run setup refuses run ${runId}: its existing row carries no definition digest `+"(pre-identity legacy row) — allocate a new run id instead of attaching an unverifiable identity"};if(effectiveDigest!==digest)return{ok:!1,error:`inline run setup refuses run ${runId}: the resolved definition digest (${digest}) does not match the run's recorded ${resumeDigest!==void 0?"resume":""} digest (${effectiveDigest}) — `+"a changed definition must resume through the explicit resume rules, not silently re-attach"};if(existing.workflow_name!==resolved.workflow.name)return{ok:!1,error:`inline run setup refuses run ${runId}: the run row records workflow "${existing.workflow_name}" but the resolved definition is "${resolved.workflow.name}" — conflicting run identity`};if(typeof metadata.definitionSource!=="object"||metadata.definitionSource===null||Array.isArray(metadata.definitionSource))return{ok:!1,error:`inline run setup refuses run ${runId}: its existing row carries no definition source `+"(path/layer/workdir) — allocate a new run id instead of attaching an unverifiable launch source"};let existingSource=metadata.definitionSource;if(!(typeof existingSource.path==="string"&&resolve6(existingSource.path)===resolved.path&&normalizePersistedWorkflowLayer(existingSource.layer)===resolved.layer&&typeof existingSource.workdir==="string"&&resolve6(existingSource.workdir)===workdir))return{ok:!1,error:`inline run setup refuses run ${runId}: the recorded definition source (${JSON.stringify(existingSource)}) does not match the resolved launch source (${JSON.stringify(source)}) — conflicting project/workdir identity`};return{ok:!0,attached:!0,runId,workflowName:resolved.workflow.name,definitionDigest:digest,workflowVersion:version3,resolvedPath:resolved.path,layer:resolved.layer,workdir,status:existing.status}}return await new WorkflowService(createDefaultWorkflowEngineHost(),new DbWorkflowPersistenceAdapter(db2)).createOrAttachRun({id:runId,workflow_name:resolved.workflow.name,mode:"state-machine",status:"running",started_at:new Date().toISOString(),completed_at:null,metadata_json:JSON.stringify({definitionDigest:digest,workflowVersion:version3,definitionSource:source})}),{ok:!0,attached:!1,runId,workflowName:resolved.workflow.name,definitionDigest:digest,workflowVersion:version3,resolvedPath:resolved.path,layer:resolved.layer,workdir,status:"running"}}async function runDecideForInlineRun(input){let optionsFile=join9(resolve6(input.workdir),input.optionsFile),raw;try{raw=JSON.parse(await readFile2(optionsFile,"utf8"))}catch(error51){return{ok:!1,error:`decide: unreadable options file ${input.optionsFile}: ${String(error51)}`}}let parsed=DecideOptionsSchema.safeParse(raw);if(!parsed.success)return{ok:!1,error:`decide: invalid options — ${parsed.error.issues.map((i2)=>i2.message).join("; ")}`};let result=await new DecideActionRunner(createNodeFileSystem2(),{enabled:input.enabled}).execute(raw,{runId:"inline-decide",stateOrNodeId:"decide",workdir:resolve6(input.workdir),vars:{},env:{}});if(!result.ok||result.data===void 0)return{ok:!1,error:result.error??"decide: action failed without an error message"};let decision=result.data.decision;return{ok:!0,value:decision.value,degraded:decision.degraded,reason:decision.reason,source:decision.source,backend:decision.backend,confidence:decision.confidence,resultFile:join9(resolve6(input.workdir),parsed.data.resultFile),durationMs:decision.durationMs}}async function carryRunRecordDir(srcRoot,destRoot,rel,runId,skips,moves){let fs2=createNodeFileSystem2();await resolveDurableArtifactPath(fs2,resolve6(srcRoot,"../../.."),join9(srcRoot,rel,"probe"),"runs"),await resolveDurableArtifactPath(fs2,resolve6(destRoot,"../../.."),join9(destRoot,rel,"probe"),"runs");let entries;try{entries=await readdir(join9(srcRoot,rel),{withFileTypes:!0})}catch(error51){if(error51.code==="ENOENT")return;throw error51}for(let entry of entries){if(rel===""&&![runId,`${runId}.md`,`${runId}.state.json`,`${runId}.log`].includes(entry.name))continue;let relNext=rel===""?entry.name:`${rel}/${entry.name}`;if(entry.isDirectory()){await carryRunRecordDir(srcRoot,destRoot,relNext,runId,skips,moves);let target=join9(destRoot,relNext);if(existsSync5(target))moves.push({source:join9(srcRoot,relNext),target:fs2.realPath?.(target)??target});continue}let source=await resolveDurableArtifactPath(fs2,resolve6(srcRoot,"../../.."),join9(srcRoot,relNext),"runs"),dest=await resolveDurableArtifactPath(fs2,resolve6(destRoot,"../../.."),join9(destRoot,relNext),"runs");if(!(await lstat(source)).isFile())throw Error(`persist-out: retained item is not a regular file: ${source}`);let sourceBytes=await readFile2(source),existing=await readExistingRunFile(dest);if(existing!==void 0){if(!existing.equals(sourceBytes)){if(rel!=="")throw Error(`persist-out: retained data conflicts: ${relNext}`);skips.push({id:`${runId}/${relNext}`,reason:`record-conflict:${relNext}`});continue}}else await mkdir2(join9(dest,".."),{recursive:!0}),writeFileSync4(dest,sourceBytes,{flag:"wx"});if(moves.push({source,target:fs2.realPath?.(dest)??dest}),moves.push({source:join9(srcRoot,relNext),target:fs2.realPath?.(dest)??dest}),rel!=="")moves.push({source:join9(srcRoot,rel),target:fs2.realPath?.(join9(destRoot,rel))??join9(destRoot,rel)})}}function writeInlineRunOutcome(runId,outcome){let runDir=runStoragePaths(process.cwd()).recordsDir;if(!existsSync5(runDir))mkdirSync3(runDir,{recursive:!0});let statePath=join9(runDir,`${runId}.state.json`),markdownPath=join9(runDir,`${runId}.md`),prior={};try{let parsed=JSON.parse(readFileSync5(statePath,"utf8"));if(parsed!==null&&typeof parsed==="object"&&!Array.isArray(parsed))prior=parsed}catch{}let at2=new Date().toISOString(),state={schemaVersion:1,runId,...outcome.workflowName!==void 0?{workflowName:outcome.workflowName}:{},...outcome.status!==void 0?{status:outcome.status}:{},startedAt:typeof prior.startedAt==="string"?prior.startedAt:at2,updatedAt:at2,...outcome.attached!==void 0?{attached:outcome.attached}:{},...outcome.definitionDigest!==void 0?{definitionDigest:outcome.definitionDigest}:{},...outcome.workflowVersion!==void 0?{workflowVersion:outcome.workflowVersion}:{},...outcome.resolvedPath!==void 0?{resolvedPath:outcome.resolvedPath}:{},...outcome.layer!==void 0?{layer:outcome.layer}:{},...outcome.workdir!==void 0?{workdir:outcome.workdir}:{},ok:outcome.ok,...outcome.ok===!1&&outcome.error!==void 0?{error:outcome.error}:{}},temp=`${statePath}.tmp`;try{writeFileSync4(temp,`${JSON.stringify(state,null,4)}
|
|
1503
1566
|
`),renameSync3(temp,statePath)}catch{try{unlinkSync2(temp)}catch{}}let headerFd;try{headerFd=openSync(markdownPath,"wx"),writeSync(headerFd,`# spur inline run ${runId} — ${outcome.workflowName??"unknown workflow"} — setup ${at2}
|
|
1504
1567
|
`)}catch{}finally{if(headerFd!==void 0)closeSync(headerFd)}}function projectInlineRunClose(runId,status,context4){try{let runDir=runStoragePaths(process.cwd()).recordsDir;if(!existsSync5(runDir))mkdirSync3(runDir,{recursive:!0});let statePath=join9(runDir,`${runId}.state.json`),prior={};try{let parsed=JSON.parse(readFileSync5(statePath,"utf8"));if(parsed!==null&&typeof parsed==="object"&&!Array.isArray(parsed))prior=parsed}catch{}let at2=new Date().toISOString(),state={schemaVersion:1,...prior,runId,status,ok:!0,startedAt:typeof prior.startedAt==="string"?prior.startedAt:context4?.startedAt??at2,updatedAt:at2};delete state.error;let temp=`${statePath}.tmp`;try{writeFileSync4(temp,`${JSON.stringify(state,null,4)}
|
|
1505
1568
|
`),renameSync3(temp,statePath)}catch(error51){try{unlinkSync2(temp)}catch{}throw error51}return}catch(error51){let detail=error51 instanceof Error?error51.message:String(error51);return`failed to project the committed ${status} status into the run-record state file for run ${runId}: ${detail} (the run row is committed; replay the same close to repair)`}}var CLOSE_STATUSES=new Set(["done","failed","paused"]);function isInlineRunCloseStatus(status){return CLOSE_STATUSES.has(status)}var ACTION_STATUSES=new Set(["done","failed"]);function isInlineRunActionStatus(status){return ACTION_STATUSES.has(status)}function inlineRunRecordLogPath(runDir,runId){let markdownPath=join9(runDir,`${runId}.md`),legacyLogPath=join9(runDir,`${runId}.log`);if(existsSync5(legacyLogPath)&&!existsSync5(markdownPath))return legacyLogPath;return markdownPath}function appendInlineRunLogLine(runId,detail){try{let runDir=runStoragePaths(process.cwd()).recordsDir;if(!existsSync5(runDir))mkdirSync3(runDir,{recursive:!0});let safeRunId=runId.replace(/[^A-Za-z0-9._-]/g,"_"),stamp=new Date().toISOString().replace(/\.\d{3}Z$/,"Z");appendFileSync4(inlineRunRecordLogPath(runDir,safeRunId),`[${stamp}] ${detail}
|
|
1506
1569
|
`)}catch{}}async function runInlineRunTrace(input){let operation=input.close?"run.close":"action.finish";if(input.close){let invalidReason=(error51)=>{return process.stdout.write(`${JSON.stringify({ok:!1,runId:input.runId,error:error51,code:"INVALID_CLOSE_REASON"})}
|
|
1507
1570
|
`),1};if(input.reason!==void 0&&!isTerminalReason(input.reason))return invalidReason(`close reason "${input.reason}" is not a terminal-reason enum value; pass one of: ${TERMINAL_REASONS.join(", ")}`);if(input.status==="failed"&&input.reason===void 0)return invalidReason(`close status failed requires an explicit reason from the terminal-reason enum (0937 R2); pass one of: ${TERMINAL_REASONS.join(", ")}`)}let closeReason=input.close?input.reason??(input.status==="paused"?"paused-operator":"done"):void 0,fail=(error51)=>{return appendInlineRunLogLine(input.runId,`trace-emission-failed operation=${operation} run=${input.runId}${input.node===""?"":` node=${input.node}`}${input.kind===""?"":` kind=${input.kind}`}: ${error51}`),process.stdout.write(`${JSON.stringify({ok:!1,runId:input.runId,error:error51})}
|
|
1508
|
-
`),input.close?1:0},projectDb;try{projectDb=await openInlineRunProjectDb(process.cwd());let writer=createWorkflowActionTraceWriter(projectDb.adapter,(failure)=>{let detail=failure;appendInlineRunLogLine(input.runId,`trace-emission-failed operation=${detail.operation??operation} run=${input.runId}: ${detail.error??"unknown error"}`)}),result=input.close?await writer.closeRun(input.runId,input.status,void 0,closeReason):await writer.recordAction({runId:input.runId,node:input.node,kind:input.kind,status:input.status,ok:input.ok,durationMs:input.durationMs});if(result.ok!==!0&&result.failure!==void 0){let failure=result.failure;return fail(failure.error??"unknown trace emission failure")}let stateError=input.close?projectInlineRunClose(input.runId,input.status,{startedAt:typeof result.startedAt==="string"?result.startedAt:void 0}):void 0;if(input.close&&input.status==="done"&&result.actionRows===0){let error51=`run ${input.runId} closed done with zero action_runs rows; emit --action/--actions-file during the run (no backfill); see inline-pipeline-driver.md#structured-trace-emission-adr-117-task-0868${stateError!==void 0?`; run-record state projection also failed: ${stateError}`:""}`;return appendInlineRunLogLine(input.runId,`trace-close-failed run=${input.runId}: ${error51}`),process.stdout.write(`${JSON.stringify({ok:!1,runId:input.runId,error:error51,code:"NO_ACTION_ROWS",actionRows:0})}
|
|
1571
|
+
`),input.close?1:0},projectDb;try{projectDb=await openInlineRunProjectDb(process.cwd());let writer=createWorkflowActionTraceWriter(projectDb.adapter,(failure)=>{let detail=failure;appendInlineRunLogLine(input.runId,`trace-emission-failed operation=${detail.operation??operation} run=${input.runId}: ${detail.error??"unknown error"}`)}),result=input.close?await writer.closeRun(input.runId,input.status,void 0,closeReason):await writer.recordAction({runId:input.runId,node:input.node,kind:input.kind,status:input.status,ok:input.ok,durationMs:input.durationMs,result:{provenance:"host-reported",estimated:input.estimated===!0}});if(result.ok!==!0&&result.failure!==void 0){let failure=result.failure;return fail(failure.error??"unknown trace emission failure")}let stateError=input.close?projectInlineRunClose(input.runId,input.status,{startedAt:typeof result.startedAt==="string"?result.startedAt:void 0}):void 0;if(input.close&&input.status==="done"&&result.actionRows===0){let error51=`run ${input.runId} closed done with zero action_runs rows; emit --action/--actions-file during the run (no backfill); see inline-pipeline-driver.md#structured-trace-emission-adr-117-task-0868${stateError!==void 0?`; run-record state projection also failed: ${stateError}`:""}`;return appendInlineRunLogLine(input.runId,`trace-close-failed run=${input.runId}: ${error51}`),process.stdout.write(`${JSON.stringify({ok:!1,runId:input.runId,error:error51,code:"NO_ACTION_ROWS",actionRows:0})}
|
|
1509
1572
|
`),1}if(input.close&&stateError!==void 0)return appendInlineRunLogLine(input.runId,`trace-close-failed run=${input.runId}: ${stateError}`),process.stdout.write(`${JSON.stringify({ok:!1,runId:input.runId,error:stateError,code:"RUN_RECORD_STATE_FAILED"})}
|
|
1510
1573
|
`),1;let{startedAt:_threaded,...stdoutResult}=result;return process.stdout.write(`${JSON.stringify({...stdoutResult,runId:input.runId})}
|
|
1511
1574
|
`),0}catch(error51){if(input.close&&error51.name==="RunRowNotFoundError"){let message=error51 instanceof Error?error51.message:String(error51);return appendInlineRunLogLine(input.runId,`trace-close-failed run=${input.runId}: ${message}`),process.stdout.write(`${JSON.stringify({ok:!1,runId:input.runId,error:message,code:"RUN_NOT_FOUND"})}
|
|
1512
1575
|
`),1}return fail(error51 instanceof Error?error51.message:String(error51))}finally{projectDb?.close()}}async function runInlineRunTraceBatch(input){let batchFailed=(error51)=>{return process.stdout.write(`${JSON.stringify({ok:!1,runId:input.runId,error:error51})}
|
|
1513
|
-
`),1},rows;try{rows=JSON.parse(readFileSync5(input.actionsFile,"utf8"))}catch(error51){return batchFailed(`cannot read actions file ${input.actionsFile}: ${error51 instanceof Error?error51.message:String(error51)}`)}if(!Array.isArray(rows))return batchFailed("actions file must be a JSON array of {node,kind,status,ok,durationMs}");let entries=[],rowError=(index2,error51)=>`actions[${index2}]: ${error51}`;for(let[index2,row]of rows.entries()){if(row===null||typeof row!=="object"||Array.isArray(row))return batchFailed(rowError(index2,"entry must be a JSON object"));let record3=row,{node,kind,status,ok,durationMs}=record3;if(typeof node!=="string"||node.trim()==="")return batchFailed(rowError(index2,"node must be a non-empty string"));if(typeof kind!=="string"||kind.trim()==="")return batchFailed(rowError(index2,"kind must be a non-empty string"));if(typeof status!=="string"||!isInlineRunActionStatus(status))return batchFailed(rowError(index2,'status must be "done" or "failed"'));if(typeof ok!=="boolean")return batchFailed(rowError(index2,"ok must be a boolean"));if(typeof durationMs!=="number"||!Number.isFinite(durationMs)||durationMs<0)return batchFailed(rowError(index2,"durationMs must be a finite non-negative number"));entries.push({node,kind,status,ok,durationMs})}let projectDb,recorded=0,reportEmissionFailure=(node,kind,error51)=>{appendInlineRunLogLine(input.runId,`trace-emission-failed operation=action.finish run=${input.runId} node=${node} kind=${kind}: ${error51}`),process.stdout.write(`${JSON.stringify({ok:!1,runId:input.runId,recorded,error:error51})}
|
|
1514
|
-
`)};try{projectDb=await openInlineRunProjectDb(process.cwd());let writer=createWorkflowActionTraceWriter(projectDb.adapter,(failure)=>{let detail=failure;appendInlineRunLogLine(input.runId,`trace-emission-failed operation=${detail.operation??"action.finish"} run=${input.runId}: ${detail.error??"unknown error"}`)});for(let entry of entries){let result=await writer.recordAction({runId:input.runId,node:entry.node,kind:entry.kind,status:entry.status,ok:entry.ok,durationMs:entry.durationMs});if(result.ok===!0){recorded+=1;continue}let failure=result.failure;return reportEmissionFailure(entry.node,entry.kind,failure?.error??"unknown trace emission failure"),0}return process.stdout.write(`${JSON.stringify({ok:!0,runId:input.runId,recorded})}
|
|
1576
|
+
`),1},rows;try{rows=JSON.parse(readFileSync5(input.actionsFile,"utf8"))}catch(error51){return batchFailed(`cannot read actions file ${input.actionsFile}: ${error51 instanceof Error?error51.message:String(error51)}`)}if(!Array.isArray(rows))return batchFailed("actions file must be a JSON array of {node,kind,status,ok,durationMs,estimated?}");let entries=[],rowError=(index2,error51)=>`actions[${index2}]: ${error51}`;for(let[index2,row]of rows.entries()){if(row===null||typeof row!=="object"||Array.isArray(row))return batchFailed(rowError(index2,"entry must be a JSON object"));let record3=row,{node,kind,status,ok,durationMs,estimated}=record3;if(typeof node!=="string"||node.trim()==="")return batchFailed(rowError(index2,"node must be a non-empty string"));if(typeof kind!=="string"||kind.trim()==="")return batchFailed(rowError(index2,"kind must be a non-empty string"));if(typeof status!=="string"||!isInlineRunActionStatus(status))return batchFailed(rowError(index2,'status must be "done" or "failed"'));if(typeof ok!=="boolean")return batchFailed(rowError(index2,"ok must be a boolean"));if(typeof durationMs!=="number"||!Number.isFinite(durationMs)||durationMs<0)return batchFailed(rowError(index2,"durationMs must be a finite non-negative number"));if(estimated!==void 0&&typeof estimated!=="boolean")return batchFailed(rowError(index2,"estimated must be a boolean"));entries.push({node,kind,status,ok,durationMs,...estimated===!0?{estimated:!0}:{}})}let projectDb,recorded=0,reportEmissionFailure=(node,kind,error51)=>{appendInlineRunLogLine(input.runId,`trace-emission-failed operation=action.finish run=${input.runId} node=${node} kind=${kind}: ${error51}`),process.stdout.write(`${JSON.stringify({ok:!1,runId:input.runId,recorded,error:error51})}
|
|
1577
|
+
`)};try{projectDb=await openInlineRunProjectDb(process.cwd());let writer=createWorkflowActionTraceWriter(projectDb.adapter,(failure)=>{let detail=failure;appendInlineRunLogLine(input.runId,`trace-emission-failed operation=${detail.operation??"action.finish"} run=${input.runId}: ${detail.error??"unknown error"}`)});for(let entry of entries){let result=await writer.recordAction({runId:input.runId,node:entry.node,kind:entry.kind,status:entry.status,ok:entry.ok,durationMs:entry.durationMs,result:{provenance:"host-reported",estimated:entry.estimated===!0}});if(result.ok===!0){recorded+=1;continue}let failure=result.failure;return reportEmissionFailure(entry.node,entry.kind,failure?.error??"unknown trace emission failure"),0}return process.stdout.write(`${JSON.stringify({ok:!0,runId:input.runId,recorded})}
|
|
1515
1578
|
`),0}catch(error51){let message=error51 instanceof Error?error51.message:String(error51);return appendInlineRunLogLine(input.runId,`trace-emission-failed run=${input.runId}: ${message}`),process.stdout.write(`${JSON.stringify({ok:!1,runId:input.runId,recorded,error:message})}
|
|
1516
1579
|
`),0}finally{projectDb?.close()}}async function runInlineRunFingerprint(input){let workdir=process.cwd(),contents=await readProofInputContents(void 0,workdir,{taskFile:input.taskFile,...input.featureFile!==void 0&&input.featureFile.trim()!==""?{featureFile:input.featureFile}:{}});if(!contents.ok)return console.error(`inline-run-setup: FAIL — ${contents.error}`),1;let digest=await computeProofInputFingerprint({cwd:workdir,...contents.taskContent!==void 0?{taskContent:contents.taskContent}:{},...contents.featureContent!==void 0?{featureContent:contents.featureContent}:{}});return process.stdout.write(`${digest}
|
|
1517
1580
|
`),0}async function runInlineRunDecide(input){let decideFailed=(error51)=>{return process.stdout.write(`${JSON.stringify({ok:!1,runId:input.runId,error:error51})}
|
|
1518
1581
|
`),1},outcome;try{outcome=await runDecideForInlineRun({workdir:process.cwd(),optionsFile:input.optionsFile,enabled:input.enabled})}catch(error51){return decideFailed(error51 instanceof Error?error51.message:String(error51))}if(!outcome.ok)return decideFailed(outcome.error??"decide failed without an error message");return process.stdout.write(`${JSON.stringify({runId:input.runId,node:input.node,...outcome,ok:!0})}
|
|
1519
|
-
`),appendInlineRunLogLine(input.runId,`decide node=${input.node} value=${outcome.value??""} source=${outcome.source??"default"} reason=${outcome.reason??""}`),runInlineRunTrace({runId:input.runId,close:!1,node:input.node,kind:"decide",status:"done",ok:!0,durationMs:outcome.durationMs??0})}async function runInlineRunPersistOut(input){try{let result=await persistWorktreeRuns({fromWorkdir:input.from,toWorkdir:process.cwd(),...input.taskFiles.length>0?{taskFiles:input.taskFiles}:{}}),keyConflicts=result.skipped.filter((skip)=>skip.reason==="external-key-conflict");if(keyConflicts.length>0||result.skipped.some((skip)=>skip.reason.startsWith("record-conflict:"))){let error51=keyConflicts.length>0?`persist-out: external-key conflict for source runs ${keyConflicts.map((skip)=>skip.id).join(", ")}; retain the source worktree and reconcile provenance before teardown
|
|
1582
|
+
`),appendInlineRunLogLine(input.runId,`decide node=${input.node} value=${outcome.value??""} source=${outcome.source??"default"} reason=${outcome.reason??""}`),runInlineRunTrace({runId:input.runId,close:!1,node:input.node,kind:"decide",status:"done",ok:!0,durationMs:outcome.durationMs??0})}async function runInlineRunPersistOut(input){try{let result=await persistWorktreeRuns({fromWorkdir:input.from,toWorkdir:process.cwd(),...input.taskFiles.length>0?{taskFiles:input.taskFiles}:{}}),keyConflicts=result.skipped.filter((skip)=>skip.reason==="external-key-conflict");if(keyConflicts.length>0||result.skipped.some((skip)=>skip.reason.startsWith("record-conflict:"))){let landed=`already persisted before this refusal: ${result.persisted} run row(s)${result.skipped.length>0?`, ${result.skipped.length} skipped`:""}; the durable evidence plane and every cited/owned .spur/run file were copied by the same pass`,error51=keyConflicts.length>0?`persist-out: external-key conflict for source runs ${keyConflicts.map((skip)=>skip.id).join(", ")}; ${landed}. retain the source worktree and reconcile provenance before teardown`:`persist-out: unresolved retained record conflicts; ${landed}. retain the worktree and reconcile copies before teardown`;return process.stdout.write(`${JSON.stringify({...result,ok:!1,error:error51})}
|
|
1520
1583
|
`),1}return process.stdout.write(`${JSON.stringify({ok:!0,persisted:result.persisted,skipped:result.skipped})}
|
|
1521
1584
|
`),0}catch(error51){let message=error51 instanceof Error?error51.message:String(error51);return process.stdout.write(`${JSON.stringify({ok:!1,error:message})}
|
|
1522
|
-
`),1}}async function runInlineRunSetup(input){let workdir=process.cwd(),projectDb=await openInlineRunProjectDb(workdir),exitCode=0;try{let result=await createOrAttachInlineRun({workdir,getDb:async()=>projectDb.adapter,file:input.file,runId:input.runId,inventory:input.inventory,...input.embeddedSchemas!==void 0?{embeddedSchemas:input.embeddedSchemas}:{}});if(writeInlineRunOutcome(input.runId,result),!result.ok)console.error(`inline-run-setup: FAIL for run ${input.runId}`),console.error(` ${result.error}`),exitCode=1;else console.error(`inline-run-setup: ${result.attached?"attached":"created"} run ${input.runId} (${result.workflowName}, layer ${result.layer}, digest ${result.definitionDigest}, status ${result.status})`)}finally{projectDb.close()}return exitCode}var section_matrix_schema_default={$schema:"http://json-schema.org/draft-07/schema#",$id:"https://gobing.ai/spur/schemas/section-matrix.schema.json",title:"Section-Status-Matrix Schema",description:"Validates the shipped section-matrix.yaml — which sections are required/optional/forbidden per task status. Design §3.2. Authored for ts-runtime's loadStructuredConfig validator (supports properties/required/additionalProperties + $defs/$ref/enum; NOT patternProperties/uniqueItems).",type:"object",required:["variants"],additionalProperties:!1,properties:{$schema:{type:"string",description:"JSON Schema ref this file validates against (loadStructuredConfig reads it)."},variants:{type:"object",description:"Map of template variant → per-status matrix. Variant names are extensible (user-defined variants allowed); each value is a variant.",additionalProperties:{$ref:"#/$defs/variant"}}},$defs:{section:{enum:["Background","Requirements","Acceptance Criteria","Q&A","Design","Plan","Solution","Root Cause","Testing","Review","References","Notes","History"],description:"Canonical task section vocabulary (DD-08). Any other value is a typo."},sectionList:{type:"array",items:{$ref:"#/$defs/section"}},entry:{type:"object",additionalProperties:!1,properties:{required:{$ref:"#/$defs/sectionList"},optional:{$ref:"#/$defs/sectionList"},forbidden:{$ref:"#/$defs/sectionList"},gate:{type:"boolean"}}},variant:{type:"object",additionalProperties:!1,description:"A variant may declare any subset of the 7 canonical statuses (enumerated below); an unknown status key is rejected.",properties:{backlog:{$ref:"#/$defs/entry"},todo:{$ref:"#/$defs/entry"},wip:{$ref:"#/$defs/entry"},testing:{$ref:"#/$defs/entry"},blocked:{$ref:"#/$defs/entry"},done:{$ref:"#/$defs/entry"},cancelled:{$ref:"#/$defs/entry"}}}}};var spur_config_schema_default={$schema:"https://json-schema.org/draft/2020-12/schema",$id:"https://github.com/gobing-ai/spur/schemas/spur-config.schema.json",title:"Spur Project Configuration",description:"Schema for .spur/config.yaml — the single project configuration surface consumed by spur and (future) spur-server.",type:"object",properties:{$schema:{type:"string",description:"Reference to this schema for IDE validation. spur resolves this at runtime via loadStructuredConfig."},version:{type:"string",description:"Config schema version (string, not integer). Current recommended: '1.2' (config-1.2 layered global/project merge, ADR-033 executor tiers + planning blocks). '1' remains accepted for backward compatibility."},name:{type:"string",description:"Project name written by spur init."},bootstrap:{type:"object",description:"Portable bootstrap block consumed by @gobing-ai/ts-infra runNodeApplication. Shared across spur and spur-server.",properties:{logging:{type:"object",properties:{enabled:{type:"boolean",description:"Enable structured logging via LogTape."},level:{type:"string",enum:["trace","debug","info","warn","error","fatal"],description:"Minimum log level."},console:{type:"boolean",description:"Emit log records to console (stderr)."},json:{type:"boolean",description:"Format log records as JSON Lines. false = text format."},file:{type:"boolean",description:"Write log records to a file sink. Uses filePath when set, otherwise disabled."},filePath:{type:"string",description:"Path to the log file. Relative to project root. Default: .spur/logs/spur.log."}}},telemetry:{type:"object",properties:{enabled:{type:"boolean",description:"Enable OpenTelemetry tracing/metrics export."},serviceName:{type:"string",description:"Service name reported to OTel collectors."},environment:{type:"string",description:"Deployment environment label."}}},database:{type:"object",properties:{enabled:{type:"boolean",description:"Enable the SQLite database adapter."},driver:{type:"string",enum:["bun-sqlite"],description:"Database driver. Currently only bun-sqlite."},url:{type:"string",description:"Database file path. Supports ${DATABASE_URL} interpolation. Default: .spur/spur.db."}}},scheduler:{type:"object",properties:{enabled:{type:"boolean",description:"Enable the scheduled-task runner. OFF by default for CLI (run-once)."},jobs:{type:"array",description:"Declarative scheduled commands (task 0734). Each entry registers one scheduler tick that enqueues a `scheduler.custom` queue job running `command` through `/bin/sh -c`. Normalized and validated by @gobing-ai/ts-infra runNodeApplication before the server starts.",items:{type:"object",required:["name","command"],properties:{name:{type:"string",minLength:1,description:"Job name, unique across the list after trimming. Reported as the `scheduler.custom:<name>` display name on scheduler.job.executed."},command:{type:"string",minLength:1,description:"Shell command run by `/bin/sh -c` with the project root as cwd. Trusted operator input — never logged."},intervalMinutes:{type:"integer",minimum:1,maximum:35791,description:"Fixed interval in minutes. Mutually exclusive with `cron`. The upper bound is the Node timer ceiling (2147483647 ms)."},cron:{type:"string",minLength:1,description:"Five-field cron expression (minute hour day-of-month month day-of-week) evaluated in local time. Mutually exclusive with `intervalMinutes`."}},oneOf:[{required:["intervalMinutes"],not:{required:["cron"]}},{required:["cron"],not:{required:["intervalMinutes"]}}]}}}}}},agent:{type:"object",properties:{default:{type:"string",description:"Default role for `--agent auto` when nothing is declared (0542 R2). A role id (scribe, coder, reviewer, planner) selects its tier's cheapest eligible executor; a configured executor name still resolves during the transition with a one-time warning; any other value is rejected naming both accepted sets."},executors:{type:"array",description:"Named executor profiles: each pairs a canonical agent with an optional model override. Referenced by name from `agent.default` and stage model_policy (default-by-phase removed 0452).",items:{type:"object",required:["name","agent"],properties:{name:{type:"string",minLength:1,description:"Executor selector name (unique across the list)."},agent:{type:"string",minLength:1,description:"Canonical coding agent (claude, codex, gemini, pi, opencode, antigravity-cli, openclaw, hermes, omp)."},model:{type:"string",minLength:1,description:"Opaque model override passed straight to the agent (e.g. zai//glm-5.2). Applied only when the user passes no explicit --model."},tier:{type:"string",enum:["cheap","standard","capable-1","capable-2","capable-3"],description:"Capability tier for stage-registry adaptive model routing (ADR-033, 0343). Live values: cheap | standard | capable-1 | capable-2 | capable-3 (1=low output quality, 3=high within the capable band). A stage starts on the cheapest eligible executor meeting its model_policy min_tier. Bare legacy `capable` is accepted at runtime (zod preprocess → capable-1) during the deprecation window but is not part of this editor enum."},disabled:{description:"Routing kill-switch (111; ownership widened 0890): a disabled profile never serves a role, team, stage, or explicit selection, and doctor inventories it without probing. Omitted = enabled. Bare `true` is operator-owned (only humans write booleans); automatic writers emit the object form carrying owner (operator|quota|probe), since (RFC 3339) and reason.",anyOf:[{type:"boolean"},{type:"object",additionalProperties:!1,required:["owner","since","reason"],properties:{owner:{enum:["operator","quota","probe"]},since:{type:"string",format:"date-time",minLength:1},reason:{type:"string",minLength:1}}}]}}}},fleet:{type:"object",description:"The project's agent fleet (G65 / 0858): the single declaration of composition, the on/off switch, and the dispatch strategy. PROJECT LAYER ONLY — a global-layer agent.fleet fails the load. Replaces the retired .spur/fleet.json (0835) and agent.team (0857). Mirrors @gobing-ai/spur-config AgentFleetSchema (Zod is SSOT).",properties:{enabled:{type:"boolean",default:!1,description:"The single fleet switch. `spur serve` materializes and autostarts the roster only when true; an absent or disabled fleet starts nothing."},strategy:{type:"string",enum:["rest","gtd"],default:"rest",description:"Dispatch strategy, reconciled into project_strategy at serve start (0859). One name is added by a typed code change, not by config."},orchestrator:{type:"string",minLength:1,description:"memberLocalId of the one planner-role member carrying purpose: orchestrator. Absent = no orchestrator declared (never inferred)."},members:{type:"array",default:[],description:"The roster. Each member declares a role or an executor. `enabled: false` keeps the member's derived <role>-<n> id index but does not materialize it.",items:{type:"object",properties:{id:{type:"string",minLength:1,description:"Explicit stable id; wins over the derived <role>-<n> form."},role:{type:"string",enum:["scribe","coder","reviewer","planner"],description:"Layer-1 role id (closed vocabulary)."},executor:{type:"string",minLength:1,description:"Executor profile name or a raw canonical agent type."},purpose:{type:"string",description:"Free-form member purpose; `orchestrator` is the value the orchestrator pointer binds to."},enabled:{type:"boolean",description:"Default true. False preserves the member's derived id index without materializing it."}},anyOf:[{required:["role"]},{required:["executor"]}]}}}},roles:{type:"object",description:"Per-role tier/stage overrides over DEFAULT_AGENT_ROLES (0572 / ADR-061). Keys are the closed role vocabulary (scribe, coder, reviewer, planner); a present field replaces the default for that role, an omitted field keeps it. Mirrors @gobing-ai/spur-config AgentRoleConfigSchema (Zod is SSOT).",additionalProperties:{type:"object",properties:{tier:{type:"string",enum:["cheap","standard","capable-1","capable-2","capable-3"],description:"Replacement capability tier for the role. Must not sit below the highest min_tier among the role's folded stages (enforced at the CLI boundary)."},stages:{type:"array",minItems:1,items:{type:"string",minLength:1},description:"Replacement folded-stage list for the role. Ids must come from the canonical stage registry (validated at the CLI boundary). Omit the field to keep the default — an empty array is rejected."}}}}}},rules:{type:"object",properties:{paths:{type:"array",items:{type:"string"},description:"Glob paths to rule files."}}},workflows:{type:"object",properties:{paths:{type:"array",items:{type:"string"},description:"Glob paths to workflow directories."}}},redaction:{type:"object",properties:{enabled:{type:"boolean",description:"Enable sensitive-data redaction in CLI output."}}},history:{type:"object",description:"History import/analyze configuration (feature E3). Opt-in operation-triggered refresh.",properties:{refresh:{type:"object",properties:{on_completion:{type:"boolean",description:"Enqueue a coalesced history refresh when a task or pipeline run completes. Default false (opt-in; hidden automation is out of contract)."},debounce_ms:{type:"integer",minimum:0,description:"Coalescing window in milliseconds. Completions inside the window join one pending refresh. Default 60000."}}}}},builder:{type:"object",description:"Builder noun configuration. Currently hosts the release plumbing knobs for `spur builder bump-ver` / `drop-tags`; every field defaults to the built-in release convention, so an absent builder section keeps default behavior.",properties:{"bump-ver":{type:"object",description:"Release knobs for bump-ver/drop-tags. Defaults: -v separator, publish.yml workflow, chore(release) commit, gh run list limit 5.",properties:{aggregatePackage:{type:"string",minLength:1,description:'Package whose own release tag is the publish trigger for the aggregate (--all) path, as an unscoped package id (e.g. "spur" for @gobing-ai/spur). Default: the package whose full name equals the workspace root manifest name.'},tagVersionSeparator:{type:"string",minLength:1,description:'Release tag format: <package><separator><version>. Default "-v".'},publishWorkflow:{type:"string",minLength:1,description:'GitHub Actions workflow file the pushed release tag triggers. Default "publish.yml".'},releaseCommitType:{type:"string",minLength:1,description:'Conventional commit type for the release commit. Default "chore".'},releaseCommitScope:{type:"string",minLength:1,description:'Conventional commit scope for the release commit. Default "release".'},ghRunListLimit:{type:"integer",minimum:1,description:"gh run list --limit used to point at the triggered publish run. Default 5."},versionCarriers:{type:"array",description:"Extra version carriers beyond workspace package.json files. Default: none. Types are registered in apps/cli/src/version-carriers.ts (registerCarrierType), which validates instances at release time; registering a new type extends this description in the same commit.",items:{type:"object",description:"One carrier instance. Required field: type (string). Built-ins: plugin-manifest { paths: [..] } — repo-wide manifests synced to the release version (e.g. per-platform plugin.json mirrors); ts-literal { file?, identifier? } — version constant in a package source file (defaults src/config.ts / binaryVersion).",properties:{type:{type:"string",minLength:1}},required:["type"]}}}}}},tasks:{type:"object",description:"Task-folder registration (design §9). Absorbs the legacy docs/.tasks/config.json folders + baseCounter concepts. Mirrors @gobing-ai/spur-config tasksConfigSchema (Zod is SSOT).",properties:{folders:{type:"object",description:"Map of task-folder path → folder config.",additionalProperties:{type:"object",properties:{baseCounter:{type:"integer",minimum:0,description:"WBS base counter for new tasks in this folder. Default 0."},label:{type:"string",description:"Human-readable folder label."}}}},active:{type:"string",description:"Default folder for `spur task create`. Default: docs/tasks."},severity:{type:"object",description:"Rule severity overrides map by code (error | warning | off).",additionalProperties:{type:"string",enum:["error","warning","off"]}}}},features:{type:"object",description:"Feature directory location (design §9). Mirrors @gobing-ai/spur-config featuresConfigSchema (Zod is SSOT).",properties:{dir:{type:"string",description:"Feature files directory. Default: docs/features."}}}}};var state_machine_workflow_schema_default={$schema:"https://json-schema.org/draft/2020-12/schema",$id:"https://github.com/gobing-ai/spur/schemas/state-machine-workflow.schema.json",title:"@gobing-ai/ts-dual-workflow-engine State-machine Workflow",type:"object",additionalProperties:!1,required:["name","initialState","states","transitions"],properties:{$schema:{type:"string"},kind:{const:"state-machine"},name:{type:"string",minLength:1},version:{type:"string",minLength:1,description:"Optional behavior-neutral identity tag (0756). Absent = unversioned; present = a non-empty opaque literal surfaced as explicit(<literal>). Not parsed, ordered, or compatibility-checked; no registry."},description:{type:"string"},initialState:{type:"string",minLength:1},terminalStates:{type:"array",items:{type:"string",minLength:1}},failureStates:{type:"array",items:{type:"string",minLength:1},description:"Subset of terminalStates whose reach finalizes the run as failed. Absent ⇒ every terminal is a success."},iterationBound:{type:"integer",exclusiveMinimum:0},vars:{type:"object",propertyNames:{pattern:"^[A-Za-z_][A-Za-z0-9_]*$"},additionalProperties:{type:"string"}},env:{type:"object",additionalProperties:!1,properties:{allow:{type:"array",items:{type:"string",pattern:"^[A-Za-z_][A-Za-z0-9_]*$"}}}},extensions:{type:"object",additionalProperties:!1,properties:{actions:{type:"array",items:{$ref:"#/$defs/relativeExtensionPath"}},guards:{type:"array",items:{$ref:"#/$defs/relativeExtensionPath"}}}},states:{type:"array",items:{type:"object",additionalProperties:!1,required:["id"],properties:{id:{type:"string",minLength:1},description:{type:"string"},pause:{type:"boolean",description:"When true, the engine pauses the run at this state for HITL (E3); resume with `spur workflow continue`."},onEnter:{type:"array",items:{$ref:"#/$defs/action"}},onExit:{type:"array",items:{$ref:"#/$defs/action"}}}}},transitions:{type:"array",items:{type:"object",additionalProperties:!1,required:["from","to"],properties:{from:{type:"string",minLength:1},to:{type:"string",minLength:1},terminalReason:{type:"string",description:"Closed terminal-reason enum declared when this edge finalizes the run (0937 R3; required for edges into failureStates)."},description:{type:"string"},trigger:{type:"string"},guard:{$ref:"#/$defs/guard"}}}}},$defs:{action:{type:"object",additionalProperties:!1,required:["kind"],properties:{kind:{type:"string",minLength:1},options:{type:"object",additionalProperties:!0},onError:{type:"string",enum:["fail","continue"],description:"Per-action error handling policy: 'fail' halts the run; 'continue' logs the failure and proceeds so transition guards can route the outcome."}}},guard:{type:"object",additionalProperties:!1,required:["kind"],properties:{kind:{type:"string",minLength:1},options:{type:"object",additionalProperties:!0}}},relativeExtensionPath:{type:"string",minLength:1,description:"Relative module path; absolute paths and '..' traversal are forbidden.",not:{anyOf:[{pattern:"^[/\\\\]"},{pattern:"^[A-Za-z]:[/\\\\]"},{pattern:"(^|[/\\\\])\\.\\.([/\\\\]|$)"}]}}}};var transition_flow_workflow_schema_default={$schema:"https://json-schema.org/draft/2020-12/schema",$id:"https://github.com/gobing-ai/spur/schemas/transition-flow-workflow.schema.json",title:"@gobing-ai/ts-dual-workflow-engine Transition-flow Workflow",type:"object",additionalProperties:!1,required:["kind","name","initialNode","nodes","edges"],properties:{$schema:{type:"string"},kind:{const:"transition-flow"},name:{type:"string",minLength:1},version:{type:"string",minLength:1,description:"Optional behavior-neutral identity tag (0756). Absent = unversioned; present = a non-empty opaque literal surfaced as explicit(<literal>). Not parsed, ordered, or compatibility-checked; no registry."},description:{type:"string"},initialNode:{type:"string",minLength:1},terminalNodes:{type:"array",items:{type:"string",minLength:1}},iterationBound:{type:"integer",exclusiveMinimum:0},vars:{type:"object",propertyNames:{pattern:"^[A-Za-z_][A-Za-z0-9_]*$"},additionalProperties:{type:"string"}},env:{type:"object",additionalProperties:!1,properties:{allow:{type:"array",items:{type:"string",pattern:"^[A-Za-z_][A-Za-z0-9_]*$"}}}},extensions:{type:"object",additionalProperties:!1,properties:{actions:{type:"array",items:{$ref:"#/$defs/relativeExtensionPath"}},guards:{type:"array",items:{$ref:"#/$defs/relativeExtensionPath"}}}},nodes:{type:"array",items:{type:"object",additionalProperties:!1,required:["id"],properties:{id:{type:"string",minLength:1},description:{type:"string"},type:{enum:["action","gate","parallel","decision"]},action:{$ref:"#/$defs/action"}}}},edges:{type:"array",items:{type:"object",additionalProperties:!1,required:["from","to"],properties:{from:{type:"string",minLength:1},to:{type:"string",minLength:1},description:{type:"string"},condition:{$ref:"#/$defs/guard"}}}}},$defs:{action:{type:"object",additionalProperties:!1,required:["kind"],properties:{kind:{type:"string",minLength:1},options:{type:"object",additionalProperties:!0},onError:{type:"string",enum:["fail","continue"],description:"Per-action error handling policy: 'fail' halts the run; 'continue' logs the failure and proceeds so edge conditions can route the outcome."}}},guard:{type:"object",additionalProperties:!1,required:["kind"],properties:{kind:{type:"string",minLength:1},options:{type:"object",additionalProperties:!0}}},relativeExtensionPath:{type:"string",minLength:1,description:"Relative module path; absolute paths and '..' traversal are forbidden.",not:{anyOf:[{pattern:"^[/\\\\]"},{pattern:"^[A-Za-z]:[/\\\\]"},{pattern:"(^|[/\\\\])\\.\\.([/\\\\]|$)"}]}}}};var EMBEDDED_SPUR_SCHEMAS=new Map([["schemas/spur-config.schema.json",JSON.stringify(spur_config_schema_default)],["schemas/section-matrix.schema.json",JSON.stringify(section_matrix_schema_default)],["schemas/state-machine-workflow.schema.json",JSON.stringify(state_machine_workflow_schema_default)],["schemas/transition-flow-workflow.schema.json",JSON.stringify(transition_flow_workflow_schema_default)]]);export{writeInlineRunOutcome,validateFeatureVerificationReceipt,startFeatureVerificationReceipt,splitLaunchCommand,runInlineRunTraceBatch,runInlineRunTrace,runInlineRunSetup,runInlineRunPersistOut,runInlineRunFingerprint,runInlineRunDecide,runDecideForInlineRun,resolveWorkflowDefinition,resolveDecideDecisionMakerEnabled,readProofInputContents,persistWorktreeRuns,openInlineRunProjectDb,isInlineRunCloseStatus,isInlineRunActionStatus,inlineRunRecordLogPath,featureReceiptPaths,createWorkflowActionTraceWriter,createOrAttachInlineRun,computeProofInputFingerprint,completeFeatureVerificationReceipt,captureFeatureReceiptDigest,appendInlineRunLogLine,RunDao,EMBEDDED_SPUR_SCHEMAS,DEFAULT_FEATURE_VERIFICATION_CMD,ArtifactDao};
|
|
1585
|
+
`),1}}async function runInlineRunSetup(input){let workdir=process.cwd(),projectDb=await openInlineRunProjectDb(workdir),exitCode=0;try{let result=await createOrAttachInlineRun({workdir,getDb:async()=>projectDb.adapter,file:input.file,runId:input.runId,inventory:input.inventory,...input.embeddedSchemas!==void 0?{embeddedSchemas:input.embeddedSchemas}:{}});if(writeInlineRunOutcome(input.runId,result),!result.ok)console.error(`inline-run-setup: FAIL for run ${input.runId}`),console.error(` ${result.error}`),exitCode=1;else console.error(`inline-run-setup: ${result.attached?"attached":"created"} run ${input.runId} (${result.workflowName}, layer ${result.layer}, digest ${result.definitionDigest}, status ${result.status})`)}finally{projectDb.close()}return exitCode}var section_matrix_schema_default={$schema:"http://json-schema.org/draft-07/schema#",$id:"https://gobing.ai/spur/schemas/section-matrix.schema.json",title:"Section-Status-Matrix Schema",description:"Validates the shipped section-matrix.yaml — which sections are required/optional/forbidden per task status. Design §3.2. Authored for ts-runtime's loadStructuredConfig validator (supports properties/required/additionalProperties + $defs/$ref/enum; NOT patternProperties/uniqueItems).",type:"object",required:["variants"],additionalProperties:!1,properties:{$schema:{type:"string",description:"JSON Schema ref this file validates against (loadStructuredConfig reads it)."},variants:{type:"object",description:"Map of template variant → per-status matrix. Variant names are extensible (user-defined variants allowed); each value is a variant.",additionalProperties:{$ref:"#/$defs/variant"}}},$defs:{section:{enum:["Background","Requirements","Acceptance Criteria","Q&A","Design","Plan","Solution","Root Cause","Testing","Review","References","Notes","History"],description:"Canonical task section vocabulary (DD-08). Any other value is a typo."},sectionList:{type:"array",items:{$ref:"#/$defs/section"}},entry:{type:"object",additionalProperties:!1,properties:{required:{$ref:"#/$defs/sectionList"},optional:{$ref:"#/$defs/sectionList"},forbidden:{$ref:"#/$defs/sectionList"},gate:{type:"boolean"}}},variant:{type:"object",additionalProperties:!1,description:"A variant may declare any subset of the 7 canonical statuses (enumerated below); an unknown status key is rejected.",properties:{backlog:{$ref:"#/$defs/entry"},todo:{$ref:"#/$defs/entry"},wip:{$ref:"#/$defs/entry"},testing:{$ref:"#/$defs/entry"},blocked:{$ref:"#/$defs/entry"},done:{$ref:"#/$defs/entry"},cancelled:{$ref:"#/$defs/entry"}}}}};var spur_config_schema_default={$schema:"https://json-schema.org/draft/2020-12/schema",$id:"https://github.com/gobing-ai/spur/schemas/spur-config.schema.json",title:"Spur Project Configuration",description:"Schema for .spur/config.yaml — the single project configuration surface consumed by spur and (future) spur-server.",type:"object",properties:{$schema:{type:"string",description:"Reference to this schema for IDE validation. spur resolves this at runtime via loadStructuredConfig."},version:{type:"string",description:"Config schema version (string, not integer). Current recommended: '1.2' (config-1.2 layered global/project merge, ADR-033 executor tiers + planning blocks). '1' remains accepted for backward compatibility."},name:{type:"string",description:"Project name written by spur init."},bootstrap:{type:"object",description:"Portable bootstrap block consumed by @gobing-ai/ts-infra runNodeApplication. Shared across spur and spur-server.",properties:{logging:{type:"object",properties:{enabled:{type:"boolean",description:"Enable structured logging via LogTape."},level:{type:"string",enum:["trace","debug","info","warn","error","fatal"],description:"Minimum log level."},console:{type:"boolean",description:"Emit log records to console (stderr)."},json:{type:"boolean",description:"Format log records as JSON Lines. false = text format."},file:{type:"boolean",description:"Write log records to a file sink. Uses filePath when set, otherwise disabled."},filePath:{type:"string",description:"Path to the log file. Relative to project root. Default: .spur/logs/spur.log."}}},telemetry:{type:"object",properties:{enabled:{type:"boolean",description:"Enable OpenTelemetry tracing/metrics export."},serviceName:{type:"string",description:"Service name reported to OTel collectors."},environment:{type:"string",description:"Deployment environment label."}}},database:{type:"object",properties:{enabled:{type:"boolean",description:"Enable the SQLite database adapter."},driver:{type:"string",enum:["bun-sqlite"],description:"Database driver. Currently only bun-sqlite."},url:{type:"string",description:"Database file path. Supports ${DATABASE_URL} interpolation. Default: .spur/spur.db."}}},scheduler:{type:"object",properties:{enabled:{type:"boolean",description:"Enable the scheduled-task runner. OFF by default for CLI (run-once)."},jobs:{type:"array",description:"Declarative scheduled commands (task 0734). Each entry registers one scheduler tick that enqueues a `scheduler.custom` queue job running `command` through `/bin/sh -c`. Normalized and validated by @gobing-ai/ts-infra runNodeApplication before the server starts.",items:{type:"object",required:["name","command"],properties:{name:{type:"string",minLength:1,description:"Job name, unique across the list after trimming. Reported as the `scheduler.custom:<name>` display name on scheduler.job.executed."},command:{type:"string",minLength:1,description:"Shell command run by `/bin/sh -c` with the project root as cwd. Trusted operator input — never logged."},intervalMinutes:{type:"integer",minimum:1,maximum:35791,description:"Fixed interval in minutes. Mutually exclusive with `cron`. The upper bound is the Node timer ceiling (2147483647 ms)."},cron:{type:"string",minLength:1,description:"Five-field cron expression (minute hour day-of-month month day-of-week) evaluated in local time. Mutually exclusive with `intervalMinutes`."}},oneOf:[{required:["intervalMinutes"],not:{required:["cron"]}},{required:["cron"],not:{required:["intervalMinutes"]}}]}}}}}},agent:{type:"object",properties:{default:{type:"string",description:"Default role for `--agent auto` when nothing is declared (0542 R2). A role id (scribe, coder, reviewer, planner) selects its tier's cheapest eligible executor; a configured executor name still resolves during the transition with a one-time warning; any other value is rejected naming both accepted sets."},executors:{type:"array",description:"Named executor profiles: each pairs a canonical agent with an optional model override. Referenced by name from `agent.default` and stage model_policy (default-by-phase removed 0452).",items:{type:"object",required:["name","agent"],properties:{name:{type:"string",minLength:1,description:"Executor selector name (unique across the list)."},agent:{type:"string",minLength:1,description:"Canonical coding agent (claude, codex, gemini, pi, opencode, antigravity-cli, openclaw, hermes, omp)."},model:{type:"string",minLength:1,description:"Opaque model override passed straight to the agent (e.g. zai//glm-5.2). Applied only when the user passes no explicit --model."},tier:{type:"string",enum:["cheap","standard","capable-1","capable-2","capable-3"],description:"Capability tier for stage-registry adaptive model routing (ADR-033, 0343). Live values: cheap | standard | capable-1 | capable-2 | capable-3 (1=low output quality, 3=high within the capable band). A stage starts on the cheapest eligible executor meeting its model_policy min_tier. Bare legacy `capable` is accepted at runtime (zod preprocess → capable-1) during the deprecation window but is not part of this editor enum."},disabled:{description:"Routing kill-switch (111; ownership widened 0890): a disabled profile never serves a role, team, stage, or explicit selection, and doctor inventories it without probing. Omitted = enabled. Bare `true` is operator-owned (only humans write booleans); automatic writers emit the object form carrying owner (operator|quota|probe), since (RFC 3339) and reason.",anyOf:[{type:"boolean"},{type:"object",additionalProperties:!1,required:["owner","since","reason"],properties:{owner:{enum:["operator","quota","probe"]},since:{type:"string",format:"date-time",minLength:1},reason:{type:"string",minLength:1}}}]}}}},fleet:{type:"object",description:"The project's agent fleet (G65 / 0858): the single declaration of composition, the on/off switch, and the dispatch strategy. PROJECT LAYER ONLY — a global-layer agent.fleet fails the load. Replaces the retired .spur/fleet.json (0835) and agent.team (0857). Mirrors @gobing-ai/spur-config AgentFleetSchema (Zod is SSOT).",properties:{enabled:{type:"boolean",default:!1,description:"The single fleet switch. `spur serve` materializes and autostarts the roster only when true; an absent or disabled fleet starts nothing."},strategy:{type:"string",enum:["rest","gtd"],default:"rest",description:"Dispatch strategy, reconciled into project_strategy at serve start (0859). One name is added by a typed code change, not by config."},orchestrator:{type:"string",minLength:1,description:"memberLocalId of the one planner-role member carrying purpose: orchestrator. Absent = no orchestrator declared (never inferred)."},members:{type:"array",default:[],description:"The roster. Each member declares a role or an executor. `enabled: false` keeps the member's derived <role>-<n> id index but does not materialize it.",items:{type:"object",properties:{id:{type:"string",minLength:1,description:"Explicit stable id; wins over the derived <role>-<n> form."},role:{type:"string",enum:["scribe","coder","reviewer","planner"],description:"Layer-1 role id (closed vocabulary)."},executor:{type:"string",minLength:1,description:"Executor profile name or a raw canonical agent type."},purpose:{type:"string",description:"Free-form member purpose; `orchestrator` is the value the orchestrator pointer binds to."},enabled:{type:"boolean",description:"Default true. False preserves the member's derived id index without materializing it."}},anyOf:[{required:["role"]},{required:["executor"]}]}}}},roles:{type:"object",description:"Per-role tier/stage overrides over DEFAULT_AGENT_ROLES (0572 / ADR-061). Keys are the closed role vocabulary (scribe, coder, reviewer, planner); a present field replaces the default for that role, an omitted field keeps it. Mirrors @gobing-ai/spur-config AgentRoleConfigSchema (Zod is SSOT).",additionalProperties:{type:"object",properties:{tier:{type:"string",enum:["cheap","standard","capable-1","capable-2","capable-3"],description:"Replacement capability tier for the role. Must not sit below the highest min_tier among the role's folded stages (enforced at the CLI boundary)."},stages:{type:"array",minItems:1,items:{type:"string",minLength:1},description:"Replacement folded-stage list for the role. Ids must come from the canonical stage registry (validated at the CLI boundary). Omit the field to keep the default — an empty array is rejected."}}}}}},rules:{type:"object",properties:{paths:{type:"array",items:{type:"string"},description:"Glob paths to rule files."}}},workflows:{type:"object",properties:{paths:{type:"array",items:{type:"string"},description:"Glob paths to workflow directories."}}},decisions:{type:"object",description:"Decision-catalog resolution and DecisionMaker selection (feature P / ADR-134). The whole section is optional.",properties:{paths:{type:"array",items:{type:"string"},description:"Extra catalog folders for the registered decision layer (absolute, project-relative, or 'bundled:<sub>' against the installed package's config root)."},maker:{type:"string",pattern:"^[a-z][a-z0-9-]*$",description:"Default DecisionMaker for every decision point (built-ins: typesafe | fm-local | laya-local). Must be registered; an unknown name is a config error, never a silent fallback."},makers:{type:"object",additionalProperties:{type:"string"},description:"Per-decision-point maker overrides, keyed by decision id; outrank decisions.maker."}}},redaction:{type:"object",properties:{enabled:{type:"boolean",description:"Enable sensitive-data redaction in CLI output."}}},history:{type:"object",description:"History import/analyze configuration (feature E3). Opt-in operation-triggered refresh.",properties:{refresh:{type:"object",properties:{on_completion:{type:"boolean",description:"Enqueue a coalesced history refresh when a task or pipeline run completes. Default false (opt-in; hidden automation is out of contract)."},debounce_ms:{type:"integer",minimum:0,description:"Coalescing window in milliseconds. Completions inside the window join one pending refresh. Default 60000."}}}}},builder:{type:"object",description:"Builder noun configuration. Currently hosts the release plumbing knobs for `spur builder bump-ver` / `drop-tags`; every field defaults to the built-in release convention, so an absent builder section keeps default behavior.",properties:{"bump-ver":{type:"object",description:"Release knobs for bump-ver/drop-tags. Defaults: -v separator, publish.yml workflow, chore(release) commit, gh run list limit 5.",properties:{aggregatePackage:{type:"string",minLength:1,description:'Package whose own release tag is the publish trigger for the aggregate (--all) path, as an unscoped package id (e.g. "spur" for @gobing-ai/spur). Default: the package whose full name equals the workspace root manifest name.'},tagVersionSeparator:{type:"string",minLength:1,description:'Release tag format: <package><separator><version>. Default "-v".'},publishWorkflow:{type:"string",minLength:1,description:'GitHub Actions workflow file the pushed release tag triggers. Default "publish.yml".'},releaseCommitType:{type:"string",minLength:1,description:'Conventional commit type for the release commit. Default "chore".'},releaseCommitScope:{type:"string",minLength:1,description:'Conventional commit scope for the release commit. Default "release".'},ghRunListLimit:{type:"integer",minimum:1,description:"gh run list --limit used to point at the triggered publish run. Default 5."},versionCarriers:{type:"array",description:"Extra version carriers beyond workspace package.json files. Default: none. Types are registered in apps/cli/src/version-carriers.ts (registerCarrierType), which validates instances at release time; registering a new type extends this description in the same commit.",items:{type:"object",description:"One carrier instance. Required field: type (string). Built-ins: plugin-manifest { paths: [..] } — repo-wide manifests synced to the release version (e.g. per-platform plugin.json mirrors); ts-literal { file?, identifier? } — version constant in a package source file (defaults src/config.ts / binaryVersion).",properties:{type:{type:"string",minLength:1}},required:["type"]}}}}}},tasks:{type:"object",description:"Task-folder registration (design §9). Absorbs the legacy docs/.tasks/config.json folders + baseCounter concepts. Mirrors @gobing-ai/spur-config tasksConfigSchema (Zod is SSOT).",properties:{folders:{type:"object",description:"Map of task-folder path → folder config.",additionalProperties:{type:"object",properties:{baseCounter:{type:"integer",minimum:0,description:"WBS base counter for new tasks in this folder. Default 0."},label:{type:"string",description:"Human-readable folder label."}}}},active:{type:"string",description:"Default folder for `spur task create`. Default: docs/tasks."},severity:{type:"object",description:"Rule severity overrides map by code (error | warning | off).",additionalProperties:{type:"string",enum:["error","warning","off"]}}}},features:{type:"object",description:"Feature directory location (design §9). Mirrors @gobing-ai/spur-config featuresConfigSchema (Zod is SSOT).",properties:{dir:{type:"string",description:"Feature files directory. Default: docs/features."}}}}};var state_machine_workflow_schema_default={$schema:"https://json-schema.org/draft/2020-12/schema",$id:"https://github.com/gobing-ai/spur/schemas/state-machine-workflow.schema.json",title:"@gobing-ai/ts-dual-workflow-engine State-machine Workflow",type:"object",additionalProperties:!1,required:["name","initialState","states","transitions"],properties:{$schema:{type:"string"},kind:{const:"state-machine"},name:{type:"string",minLength:1},version:{type:"string",minLength:1,description:"Optional behavior-neutral identity tag (0756). Absent = unversioned; present = a non-empty opaque literal surfaced as explicit(<literal>). Not parsed, ordered, or compatibility-checked; no registry."},description:{type:"string"},initialState:{type:"string",minLength:1},terminalStates:{type:"array",items:{type:"string",minLength:1}},failureStates:{type:"array",items:{type:"string",minLength:1},description:"Subset of terminalStates whose reach finalizes the run as failed. Absent ⇒ every terminal is a success."},iterationBound:{type:"integer",exclusiveMinimum:0},vars:{type:"object",propertyNames:{pattern:"^[A-Za-z_][A-Za-z0-9_]*$"},additionalProperties:{type:"string"}},env:{type:"object",additionalProperties:!1,properties:{allow:{type:"array",items:{type:"string",pattern:"^[A-Za-z_][A-Za-z0-9_]*$"}}}},extensions:{type:"object",additionalProperties:!1,properties:{actions:{type:"array",items:{$ref:"#/$defs/relativeExtensionPath"}},guards:{type:"array",items:{$ref:"#/$defs/relativeExtensionPath"}}}},states:{type:"array",items:{type:"object",additionalProperties:!1,required:["id"],properties:{id:{type:"string",minLength:1},description:{type:"string"},pause:{type:"boolean",description:"When true, the engine pauses the run at this state for HITL (E3); resume with `spur workflow continue`."},onEnter:{type:"array",items:{$ref:"#/$defs/action"}},onExit:{type:"array",items:{$ref:"#/$defs/action"}}}}},transitions:{type:"array",items:{type:"object",additionalProperties:!1,required:["from","to"],properties:{from:{type:"string",minLength:1},to:{type:"string",minLength:1},terminalReason:{type:"string",description:"Closed terminal-reason enum declared when this edge finalizes the run (0937 R3; required for edges into failureStates)."},description:{type:"string"},trigger:{type:"string"},guard:{$ref:"#/$defs/guard"}}}}},$defs:{action:{type:"object",additionalProperties:!1,required:["kind"],properties:{kind:{type:"string",minLength:1},options:{type:"object",additionalProperties:!0},onError:{type:"string",enum:["fail","continue"],description:"Per-action error handling policy: 'fail' halts the run; 'continue' logs the failure and proceeds so transition guards can route the outcome."}}},guard:{type:"object",additionalProperties:!1,required:["kind"],properties:{kind:{type:"string",minLength:1},options:{type:"object",additionalProperties:!0}}},relativeExtensionPath:{type:"string",minLength:1,description:"Relative module path; absolute paths and '..' traversal are forbidden.",not:{anyOf:[{pattern:"^[/\\\\]"},{pattern:"^[A-Za-z]:[/\\\\]"},{pattern:"(^|[/\\\\])\\.\\.([/\\\\]|$)"}]}}}};var transition_flow_workflow_schema_default={$schema:"https://json-schema.org/draft/2020-12/schema",$id:"https://github.com/gobing-ai/spur/schemas/transition-flow-workflow.schema.json",title:"@gobing-ai/ts-dual-workflow-engine Transition-flow Workflow",type:"object",additionalProperties:!1,required:["kind","name","initialNode","nodes","edges"],properties:{$schema:{type:"string"},kind:{const:"transition-flow"},name:{type:"string",minLength:1},version:{type:"string",minLength:1,description:"Optional behavior-neutral identity tag (0756). Absent = unversioned; present = a non-empty opaque literal surfaced as explicit(<literal>). Not parsed, ordered, or compatibility-checked; no registry."},description:{type:"string"},initialNode:{type:"string",minLength:1},terminalNodes:{type:"array",items:{type:"string",minLength:1}},iterationBound:{type:"integer",exclusiveMinimum:0},vars:{type:"object",propertyNames:{pattern:"^[A-Za-z_][A-Za-z0-9_]*$"},additionalProperties:{type:"string"}},env:{type:"object",additionalProperties:!1,properties:{allow:{type:"array",items:{type:"string",pattern:"^[A-Za-z_][A-Za-z0-9_]*$"}}}},extensions:{type:"object",additionalProperties:!1,properties:{actions:{type:"array",items:{$ref:"#/$defs/relativeExtensionPath"}},guards:{type:"array",items:{$ref:"#/$defs/relativeExtensionPath"}}}},nodes:{type:"array",items:{type:"object",additionalProperties:!1,required:["id"],properties:{id:{type:"string",minLength:1},description:{type:"string"},type:{enum:["action","gate","parallel","decision"]},action:{$ref:"#/$defs/action"}}}},edges:{type:"array",items:{type:"object",additionalProperties:!1,required:["from","to"],properties:{from:{type:"string",minLength:1},to:{type:"string",minLength:1},description:{type:"string"},condition:{$ref:"#/$defs/guard"}}}}},$defs:{action:{type:"object",additionalProperties:!1,required:["kind"],properties:{kind:{type:"string",minLength:1},options:{type:"object",additionalProperties:!0},onError:{type:"string",enum:["fail","continue"],description:"Per-action error handling policy: 'fail' halts the run; 'continue' logs the failure and proceeds so edge conditions can route the outcome."}}},guard:{type:"object",additionalProperties:!1,required:["kind"],properties:{kind:{type:"string",minLength:1},options:{type:"object",additionalProperties:!0}}},relativeExtensionPath:{type:"string",minLength:1,description:"Relative module path; absolute paths and '..' traversal are forbidden.",not:{anyOf:[{pattern:"^[/\\\\]"},{pattern:"^[A-Za-z]:[/\\\\]"},{pattern:"(^|[/\\\\])\\.\\.([/\\\\]|$)"}]}}}};var EMBEDDED_SPUR_SCHEMAS=new Map([["schemas/spur-config.schema.json",JSON.stringify(spur_config_schema_default)],["schemas/section-matrix.schema.json",JSON.stringify(section_matrix_schema_default)],["schemas/state-machine-workflow.schema.json",JSON.stringify(state_machine_workflow_schema_default)],["schemas/transition-flow-workflow.schema.json",JSON.stringify(transition_flow_workflow_schema_default)]]);export{writeInlineRunOutcome,validateFeatureVerificationReceipt,startFeatureVerificationReceipt,splitLaunchCommand,runInlineRunTraceBatch,runInlineRunTrace,runInlineRunSetup,runInlineRunPersistOut,runInlineRunFingerprint,runInlineRunDecide,runDecideForInlineRun,resolveWorkflowDefinition,resolveDecideDecisionMakerEnabled,readProofInputContents,readInstalledInventory,persistWorktreeRuns,openInlineRunProjectDb,isInlineRunCloseStatus,isInlineRunActionStatus,inlineRunRecordLogPath,featureReceiptPaths,createWorkflowActionTraceWriter,createOrAttachInlineRun,computeProofInputFingerprint,completeFeatureVerificationReceipt,captureFeatureReceiptDigest,appendInlineRunLogLine,RunDao,EMBEDDED_SPUR_SCHEMAS,DEFAULT_FEATURE_VERIFICATION_CMD,ArtifactDao};
|