@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
@@ -21,7 +21,7 @@ import {
21
21
  setTaskEventHandler,
22
22
  setToolOutputHandler,
23
23
  withWorkspace
24
- } from "./chunk-RV3CJQGC.js";
24
+ } from "./chunk-2AXI2OPK.js";
25
25
  import {
26
26
  defineTool
27
27
  } from "./chunk-TCFNCUKS.js";
@@ -39,7 +39,7 @@ import {
39
39
  import {
40
40
  adaptToolsForModel,
41
41
  recordOutcome
42
- } from "./chunk-NVA62I52.js";
42
+ } from "./chunk-6WGHIUWX.js";
43
43
  import {
44
44
  stepCountIs,
45
45
  streamText
@@ -53,7 +53,7 @@ import {
53
53
  MessageRepository,
54
54
  SessionRepository,
55
55
  getDb
56
- } from "./chunk-TLQVDPEQ.js";
56
+ } from "./chunk-DJ7WG6GZ.js";
57
57
  import {
58
58
  atomicWriteFile,
59
59
  createLogger,
@@ -18680,4 +18680,4 @@ export {
18680
18680
  formatTickMessage,
18681
18681
  DaemonController
18682
18682
  };
18683
- //# sourceMappingURL=chunk-SCGV333Z.js.map
18683
+ //# sourceMappingURL=chunk-HKRUCBMI.js.map
@@ -24,7 +24,7 @@ import {
24
24
  setTaskEventHandler,
25
25
  setToolOutputHandler,
26
26
  withWorkspace
27
- } from "./chunk-6G2HA63H.js";
27
+ } from "./chunk-3AYD5ONW.js";
28
28
  import {
29
29
  defineTool
30
30
  } from "./chunk-2JGN7EGX.js";
@@ -42,7 +42,7 @@ import {
42
42
  import {
43
43
  adaptToolsForModel,
44
44
  recordOutcome
45
- } from "./chunk-4LR7LQPG.js";
45
+ } from "./chunk-CZILJ33T.js";
46
46
  import {
47
47
  stepCountIs,
48
48
  streamText
@@ -56,7 +56,7 @@ import {
56
56
  MessageRepository,
57
57
  SessionRepository,
58
58
  getDb
59
- } from "./chunk-Z5QQ5OGV.js";
59
+ } from "./chunk-52Q6CE4Y.js";
60
60
  import {
61
61
  atomicWriteFile,
62
62
  createLogger,
@@ -18683,4 +18683,4 @@ export {
18683
18683
  formatTickMessage,
18684
18684
  DaemonController
18685
18685
  };
18686
- //# sourceMappingURL=chunk-PIT7VD46.js.map
18686
+ //# sourceMappingURL=chunk-N5V2PGPN.js.map
@@ -3,11 +3,11 @@ import {
3
3
  formatModelMenu,
4
4
  formatRoleConfirmation,
5
5
  getModelForRole
6
- } from "./chunk-N7JKT44Y.js";
6
+ } from "./chunk-GUHXB5DX.js";
7
7
  import {
8
8
  autoSelectPreset,
9
9
  getPresetWorkflow
10
- } from "./chunk-FGYEICUI.js";
10
+ } from "./chunk-6UFDBLUX.js";
11
11
  import {
12
12
  loadRoutingIntelligence
13
13
  } from "./chunk-HUR6VPUJ.js";
@@ -390,7 +390,7 @@ Tokens: ${tokens.input.toLocaleString()} in / ${tokens.output.toLocaleString()}
390
390
  usage: "/project [name|list|register|show <name>]",
