@brainst0rm/cli 0.14.1 → 0.14.3

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.
Files changed (103) hide show
  1. package/dist/{App-DSD2B5RV.js → App-4GFCMEPX.js} +10 -10
  2. package/dist/{App-6WBAUX35.js → App-KTUPXXQM.js} +10 -10
  3. package/dist/{agent-D5GTWGPD.js → agent-EYT6BPVT.js} +2 -2
  4. package/dist/{agent-DOR4KPUH.js → agent-KTWFCMY5.js} +2 -2
  5. package/dist/brainstorm.js +56 -56
  6. package/dist/{chunk-RV3CJQGC.js → chunk-2AXI2OPK.js} +43 -7
  7. package/dist/chunk-2AXI2OPK.js.map +1 -0
  8. package/dist/{chunk-6G2HA63H.js → chunk-3AYD5ONW.js} +43 -7
  9. package/dist/chunk-3AYD5ONW.js.map +1 -0
  10. package/dist/{chunk-UPP3TOCP.js → chunk-3RH5MKZF.js} +5 -5
  11. package/dist/{chunk-GLWCTGWG.js → chunk-4NNXZFPX.js} +2 -2
  12. package/dist/{chunk-Z5QQ5OGV.js → chunk-52Q6CE4Y.js} +19 -2
  13. package/dist/chunk-52Q6CE4Y.js.map +1 -0
  14. package/dist/{chunk-FGYEICUI.js → chunk-6UFDBLUX.js} +36 -4
  15. package/dist/chunk-6UFDBLUX.js.map +1 -0
  16. package/dist/{chunk-NVA62I52.js → chunk-6WGHIUWX.js} +2 -2
  17. package/dist/{chunk-4LR7LQPG.js → chunk-CZILJ33T.js} +2 -2
  18. package/dist/{chunk-TLQVDPEQ.js → chunk-DJ7WG6GZ.js} +19 -2
  19. package/dist/chunk-DJ7WG6GZ.js.map +1 -0
  20. package/dist/{chunk-N7JKT44Y.js → chunk-GUHXB5DX.js} +2 -2
  21. package/dist/{chunk-SCGV333Z.js → chunk-HKRUCBMI.js} +4 -4
  22. package/dist/{chunk-PIT7VD46.js → chunk-N5V2PGPN.js} +4 -4
  23. package/dist/{chunk-GF5TKYDA.js → chunk-RVQOLZR6.js} +14 -14
  24. package/dist/{chunk-AH5SFL5J.js → chunk-RVXUVX5W.js} +14 -14
  25. package/dist/{chunk-4PCWPRRN.js → chunk-WRO5TVID.js} +5 -5
  26. package/dist/{chunk-ZYGUHAHM.js → chunk-Z5RDHTWQ.js} +36 -4
  27. package/dist/chunk-Z5RDHTWQ.js.map +1 -0
  28. package/dist/{dist-QUYR4VH7.js → dist-5NJP3JHL.js} +23 -3
  29. package/dist/{dist-QUYR4VH7.js.map → dist-5NJP3JHL.js.map} +1 -1
  30. package/dist/{dist-P6IZYZBM.js → dist-7AIEUUFF.js} +2 -2
  31. package/dist/{dist-RVTIEEXC.js → dist-DCJYPRUZ.js} +3 -3
  32. package/dist/{dist-PGQ4UIM4.js → dist-DXQQF55Y.js} +3 -3
  33. package/dist/{dist-JQXY4E6A.js → dist-KSUHKNET.js} +88 -15
  34. package/dist/dist-KSUHKNET.js.map +1 -0
  35. package/dist/{dist-TS5U3BDK.js → dist-LCPM5BXN.js} +5 -5
  36. package/dist/{dist-VB7CXEYB.js → dist-MKAADC4H.js} +5 -5
  37. package/dist/{dist-MKWOTCNR.js → dist-NQQPQGZU.js} +6 -6
  38. package/dist/{dist-VECPW2NV.js → dist-NTQ7LFRW.js} +5 -5
  39. package/dist/{dist-ESUVKHL4.js → dist-QFVAD45U.js} +6 -6
  40. package/dist/{dist-7IRVYQYG.js → dist-RUBJT7FI.js} +2 -2
  41. package/dist/{dist-P2J4GXPC.js → dist-S7FLVLXS.js} +2 -2
  42. package/dist/{dist-4JONNOLT.js → dist-U3G5HT5D.js} +6 -6
  43. package/dist/{dist-IUVHFJV2.js → dist-UETKBS6A.js} +6 -6
  44. package/dist/{dist-ODBEXWTS.js → dist-WLMQD6I5.js} +5 -5
  45. package/dist/{dist-GNYSGXLR.js → dist-XFJ337R7.js} +23 -3
  46. package/dist/{dist-GNYSGXLR.js.map → dist-XFJ337R7.js.map} +1 -1
  47. package/dist/{dist-T6BIJZSD.js → dist-Y5FZXOVL.js} +2 -2
  48. package/dist/{dist-2DSARR2V.js → dist-ZPASHTYZ.js} +88 -15
  49. package/dist/dist-ZPASHTYZ.js.map +1 -0
  50. package/dist/{handler-VOVQRV5B.js → handler-CPXQZBSW.js} +6 -6
  51. package/dist/{handler-MHEFUP32.js → handler-FIBSROM4.js} +6 -6
  52. package/dist/index.js +56 -56
  53. package/dist/{mcp-server-C732TVIQ.js → mcp-server-56FVMXTC.js} +2 -2
  54. package/dist/{mcp-server-JUYR37EX.js → mcp-server-XXUZDYW6.js} +2 -2
  55. package/dist/{roles-QTZ54BOF.js → roles-CJTZSFFW.js} +6 -6
  56. package/dist/{roles-LDNPU3NI.js → roles-MVBHE5QW.js} +6 -6
  57. package/dist/{slash-VYIMEVPU.js → slash-WFDKT67A.js} +8 -8
  58. package/dist/{slash-VAUFJQBQ.js → slash-Y3E5KBOJ.js} +8 -8
  59. package/package.json +28 -28
  60. package/dist/chunk-6G2HA63H.js.map +0 -1
  61. package/dist/chunk-FGYEICUI.js.map +0 -1
  62. package/dist/chunk-RV3CJQGC.js.map +0 -1
  63. package/dist/chunk-TLQVDPEQ.js.map +0 -1
  64. package/dist/chunk-Z5QQ5OGV.js.map +0 -1
  65. package/dist/chunk-ZYGUHAHM.js.map +0 -1
  66. package/dist/dist-2DSARR2V.js.map +0 -1
  67. package/dist/dist-JQXY4E6A.js.map +0 -1
  68. /package/dist/{App-DSD2B5RV.js.map → App-4GFCMEPX.js.map} +0 -0
  69. /package/dist/{App-6WBAUX35.js.map → App-KTUPXXQM.js.map} +0 -0
  70. /package/dist/{agent-D5GTWGPD.js.map → agent-EYT6BPVT.js.map} +0 -0
  71. /package/dist/{agent-DOR4KPUH.js.map → agent-KTWFCMY5.js.map} +0 -0
  72. /package/dist/{chunk-UPP3TOCP.js.map → chunk-3RH5MKZF.js.map} +0 -0
  73. /package/dist/{chunk-GLWCTGWG.js.map → chunk-4NNXZFPX.js.map} +0 -0
  74. /package/dist/{chunk-NVA62I52.js.map → chunk-6WGHIUWX.js.map} +0 -0
  75. /package/dist/{chunk-4LR7LQPG.js.map → chunk-CZILJ33T.js.map} +0 -0
  76. /package/dist/{chunk-N7JKT44Y.js.map → chunk-GUHXB5DX.js.map} +0 -0
  77. /package/dist/{chunk-SCGV333Z.js.map → chunk-HKRUCBMI.js.map} +0 -0
  78. /package/dist/{chunk-PIT7VD46.js.map → chunk-N5V2PGPN.js.map} +0 -0
  79. /package/dist/{chunk-GF5TKYDA.js.map → chunk-RVQOLZR6.js.map} +0 -0
  80. /package/dist/{chunk-AH5SFL5J.js.map → chunk-RVXUVX5W.js.map} +0 -0
  81. /package/dist/{chunk-4PCWPRRN.js.map → chunk-WRO5TVID.js.map} +0 -0
  82. /package/dist/{dist-4JONNOLT.js.map → dist-7AIEUUFF.js.map} +0 -0
  83. /package/dist/{dist-7IRVYQYG.js.map → dist-DCJYPRUZ.js.map} +0 -0
  84. /package/dist/{dist-ESUVKHL4.js.map → dist-DXQQF55Y.js.map} +0 -0
  85. /package/dist/{dist-IUVHFJV2.js.map → dist-LCPM5BXN.js.map} +0 -0
  86. /package/dist/{dist-VB7CXEYB.js.map → dist-MKAADC4H.js.map} +0 -0
  87. /package/dist/{dist-MKWOTCNR.js.map → dist-NQQPQGZU.js.map} +0 -0
  88. /package/dist/{dist-P2J4GXPC.js.map → dist-NTQ7LFRW.js.map} +0 -0
  89. /package/dist/{dist-P6IZYZBM.js.map → dist-QFVAD45U.js.map} +0 -0
  90. /package/dist/{dist-PGQ4UIM4.js.map → dist-RUBJT7FI.js.map} +0 -0
  91. /package/dist/{dist-RVTIEEXC.js.map → dist-S7FLVLXS.js.map} +0 -0
  92. /package/dist/{dist-T6BIJZSD.js.map → dist-U3G5HT5D.js.map} +0 -0
  93. /package/dist/{dist-TS5U3BDK.js.map → dist-UETKBS6A.js.map} +0 -0
  94. /package/dist/{dist-ODBEXWTS.js.map → dist-WLMQD6I5.js.map} +0 -0
  95. /package/dist/{dist-VECPW2NV.js.map → dist-Y5FZXOVL.js.map} +0 -0
  96. /package/dist/{handler-VOVQRV5B.js.map → handler-CPXQZBSW.js.map} +0 -0
  97. /package/dist/{handler-MHEFUP32.js.map → handler-FIBSROM4.js.map} +0 -0
  98. /package/dist/{mcp-server-C732TVIQ.js.map → mcp-server-56FVMXTC.js.map} +0 -0
  99. /package/dist/{mcp-server-JUYR37EX.js.map → mcp-server-XXUZDYW6.js.map} +0 -0
  100. /package/dist/{roles-LDNPU3NI.js.map → roles-CJTZSFFW.js.map} +0 -0
  101. /package/dist/{roles-QTZ54BOF.js.map → roles-MVBHE5QW.js.map} +0 -0
  102. /package/dist/{slash-VAUFJQBQ.js.map → slash-WFDKT67A.js.map} +0 -0
  103. /package/dist/{slash-VYIMEVPU.js.map → slash-Y3E5KBOJ.js.map} +0 -0
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../workflow/src/engine.ts","../../workflow/src/context-filter.ts","../../workflow/src/artifact-store.ts","../../workflow/src/confidence.ts","../../workflow/src/presets.ts","../../workflow/src/recipes.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport type {\n WorkflowDefinition,\n WorkflowRun,\n WorkflowStepRun,\n WorkflowStepDef,\n WorkflowEvent,\n Artifact,\n AgentProfile,\n AgentRole,\n StepStatus,\n} from \"@brainst0rm/shared\";\nimport type { BrainstormConfig } from \"@brainst0rm/config\";\nimport type { ProviderRegistry } from \"@brainst0rm/providers\";\nimport { BrainstormRouter, CostTracker } from \"@brainst0rm/router\";\nimport {\n createDefaultToolRegistry,\n type ToolRegistry,\n} from \"@brainst0rm/tools\";\nimport { runAgentLoop, buildSystemPrompt, loadSkills } from \"@brainst0rm/core\";\nimport { AgentManager, buildAgentSystemPrompt } from \"@brainst0rm/agents\";\nimport { buildStepContext } from \"./context-filter.js\";\nimport { writeArtifact } from \"./artifact-store.js\";\nimport {\n extractConfidence,\n determineEscalation,\n isReviewApproved,\n} from \"./confidence.js\";\n\n/**\n * Shell commands that may run as a workflow kill-gate. Each entry is a\n * prefix; the gate is accepted only if it matches one of these with a\n * word boundary AND contains no shell metacharacters AND contains no\n * per-command danger patterns. Exported so tests can assert the surface\n * directly without spinning up a full workflow run.\n */\nexport const ALLOWED_GATE_PREFIXES = [\n \"npm test\",\n \"npm run \",\n \"npx turbo run \",\n \"npx vitest\",\n \"git diff --quiet\",\n \"git status --porcelain\",\n \"make \",\n \"cargo test\",\n \"cargo build\",\n \"go test\",\n \"pytest\",\n] as const;\n\n/**\n * Per-allowed-prefix danger patterns. If the gate string passes prefix +\n * metachar checks but matches any pattern here, it is still rejected.\n *\n * `go test -exec=PROGRAM` and `go test -exec PROGRAM` cause `go` to run\n * PROGRAM as the test binary wrapper — direct arbitrary command execution\n * without any shell metacharacter. v13 Attacker bypass #2; closed here.\n *\n * `cargo test` has a similar `--exec`-shape flag risk; pre-emptively block.\n */\nconst DANGER_PATTERNS: ReadonlyArray<RegExp> = [\n // The \"flag-loader\" bypass class. Each pattern matches a flag that\n // causes an allowed tool to LOAD and EXECUTE attacker-supplied content\n // (a config file, a reporter, a wrapper binary, a linker flag) —\n // bypassing the metachar deny entirely because the dangerous side\n // effect happens inside the trusted binary's argument parsing.\n //\n // v13 Attacker named `-exec` for go/cargo. v15 Attacker named\n // additional same-class bypasses: vitest --config / --reporter,\n // go -toolexec, go -gcflags='all=-N -l <attacker>'. P9a-2 extends\n // DANGER_PATTERNS to the union of known flag-loader shapes.\n //\n // Pattern shape: (?:^|\\s) — flag must appear after start-or-whitespace\n // (so `--config` inside a longer arg like `foo--configbar` doesn't trip).\n // [\\s=] suffix — flag must end with whitespace or `=` (otherwise the\n // string is a prefix of a longer word, e.g. `--executor` shouldn't trip\n // `-exec`).\n /(?:^|\\s)-{1,2}exec[\\s=]/, // go test -exec, cargo test --exec — v13 #2\n /(?:^|\\s)-{1,2}toolexec[\\s=]/, // go test -toolexec — v15\n /(?:^|\\s)-{1,2}gcflags[\\s=]/, // go test -gcflags='all=-N ...' — v15\n /(?:^|\\s)-{1,2}ldflags[\\s=]/, // go test -ldflags — v15 (linker arg injection)\n /(?:^|\\s)-{1,2}config[\\s=]/, // vitest --config, npm test --config — v15\n /(?:^|\\s)-{1,2}reporter[\\s=]/, // vitest --reporter, npm test --reporter — v15\n /(?:^|\\s)-{1,2}target-dir[\\s=]/, // cargo --target-dir — write-where-attacker-wants\n /(?:^|\\s)-{1,2}plugin[\\s=]/, // generic plugin-loader form (jest, eslint, etc.)\n];\n\n/**\n * Validate a kill-gate command string before execution. Gates run via\n * /bin/sh -c, so a prefix match alone is not safe — \"npm test; rm -rf /\"\n * starts with \"npm test\" but chains a second command. Defenses, in order:\n *\n * 1. **Word-bounded prefix match.** Accept either exact equality with\n * a prefix OR prefix followed by whitespace. Closes v13 Attacker\n * bypass #1: `validateGateCommand(\"npx vitest-pwn\")` no longer\n * passes by starting with \"npx vitest\". The trailing character\n * after the prefix MUST be whitespace (or end-of-string).\n *\n * 2. **Shell metacharacter deny.** Rejects any character that could\n * chain, pipe, redirect, substitute, or expand\n * ( `;`, `&`, `|`, backtick, `$`, `<`, `>`, parens, newlines, `{}`,\n * `*`, `?`, `~` ). Plain whitespace-delimited arguments such as\n * \"npm run build --if-present\" still pass.\n *\n * 3. **Per-command danger pattern deny** (post-metachar). The `-exec`\n * flag on `go test` / `cargo test` runs an arbitrary wrapper binary\n * directly, bypassing shell metachar checks entirely. Closes v13\n * Attacker bypass #2.\n *\n * Returns `{allowed: true}` on accept, or `{allowed: false, reason}` on\n * reject. The reason string is operator-readable; callers should surface\n * it as-is.\n */\nexport function validateGateCommand(gate: string): {\n allowed: boolean;\n reason?: string;\n} {\n const trimmed = gate.trimStart();\n\n // 1. Word-bounded prefix match.\n const prefixOk = ALLOWED_GATE_PREFIXES.some((prefix) => {\n if (trimmed === prefix) return true; // exact match\n if (!trimmed.startsWith(prefix)) return false;\n // If the prefix already ends with whitespace (\"npm run \",\n // \"npx turbo run \", \"make \"), the word boundary is baked in by\n // startsWith — and the next char IS the start of an argument,\n // which is fine. Only enforce next-char whitespace for prefixes\n // that DON'T end with whitespace (\"npm test\", \"npx vitest\",\n // \"go test\", \"cargo test\", \"pytest\", etc.) — those would\n // otherwise collide on shapes like \"npx vitest-pwn\".\n if (/\\s$/.test(prefix)) return true;\n const nextChar = trimmed.charAt(prefix.length);\n return nextChar === \" \" || nextChar === \"\\t\";\n });\n if (!prefixOk) {\n return {\n allowed: false,\n reason: `Gate rejected: command not in allowlist or fails word-boundary check. Allowed prefixes: ${ALLOWED_GATE_PREFIXES.join(\", \")}`,\n };\n }\n\n // 2. Shell metacharacter deny (expanded vs v12 to include {}, *, ?, ~).\n // `{a,b}` brace expansion + `*` glob + `~` home expansion are all\n // shell-evaluated before arguments reach the command and could\n // expand into unexpected forms.\n if (/[;&|`$<>\\n\\r(){}*?~]/.test(trimmed)) {\n return {\n allowed: false,\n reason:\n \"Gate rejected: command contains shell metacharacters or expansion forms that would allow chaining, substitution, or argument-shape attack\",\n };\n }\n\n // 3. Per-command danger patterns.\n for (const pattern of DANGER_PATTERNS) {\n if (pattern.test(trimmed)) {\n return {\n allowed: false,\n reason: `Gate rejected: command matches a known dangerous pattern (${pattern.source}) — e.g., go/cargo -exec runs an arbitrary wrapper binary`,\n };\n }\n }\n return { allowed: true };\n}\n\nexport interface WorkflowEngineOptions {\n config: BrainstormConfig;\n db: any;\n registry: ProviderRegistry;\n router: BrainstormRouter;\n costTracker: CostTracker;\n agentManager: AgentManager;\n projectPath: string;\n /** Per-step model overrides: stepId → modelId. Used for cross-model workflows. */\n stepModelOverrides?: Record<string, string>;\n /** Build state tracker — if build is broken, workflow pauses before next step. */\n buildState?: { isBroken(): boolean; getLastError(): string | null };\n}\n\nexport async function* runWorkflow(\n definition: WorkflowDefinition,\n userRequest: string,\n agentOverrides: Record<string, string>, // role → agentId overrides\n options: WorkflowEngineOptions,\n): AsyncGenerator<WorkflowEvent> {\n const { router, costTracker, agentManager, config, registry, projectPath } =\n options;\n\n // Load skills once for the entire workflow — keyed by name for role-based injection\n const allSkills = loadSkills(projectPath);\n const skillMap = new Map<string, { description: string; content: string }>();\n for (const s of allSkills) {\n skillMap.set(s.name, { description: s.description, content: s.content });\n }\n\n // Initialize the run\n const run: WorkflowRun = {\n id: randomUUID(),\n workflowId: definition.id,\n description: userRequest,\n status: \"running\",\n steps: [],\n artifacts: [],\n totalCost: 0,\n estimatedCost: 0,\n iteration: 0,\n maxIterations: definition.maxIterations,\n communicationMode: definition.communicationMode,\n createdAt: Math.floor(Date.now() / 1000),\n updatedAt: Math.floor(Date.now() / 1000),\n };\n\n // Resolve agents for each step\n const stepAgents = new Map<string, AgentProfile>();\n for (const step of definition.steps) {\n const overrideId =\n agentOverrides[step.agentRole] ?? agentOverrides[step.id];\n let agent: AgentProfile | null = null;\n\n if (overrideId) {\n agent = agentManager.get(overrideId);\n }\n if (!agent && step.agentId) {\n agent = agentManager.get(step.agentId);\n }\n if (!agent) {\n agent = agentManager.resolveByRole(step.agentRole);\n }\n if (!agent) {\n // Create a default agent for this role\n agent = createDefaultAgent(step.agentRole);\n }\n stepAgents.set(step.id, agent);\n }\n\n // Cost forecast\n const forecast: Array<{ step: string; cost: number }> = [];\n for (const step of definition.steps) {\n const agent = stepAgents.get(step.id);\n if (!agent) continue;\n const task = router.classify(userRequest);\n const decision = router.route(task);\n forecast.push({ step: step.id, cost: decision.estimatedCost });\n }\n const safetyMargin = config.general?.costSafetyMargin ?? 1.3;\n const totalEstimate =\n forecast.reduce((sum, f) => sum + f.cost, 0) * safetyMargin;\n run.estimatedCost = totalEstimate;\n\n yield {\n type: \"cost-forecast\",\n estimated: totalEstimate,\n breakdown: forecast,\n };\n yield { type: \"workflow-started\", run };\n\n // Execute steps\n let stepIndex = 0;\n const MAX_CONFIDENCE_RETRIES = 2;\n // Retry counter is scoped by stepIndex, not by loop iteration. The\n // previous version declared `let confidenceRetries = 0` inside the\n // while body, so every `continue` (used below to re-run the same\n // step after a low-confidence escalation) re-entered the loop head\n // and reset the counter to 0 — MAX_CONFIDENCE_RETRIES was never\n // reachable and the step could loop indefinitely against the budget.\n let confidenceRetries = 0;\n let confidenceRetryStepIndex = stepIndex;\n while (stepIndex < definition.steps.length) {\n if (confidenceRetryStepIndex !== stepIndex) {\n confidenceRetries = 0;\n confidenceRetryStepIndex = stepIndex;\n }\n const stepDef = definition.steps[stepIndex];\n const agent = stepAgents.get(stepDef.id);\n if (!agent) {\n yield {\n type: \"step-failed\" as any,\n step: {\n id: randomUUID(),\n stepDefId: stepDef.id,\n agentId: \"unknown\",\n status: \"failed\" as const,\n cost: 0,\n iteration: run.iteration,\n },\n error: new Error(`No agent resolved for step \"${stepDef.id}\"`),\n };\n stepIndex++;\n continue;\n }\n\n // Create step run\n const stepRun: WorkflowStepRun = {\n id: randomUUID(),\n stepDefId: stepDef.id,\n agentId: agent.id,\n status: \"running\",\n cost: 0,\n iteration: run.iteration,\n startedAt: Math.floor(Date.now() / 1000),\n };\n run.steps.push(stepRun);\n\n yield { type: \"step-started\", step: stepRun, agent };\n\n // Check build state before executing step — pause if build is broken\n if (options.buildState) {\n const bs = options.buildState;\n if (bs.isBroken()) {\n yield {\n type: \"workflow-paused\",\n reason: `Build is broken: ${bs.getLastError()}. Fix before continuing.`,\n run,\n };\n stepRun.status = \"skipped\";\n stepRun.error = \"Build broken — step skipped\";\n break;\n }\n }\n\n try {\n // Build context for this step\n const isRetry = run.iteration > 0 && stepDef.loopBackTo !== undefined;\n const ctx = buildStepContext(stepDef, agent, run, isRetry, skillMap);\n\n // Build tools (respect agent's allowedTools)\n const tools = createDefaultToolRegistry();\n\n // Run the agent loop\n let fullResponse = \"\";\n const sessionId = run.id;\n const systemPrompt = ctx.systemPrompt;\n\n // Per-step model override for cross-model workflows\n const stepModelId = options.stepModelOverrides?.[stepDef.id];\n\n // Enforce per-agent tool allowlist via roleToolFilter\n const roleToolFilter =\n agent.allowedTools && agent.allowedTools !== \"all\"\n ? { allowedTools: agent.allowedTools as string[] }\n : undefined;\n\n for await (const event of runAgentLoop(ctx.messages, {\n config,\n registry,\n router,\n costTracker,\n tools,\n sessionId,\n projectPath,\n systemPrompt,\n disableTools: !shouldUseTools(stepDef, agent),\n roleToolFilter,\n ...(stepModelId ? { preferredModelId: stepModelId } : {}),\n })) {\n // Forward agent events as step progress\n yield { type: \"step-progress\", stepId: stepDef.id, event };\n\n if (event.type === \"text-delta\") {\n fullResponse += event.delta;\n }\n if (event.type === \"done\") {\n stepRun.cost = event.totalCost - run.totalCost;\n run.totalCost = event.totalCost;\n }\n }\n\n // Create artifact from response\n const artifact: Artifact = {\n id: stepDef.outputArtifact,\n stepId: stepDef.id,\n agentId: agent.id,\n content: fullResponse,\n contentType: detectContentType(fullResponse),\n metadata: {},\n confidence: 0,\n cost: stepRun.cost,\n timestamp: Math.floor(Date.now() / 1000),\n iteration: run.iteration,\n };\n\n // Extract confidence\n artifact.confidence = extractConfidence(artifact);\n\n run.artifacts.push(artifact);\n writeArtifact(run.id, artifact);\n stepRun.artifactId = artifact.id;\n stepRun.status = \"completed\";\n stepRun.completedAt = Math.floor(Date.now() / 1000);\n\n yield { type: \"step-completed\", step: stepRun, artifact };\n\n if (stepDef.killGates && stepDef.killGates.length > 0) {\n for (const gate of stepDef.killGates) {\n const verdict = validateGateCommand(gate);\n if (!verdict.allowed) {\n yield {\n type: \"gate-failed\" as const,\n step: stepRun,\n gate,\n output: verdict.reason ?? \"Gate rejected\",\n };\n run.status = \"paused\";\n return;\n }\n\n try {\n const { execFileSync } = await import(\"node:child_process\");\n execFileSync(\"/bin/sh\", [\"-c\", gate], {\n cwd: projectPath,\n timeout: 60000,\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n });\n yield {\n type: \"gate-passed\",\n step: stepRun,\n gate,\n };\n } catch (err: any) {\n const output = (err.stderr?.toString() ?? err.message ?? \"\").slice(\n 0,\n 500,\n );\n yield {\n type: \"gate-failed\",\n step: stepRun,\n gate,\n output,\n };\n // Gate failed — pause workflow\n run.status = \"paused\";\n return;\n }\n }\n }\n\n // Check confidence escalation\n const escalation = determineEscalation(\n artifact.confidence,\n agent.confidenceThreshold,\n run.iteration < run.maxIterations,\n );\n if (escalation === \"pause\") {\n yield {\n type: \"confidence-escalation\",\n step: stepRun,\n confidence: artifact.confidence,\n action: \"paused — low confidence\",\n };\n run.status = \"paused\";\n return; // Pause workflow for user decision\n }\n if (escalation === \"retry\") {\n confidenceRetries++;\n if (confidenceRetries > MAX_CONFIDENCE_RETRIES) {\n yield {\n type: \"confidence-escalation\",\n step: stepRun,\n confidence: artifact.confidence,\n action: \"max confidence retries reached — continuing\",\n };\n } else {\n yield {\n type: \"confidence-escalation\",\n step: stepRun,\n confidence: artifact.confidence,\n action: `retrying step (${confidenceRetries}/${MAX_CONFIDENCE_RETRIES})`,\n };\n continue; // Re-run same step\n }\n }\n\n // Handle review step rejection → loop back\n if (stepDef.isReviewStep && !isReviewApproved(artifact)) {\n if (run.iteration < run.maxIterations && stepDef.loopBackTo) {\n run.iteration++;\n const loopBackIndex = definition.steps.findIndex(\n (s) => s.id === stepDef.loopBackTo,\n );\n if (loopBackIndex >= 0) {\n yield {\n type: \"review-rejected\",\n step: stepRun,\n reason: artifact.content.slice(0, 200),\n loopingBackTo: stepDef.loopBackTo,\n };\n stepIndex = loopBackIndex;\n continue;\n }\n }\n }\n\n stepIndex++;\n } catch (error: any) {\n stepRun.status = \"failed\";\n stepRun.error = error.message;\n stepRun.completedAt = Math.floor(Date.now() / 1000);\n\n yield { type: \"step-failed\", step: stepRun, error };\n\n // Record failure for routing fallback\n router.recordFailure(agent.modelId, error.message);\n\n run.status = \"failed\";\n yield { type: \"workflow-failed\", run, error };\n return;\n }\n }\n\n run.status = \"completed\";\n run.updatedAt = Math.floor(Date.now() / 1000);\n yield { type: \"workflow-completed\", run };\n}\n\nfunction shouldUseTools(step: WorkflowStepDef, agent: AgentProfile): boolean {\n if (agent.allowedTools === \"all\") return true;\n if (Array.isArray(agent.allowedTools) && agent.allowedTools.length > 0)\n return true;\n return false;\n}\n\nfunction detectContentType(content: string): Artifact[\"contentType\"] {\n const trimmed = content.trim();\n if (trimmed.startsWith(\"{\") || trimmed.startsWith(\"[\")) {\n try {\n JSON.parse(trimmed);\n return \"json\";\n } catch {}\n }\n if (trimmed.includes(\"```\")) return \"code\";\n if (trimmed.includes(\"# \") || trimmed.includes(\"## \")) return \"markdown\";\n return \"text\";\n}\n\nfunction createDefaultAgent(role: string): AgentProfile {\n const now = Math.floor(Date.now() / 1000);\n return {\n id: `default-${role}`,\n displayName: role.charAt(0).toUpperCase() + role.slice(1),\n role: role as AgentRole,\n description: \"\",\n modelId: \"auto\",\n allowedTools: role === \"coder\" ? \"all\" : [\"file_read\", \"glob\", \"grep\"],\n budget: { exhaustionAction: \"downgrade\" },\n confidenceThreshold: 0.7,\n maxSteps: 10,\n fallbackChain: [],\n guardrails: {},\n lifecycle: \"active\",\n createdAt: now,\n updatedAt: now,\n };\n}\n","import type {\n AgentProfile,\n Artifact,\n WorkflowRun,\n WorkflowStepDef,\n} from \"@brainst0rm/shared\";\nimport { buildAgentSystemPrompt } from \"@brainst0rm/agents\";\n\nexport interface FilteredContext {\n systemPrompt: string;\n messages: Array<{ role: \"user\" | \"assistant\" | \"system\"; content: string }>;\n}\n\n/**\n * Build context for a workflow step based on communication mode.\n *\n * Handoff: agent sees only its input artifacts + original request.\n * Shared: agent sees full conversation history from all prior agents.\n */\nexport function buildStepContext(\n step: WorkflowStepDef,\n agent: AgentProfile,\n run: WorkflowRun,\n isRetryAfterReject: boolean,\n loadedSkills?: Map<string, { description: string; content: string }>,\n): FilteredContext {\n if (run.communicationMode === \"shared\") {\n return buildSharedContext(\n step,\n agent,\n run,\n isRetryAfterReject,\n loadedSkills,\n );\n }\n return buildHandoffContext(\n step,\n agent,\n run,\n isRetryAfterReject,\n loadedSkills,\n );\n}\n\nfunction buildHandoffContext(\n step: WorkflowStepDef,\n agent: AgentProfile,\n run: WorkflowRun,\n isRetryAfterReject: boolean,\n loadedSkills?: Map<string, { description: string; content: string }>,\n): FilteredContext {\n const systemPrompt = buildAgentSystemPrompt(\n agent,\n step.description,\n loadedSkills,\n );\n const messages: FilteredContext[\"messages\"] = [];\n\n // Original user request\n messages.push({ role: \"user\", content: run.description });\n\n // Input artifacts from previous steps\n for (const artifactId of step.inputArtifacts) {\n // Find the most recent artifact with this ID for the current or most recent iteration\n const artifact = findLatestArtifact(\n run.artifacts,\n artifactId,\n run.iteration,\n );\n if (!artifact) continue;\n\n messages.push({\n role: \"assistant\",\n content: `[${artifact.id} from ${artifact.agentId}]:\\n\\n${artifact.content}`,\n });\n }\n\n // If retrying after reviewer rejection, add the review feedback\n if (isRetryAfterReject) {\n const reviewArtifact = findLatestArtifact(\n run.artifacts,\n \"review\",\n run.iteration - 1,\n );\n if (reviewArtifact) {\n messages.push({\n role: \"user\",\n content: `The reviewer rejected the previous implementation. Please address these issues:\\n\\n${reviewArtifact.content}`,\n });\n }\n }\n\n return { systemPrompt, messages };\n}\n\nfunction buildSharedContext(\n step: WorkflowStepDef,\n agent: AgentProfile,\n run: WorkflowRun,\n isRetryAfterReject: boolean,\n loadedSkills?: Map<string, { description: string; content: string }>,\n): FilteredContext {\n const systemPrompt = buildAgentSystemPrompt(\n agent,\n step.description,\n loadedSkills,\n );\n const messages: FilteredContext[\"messages\"] = [];\n\n // Original user request\n messages.push({ role: \"user\", content: run.description });\n\n // All prior artifacts in chronological order\n const sorted = [...run.artifacts].sort((a, b) => a.timestamp - b.timestamp);\n for (const artifact of sorted) {\n messages.push({\n role: \"assistant\",\n content: `[${artifact.agentId} — ${artifact.id}]:\\n\\n${artifact.content}`,\n });\n }\n\n // Current step instruction\n messages.push({\n role: \"user\",\n content: `Now it's your turn as ${agent.displayName}. ${step.description}`,\n });\n\n return { systemPrompt, messages };\n}\n\nfunction findLatestArtifact(\n artifacts: Artifact[],\n id: string,\n maxIteration: number,\n): Artifact | undefined {\n // Find artifact matching id at the current or most recent iteration\n for (let i = maxIteration; i >= 0; i--) {\n const found = artifacts.find((a) => a.id === id && a.iteration === i);\n if (found) return found;\n }\n // Fallback: any artifact with this ID\n return [...artifacts].reverse().find((a: Artifact) => a.id === id);\n}\n","/**\n * Artifact Store — persist workflow step outputs to disk.\n *\n * Creates a workspace directory per workflow run and writes each\n * step's artifact as a file with metadata manifest.\n */\n\nimport {\n mkdirSync,\n writeFileSync,\n readFileSync,\n existsSync,\n readdirSync,\n} from \"node:fs\";\nimport { join, resolve, sep } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport type { Artifact, WorkflowRun } from \"@brainst0rm/shared\";\n\nconst ARTIFACTS_BASE = join(homedir(), \".brainstorm\", \"artifacts\");\n\n/**\n * Sanitize a stepId before it lands in a filesystem path. stepIds come from\n * workflow definitions and — on the review-step path — can be influenced by\n * LLM output, so a stepId like \"../../.ssh/authorized_keys\" would otherwise\n * let writeArtifact() write outside the workspace directory.\n */\nfunction sanitizeStepId(raw: string): string {\n if (typeof raw !== \"string\" || raw.length === 0) {\n throw new Error(\"artifact-store: empty stepId\");\n }\n if (raw.length > 100) {\n throw new Error(\n `artifact-store: stepId too long (${raw.length} > 100 chars)`,\n );\n }\n if (raw.includes(\"/\") || raw.includes(\"\\\\\")) {\n throw new Error(\n `artifact-store: path separator in stepId (${JSON.stringify(raw)})`,\n );\n }\n if (raw.includes(\"..\") || raw.startsWith(\".\")) {\n throw new Error(\n `artifact-store: traversal or dot-prefix in stepId (${JSON.stringify(raw)})`,\n );\n }\n for (let i = 0; i < raw.length; i++) {\n const code = raw.charCodeAt(i);\n if (code < 0x20 || code === 0x7f) {\n throw new Error(`artifact-store: control character in stepId`);\n }\n }\n return raw;\n}\n\nexport interface ArtifactManifest {\n runId: string;\n description: string;\n preset: string;\n startedAt: string;\n completedAt?: string;\n totalCost: number;\n steps: Array<{\n stepId: string;\n agentRole: string;\n modelUsed: string;\n artifactPath: string;\n contentType: string;\n confidence: number;\n cost: number;\n iteration: number;\n }>;\n}\n\n/**\n * Get the workspace directory for a workflow run.\n */\nexport function getWorkspaceDir(runId: string): string {\n return join(ARTIFACTS_BASE, runId);\n}\n\n/**\n * Ensure the workspace directory exists.\n */\nexport function ensureWorkspace(runId: string): string {\n const dir = getWorkspaceDir(runId);\n mkdirSync(dir, { recursive: true });\n return dir;\n}\n\n/**\n * Write an artifact to disk and return the file path.\n */\nexport function writeArtifact(runId: string, artifact: Artifact): string {\n const dir = ensureWorkspace(runId);\n const safeStepId = sanitizeStepId(artifact.stepId);\n const iteration = Number(artifact.iteration);\n if (!Number.isFinite(iteration) || iteration < 0) {\n throw new Error(\n `artifact-store: invalid iteration (${String(artifact.iteration)})`,\n );\n }\n const ext =\n artifact.contentType === \"json\"\n ? \"json\"\n : artifact.contentType === \"code\"\n ? \"ts\"\n : artifact.contentType === \"markdown\"\n ? \"md\"\n : \"txt\";\n const filename = `step-${safeStepId}-${iteration}.${ext}`;\n const filePath = join(dir, filename);\n\n // Belt-and-braces: even with sanitation, assert the resolved path stays\n // under the workspace root before committing the write.\n const root = resolve(dir);\n const target = resolve(filePath);\n if (target !== root && !target.startsWith(root + sep)) {\n throw new Error(\n `artifact-store: resolved path escapes workspace (${target})`,\n );\n }\n\n writeFileSync(filePath, artifact.content, \"utf-8\");\n return filePath;\n}\n\n/**\n * Write or update the manifest for a workflow run.\n */\nexport function writeManifest(runId: string, manifest: ArtifactManifest): void {\n const dir = ensureWorkspace(runId);\n const filePath = join(dir, \"manifest.json\");\n writeFileSync(filePath, JSON.stringify(manifest, null, 2), \"utf-8\");\n}\n\n/**\n * Read a manifest for a workflow run.\n */\nexport function readManifest(runId: string): ArtifactManifest | null {\n const filePath = join(getWorkspaceDir(runId), \"manifest.json\");\n if (!existsSync(filePath)) return null;\n try {\n return JSON.parse(readFileSync(filePath, \"utf-8\"));\n } catch {\n return null;\n }\n}\n\n/**\n * List all workflow runs with manifests, most recent first.\n */\nexport function listRuns(limit = 10): ArtifactManifest[] {\n if (!existsSync(ARTIFACTS_BASE)) return [];\n\n // runIds are randomUUID() (engine.ts:62), so sorting directory names\n // lexically returns runs in essentially random order — not \"most\n // recent first\" as the `.reverse().slice(limit)` shape implied.\n // Read every manifest, sort by startedAt, then slice. For typical\n // workflow-run counts (dozens, not thousands) the full-scan cost\n // is negligible; a manifest that fails to parse is silently\n // dropped (same behavior as before).\n const dirs = readdirSync(ARTIFACTS_BASE, { withFileTypes: true })\n .filter((d) => d.isDirectory())\n .map((d) => d.name);\n\n const manifests: ArtifactManifest[] = [];\n for (const dir of dirs) {\n const m = readManifest(dir);\n if (m) manifests.push(m);\n }\n manifests.sort((a, b) => b.startedAt.localeCompare(a.startedAt));\n return manifests.slice(0, limit);\n}\n\n/**\n * Read an artifact's content from disk.\n */\nexport function readArtifact(\n runId: string,\n stepId: string,\n iteration = 0,\n): string | null {\n const dir = getWorkspaceDir(runId);\n if (!existsSync(dir)) return null;\n\n const safeStepId = sanitizeStepId(stepId);\n const files = readdirSync(dir).filter((f) =>\n f.startsWith(`step-${safeStepId}-`),\n );\n if (files.length === 0) return null;\n\n const target = files.find((f) => f.includes(`-${iteration}.`));\n if (!target) return null;\n try {\n return readFileSync(join(dir, target), \"utf-8\");\n } catch {\n return null;\n }\n}\n","import type { Artifact, WorkflowStepDef, ModelEntry } from \"@brainst0rm/shared\";\n\nexport type EscalationAction = \"continue\" | \"retry\" | \"pause\";\n\nexport interface ModelEscalation {\n action: EscalationAction;\n /** If action is 'retry', the model to escalate to (higher capability). */\n escalateToModelId?: string;\n /** Reason for escalation. */\n reason: string;\n}\n\n/**\n * Extract confidence from an artifact.\n * Priority: structured JSON field > heuristic text scan > default.\n */\nexport function extractConfidence(artifact: Artifact): number {\n // 1. Structured JSON output with confidence field\n if (artifact.contentType === \"json\") {\n try {\n const parsed = JSON.parse(artifact.content);\n if (typeof parsed.confidence === \"number\") {\n return Math.max(0, Math.min(1, parsed.confidence));\n }\n } catch {\n /* not valid JSON */\n }\n }\n\n // 2. Heuristic scan for confidence language\n const text = artifact.content.toLowerCase();\n\n if (\n text.includes(\"i am not sure\") ||\n text.includes(\"i'm uncertain\") ||\n text.includes(\"might not be correct\") ||\n text.includes(\"i am unsure\")\n ) {\n return 0.4;\n }\n if (\n text.includes(\"i'm fairly confident\") ||\n text.includes(\"should work\") ||\n text.includes(\"likely correct\")\n ) {\n return 0.7;\n }\n if (\n text.includes(\"i am confident\") ||\n text.includes(\"this will work\") ||\n text.includes(\"i am certain\")\n ) {\n return 0.9;\n }\n\n // 3. Default moderate confidence\n return 0.6;\n}\n\n/**\n * Determine escalation action based on confidence vs threshold.\n */\nexport function determineEscalation(\n confidence: number,\n threshold: number,\n canRetry: boolean,\n): EscalationAction {\n if (confidence >= threshold) return \"continue\";\n\n const deficit = threshold - confidence;\n\n // Large deficit → pause for user decision\n if (deficit > 0.3) return \"pause\";\n\n // Small deficit and can retry → retry with same or better model\n if (deficit > 0.1 && canRetry) return \"retry\";\n\n // Marginal → continue with warning\n return \"continue\";\n}\n\n/**\n * Check if a review artifact indicates rejection.\n */\nexport function isReviewApproved(artifact: Artifact): boolean {\n // Try structured JSON first\n try {\n const parsed = JSON.parse(artifact.content);\n if (typeof parsed.approved === \"boolean\") return parsed.approved;\n } catch {\n /* not JSON */\n }\n\n // Heuristic fallback — check rejection signals FIRST so they take precedence\n const text = artifact.content.toLowerCase();\n if (\n text.includes(\"rejected\") ||\n text.includes(\"needs changes\") ||\n text.includes(\"not approved\")\n )\n return false;\n if (text.includes(\"issues found\") || text.includes(\"critical\")) return false;\n if (\n text.includes(\"approved\") ||\n text.includes(\"lgtm\") ||\n text.includes(\"looks good\")\n )\n return true;\n\n return false; // default to NOT approved — reviews must explicitly approve\n}\n\n/**\n * Determine cross-model escalation when a step's confidence is too low.\n *\n * Given the current model and available models, find a more capable model\n * to retry the step on. Uses quality tier as the primary escalation axis.\n */\nexport function determineModelEscalation(\n confidence: number,\n threshold: number,\n currentModel: ModelEntry,\n availableModels: ModelEntry[],\n canRetry: boolean,\n): ModelEscalation {\n const action = determineEscalation(confidence, threshold, canRetry);\n\n if (action !== \"retry\") {\n return {\n action,\n reason:\n action === \"continue\"\n ? `Confidence ${(confidence * 100).toFixed(0)}% meets threshold`\n : `Confidence ${(confidence * 100).toFixed(0)}% too low — pausing for user decision`,\n };\n }\n\n // Find a more capable model (higher quality tier)\n const betterModels = availableModels\n .filter(\n (m) =>\n m.status === \"available\" &&\n m.id !== currentModel.id &&\n m.capabilities.qualityTier < currentModel.capabilities.qualityTier, // lower tier = higher quality\n )\n .sort((a, b) => a.capabilities.qualityTier - b.capabilities.qualityTier);\n\n if (betterModels.length === 0) {\n // Already on the best available model — retry with same model\n return {\n action: \"retry\",\n reason: `Confidence ${(confidence * 100).toFixed(0)}% below threshold — retrying on same model (no higher-quality model available)`,\n };\n }\n\n const escalateTarget = betterModels[0];\n return {\n action: \"retry\",\n escalateToModelId: escalateTarget.id,\n reason: `Confidence ${(confidence * 100).toFixed(0)}% below threshold — escalating from ${currentModel.name} to ${escalateTarget.name}`,\n };\n}\n","import type { WorkflowDefinition } from \"@brainst0rm/shared\";\n\nexport const PRESET_WORKFLOWS: WorkflowDefinition[] = [\n {\n id: \"implement-feature\",\n name: \"Implement Feature\",\n description: \"Full feature implementation: plan → code → review → fix loop\",\n communicationMode: \"handoff\",\n maxIterations: 3,\n steps: [\n {\n id: \"plan\",\n agentRole: \"architect\",\n description:\n \"Create a detailed implementation plan with file structure, interfaces, and step-by-step instructions\",\n inputArtifacts: [],\n outputArtifact: \"spec\",\n outputSchema: \"implementation-spec\",\n isReviewStep: false,\n },\n {\n id: \"code\",\n agentRole: \"coder\",\n description: \"Implement the code according to the specification\",\n inputArtifacts: [\"spec\"],\n outputArtifact: \"code\",\n isReviewStep: false,\n },\n {\n id: \"review\",\n agentRole: \"reviewer\",\n description:\n \"Review the implementation for correctness, security, and adherence to the spec\",\n inputArtifacts: [\"spec\", \"code\"],\n outputArtifact: \"review\",\n outputSchema: \"review-result\",\n isReviewStep: true,\n loopBackTo: \"code\",\n },\n ],\n },\n {\n id: \"fix-bug\",\n name: \"Fix Bug\",\n description: \"Bug diagnosis → fix → review\",\n communicationMode: \"handoff\",\n maxIterations: 2,\n steps: [\n {\n id: \"diagnose\",\n agentRole: \"debugger\",\n description: \"Identify the root cause of the bug and recommend a fix\",\n inputArtifacts: [],\n outputArtifact: \"diagnosis\",\n outputSchema: \"debug-result\",\n isReviewStep: false,\n },\n {\n id: \"fix\",\n agentRole: \"coder\",\n description: \"Implement the fix based on the diagnosis\",\n inputArtifacts: [\"diagnosis\"],\n outputArtifact: \"code\",\n isReviewStep: false,\n },\n {\n id: \"verify\",\n agentRole: \"reviewer\",\n description:\n \"Verify the fix addresses the root cause without introducing new issues\",\n inputArtifacts: [\"diagnosis\", \"code\"],\n outputArtifact: \"review\",\n outputSchema: \"review-result\",\n isReviewStep: true,\n loopBackTo: \"fix\",\n },\n ],\n },\n {\n id: \"code-review\",\n name: \"Code Review\",\n description: \"Single-step code review with quality model\",\n communicationMode: \"handoff\",\n maxIterations: 1,\n steps: [\n {\n id: \"review\",\n agentRole: \"reviewer\",\n description:\n \"Review the code for bugs, security issues, performance problems, and style\",\n inputArtifacts: [],\n outputArtifact: \"review\",\n outputSchema: \"review-result\",\n isReviewStep: false, // no loop — single pass\n },\n ],\n },\n {\n id: \"explain\",\n name: \"Explain\",\n description: \"Technical explanation with quality model\",\n communicationMode: \"handoff\",\n maxIterations: 1,\n steps: [\n {\n id: \"explain\",\n agentRole: \"analyst\",\n description: \"Provide a clear, thorough technical explanation\",\n inputArtifacts: [],\n outputArtifact: \"explanation\",\n isReviewStep: false,\n },\n ],\n },\n {\n id: \"consensus-review\",\n name: \"Consensus Review\",\n description:\n \"3-reviewer parallel code review with consensus voting. Security + code quality + style reviewers on different models. 2-of-3 must pass.\",\n communicationMode: \"parallel\",\n maxIterations: 1,\n steps: [\n {\n id: \"security-review\",\n agentRole: \"security-reviewer\",\n description:\n \"Security review: auth, injection, credentials, input validation\",\n inputArtifacts: [],\n outputArtifact: \"security-review\",\n outputSchema: \"review-result\",\n isReviewStep: false,\n },\n {\n id: \"quality-review\",\n agentRole: \"code-reviewer\",\n description:\n \"Code quality review: correctness, error handling, API design\",\n inputArtifacts: [],\n outputArtifact: \"quality-review\",\n outputSchema: \"review-result\",\n isReviewStep: false,\n },\n {\n id: \"style-review\",\n agentRole: \"style-reviewer\",\n description: \"Style review: naming, organization, idiomatic patterns\",\n inputArtifacts: [],\n outputArtifact: \"style-review\",\n outputSchema: \"review-result\",\n isReviewStep: false,\n },\n ],\n },\n {\n id: \"feature-pipeline\",\n name: \"Feature Pipeline\",\n description:\n \"Full SDLC pipeline: spec → design → implement → review → test → compliance → integrate. Each phase has mandatory gates.\",\n communicationMode: \"handoff\",\n maxIterations: 2,\n steps: [\n {\n id: \"spec\",\n agentRole: \"product-manager\",\n description: \"Write feature specification with acceptance criteria\",\n inputArtifacts: [],\n outputArtifact: \"spec\",\n outputSchema: \"feature-spec\",\n isReviewStep: false,\n },\n {\n id: \"design\",\n agentRole: \"architect\",\n description: \"Design architecture, data model, API surface\",\n inputArtifacts: [\"spec\"],\n outputArtifact: \"design\",\n outputSchema: \"architecture-design\",\n isReviewStep: false,\n },\n {\n id: \"implement\",\n agentRole: \"coder\",\n description: \"Write compilable code. Gate: build must pass.\",\n inputArtifacts: [\"spec\", \"design\"],\n outputArtifact: \"code\",\n isReviewStep: false,\n },\n {\n id: \"review\",\n agentRole: \"reviewer\",\n description:\n \"3-agent consensus review. Gate: 2-of-3 must pass. Critical → loop to implement.\",\n inputArtifacts: [\"code\"],\n outputArtifact: \"review\",\n outputSchema: \"review-result\",\n isReviewStep: true,\n loopBackTo: \"implement\",\n },\n {\n id: \"test\",\n agentRole: \"qa\",\n description: \"Write tests and run them. Gate: tests must pass.\",\n inputArtifacts: [\"code\", \"spec\"],\n outputArtifact: \"tests\",\n isReviewStep: false,\n },\n {\n id: \"compliance\",\n agentRole: \"compliance\",\n description: \"Map implementation to SOC2/HIPAA controls with evidence\",\n inputArtifacts: [\"code\", \"spec\"],\n outputArtifact: \"compliance\",\n isReviewStep: false,\n },\n {\n id: \"integrate\",\n agentRole: \"devops\",\n description: \"CI/CD pipeline and dashboard integration\",\n inputArtifacts: [\"code\", \"tests\"],\n outputArtifact: \"integration\",\n isReviewStep: false,\n },\n ],\n },\n];\n\nexport function getPresetWorkflow(id: string): WorkflowDefinition | undefined {\n return PRESET_WORKFLOWS.find((w) => w.id === id);\n}\n\n/**\n * Auto-select a preset workflow from natural language.\n */\nexport function autoSelectPreset(description: string): string | null {\n const lower = description.toLowerCase();\n\n if (/\\b(build|implement|add|create|scaffold|new feature)\\b/.test(lower))\n return \"implement-feature\";\n if (/\\b(fix|debug|error|broken|bug|crash|failing)\\b/.test(lower))\n return \"fix-bug\";\n if (/\\b(review|check|audit|inspect)\\b/.test(lower)) return \"code-review\";\n if (/\\b(explain|what is|how does|why|describe|understand)\\b/.test(lower))\n return \"explain\";\n\n return null;\n}\n","/**\n * Recipe System — shareable YAML workflow definitions.\n *\n * Recipes live in `.brainstorm/recipes/` (project-level) or\n * `~/.brainstorm/recipes/` (global). Each is a YAML file that\n * maps to a WorkflowDefinition.\n *\n * Flywheel: shared recipes = same workflow across users →\n * BrainstormLLM sees repeated patterns → learns optimal phase config.\n *\n * Format:\n * ```yaml\n * name: Implement Feature\n * description: Plan → code → review loop\n * communication: handoff\n * maxIterations: 3\n * steps:\n * - id: plan\n * role: architect\n * description: Create implementation plan\n * output: spec\n * outputSchema: implementation-spec\n * - id: code\n * role: coder\n * description: Implement the code\n * input: [spec]\n * output: code\n * - id: review\n * role: reviewer\n * description: Review for correctness\n * input: [spec, code]\n * output: review\n * review: true\n * loopBack: code\n * ```\n */\n\nimport {\n readdirSync,\n readFileSync,\n writeFileSync,\n existsSync,\n mkdirSync,\n} from \"node:fs\";\nimport { join, basename, extname } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { parse as parseYAML } from \"yaml\";\nimport type {\n WorkflowDefinition,\n WorkflowStepDef,\n AgentRole,\n CommunicationMode,\n} from \"@brainst0rm/shared\";\n\nexport interface RecipeFile {\n name: string;\n description: string;\n communication?: CommunicationMode;\n maxIterations?: number;\n steps: RecipeStep[];\n}\n\ninterface RecipeStep {\n id: string;\n role: string;\n description: string;\n input?: string[];\n output: string;\n outputSchema?: string;\n review?: boolean;\n loopBack?: string;\n skip?: string;\n}\n\n/**\n * Load all recipes from project-level and global recipe directories.\n * Project recipes override global ones with the same filename.\n */\nexport function loadRecipes(projectPath: string): WorkflowDefinition[] {\n const globalDir = join(homedir(), \".brainstorm\", \"recipes\");\n const projectDir = join(projectPath, \".brainstorm\", \"recipes\");\n\n const globalRecipes = loadRecipesFromDir(globalDir);\n const projectRecipes = loadRecipesFromDir(projectDir);\n\n // Project recipes override global ones by id\n const merged = new Map<string, WorkflowDefinition>();\n for (const r of globalRecipes) merged.set(r.id, r);\n for (const r of projectRecipes) merged.set(r.id, r);\n\n return [...merged.values()];\n}\n\n/**\n * Load a single recipe by name (filename without extension).\n */\nexport function loadRecipe(\n projectPath: string,\n name: string,\n): WorkflowDefinition | null {\n const projectFile = join(\n projectPath,\n \".brainstorm\",\n \"recipes\",\n `${name}.yaml`,\n );\n const globalFile = join(homedir(), \".brainstorm\", \"recipes\", `${name}.yaml`);\n\n // Project-level takes precedence\n const file = existsSync(projectFile)\n ? projectFile\n : existsSync(globalFile)\n ? globalFile\n : null;\n\n if (!file) return null;\n\n try {\n const content = readFileSync(file, \"utf-8\");\n return parseRecipeYAML(name, content);\n } catch {\n return null;\n }\n}\n\n/**\n * Initialize the recipe directory with example recipes.\n */\nexport function initRecipeDir(projectPath: string): string {\n const dir = join(projectPath, \".brainstorm\", \"recipes\");\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n\n // Write example recipe if directory is empty\n const files = readdirSync(dir).filter(\n (f) => extname(f) === \".yaml\" || extname(f) === \".yml\",\n );\n if (files.length === 0) {\n const example = `# Example recipe — customize or create new ones\nname: Quick Review\ndescription: Fast code review with a quality model\ncommunication: handoff\nmaxIterations: 1\nsteps:\n - id: review\n role: reviewer\n description: Review code for bugs, security, and style issues\n output: review\n outputSchema: review-result\n`;\n const examplePath = join(dir, \"quick-review.yaml\");\n writeFileSync(examplePath, example, \"utf-8\");\n }\n\n return dir;\n}\n\n/**\n * List available recipes (names + descriptions).\n */\nexport function listRecipes(\n projectPath: string,\n): Array<{ id: string; name: string; description: string; source: string }> {\n const globalDir = join(homedir(), \".brainstorm\", \"recipes\");\n const projectDir = join(projectPath, \".brainstorm\", \"recipes\");\n\n const results: Array<{\n id: string;\n name: string;\n description: string;\n source: string;\n }> = [];\n const seen = new Set<string>();\n\n // Project recipes first (they override global)\n for (const recipe of loadRecipesFromDir(projectDir)) {\n results.push({\n id: recipe.id,\n name: recipe.name,\n description: recipe.description,\n source: \"project\",\n });\n seen.add(recipe.id);\n }\n\n for (const recipe of loadRecipesFromDir(globalDir)) {\n if (!seen.has(recipe.id)) {\n results.push({\n id: recipe.id,\n name: recipe.name,\n description: recipe.description,\n source: \"global\",\n });\n }\n }\n\n return results;\n}\n\n// ── Internal ──────────────────────────────────────────────────────────\n\nfunction loadRecipesFromDir(dir: string): WorkflowDefinition[] {\n if (!existsSync(dir)) return [];\n\n const recipes: WorkflowDefinition[] = [];\n const files = readdirSync(dir).filter(\n (f) => extname(f) === \".yaml\" || extname(f) === \".yml\",\n );\n\n for (const file of files) {\n try {\n const content = readFileSync(join(dir, file), \"utf-8\");\n const id = basename(file, extname(file));\n recipes.push(parseRecipeYAML(id, content));\n } catch {\n // Skip malformed recipes\n }\n }\n\n return recipes;\n}\n\nfunction parseRecipeYAML(id: string, content: string): WorkflowDefinition {\n const raw = parseYAML(content) as RecipeFile;\n\n if (!raw.name || !raw.steps || !Array.isArray(raw.steps)) {\n throw new Error(`Invalid recipe: missing name or steps`);\n }\n\n const steps: WorkflowStepDef[] = raw.steps.map((s) => ({\n id: s.id,\n agentRole: (s.role ?? \"coder\") as AgentRole,\n description: s.description ?? \"\",\n inputArtifacts: s.input ?? [],\n outputArtifact: s.output,\n outputSchema: s.outputSchema,\n isReviewStep: s.review ?? false,\n loopBackTo: s.loopBack,\n skipCondition: s.skip,\n }));\n\n return {\n id,\n name: raw.name,\n description: raw.description ?? \"\",\n steps,\n communicationMode: raw.communication ?? \"handoff\",\n maxIterations: raw.maxIterations ?? 2,\n };\n}\n"],"mappings":"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","names":["readdirSync","readFileSync","writeFileSync","existsSync","mkdirSync","join","homedir","parseYAML"]}