@corbat-tech/coco 2.38.0 → 2.39.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3362,8 +3362,330 @@ function defineTool(definition) {
3362
3362
 
3363
3363
  // src/cli/repl/agents/manager.ts
3364
3364
  init_logger();
3365
-
3366
- // src/runtime/multi-agent.ts
3365
+ var LEGACY_ROLE_MAPPINGS = [
3366
+ { legacy: "explore", role: "researcher", reason: "read-only codebase exploration" },
3367
+ { legacy: "researcher", role: "researcher", reason: "legacy executor role" },
3368
+ { legacy: "plan", role: "planner", reason: "task planning" },
3369
+ { legacy: "planner", role: "planner", reason: "legacy executor role" },
3370
+ { legacy: "architect", role: "architect", reason: "architecture design" },
3371
+ { legacy: "editor", role: "editor", reason: "implementation edits" },
3372
+ { legacy: "debug", role: "coder", reason: "debugging maps to coding capability" },
3373
+ { legacy: "coder", role: "coder", reason: "legacy executor role" },
3374
+ { legacy: "test", role: "tester", reason: "test authoring/execution" },
3375
+ { legacy: "tester", role: "tester", reason: "legacy executor role" },
3376
+ { legacy: "tdd", role: "tester", reason: "test-first implementation" },
3377
+ { legacy: "e2e", role: "tester", reason: "end-to-end testing" },
3378
+ { legacy: "review", role: "reviewer", reason: "code review" },
3379
+ { legacy: "reviewer", role: "reviewer", reason: "legacy executor role" },
3380
+ { legacy: "refactor", role: "optimizer", reason: "structure optimization" },
3381
+ { legacy: "optimizer", role: "optimizer", reason: "legacy executor role" },
3382
+ { legacy: "security", role: "security", reason: "security analysis" },
3383
+ { legacy: "qa", role: "qa", reason: "quality assurance" },
3384
+ { legacy: "integrator", role: "integrator", reason: "integration coordination" },
3385
+ { legacy: "pm", role: "pm", reason: "product/project coordination" },
3386
+ { legacy: "docs", role: "docs", reason: "documentation" },
3387
+ { legacy: "database", role: "database", reason: "database work" }
3388
+ ];
3389
+ var LEGACY_ROLE_MAP = new Map(LEGACY_ROLE_MAPPINGS.map((mapping) => [mapping.legacy, mapping]));
3390
+ function mapLegacyAgentRole(legacyRole, fallback = "coder") {
3391
+ return LEGACY_ROLE_MAP.get(legacyRole)?.role ?? fallback;
3392
+ }
3393
+ function assertProvenance(provenance) {
3394
+ if (!provenance.workflowRunId) {
3395
+ throw new Error("Shared workspace writes require workflowRunId provenance.");
3396
+ }
3397
+ }
3398
+ function snapshotFromRecords(records, role) {
3399
+ const includeSensitive = role === void 0 || role === "security" || role === "integrator" || role === "pm";
3400
+ const facts = /* @__PURE__ */ new Map();
3401
+ const decisions = /* @__PURE__ */ new Map();
3402
+ const risks = /* @__PURE__ */ new Map();
3403
+ const files = /* @__PURE__ */ new Map();
3404
+ const testResults = /* @__PURE__ */ new Map();
3405
+ const artifacts = [];
3406
+ for (const record of records) {
3407
+ if (!includeSensitive && (record.kind === "risk" || record.provenance.risk === "secrets-sensitive")) {
3408
+ continue;
3409
+ }
3410
+ switch (record.kind) {
3411
+ case "fact":
3412
+ facts.set(record.key, record.value);
3413
+ break;
3414
+ case "decision":
3415
+ decisions.set(record.key, record.value);
3416
+ break;
3417
+ case "risk":
3418
+ risks.set(record.key, record.value);
3419
+ break;
3420
+ case "file":
3421
+ files.set(record.key, record.value);
3422
+ break;
3423
+ case "testResult":
3424
+ testResults.set(record.key, record.value);
3425
+ break;
3426
+ case "artifact":
3427
+ if (isAgentArtifact(record.value)) {
3428
+ if (includeSensitive || record.value.kind !== "riskReport") {
3429
+ artifacts.push(cloneArtifact(record.value));
3430
+ }
3431
+ }
3432
+ break;
3433
+ }
3434
+ }
3435
+ return {
3436
+ facts: Object.fromEntries(facts),
3437
+ decisions: Object.fromEntries(decisions),
3438
+ risks: Object.fromEntries(risks),
3439
+ files: Object.fromEntries(files),
3440
+ testResults: Object.fromEntries(testResults),
3441
+ artifacts
3442
+ };
3443
+ }
3444
+ var InMemorySharedWorkspaceStore = class {
3445
+ records = [];
3446
+ write(input) {
3447
+ assertProvenance(input.provenance);
3448
+ const record = {
3449
+ id: `state-${randomUUID()}`,
3450
+ kind: input.kind,
3451
+ key: input.key,
3452
+ value: cloneUnknown(input.value),
3453
+ provenance: { ...input.provenance },
3454
+ createdAt: input.createdAt ?? (/* @__PURE__ */ new Date()).toISOString()
3455
+ };
3456
+ this.records.push(record);
3457
+ return cloneRecord(record);
3458
+ }
3459
+ list() {
3460
+ return this.records.map(cloneRecord);
3461
+ }
3462
+ snapshot() {
3463
+ return snapshotFromRecords(this.records);
3464
+ }
3465
+ readForRole(role) {
3466
+ return snapshotFromRecords(this.records, role);
3467
+ }
3468
+ clear() {
3469
+ this.records = [];
3470
+ }
3471
+ };
3472
+ function createAgentTraceContext(input = {}) {
3473
+ return {
3474
+ traceId: input.traceId ?? `trace-${randomUUID()}`,
3475
+ spanId: input.spanId ?? `span-${randomUUID()}`,
3476
+ parentSpanId: input.parentSpanId,
3477
+ workflowRunId: input.workflowRunId,
3478
+ agentRunId: input.agentRunId,
3479
+ taskId: input.taskId,
3480
+ toolCallId: input.toolCallId
3481
+ };
3482
+ }
3483
+ var AgentGraphEngine = class {
3484
+ eventLog;
3485
+ sharedState;
3486
+ nodeExecutor;
3487
+ gateEvaluator;
3488
+ trace;
3489
+ constructor(options = {}) {
3490
+ this.eventLog = options.eventLog;
3491
+ this.sharedState = options.sharedState ?? new InMemorySharedWorkspaceStore();
3492
+ this.nodeExecutor = options.nodeExecutor ?? defaultAgentGraphNodeExecutor;
3493
+ this.gateEvaluator = options.gateEvaluator ?? defaultAgentGateEvaluator;
3494
+ this.trace = options.trace ?? createAgentTraceContext();
3495
+ }
3496
+ async run(input) {
3497
+ const validation = validateAgentGraph(input.graph);
3498
+ if (!validation.valid) {
3499
+ throw new Error(
3500
+ `Invalid agent graph: ${validation.issues.map((issue) => issue.message).join("; ")}`
3501
+ );
3502
+ }
3503
+ const startedAt = (/* @__PURE__ */ new Date()).toISOString();
3504
+ const nodeResults = /* @__PURE__ */ new Map();
3505
+ const artifacts = [];
3506
+ const graphTrace = createAgentTraceContext({
3507
+ ...this.trace,
3508
+ workflowRunId: input.workflowRunId
3509
+ });
3510
+ this.eventLog?.record("agent.graph.started", {
3511
+ workflowRunId: input.workflowRunId,
3512
+ trace: graphTrace,
3513
+ levels: validation.levels
3514
+ });
3515
+ try {
3516
+ for (const level of validation.levels) {
3517
+ const batches = chunk(level, input.graph.parallelism ?? level.length);
3518
+ for (const batch of batches) {
3519
+ const levelResults = await Promise.all(
3520
+ batch.map(
3521
+ (nodeId) => this.executeNode({
3522
+ node: input.graph.nodes.find((candidate) => candidate.id === nodeId),
3523
+ graph: input.graph,
3524
+ workflowRunId: input.workflowRunId,
3525
+ input: input.input,
3526
+ graphTrace,
3527
+ nodeResults
3528
+ })
3529
+ )
3530
+ );
3531
+ for (const result2 of levelResults) {
3532
+ nodeResults.set(result2.taskId, result2);
3533
+ artifacts.push(...result2.artifacts.map(cloneArtifact));
3534
+ }
3535
+ }
3536
+ }
3537
+ const completedAt = (/* @__PURE__ */ new Date()).toISOString();
3538
+ const result = {
3539
+ id: input.workflowRunId,
3540
+ status: "completed",
3541
+ nodeResults: Object.fromEntries(nodeResults),
3542
+ artifacts,
3543
+ stateSnapshot: this.sharedState.snapshot(),
3544
+ trace: graphTrace,
3545
+ startedAt,
3546
+ completedAt
3547
+ };
3548
+ this.eventLog?.record("agent.graph.completed", {
3549
+ workflowRunId: input.workflowRunId,
3550
+ trace: graphTrace,
3551
+ nodeCount: nodeResults.size
3552
+ });
3553
+ return result;
3554
+ } catch (error) {
3555
+ const completedAt = (/* @__PURE__ */ new Date()).toISOString();
3556
+ const message = error instanceof Error ? error.message : String(error);
3557
+ this.eventLog?.record("agent.graph.failed", {
3558
+ workflowRunId: input.workflowRunId,
3559
+ trace: graphTrace,
3560
+ error: message
3561
+ });
3562
+ return {
3563
+ id: input.workflowRunId,
3564
+ status: "failed",
3565
+ nodeResults: Object.fromEntries(nodeResults),
3566
+ artifacts,
3567
+ stateSnapshot: this.sharedState.snapshot(),
3568
+ trace: graphTrace,
3569
+ startedAt,
3570
+ completedAt,
3571
+ error: message
3572
+ };
3573
+ }
3574
+ }
3575
+ async executeNode(input) {
3576
+ const attempts = input.node.retryPolicy?.maxAttempts ?? 1;
3577
+ let lastResult;
3578
+ for (let attempt = 1; attempt <= attempts; attempt++) {
3579
+ const task = graphNodeToTask(input.node, input.input);
3580
+ const trace = createAgentTraceContext({
3581
+ traceId: input.graphTrace.traceId,
3582
+ parentSpanId: input.graphTrace.spanId,
3583
+ workflowRunId: input.workflowRunId,
3584
+ taskId: task.id
3585
+ });
3586
+ this.eventLog?.record("agent.started", {
3587
+ workflowRunId: input.workflowRunId,
3588
+ nodeId: input.node.id,
3589
+ taskId: task.id,
3590
+ role: task.role,
3591
+ attempt,
3592
+ trace
3593
+ });
3594
+ const result = await this.nodeExecutor({
3595
+ node: input.node,
3596
+ task,
3597
+ attempt,
3598
+ workflowRunId: input.workflowRunId,
3599
+ trace,
3600
+ dependencyResults: input.nodeResults,
3601
+ sharedState: this.sharedState,
3602
+ eventLog: this.eventLog ?? NULL_EVENT_LOG
3603
+ });
3604
+ lastResult = result;
3605
+ for (const artifact of result.artifacts) {
3606
+ this.sharedState.write({
3607
+ kind: "artifact",
3608
+ key: artifact.id,
3609
+ value: artifact,
3610
+ provenance: {
3611
+ workflowRunId: input.workflowRunId,
3612
+ agentRunId: result.id,
3613
+ nodeId: input.node.id,
3614
+ taskId: task.id,
3615
+ risk: input.node.risk
3616
+ }
3617
+ });
3618
+ this.eventLog?.record("agent.artifact.created", {
3619
+ workflowRunId: input.workflowRunId,
3620
+ nodeId: input.node.id,
3621
+ agentRunId: result.id,
3622
+ artifactId: artifact.id,
3623
+ kind: artifact.kind,
3624
+ trace
3625
+ });
3626
+ }
3627
+ if (result.success) {
3628
+ await this.evaluateNodeGates(input.graph, input.node, result, input.workflowRunId, trace);
3629
+ this.eventLog?.record("agent.completed", {
3630
+ workflowRunId: input.workflowRunId,
3631
+ nodeId: input.node.id,
3632
+ agentRunId: result.id,
3633
+ taskId: task.id,
3634
+ role: result.role,
3635
+ attempt,
3636
+ trace
3637
+ });
3638
+ return result;
3639
+ }
3640
+ this.eventLog?.record("agent.failed", {
3641
+ workflowRunId: input.workflowRunId,
3642
+ nodeId: input.node.id,
3643
+ agentRunId: result.id,
3644
+ taskId: task.id,
3645
+ role: result.role,
3646
+ attempt,
3647
+ error: result.error,
3648
+ trace
3649
+ });
3650
+ if (attempt < attempts && input.node.retryPolicy?.backoffMs) {
3651
+ await new Promise((resolve3) => setTimeout(resolve3, input.node.retryPolicy.backoffMs));
3652
+ }
3653
+ }
3654
+ throw new Error(
3655
+ `Node '${input.node.id}' failed after ${attempts} attempt(s): ${lastResult?.error ?? "unknown error"}`
3656
+ );
3657
+ }
3658
+ async evaluateNodeGates(graph, node, result, workflowRunId, trace) {
3659
+ for (const gateId of node.gates ?? []) {
3660
+ const gate = graph.gates?.find((candidate) => candidate.id === gateId);
3661
+ if (!gate) continue;
3662
+ const evaluation = await this.gateEvaluator({
3663
+ gate,
3664
+ node,
3665
+ result,
3666
+ workflowRunId,
3667
+ trace,
3668
+ sharedState: this.sharedState,
3669
+ eventLog: this.eventLog ?? NULL_EVENT_LOG
3670
+ });
3671
+ const eventType = evaluation.passed ? "workflow.gate.passed" : "workflow.gate.failed";
3672
+ this.eventLog?.record(eventType, {
3673
+ workflowRunId,
3674
+ nodeId: node.id,
3675
+ gateId: gate.id,
3676
+ kind: gate.kind,
3677
+ required: gate.required,
3678
+ reason: evaluation.reason,
3679
+ trace
3680
+ });
3681
+ if (!evaluation.passed && gate.required) {
3682
+ throw new Error(
3683
+ `Required gate '${gate.id}' failed for node '${node.id}': ${evaluation.reason ?? "no reason"}`
3684
+ );
3685
+ }
3686
+ }
3687
+ }
3688
+ };
3367
3689
  function createAgentArtifact(input) {
3368
3690
  return {
3369
3691
  ...input,
@@ -3495,6 +3817,101 @@ function buildExecutionLevels(graph, issues) {
3495
3817
  }
3496
3818
  return levels;
3497
3819
  }
3820
+ var NULL_EVENT_LOG = {
3821
+ record(type, data = {}) {
3822
+ return {
3823
+ id: `event-${randomUUID()}`,
3824
+ type,
3825
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
3826
+ data
3827
+ };
3828
+ },
3829
+ list() {
3830
+ return [];
3831
+ },
3832
+ count() {
3833
+ return 0;
3834
+ },
3835
+ clear() {
3836
+ }
3837
+ };
3838
+ function graphNodeToTask(node, workflowInput) {
3839
+ return {
3840
+ id: node.id,
3841
+ role: node.agentRole ?? "coder",
3842
+ objective: node.description,
3843
+ context: {
3844
+ workflowInput,
3845
+ condition: node.condition
3846
+ },
3847
+ dependencies: node.dependsOn,
3848
+ constraints: node.requiredTools?.map((tool) => `Requires tool: ${tool}`)
3849
+ };
3850
+ }
3851
+ async function defaultAgentGraphNodeExecutor(execution) {
3852
+ const startedAt = (/* @__PURE__ */ new Date()).toISOString();
3853
+ const dependencyOutputs = Object.fromEntries(
3854
+ [...execution.dependencyResults.entries()].map(([id, result]) => [
3855
+ id,
3856
+ { success: result.success, output: result.output }
3857
+ ])
3858
+ );
3859
+ const output = [
3860
+ `Node '${execution.node.id}' executed by ${execution.task.role}.`,
3861
+ `Objective: ${execution.task.objective}`,
3862
+ Object.keys(dependencyOutputs).length > 0 ? `Dependencies: ${JSON.stringify(dependencyOutputs)}` : "Dependencies: none"
3863
+ ].join("\n");
3864
+ return normalizeAgentRunResult({
3865
+ id: `${execution.workflowRunId}-${execution.node.id}-attempt-${execution.attempt}`,
3866
+ taskId: execution.task.id,
3867
+ role: execution.task.role,
3868
+ success: true,
3869
+ output,
3870
+ startedAt,
3871
+ completedAt: (/* @__PURE__ */ new Date()).toISOString(),
3872
+ turns: 0,
3873
+ toolsUsed: [],
3874
+ durationMs: 0,
3875
+ metadata: {
3876
+ workflowRunId: execution.workflowRunId,
3877
+ nodeId: execution.node.id,
3878
+ trace: execution.trace,
3879
+ simulated: true
3880
+ }
3881
+ });
3882
+ }
3883
+ async function defaultAgentGateEvaluator(input) {
3884
+ if (!input.result.success) {
3885
+ return { passed: false, reason: "Agent result was not successful." };
3886
+ }
3887
+ return { passed: true };
3888
+ }
3889
+ function chunk(items, size) {
3890
+ const safeSize = Math.max(1, size);
3891
+ const result = [];
3892
+ for (let index = 0; index < items.length; index += safeSize) {
3893
+ result.push(items.slice(index, index + safeSize));
3894
+ }
3895
+ return result;
3896
+ }
3897
+ function cloneUnknown(value) {
3898
+ if (value === void 0 || value === null) return value;
3899
+ try {
3900
+ return JSON.parse(JSON.stringify(value));
3901
+ } catch {
3902
+ return value;
3903
+ }
3904
+ }
3905
+ function cloneRecord(record) {
3906
+ return {
3907
+ ...record,
3908
+ value: cloneUnknown(record.value),
3909
+ provenance: { ...record.provenance }
3910
+ };
3911
+ }
3912
+ function isAgentArtifact(value) {
3913
+ return typeof value === "object" && value !== null && "id" in value && "kind" in value && "content" in value && "createdAt" in value;
3914
+ }
3498
3915
  function cloneArtifact(artifact) {
3499
3916
  return {
3500
3917
  ...artifact,
@@ -4433,29 +4850,7 @@ var AgentManager = class extends EventEmitter {
4433
4850
  }
4434
4851
  };
4435
4852
  function agentTypeToRuntimeRole(type) {
4436
- switch (type) {
4437
- case "explore":
4438
- return "researcher";
4439
- case "plan":
4440
- return "planner";
4441
- case "test":
4442
- case "e2e":
4443
- case "tdd":
4444
- return "tester";
4445
- case "debug":
4446
- case "refactor":
4447
- return "coder";
4448
- case "review":
4449
- return "reviewer";
4450
- case "architect":
4451
- return "architect";
4452
- case "security":
4453
- return "security";
4454
- case "docs":
4455
- return "docs";
4456
- case "database":
4457
- return "database";
4458
- }
4853
+ return mapLegacyAgentRole(type);
4459
4854
  }
4460
4855
 
4461
4856
  // src/agents/provider-bridge.ts
@@ -5713,14 +6108,14 @@ ${message}
5713
6108
  const subprocess = execa(command, options);
5714
6109
  let stdoutBuffer = "";
5715
6110
  let stderrBuffer = "";
5716
- subprocess.stdout?.on("data", (chunk) => {
5717
- const text2 = chunk.toString();
6111
+ subprocess.stdout?.on("data", (chunk2) => {
6112
+ const text2 = chunk2.toString();
5718
6113
  stdoutBuffer += text2;
5719
6114
  process.stdout.write(text2);
5720
6115
  heartbeat.activity();
5721
6116
  });
5722
- subprocess.stderr?.on("data", (chunk) => {
5723
- const text2 = chunk.toString();
6117
+ subprocess.stderr?.on("data", (chunk2) => {
6118
+ const text2 = chunk2.toString();
5724
6119
  stderrBuffer += text2;
5725
6120
  process.stderr.write(text2);
5726
6121
  heartbeat.activity();
@@ -6396,7 +6791,7 @@ var AGENT_TYPES = [
6396
6791
  "docs",
6397
6792
  "database"
6398
6793
  ];
6399
- var LEGACY_ROLE_MAP = {
6794
+ var LEGACY_ROLE_MAP2 = {
6400
6795
  researcher: "explore",
6401
6796
  coder: "debug",
6402
6797
  // "debug" has write + bash + read — closest to general coding
@@ -6416,7 +6811,7 @@ var SpawnSimpleAgentSchema = z.object({
6416
6811
  });
6417
6812
  function resolveAgentType(input) {
6418
6813
  if (input.type) return input.type;
6419
- if (input.role && input.role in LEGACY_ROLE_MAP) return LEGACY_ROLE_MAP[input.role];
6814
+ if (input.role && input.role in LEGACY_ROLE_MAP2) return LEGACY_ROLE_MAP2[input.role];
6420
6815
  return "explore";
6421
6816
  }
6422
6817
  var spawnSimpleAgentTool = defineTool({
@@ -7682,25 +8077,25 @@ var DuplicationAnalyzer = class {
7682
8077
  const lines = content.split("\n");
7683
8078
  totalLines += lines.length;
7684
8079
  for (let i = 0; i <= lines.length - this.minLines; i++) {
7685
- const chunk = lines.slice(i, i + this.minLines).join("\n").trim();
7686
- if (chunk.length < 20) continue;
7687
- if (!chunks.has(chunk)) {
7688
- chunks.set(chunk, []);
8080
+ const chunk2 = lines.slice(i, i + this.minLines).join("\n").trim();
8081
+ if (chunk2.length < 20) continue;
8082
+ if (!chunks.has(chunk2)) {
8083
+ chunks.set(chunk2, []);
7689
8084
  }
7690
- chunks.get(chunk).push({ file, line: i + 1 });
8085
+ chunks.get(chunk2).push({ file, line: i + 1 });
7691
8086
  }
7692
8087
  } catch {
7693
8088
  }
7694
8089
  }
7695
8090
  const duplicates = [];
7696
8091
  let duplicateLines = 0;
7697
- for (const [chunk, locations] of chunks.entries()) {
8092
+ for (const [chunk2, locations] of chunks.entries()) {
7698
8093
  if (locations.length > 1) {
7699
8094
  duplicates.push({
7700
- lines: chunk.split("\n"),
8095
+ lines: chunk2.split("\n"),
7701
8096
  files: locations
7702
8097
  });
7703
- duplicateLines += chunk.split("\n").length * (locations.length - 1);
8098
+ duplicateLines += chunk2.split("\n").length * (locations.length - 1);
7704
8099
  }
7705
8100
  }
7706
8101
  const percentage = totalLines > 0 ? duplicateLines / totalLines * 100 : 0;
@@ -11831,14 +12226,14 @@ ${message}
11831
12226
  const subprocess = execa(pm, cmdArgs, options);
11832
12227
  let stdoutBuffer = "";
11833
12228
  let stderrBuffer = "";
11834
- subprocess.stdout?.on("data", (chunk) => {
11835
- const text2 = chunk.toString();
12229
+ subprocess.stdout?.on("data", (chunk2) => {
12230
+ const text2 = chunk2.toString();
11836
12231
  stdoutBuffer += text2;
11837
12232
  process.stdout.write(text2);
11838
12233
  heartbeat.activity();
11839
12234
  });
11840
- subprocess.stderr?.on("data", (chunk) => {
11841
- const text2 = chunk.toString();
12235
+ subprocess.stderr?.on("data", (chunk2) => {
12236
+ const text2 = chunk2.toString();
11842
12237
  stderrBuffer += text2;
11843
12238
  process.stderr.write(text2);
11844
12239
  heartbeat.activity();
@@ -11956,14 +12351,14 @@ ${message}
11956
12351
  const subprocess = execa(pm, cmdArgs, options);
11957
12352
  let stdoutBuffer = "";
11958
12353
  let stderrBuffer = "";
11959
- subprocess.stdout?.on("data", (chunk) => {
11960
- const text2 = chunk.toString();
12354
+ subprocess.stdout?.on("data", (chunk2) => {
12355
+ const text2 = chunk2.toString();
11961
12356
  stdoutBuffer += text2;
11962
12357
  process.stdout.write(text2);
11963
12358
  heartbeat.activity();
11964
12359
  });
11965
- subprocess.stderr?.on("data", (chunk) => {
11966
- const text2 = chunk.toString();
12360
+ subprocess.stderr?.on("data", (chunk2) => {
12361
+ const text2 = chunk2.toString();
11967
12362
  stderrBuffer += text2;
11968
12363
  process.stderr.write(text2);
11969
12364
  heartbeat.activity();
@@ -12058,14 +12453,14 @@ ${message}
12058
12453
  const subprocess = execa("make", cmdArgs, options);
12059
12454
  let stdoutBuffer = "";
12060
12455
  let stderrBuffer = "";
12061
- subprocess.stdout?.on("data", (chunk) => {
12062
- const text2 = chunk.toString();
12456
+ subprocess.stdout?.on("data", (chunk2) => {
12457
+ const text2 = chunk2.toString();
12063
12458
  stdoutBuffer += text2;
12064
12459
  process.stdout.write(text2);
12065
12460
  heartbeat.activity();
12066
12461
  });
12067
- subprocess.stderr?.on("data", (chunk) => {
12068
- const text2 = chunk.toString();
12462
+ subprocess.stderr?.on("data", (chunk2) => {
12463
+ const text2 = chunk2.toString();
12069
12464
  stderrBuffer += text2;
12070
12465
  process.stderr.write(text2);
12071
12466
  heartbeat.activity();
@@ -12161,14 +12556,14 @@ ${message}
12161
12556
  const subprocess = execa("npx", ["tsc", ...cmdArgs], options);
12162
12557
  let stdoutBuffer = "";
12163
12558
  let stderrBuffer = "";
12164
- subprocess.stdout?.on("data", (chunk) => {
12165
- const text2 = chunk.toString();
12559
+ subprocess.stdout?.on("data", (chunk2) => {
12560
+ const text2 = chunk2.toString();
12166
12561
  stdoutBuffer += text2;
12167
12562
  process.stdout.write(text2);
12168
12563
  heartbeat.activity();
12169
12564
  });
12170
- subprocess.stderr?.on("data", (chunk) => {
12171
- const text2 = chunk.toString();
12565
+ subprocess.stderr?.on("data", (chunk2) => {
12566
+ const text2 = chunk2.toString();
12172
12567
  stderrBuffer += text2;
12173
12568
  process.stderr.write(text2);
12174
12569
  heartbeat.activity();
@@ -12265,14 +12660,14 @@ ${message}
12265
12660
  });
12266
12661
  let stdoutBuffer = "";
12267
12662
  let stderrBuffer = "";
12268
- subprocess.stdout?.on("data", (chunk) => {
12269
- const text2 = chunk.toString();
12663
+ subprocess.stdout?.on("data", (chunk2) => {
12664
+ const text2 = chunk2.toString();
12270
12665
  stdoutBuffer += text2;
12271
12666
  process.stdout.write(text2);
12272
12667
  heartbeat.activity();
12273
12668
  });
12274
- subprocess.stderr?.on("data", (chunk) => {
12275
- const text2 = chunk.toString();
12669
+ subprocess.stderr?.on("data", (chunk2) => {
12670
+ const text2 = chunk2.toString();
12276
12671
  stderrBuffer += text2;
12277
12672
  process.stderr.write(text2);
12278
12673
  heartbeat.activity();
@@ -12352,14 +12747,14 @@ ${message}
12352
12747
  });
12353
12748
  let stdoutBuffer = "";
12354
12749
  let stderrBuffer = "";
12355
- subprocess.stdout?.on("data", (chunk) => {
12356
- const text2 = chunk.toString();
12750
+ subprocess.stdout?.on("data", (chunk2) => {
12751
+ const text2 = chunk2.toString();
12357
12752
  stdoutBuffer += text2;
12358
12753
  process.stdout.write(text2);
12359
12754
  heartbeat.activity();
12360
12755
  });
12361
- subprocess.stderr?.on("data", (chunk) => {
12362
- const text2 = chunk.toString();
12756
+ subprocess.stderr?.on("data", (chunk2) => {
12757
+ const text2 = chunk2.toString();
12363
12758
  stderrBuffer += text2;
12364
12759
  process.stderr.write(text2);
12365
12760
  heartbeat.activity();
@@ -15885,13 +16280,13 @@ Examples:
15885
16280
  const content = await fs19.readFile(fullPath, "utf-8");
15886
16281
  if (content.length > 1e5) continue;
15887
16282
  const fileChunks = chunkContent(content, DEFAULT_CHUNK_SIZE);
15888
- for (const chunk of fileChunks) {
15889
- const vector = await getEmbedding(chunk.text);
16283
+ for (const chunk2 of fileChunks) {
16284
+ const vector = await getEmbedding(chunk2.text);
15890
16285
  chunks.push({
15891
16286
  file,
15892
- startLine: chunk.startLine,
15893
- endLine: chunk.endLine,
15894
- text: chunk.text,
16287
+ startLine: chunk2.startLine,
16288
+ endLine: chunk2.endLine,
16289
+ text: chunk2.text,
15895
16290
  vector,
15896
16291
  mtime: stat2.mtimeMs
15897
16292
  });
@@ -15925,9 +16320,9 @@ Examples:
15925
16320
  }
15926
16321
  }
15927
16322
  const queryVector = await getEmbedding(query);
15928
- const scored = index.chunks.map((chunk) => ({
15929
- chunk,
15930
- score: cosineSimilarity(queryVector, chunk.vector)
16323
+ const scored = index.chunks.map((chunk2) => ({
16324
+ chunk: chunk2,
16325
+ score: cosineSimilarity(queryVector, chunk2.vector)
15931
16326
  }));
15932
16327
  const filtered = scored.filter((s) => s.score >= effectiveThreshold).sort((a, b) => b.score - a.score).slice(0, effectiveMaxResults);
15933
16328
  const results = filtered.map((s) => {
@@ -21138,7 +21533,6 @@ var READ_ONLY_TOOL_NAMES = /* @__PURE__ */ new Set([
21138
21533
  "recall_memory",
21139
21534
  "list_memories",
21140
21535
  "list_checkpoints",
21141
- "spawnSimpleAgent",
21142
21536
  "checkAgentCapability"
21143
21537
  ]);
21144
21538
  var WRITE_CAPABLE_TOOL_NAMES = /* @__PURE__ */ new Set(["run_linter"]);
@@ -21184,6 +21578,22 @@ var DefaultPermissionPolicy = class {
21184
21578
  return { allowed: true, risk };
21185
21579
  }
21186
21580
  canExecuteToolInput(mode, tool, input) {
21581
+ if (tool.name === "spawnSimpleAgent") {
21582
+ const risk = riskForSpawnedAgent(input);
21583
+ const definition2 = getAgentMode(mode);
21584
+ if (definition2.readOnly && risk !== "read-only" && risk !== "network") {
21585
+ return {
21586
+ allowed: false,
21587
+ reason: `${definition2.label} mode is read-only; spawnSimpleAgent with this role can perform ${risk} work.`,
21588
+ risk
21589
+ };
21590
+ }
21591
+ return {
21592
+ allowed: true,
21593
+ requiresConfirmation: risk === "destructive" || risk === "secrets-sensitive",
21594
+ risk
21595
+ };
21596
+ }
21187
21597
  if (tool.name !== "run_linter") {
21188
21598
  return this.canExecuteTool(mode, tool);
21189
21599
  }
@@ -21203,6 +21613,37 @@ var DefaultPermissionPolicy = class {
21203
21613
  function createPermissionPolicy() {
21204
21614
  return new DefaultPermissionPolicy();
21205
21615
  }
21616
+ function riskForSpawnedAgent(input) {
21617
+ const type = typeof input["type"] === "string" ? input["type"] : void 0;
21618
+ const role = typeof input["role"] === "string" ? input["role"] : void 0;
21619
+ const resolved = type ?? role;
21620
+ switch (resolved) {
21621
+ case "explore":
21622
+ case "plan":
21623
+ case "review":
21624
+ case "architect":
21625
+ case "security":
21626
+ case "docs":
21627
+ case "researcher":
21628
+ case "reviewer":
21629
+ case "planner":
21630
+ return "read-only";
21631
+ case "database":
21632
+ return "secrets-sensitive";
21633
+ case "test":
21634
+ case "tdd":
21635
+ case "e2e":
21636
+ case "tester":
21637
+ return "destructive";
21638
+ case "debug":
21639
+ case "refactor":
21640
+ case "coder":
21641
+ case "optimizer":
21642
+ return "write";
21643
+ default:
21644
+ return "read-only";
21645
+ }
21646
+ }
21206
21647
 
21207
21648
  // src/providers/anthropic.ts
21208
21649
  init_errors();
@@ -22340,12 +22781,12 @@ var OpenAIProvider = class {
22340
22781
  ...reasoningEffort && { reasoning_effort: reasoningEffort }
22341
22782
  });
22342
22783
  let streamStopReason;
22343
- for await (const chunk of stream) {
22344
- const delta = chunk.choices[0]?.delta;
22784
+ for await (const chunk2 of stream) {
22785
+ const delta = chunk2.choices[0]?.delta;
22345
22786
  if (delta?.content) {
22346
22787
  yield { type: "text", text: delta.content };
22347
22788
  }
22348
- const finishReason = chunk.choices[0]?.finish_reason;
22789
+ const finishReason = chunk2.choices[0]?.finish_reason;
22349
22790
  if (finishReason) {
22350
22791
  streamStopReason = this.mapFinishReason(finishReason);
22351
22792
  }
@@ -22414,8 +22855,8 @@ var OpenAIProvider = class {
22414
22855
  });
22415
22856
  try {
22416
22857
  let streamStopReason;
22417
- for await (const chunk of stream) {
22418
- const delta = chunk.choices[0]?.delta;
22858
+ for await (const chunk2 of stream) {
22859
+ const delta = chunk2.choices[0]?.delta;
22419
22860
  if (delta?.content || delta?.tool_calls) {
22420
22861
  lastActivityTime = Date.now();
22421
22862
  }
@@ -22453,7 +22894,7 @@ var OpenAIProvider = class {
22453
22894
  }
22454
22895
  }
22455
22896
  }
22456
- const finishReason = chunk.choices[0]?.finish_reason;
22897
+ const finishReason = chunk2.choices[0]?.finish_reason;
22457
22898
  if (finishReason) {
22458
22899
  streamStopReason = this.mapFinishReason(finishReason);
22459
22900
  }
@@ -24169,12 +24610,12 @@ var GeminiProvider = class {
24169
24610
  config: this.buildConfig(messages, options)
24170
24611
  });
24171
24612
  let streamStopReason = "end_turn";
24172
- for await (const chunk of stream) {
24173
- const text2 = chunk.text;
24613
+ for await (const chunk2 of stream) {
24614
+ const text2 = chunk2.text;
24174
24615
  if (text2) {
24175
24616
  yield { type: "text", text: text2 };
24176
24617
  }
24177
- const finishReason = chunk.candidates?.[0]?.finishReason;
24618
+ const finishReason = chunk2.candidates?.[0]?.finishReason;
24178
24619
  if (finishReason) {
24179
24620
  streamStopReason = this.mapFinishReason(finishReason);
24180
24621
  }
@@ -24195,12 +24636,12 @@ var GeminiProvider = class {
24195
24636
  let streamStopReason = "end_turn";
24196
24637
  let fallbackToolCounter = 0;
24197
24638
  const emittedToolIds = /* @__PURE__ */ new Set();
24198
- for await (const chunk of stream) {
24199
- const text2 = chunk.text;
24639
+ for await (const chunk2 of stream) {
24640
+ const text2 = chunk2.text;
24200
24641
  if (text2) {
24201
24642
  yield { type: "text", text: text2 };
24202
24643
  }
24203
- const toolCalls = this.extractToolCalls(chunk, { includeLegacyFunctionCalls: true });
24644
+ const toolCalls = this.extractToolCalls(chunk2, { includeLegacyFunctionCalls: true });
24204
24645
  for (const toolCall of toolCalls) {
24205
24646
  const toolCallId = toolCall.id ?? `gemini_call_${++fallbackToolCounter}`;
24206
24647
  if (emittedToolIds.has(toolCallId)) continue;
@@ -24221,7 +24662,7 @@ var GeminiProvider = class {
24221
24662
  toolCall: normalizedToolCall
24222
24663
  };
24223
24664
  }
24224
- const finishReason = chunk.candidates?.[0]?.finishReason;
24665
+ const finishReason = chunk2.candidates?.[0]?.finishReason;
24225
24666
  if (toolCalls.length > 0) {
24226
24667
  streamStopReason = "tool_use";
24227
24668
  } else if (finishReason) {
@@ -24564,8 +25005,8 @@ var VertexProvider = class {
24564
25005
  this.ensureInitialized();
24565
25006
  const stream = await this.streamGenerateContent(messages, options);
24566
25007
  let stopReason = "end_turn";
24567
- for await (const chunk of stream) {
24568
- const candidate = chunk.candidates?.[0];
25008
+ for await (const chunk2 of stream) {
25009
+ const candidate = chunk2.candidates?.[0];
24569
25010
  const parts = candidate?.content?.parts ?? [];
24570
25011
  for (const part of parts) {
24571
25012
  if (part.text) {
@@ -24587,8 +25028,8 @@ var VertexProvider = class {
24587
25028
  let stopReason = "end_turn";
24588
25029
  let streamToolCallCounter = 0;
24589
25030
  const emittedToolFingerprints = /* @__PURE__ */ new Set();
24590
- for await (const chunk of stream) {
24591
- const candidate = chunk.candidates?.[0];
25031
+ for await (const chunk2 of stream) {
25032
+ const candidate = chunk2.candidates?.[0];
24592
25033
  const parts = candidate?.content?.parts ?? [];
24593
25034
  for (const part of parts) {
24594
25035
  if (part.text) {
@@ -25188,9 +25629,9 @@ var ResilientProvider = class {
25188
25629
  }
25189
25630
  let emittedChunk = false;
25190
25631
  try {
25191
- for await (const chunk of createStream()) {
25632
+ for await (const chunk2 of createStream()) {
25192
25633
  emittedChunk = true;
25193
- yield chunk;
25634
+ yield chunk2;
25194
25635
  }
25195
25636
  this.breaker.recordSuccess();
25196
25637
  return;
@@ -25737,19 +26178,26 @@ function createWorkflowCatalog(workflows) {
25737
26178
 
25738
26179
  // src/runtime/workflow-engine.ts
25739
26180
  var WorkflowEngine = class {
25740
- constructor(catalog = createWorkflowCatalog(), eventLog = createEventLog()) {
26181
+ constructor(catalog = createWorkflowCatalog(), eventLog = createEventLog(), options = {}) {
25741
26182
  this.catalog = catalog;
25742
26183
  this.eventLog = eventLog;
26184
+ this.sharedState = options.sharedState ?? new InMemorySharedWorkspaceStore();
26185
+ this.nodeExecutor = options.nodeExecutor;
25743
26186
  }
25744
26187
  catalog;
25745
26188
  eventLog;
25746
26189
  handlers = /* @__PURE__ */ new Map();
26190
+ sharedState;
26191
+ nodeExecutor;
25747
26192
  registerHandler(workflowId, handler) {
25748
26193
  if (!this.catalog.get(workflowId)) {
25749
26194
  throw new Error(`Unknown workflow: ${workflowId}`);
25750
26195
  }
25751
26196
  this.handlers.set(workflowId, handler);
25752
26197
  }
26198
+ registerNodeExecutor(executor) {
26199
+ this.nodeExecutor = executor;
26200
+ }
25753
26201
  createPlan(workflowId, input) {
25754
26202
  return this.catalog.createPlan(workflowId, input, this.eventLog);
25755
26203
  }
@@ -25759,23 +26207,35 @@ var WorkflowEngine = class {
25759
26207
  throw new Error(`Unknown workflow: ${request.workflowId}`);
25760
26208
  }
25761
26209
  const handler = this.handlers.get(request.workflowId);
25762
- if (!handler) {
25763
- throw new Error(`No handler registered for workflow: ${request.workflowId}`);
25764
- }
25765
26210
  const plan = request.plan ?? this.createPlan(request.workflowId, request.input);
25766
26211
  const startedAt = (/* @__PURE__ */ new Date()).toISOString();
25767
26212
  const runId = `${request.workflowId}-run-${Date.now().toString(36)}`;
26213
+ const trace = createAgentTraceContext({ workflowRunId: runId });
25768
26214
  this.eventLog.record("workflow.started", {
25769
26215
  workflowId: request.workflowId,
25770
26216
  planId: plan.id,
25771
- runId
26217
+ runId,
26218
+ trace
25772
26219
  });
25773
26220
  try {
25774
- const output = await handler(request.input, {
26221
+ const graphResult = handler ? void 0 : await new AgentGraphEngine({
26222
+ eventLog: this.eventLog,
26223
+ sharedState: this.sharedState,
26224
+ nodeExecutor: this.nodeExecutor,
26225
+ trace
26226
+ }).run({
26227
+ workflowRunId: runId,
26228
+ graph: workflowToAgentGraph(workflow),
26229
+ input: request.input
26230
+ });
26231
+ const output = graphResult ?? await handler(request.input, {
25775
26232
  workflow,
25776
26233
  plan,
25777
26234
  eventLog: this.eventLog
25778
26235
  });
26236
+ if (graphResult?.status === "failed") {
26237
+ throw new Error(graphResult.error ?? "Workflow graph failed");
26238
+ }
25779
26239
  const completedAt = (/* @__PURE__ */ new Date()).toISOString();
25780
26240
  const result = {
25781
26241
  id: runId,
@@ -25783,12 +26243,15 @@ var WorkflowEngine = class {
25783
26243
  status: "completed",
25784
26244
  output,
25785
26245
  startedAt,
25786
- completedAt
26246
+ completedAt,
26247
+ graphResult,
26248
+ trace
25787
26249
  };
25788
26250
  this.eventLog.record("workflow.completed", {
25789
26251
  workflowId: request.workflowId,
25790
26252
  planId: plan.id,
25791
- runId
26253
+ runId,
26254
+ trace
25792
26255
  });
25793
26256
  return result;
25794
26257
  } catch (error) {
@@ -25798,7 +26261,8 @@ var WorkflowEngine = class {
25798
26261
  workflowId: request.workflowId,
25799
26262
  planId: plan.id,
25800
26263
  runId,
25801
- error: message
26264
+ error: message,
26265
+ trace
25802
26266
  });
25803
26267
  return {
25804
26268
  id: runId,
@@ -25807,13 +26271,14 @@ var WorkflowEngine = class {
25807
26271
  output: null,
25808
26272
  startedAt,
25809
26273
  completedAt,
25810
- error: message
26274
+ error: message,
26275
+ trace
25811
26276
  };
25812
26277
  }
25813
26278
  }
25814
26279
  };
25815
- function createWorkflowEngine(catalog, eventLog) {
25816
- return new WorkflowEngine(catalog, eventLog);
26280
+ function createWorkflowEngine(catalog, eventLog, options) {
26281
+ return new WorkflowEngine(catalog, eventLog, options);
25817
26282
  }
25818
26283
 
25819
26284
  // src/runtime/agent-runtime.ts
@@ -25991,7 +26456,7 @@ var AgentRuntime = class {
25991
26456
  let completed = false;
25992
26457
  let failed = false;
25993
26458
  try {
25994
- for await (const chunk of provider.stream(messages, {
26459
+ for await (const chunk2 of provider.stream(messages, {
25995
26460
  model: input.options?.model,
25996
26461
  maxTokens: input.options?.maxTokens,
25997
26462
  temperature: input.options?.temperature,
@@ -26001,12 +26466,12 @@ var AgentRuntime = class {
26001
26466
  signal: input.options?.signal,
26002
26467
  thinking: input.options?.thinking
26003
26468
  })) {
26004
- if (chunk.type === "text" && chunk.text) {
26005
- content += chunk.text;
26469
+ if (chunk2.type === "text" && chunk2.text) {
26470
+ content += chunk2.text;
26006
26471
  yield {
26007
26472
  type: "text",
26008
26473
  sessionId: effectiveSession.id,
26009
- text: chunk.text
26474
+ text: chunk2.text
26010
26475
  };
26011
26476
  }
26012
26477
  }