391
391
  execute: async (args, ctx) => {
392
392
  const { ProjectManager } = await import("./dist-VBHOLVNE.js");
393
- const { getDb } = await import("./dist-P2J4GXPC.js");
393
+ const { getDb } = await import("./dist-S7FLVLXS.js");
394
394
  const db = getDb();
395
395
  const pm = new ProjectManager(db);
396
396
  const parts = args.trim().split(/\s+/);
@@ -460,7 +460,7 @@ ${lines.join("\n")}`;
460
460
  const parts = args.trim().split(/\s+/);
461
461
  const action = parts[0] || "list";
462
462
  if (action === "list" || !action) {
463
- const { getDb } = await import("./dist-P2J4GXPC.js");
463
+ const { getDb } = await import("./dist-S7FLVLXS.js");
464
464
  const db = getDb();
465
465
  const tasks = db.prepare(
466
466
  "SELECT * FROM scheduled_tasks WHERE status = 'active' ORDER BY name"
@@ -477,7 +477,7 @@ ${lines.join("\n")}`;
477
477
  ${lines.join("\n")}`;
478
478
  }
479
479
  if (action === "history") {
480
- const { getDb } = await import("./dist-P2J4GXPC.js");
480
+ const { getDb } = await import("./dist-S7FLVLXS.js");
481
481
  const db = getDb();
482
482
  const runs = db.prepare(
483
483
  "SELECT r.*, t.name as task_name FROM scheduled_task_runs r JOIN scheduled_tasks t ON r.task_id = t.id ORDER BY r.created_at DESC LIMIT 10"
@@ -503,7 +503,7 @@ ${lines.join("\n")}`;
503
503
  execute: async (args) => {
504
504
  const { OrchestrationEngine } = await import("./dist-UEJGQ36S.js");
505
505
  const { ProjectManager } = await import("./dist-VBHOLVNE.js");
506
- const { getDb } = await import("./dist-P2J4GXPC.js");
506
+ const { getDb } = await import("./dist-S7FLVLXS.js");
507
507
  const db = getDb();
508
508
  const engine = new OrchestrationEngine(db);
509
509
  const pm = new ProjectManager(db);
@@ -680,7 +680,7 @@ function createRoleCommand(roleId) {
680
680
  ctx.setOutputStyle?.(role.outputStyle);
681
681
  ctx.setMode?.(role.permissionMode);
682
682
  ctx.setStrategy?.(role.routingStrategy);
683
- const { getRolePrompt } = await import("./roles-LDNPU3NI.js");
683
+ const { getRolePrompt } = await import("./roles-MVBHE5QW.js");
684
684
  ctx.rebuildSystemPrompt?.(getRolePrompt(roleId, modelId));
685
685
  ctx.setActiveRole?.(roleId);
686
686
  return formatRoleConfirmation(roleId, modelId);
@@ -1244,7 +1244,7 @@ commands.push({
1244
1244
  if (!args.trim()) {
1245
1245
  return "Usage: /architect-edit <task description>\n\nA reasoning model (Opus/GPT-5.4) will plan the change, then a fast model (Sonnet/GPT-4.1) will apply it.";
1246
1246
  }
1247
- const { ROLES: ROLES2, getRolePrompt } = await import("./roles-LDNPU3NI.js");
1247
+ const { ROLES: ROLES2, getRolePrompt } = await import("./roles-MVBHE5QW.js");
1248
1248
  const architect = ROLES2.architect;
1249
1249
  const planModel = architect.modelChoices[0]?.modelId ?? "anthropic/claude-opus-4.6";
1250
1250
  ctx.setModel?.(planModel);
@@ -1275,7 +1275,7 @@ commands.push({
1275
1275
  description: "Switch from architect plan phase to coding apply phase",
1276
1276
  usage: "/ae-apply",
1277
1277
  execute: async (_args, ctx) => {
1278
- const { ROLES: ROLES2 } = await import("./roles-LDNPU3NI.js");
1278
+ const { ROLES: ROLES2 } = await import("./roles-MVBHE5QW.js");
1279
1279
  const dev = ROLES2["sr-developer"];
1280
1280
  const codeModel = dev.modelChoices[0]?.modelId ?? "anthropic/claude-sonnet-4.6";
1281
1281
  ctx.setModel?.(codeModel);
@@ -1295,7 +1295,7 @@ commands.push({
1295
1295
  description: "List, run, or init shareable YAML workflow recipes",
1296
1296
  usage: "/recipe [list|run <name>|init]",
1297
1297
  execute: async (args, ctx) => {
1298
- const { listRecipes, loadRecipe, initRecipeDir } = await import("./dist-IUVHFJV2.js");
1298
+ const { listRecipes, loadRecipe, initRecipeDir } = await import("./dist-UETKBS6A.js");
1299
1299
  const cwd = process.cwd();
1300
1300
  const parts = args.trim().split(/\s+/);
1301
1301
  const subcommand = parts[0]?.toLowerCase() ?? "list";
@@ -1384,7 +1384,7 @@ commands.push({
1384
1384
  const subcommand = args?.trim().toLowerCase();
1385
1385
  if (subcommand === "tools") {
1386
1386
  try {
1387
- const { listChangeSets } = await import("./dist-GNYSGXLR.js");
1387
+ const { listChangeSets } = await import("./dist-XFJ337R7.js");
1388
1388
  return [
1389
1389
  "God Mode Tools:",
1390
1390
  "",
@@ -1405,7 +1405,7 @@ commands.push({
1405
1405
  }
1406
1406
  if (subcommand === "changesets" || subcommand === "cs") {
1407
1407
  try {
1408
- const { listChangeSets } = await import("./dist-GNYSGXLR.js");
1408
+ const { listChangeSets } = await import("./dist-XFJ337R7.js");
1409
1409
  const active = listChangeSets();
1410
1410
  if (active.length === 0) return "No active changesets.";
1411
1411
  const lines = ["Pending ChangeSets:", ""];
@@ -1425,7 +1425,7 @@ commands.push({
1425
1425
  }
1426
1426
  if (subcommand === "audit") {
1427
1427
  try {
1428
- const { getAuditLog } = await import("./dist-GNYSGXLR.js");
1428
+ const { getAuditLog } = await import("./dist-XFJ337R7.js");
1429
1429
  const log = getAuditLog();
1430
1430
  if (log.length === 0) return "No God Mode audit entries this session.";
1431
1431
  const lines = ["God Mode Audit Log (this session):", ""];
@@ -1549,4 +1549,4 @@ export {
1549
1549
  executeSlashCommand,
1550
1550
  getSlashCommands
1551
1551
  };
1552
- //# sourceMappingURL=chunk-GF5TKYDA.js.map
1552
+ //# sourceMappingURL=chunk-RVQOLZR6.js.map
@@ -6,11 +6,11 @@ import {
6
6
  formatModelMenu,
7
7
  formatRoleConfirmation,
8
8
  getModelForRole
9
- } from "./chunk-GLWCTGWG.js";
9
+ } from "./chunk-4NNXZFPX.js";
10
10
  import {
11
11
  autoSelectPreset,
12
12
  getPresetWorkflow
13
- } from "./chunk-ZYGUHAHM.js";
13
+ } from "./chunk-Z5RDHTWQ.js";
14
14
  import {
15
15
  loadRoutingIntelligence
16
16
  } from "./chunk-FRRVMDNL.js";
@@ -393,7 +393,7 @@ Tokens: ${tokens.input.toLocaleString()} in / ${tokens.output.toLocaleString()}
393
393
  usage: "/project [name|list|register|show <name>]",
394
394
  execute: async (args, ctx) => {
395
395
  const { ProjectManager } = await import("./dist-GO7NB7Z2.js");
396
- const { getDb } = await import("./dist-7IRVYQYG.js");
396
+ const { getDb } = await import("./dist-RUBJT7FI.js");
397
397
  const db = getDb();
398
398
  const pm = new ProjectManager(db);
399
399
  const parts = args.trim().split(/\s+/);
@@ -463,7 +463,7 @@ ${lines.join("\n")}`;
463
463
  const parts = args.trim().split(/\s+/);
464
464
  const action = parts[0] || "list";
465
465
  if (action === "list" || !action) {
466
- const { getDb } = await import("./dist-7IRVYQYG.js");
466
+ const { getDb } = await import("./dist-RUBJT7FI.js");
467
467
  const db = getDb();
468
468
  const tasks = db.prepare(
469
469
  "SELECT * FROM scheduled_tasks WHERE status = 'active' ORDER BY name"
@@ -480,7 +480,7 @@ ${lines.join("\n")}`;
480
480
  ${lines.join("\n")}`;
481
481
  }
482
482
  if (action === "history") {
483
- const { getDb } = await import("./dist-7IRVYQYG.js");
483
+ const { getDb } = await import("./dist-RUBJT7FI.js");
484
484
  const db = getDb();
485
485
  const runs = db.prepare(
486
486
  "SELECT r.*, t.name as task_name FROM scheduled_task_runs r JOIN scheduled_tasks t ON r.task_id = t.id ORDER BY r.created_at DESC LIMIT 10"
@@ -506,7 +506,7 @@ ${lines.join("\n")}`;
506
506
  execute: async (args) => {
507
507
  const { OrchestrationEngine } = await import("./dist-WQXOVHLR.js");
508
508
  const { ProjectManager } = await import("./dist-GO7NB7Z2.js");
509
- const { getDb } = await import("./dist-7IRVYQYG.js");
509
+ const { getDb } = await import("./dist-RUBJT7FI.js");
510
510
  const db = getDb();
511
511
  const engine = new OrchestrationEngine(db);
512
512
  const pm = new ProjectManager(db);
@@ -683,7 +683,7 @@ function createRoleCommand(roleId) {
683
683
  ctx.setOutputStyle?.(role.outputStyle);
684
684
  ctx.setMode?.(role.permissionMode);
685
685
  ctx.setStrategy?.(role.routingStrategy);
686
- const { getRolePrompt } = await import("./roles-QTZ54BOF.js");
686
+ const { getRolePrompt } = await import("./roles-CJTZSFFW.js");
687
687
  ctx.rebuildSystemPrompt?.(getRolePrompt(roleId, modelId));
688
688
  ctx.setActiveRole?.(roleId);
689
689
  return formatRoleConfirmation(roleId, modelId);
@@ -1247,7 +1247,7 @@ commands.push({
1247
1247
  if (!args.trim()) {
1248
1248
  return "Usage: /architect-edit <task description>\n\nA reasoning model (Opus/GPT-5.4) will plan the change, then a fast model (Sonnet/GPT-4.1) will apply it.";
1249
1249
  }
1250
- const { ROLES: ROLES2, getRolePrompt } = await import("./roles-QTZ54BOF.js");
1250
+ const { ROLES: ROLES2, getRolePrompt } = await import("./roles-CJTZSFFW.js");
1251
1251
  const architect = ROLES2.architect;
1252
1252
  const planModel = architect.modelChoices[0]?.modelId ?? "anthropic/claude-opus-4.6";
1253
1253
  ctx.setModel?.(planModel);
@@ -1278,7 +1278,7 @@ commands.push({
1278
1278
  description: "Switch from architect plan phase to coding apply phase",
1279
1279
  usage: "/ae-apply",
1280
1280
  execute: async (_args, ctx) => {
1281
- const { ROLES: ROLES2 } = await import("./roles-QTZ54BOF.js");
1281
+ const { ROLES: ROLES2 } = await import("./roles-CJTZSFFW.js");
1282
1282
  const dev = ROLES2["sr-developer"];
1283
1283
  const codeModel = dev.modelChoices[0]?.modelId ?? "anthropic/claude-sonnet-4.6";
1284
1284
  ctx.setModel?.(codeModel);
@@ -1298,7 +1298,7 @@ commands.push({
1298
1298
  description: "List, run, or init shareable YAML workflow recipes",
1299
1299
  usage: "/recipe [list|run <name>|init]",
1300
1300
  execute: async (args, ctx) => {
1301
- const { listRecipes, loadRecipe, initRecipeDir } = await import("./dist-ESUVKHL4.js");
1301
+ const { listRecipes, loadRecipe, initRecipeDir } = await import("./dist-QFVAD45U.js");
1302
1302
  const cwd = process.cwd();
1303
1303
  const parts = args.trim().split(/\s+/);
1304
1304
  const subcommand = parts[0]?.toLowerCase() ?? "list";
@@ -1387,7 +1387,7 @@ commands.push({
1387
1387
  const subcommand = args?.trim().toLowerCase();
1388
1388
  if (subcommand === "tools") {
1389
1389
  try {
1390
- const { listChangeSets } = await import("./dist-QUYR4VH7.js");
1390
+ const { listChangeSets } = await import("./dist-5NJP3JHL.js");
1391
1391
  return [
1392
1392
  "God Mode Tools:",
1393
1393
  "",
@@ -1408,7 +1408,7 @@ commands.push({
1408
1408
  }
1409
1409
  if (subcommand === "changesets" || subcommand === "cs") {
1410
1410
  try {
1411
- const { listChangeSets } = await import("./dist-QUYR4VH7.js");
1411
+ const { listChangeSets } = await import("./dist-5NJP3JHL.js");
1412
1412
  const active = listChangeSets();
1413
1413
  if (active.length === 0) return "No active changesets.";
1414
1414
  const lines = ["Pending ChangeSets:", ""];
@@ -1428,7 +1428,7 @@ commands.push({
1428
1428
  }
1429
1429
  if (subcommand === "audit") {
1430
1430
  try {
1431
- const { getAuditLog } = await import("./dist-QUYR4VH7.js");
1431
+ const { getAuditLog } = await import("./dist-5NJP3JHL.js");
1432
1432
  const log = getAuditLog();
1433
1433
  if (log.length === 0) return "No God Mode audit entries this session.";
1434
1434
  const lines = ["God Mode Audit Log (this session):", ""];
@@ -1552,4 +1552,4 @@ export {
1552
1552
  executeSlashCommand,
1553
1553
  getSlashCommands
1554
1554
  };
1555
- //# sourceMappingURL=chunk-AH5SFL5J.js.map
1555
+ //# sourceMappingURL=chunk-RVXUVX5W.js.map
@@ -8,24 +8,24 @@ import {
8
8
  SessionManager,
9
9
  buildSystemPrompt,
10
10
  runAgentLoop
11
- } from "./chunk-PIT7VD46.js";
11
+ } from "./chunk-N5V2PGPN.js";
12
12
  import {
13
13
  createDefaultToolRegistry,
14
14
  withWorkspace
15
- } from "./chunk-6G2HA63H.js";
15
+ } from "./chunk-3AYD5ONW.js";
16
16
  import {
17
17
  createProviderRegistry
18
18
  } from "./chunk-5OQEC3FY.js";
19
19
  import {
20
20
  BrainstormRouter,
21
21
  CostTracker
22
- } from "./chunk-4LR7LQPG.js";
22
+ } from "./chunk-CZILJ33T.js";
23
23
  import {
24
24
  loadConfig
25
25
  } from "./chunk-5TPIVYD3.js";
26
26
  import {
27
27
  getDb
28
- } from "./chunk-Z5QQ5OGV.js";
28
+ } from "./chunk-52Q6CE4Y.js";
29
29
  import {
30
30
  createLogger
31
31
  } from "./chunk-E7XO6BH5.js";
@@ -1071,4 +1071,4 @@ export {
1071
1071
  formatScorecard2,
1072
1072
  saveReport
1073
1073
  };
1074
- //# sourceMappingURL=chunk-4PCWPRRN.js.map
1074
+ //# sourceMappingURL=chunk-WRO5TVID.js.map
@@ -4,13 +4,13 @@ const require = __createRequire(import.meta.url);
4
4
  import {
5
5
  loadSkills,
6
6
  runAgentLoop
7
- } from "./chunk-PIT7VD46.js";
7
+ } from "./chunk-N5V2PGPN.js";
8
8
  import {
9
9
  require_dist
10
10
  } from "./chunk-CTFDTJMG.js";
11
11
  import {
12
12
  createDefaultToolRegistry
13
- } from "./chunk-6G2HA63H.js";
13
+ } from "./chunk-3AYD5ONW.js";
14
14
  import {
15
15
  buildAgentSystemPrompt
16
16
  } from "./chunk-WHP2HLMU.js";
@@ -337,8 +337,40 @@ var DANGER_PATTERNS = [
337
337
  // vitest --reporter, npm test --reporter — v15
338
338
  /(?:^|\s)-{1,2}target-dir[\s=]/,
339
339
  // cargo --target-dir — write-where-attacker-wants
340
- /(?:^|\s)-{1,2}plugin[\s=]/
340
+ /(?:^|\s)-{1,2}plugin[\s=]/,
341
341
  // generic plugin-loader form (jest, eslint, etc.)
342
+ // v16 Attacker (post path-to-90 round) — flag-loader bypass class
343
+ // extension. Each loads an attacker-controlled file as code or treats
344
+ // an attacker-controlled path as authoritative configuration.
345
+ // The trailing class `(?:$|[\s=])` matches end-of-string OR ws/= so a
346
+ // dangerous flag is caught even when it's the final token (e.g.
347
+ // `npm test --inspect`).
348
+ /(?:^|\s)-f(?:$|[\s=])/,
349
+ // make -f /tmp/evil.Makefile — load alt Makefile
350
+ /(?:^|\s)-{1,2}makefile(?:$|[\s=])/,
351
+ // make --makefile=/tmp/evil.Makefile
352
+ /(?:^|\s)-p(?:$|[\s=])/,
353
+ // pytest -p PLUGIN — load plugin module
354
+ /(?:^|\s)-{1,2}rootdir(?:$|[\s=])/,
355
+ // pytest --rootdir — treat path as project root
356
+ /(?:^|\s)-{1,2}manifest-path(?:$|[\s=])/,
357
+ // cargo --manifest-path — alt Cargo.toml
358
+ /(?:^|\s)-{1,2}inspect-brk(?:$|[\s=])/,
359
+ // node --inspect-brk — debugger w/ arb code
360
+ /(?:^|\s)-{1,2}inspect(?:$|[\s=])/,
361
+ // node --inspect — same class
362
+ /(?:^|\s)-{1,2}userconfig(?:$|[\s=])/,
363
+ // npm --userconfig — alt npmrc with scripts
364
+ /(?:^|\s)-{1,2}env-file(?:$|[\s=])/,
365
+ // node --env-file — set env from arbitrary path
366
+ /(?:^|\s)-{1,2}prefix(?:$|[\s=])/,
367
+ // npm --prefix — alt project root for scripts
368
+ /(?:^|\s)-{1,2}require(?:$|[\s=])/,
369
+ // node --require / -r — preload arbitrary module
370
+ /(?:^|\s)-r(?:$|[\s=])/,
371
+ // node -r — short form of --require
372
+ /(?:^|\s)-{1,2}import(?:$|[\s=])/
373
+ // node --import — preload ESM module
342
374
  ];
343
375
  function validateGateCommand(gate) {
344
376
  const trimmed = gate.trimStart();
@@ -1050,4 +1082,4 @@ export {
1050
1082
  initRecipeDir,
1051
1083
  listRecipes
1052
1084
  };
1053
- //# sourceMappingURL=chunk-ZYGUHAHM.js.map
1085
+ //# sourceMappingURL=chunk-Z5RDHTWQ.js.map
@@ -0,0 +1 @@
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 // v16 Attacker (post path-to-90 round) — flag-loader bypass class\n // extension. Each loads an attacker-controlled file as code or treats\n // an attacker-controlled path as authoritative configuration.\n // The trailing class `(?:$|[\\s=])` matches end-of-string OR ws/= so a\n // dangerous flag is caught even when it's the final token (e.g.\n // `npm test --inspect`).\n /(?:^|\\s)-f(?:$|[\\s=])/, // make -f /tmp/evil.Makefile — load alt Makefile\n /(?:^|\\s)-{1,2}makefile(?:$|[\\s=])/, // make --makefile=/tmp/evil.Makefile\n /(?:^|\\s)-p(?:$|[\\s=])/, // pytest -p PLUGIN — load plugin module\n /(?:^|\\s)-{1,2}rootdir(?:$|[\\s=])/, // pytest --rootdir — treat path as project root\n /(?:^|\\s)-{1,2}manifest-path(?:$|[\\s=])/, // cargo --manifest-path — alt Cargo.toml\n /(?:^|\\s)-{1,2}inspect-brk(?:$|[\\s=])/, // node --inspect-brk — debugger w/ arb code\n /(?:^|\\s)-{1,2}inspect(?:$|[\\s=])/, // node --inspect — same class\n /(?:^|\\s)-{1,2}userconfig(?:$|[\\s=])/, // npm --userconfig — alt npmrc with scripts\n /(?:^|\\s)-{1,2}env-file(?:$|[\\s=])/, // node --env-file — set env from arbitrary path\n /(?:^|\\s)-{1,2}prefix(?:$|[\\s=])/, // npm --prefix — alt project root for scripts\n /(?:^|\\s)-{1,2}require(?:$|[\\s=])/, // node --require / -r — preload arbitrary module\n /(?:^|\\s)-r(?:$|[\\s=])/, // node -r — short form of --require\n /(?:^|\\s)-{1,2}import(?:$|[\\s=])/, // node --import — preload ESM module\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"]}
@@ -13,7 +13,7 @@ import {
13
13
  retryChangeSet,
14
14
  setAuditPersister
15
15
  } from "./chunk-4RKWJCUC.js";
16
- import "./chunk-6G2HA63H.js";
16
+ import "./chunk-3AYD5ONW.js";
17
17
  import {
18
18
  defineTool
19
19
  } from "./chunk-2JGN7EGX.js";
@@ -1165,8 +1165,27 @@ function signEvent(event, masterSecret) {
1165
1165
  return createHmac("sha256", key).update(payload).digest("hex");
1166
1166
  }
1167
1167
  var MAX_EVENT_AGE_SECONDS = 300;
1168
+ var seenEventIds = /* @__PURE__ */ new Map();
1169
+ var MAX_SEEN_IDS = 1e5;
1170
+ var FRESHNESS_MS = MAX_EVENT_AGE_SECONDS * 1e3;
1171
+ function checkAndRecordEventId(eventId, now) {
1172
+ const cutoff = now - FRESHNESS_MS;
1173
+ for (const [id, ts] of seenEventIds) {
1174
+ if (ts < cutoff) seenEventIds.delete(id);
1175
+ }
1176
+ if (seenEventIds.has(eventId)) {
1177
+ return false;
1178
+ }
1179
+ if (seenEventIds.size >= MAX_SEEN_IDS) {
1180
+ const oldestKey = seenEventIds.keys().next().value;
1181
+ if (oldestKey !== void 0) seenEventIds.delete(oldestKey);
1182
+ }
1183
+ seenEventIds.set(eventId, now);
1184
+ return true;
1185
+ }
1168
1186
  function verifyEvent(event, masterSecret) {
1169
1187
  if (!event.signature) return false;
1188
+ if (!event.id) return false;
1170
1189
  if (!event.timestamp) return false;
1171
1190
  const eventTime = new Date(event.timestamp).getTime();
1172
1191
  if (Number.isNaN(eventTime)) return false;
@@ -1177,7 +1196,8 @@ function verifyEvent(event, masterSecret) {
1177
1196
  const sigBuf = Buffer.from(signature, "hex");
1178
1197
  const expectedBuf = Buffer.from(expected, "hex");
1179
1198
  if (sigBuf.length !== expectedBuf.length) return false;
1180
- return timingSafeEqual(sigBuf, expectedBuf);
1199
+ if (!timingSafeEqual(sigBuf, expectedBuf)) return false;
1200
+ return checkAndRecordEventId(event.id, Date.now());
1181
1201
  }
1182
1202
  function createSignedEvent(type, tenantId, product, data, masterSecret, opts) {
1183
1203
  const unsigned = {
@@ -1513,4 +1533,4 @@ export {
1513
1533
  verifyJWT,
1514
1534
  verifyProductContract
1515
1535
  };
1516
- //# sourceMappingURL=dist-QUYR4VH7.js.map
1536
+ //# sourceMappingURL=dist-5NJP3JHL.js.map