@corbat-tech/coco 2.38.0 → 2.40.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { execFileSync, spawn, execSync, execFile, exec } from 'child_process';
2
+ import { execFileSync, execSync, spawn, execFile, exec } from 'child_process';
3
3
  import { setGlobalDispatcher, EnvHttpProxyAgent } from 'undici';
4
4
  import * as fs5 from 'fs';
5
5
  import fs5__default, { accessSync, mkdirSync, appendFileSync, readFileSync, writeFileSync, constants as constants$1 } from 'fs';
@@ -23,7 +23,7 @@ import Anthropic from '@anthropic-ai/sdk';
23
23
  import { jsonrepair } from 'jsonrepair';
24
24
  import OpenAI from 'openai';
25
25
  import { GoogleGenAI, FunctionCallingConfigMode } from '@google/genai';
26
- import { parse } from 'yaml';
26
+ import { parse as parse$1 } from 'yaml';
27
27
  import { minimatch } from 'minimatch';
28
28
  import hljs from 'highlight.js/lib/core';
29
29
  import bash from 'highlight.js/lib/languages/bash';
@@ -42,7 +42,7 @@ import yaml from 'highlight.js/lib/languages/yaml';
42
42
  import { diffLines, diffWords } from 'diff';
43
43
  import { glob } from 'glob';
44
44
  import { execa } from 'execa';
45
- import { parse as parse$1 } from '@typescript-eslint/typescript-estree';
45
+ import { parse } from '@typescript-eslint/typescript-estree';
46
46
  import { simpleGit } from 'simple-git';
47
47
  import { Marked } from 'marked';
48
48
  import { markedTerminal } from 'marked-terminal';
@@ -5746,12 +5746,12 @@ var init_openai = __esm({
5746
5746
  ...reasoningEffort && { reasoning_effort: reasoningEffort }
5747
5747
  });
5748
5748
  let streamStopReason;
5749
- for await (const chunk of stream) {
5750
- const delta = chunk.choices[0]?.delta;
5749
+ for await (const chunk2 of stream) {
5750
+ const delta = chunk2.choices[0]?.delta;
5751
5751
  if (delta?.content) {
5752
5752
  yield { type: "text", text: delta.content };
5753
5753
  }
5754
- const finishReason = chunk.choices[0]?.finish_reason;
5754
+ const finishReason = chunk2.choices[0]?.finish_reason;
5755
5755
  if (finishReason) {
5756
5756
  streamStopReason = this.mapFinishReason(finishReason);
5757
5757
  }
@@ -5820,8 +5820,8 @@ var init_openai = __esm({
5820
5820
  });
5821
5821
  try {
5822
5822
  let streamStopReason;
5823
- for await (const chunk of stream) {
5824
- const delta = chunk.choices[0]?.delta;
5823
+ for await (const chunk2 of stream) {
5824
+ const delta = chunk2.choices[0]?.delta;
5825
5825
  if (delta?.content || delta?.tool_calls) {
5826
5826
  lastActivityTime = Date.now();
5827
5827
  }
@@ -5859,7 +5859,7 @@ var init_openai = __esm({
5859
5859
  }
5860
5860
  }
5861
5861
  }
5862
- const finishReason = chunk.choices[0]?.finish_reason;
5862
+ const finishReason = chunk2.choices[0]?.finish_reason;
5863
5863
  if (finishReason) {
5864
5864
  streamStopReason = this.mapFinishReason(finishReason);
5865
5865
  }
@@ -7591,12 +7591,12 @@ var init_gemini = __esm({
7591
7591
  config: this.buildConfig(messages, options)
7592
7592
  });
7593
7593
  let streamStopReason = "end_turn";
7594
- for await (const chunk of stream) {
7595
- const text16 = chunk.text;
7594
+ for await (const chunk2 of stream) {
7595
+ const text16 = chunk2.text;
7596
7596
  if (text16) {
7597
7597
  yield { type: "text", text: text16 };
7598
7598
  }
7599
- const finishReason = chunk.candidates?.[0]?.finishReason;
7599
+ const finishReason = chunk2.candidates?.[0]?.finishReason;
7600
7600
  if (finishReason) {
7601
7601
  streamStopReason = this.mapFinishReason(finishReason);
7602
7602
  }
@@ -7617,12 +7617,12 @@ var init_gemini = __esm({
7617
7617
  let streamStopReason = "end_turn";
7618
7618
  let fallbackToolCounter = 0;
7619
7619
  const emittedToolIds = /* @__PURE__ */ new Set();
7620
- for await (const chunk of stream) {
7621
- const text16 = chunk.text;
7620
+ for await (const chunk2 of stream) {
7621
+ const text16 = chunk2.text;
7622
7622
  if (text16) {
7623
7623
  yield { type: "text", text: text16 };
7624
7624
  }
7625
- const toolCalls = this.extractToolCalls(chunk, { includeLegacyFunctionCalls: true });
7625
+ const toolCalls = this.extractToolCalls(chunk2, { includeLegacyFunctionCalls: true });
7626
7626
  for (const toolCall of toolCalls) {
7627
7627
  const toolCallId = toolCall.id ?? `gemini_call_${++fallbackToolCounter}`;
7628
7628
  if (emittedToolIds.has(toolCallId)) continue;
@@ -7643,7 +7643,7 @@ var init_gemini = __esm({
7643
7643
  toolCall: normalizedToolCall
7644
7644
  };
7645
7645
  }
7646
- const finishReason = chunk.candidates?.[0]?.finishReason;
7646
+ const finishReason = chunk2.candidates?.[0]?.finishReason;
7647
7647
  if (toolCalls.length > 0) {
7648
7648
  streamStopReason = "tool_use";
7649
7649
  } else if (finishReason) {
@@ -8000,8 +8000,8 @@ var init_vertex = __esm({
8000
8000
  this.ensureInitialized();
8001
8001
  const stream = await this.streamGenerateContent(messages, options);
8002
8002
  let stopReason = "end_turn";
8003
- for await (const chunk of stream) {
8004
- const candidate = chunk.candidates?.[0];
8003
+ for await (const chunk2 of stream) {
8004
+ const candidate = chunk2.candidates?.[0];
8005
8005
  const parts = candidate?.content?.parts ?? [];
8006
8006
  for (const part of parts) {
8007
8007
  if (part.text) {
@@ -8023,8 +8023,8 @@ var init_vertex = __esm({
8023
8023
  let stopReason = "end_turn";
8024
8024
  let streamToolCallCounter = 0;
8025
8025
  const emittedToolFingerprints = /* @__PURE__ */ new Set();
8026
- for await (const chunk of stream) {
8027
- const candidate = chunk.candidates?.[0];
8026
+ for await (const chunk2 of stream) {
8027
+ const candidate = chunk2.candidates?.[0];
8028
8028
  const parts = candidate?.content?.parts ?? [];
8029
8029
  for (const part of parts) {
8030
8030
  if (part.text) {
@@ -8711,8 +8711,8 @@ var init_fallback = __esm({
8711
8711
  continue;
8712
8712
  }
8713
8713
  try {
8714
- for await (const chunk of provider.stream(messages, options)) {
8715
- yield chunk;
8714
+ for await (const chunk2 of provider.stream(messages, options)) {
8715
+ yield chunk2;
8716
8716
  }
8717
8717
  breaker.recordSuccess();
8718
8718
  return;
@@ -8735,8 +8735,8 @@ var init_fallback = __esm({
8735
8735
  continue;
8736
8736
  }
8737
8737
  try {
8738
- for await (const chunk of provider.streamWithTools(messages, options)) {
8739
- yield chunk;
8738
+ for await (const chunk2 of provider.streamWithTools(messages, options)) {
8739
+ yield chunk2;
8740
8740
  }
8741
8741
  breaker.recordSuccess();
8742
8742
  return;
@@ -9005,9 +9005,9 @@ var init_resilient = __esm({
9005
9005
  }
9006
9006
  let emittedChunk = false;
9007
9007
  try {
9008
- for await (const chunk of createStream()) {
9008
+ for await (const chunk2 of createStream()) {
9009
9009
  emittedChunk = true;
9010
- yield chunk;
9010
+ yield chunk2;
9011
9011
  }
9012
9012
  this.breaker.recordSuccess();
9013
9013
  return;
@@ -10061,7 +10061,7 @@ function parseSkillMarkdown(raw) {
10061
10061
  const frontmatter = normalized.slice(3, closeIndex).trim();
10062
10062
  const afterMarkerStart = closeIndex + closeMarker.length;
10063
10063
  const contentStart = normalized[afterMarkerStart] === "\n" ? afterMarkerStart + 1 : afterMarkerStart;
10064
- const parsed = frontmatter.length > 0 ? parse(frontmatter) : {};
10064
+ const parsed = frontmatter.length > 0 ? parse$1(frontmatter) : {};
10065
10065
  return {
10066
10066
  data: parsed && typeof parsed === "object" ? parsed : {},
10067
10067
  content: normalized.slice(contentStart)
@@ -15465,7 +15465,7 @@ var init_complexity = __esm({
15465
15465
  * Analyze single file
15466
15466
  */
15467
15467
  async analyzeFile(file, content) {
15468
- const ast = parse$1(content, {
15468
+ const ast = parse(content, {
15469
15469
  loc: true,
15470
15470
  range: true,
15471
15471
  comment: false,
@@ -15516,25 +15516,25 @@ var init_complexity = __esm({
15516
15516
  const lines = content.split("\n");
15517
15517
  totalLines += lines.length;
15518
15518
  for (let i = 0; i <= lines.length - this.minLines; i++) {
15519
- const chunk = lines.slice(i, i + this.minLines).join("\n").trim();
15520
- if (chunk.length < 20) continue;
15521
- if (!chunks.has(chunk)) {
15522
- chunks.set(chunk, []);
15519
+ const chunk2 = lines.slice(i, i + this.minLines).join("\n").trim();
15520
+ if (chunk2.length < 20) continue;
15521
+ if (!chunks.has(chunk2)) {
15522
+ chunks.set(chunk2, []);
15523
15523
  }
15524
- chunks.get(chunk).push({ file, line: i + 1 });
15524
+ chunks.get(chunk2).push({ file, line: i + 1 });
15525
15525
  }
15526
15526
  } catch {
15527
15527
  }
15528
15528
  }
15529
15529
  const duplicates = [];
15530
15530
  let duplicateLines = 0;
15531
- for (const [chunk, locations] of chunks.entries()) {
15531
+ for (const [chunk2, locations] of chunks.entries()) {
15532
15532
  if (locations.length > 1) {
15533
15533
  duplicates.push({
15534
- lines: chunk.split("\n"),
15534
+ lines: chunk2.split("\n"),
15535
15535
  files: locations
15536
15536
  });
15537
- duplicateLines += chunk.split("\n").length * (locations.length - 1);
15537
+ duplicateLines += chunk2.split("\n").length * (locations.length - 1);
15538
15538
  }
15539
15539
  }
15540
15540
  const percentage = totalLines > 0 ? duplicateLines / totalLines * 100 : 0;
@@ -16062,7 +16062,7 @@ var init_completeness = __esm({
16062
16062
  for (const file of files) {
16063
16063
  try {
16064
16064
  const content = await readFile(file, "utf-8");
16065
- const ast = parse$1(content, {
16065
+ const ast = parse(content, {
16066
16066
  loc: true,
16067
16067
  range: true,
16068
16068
  jsx: file.endsWith(".tsx") || file.endsWith(".jsx")
@@ -16275,7 +16275,7 @@ var init_robustness = __esm({
16275
16275
  for (const file of targetFiles) {
16276
16276
  try {
16277
16277
  const content = await readFile(file, "utf-8");
16278
- const ast = parse$1(content, {
16278
+ const ast = parse(content, {
16279
16279
  loc: true,
16280
16280
  range: true,
16281
16281
  jsx: file.endsWith(".tsx") || file.endsWith(".jsx")
@@ -16568,7 +16568,7 @@ var init_documentation = __esm({
16568
16568
  for (const file of targetFiles) {
16569
16569
  try {
16570
16570
  const content = await readFile(file, "utf-8");
16571
- const ast = parse$1(content, {
16571
+ const ast = parse(content, {
16572
16572
  loc: true,
16573
16573
  range: true,
16574
16574
  comment: true,
@@ -16946,7 +16946,7 @@ var init_readability = __esm({
16946
16946
  for (const file of targetFiles) {
16947
16947
  try {
16948
16948
  const content = await readFile(file, "utf-8");
16949
- const ast = parse$1(content, {
16949
+ const ast = parse(content, {
16950
16950
  loc: true,
16951
16951
  range: true,
16952
16952
  jsx: file.endsWith(".tsx") || file.endsWith(".jsx")
@@ -17104,7 +17104,7 @@ var init_maintainability = __esm({
17104
17104
  try {
17105
17105
  const content = await readFile(file, "utf-8");
17106
17106
  const lineCount = countLines(content);
17107
- const ast = parse$1(content, {
17107
+ const ast = parse(content, {
17108
17108
  loc: true,
17109
17109
  range: true,
17110
17110
  jsx: file.endsWith(".tsx") || file.endsWith(".jsx")
@@ -20749,14 +20749,14 @@ ${message}
20749
20749
  const subprocess = execa(command, options);
20750
20750
  let stdoutBuffer = "";
20751
20751
  let stderrBuffer = "";
20752
- subprocess.stdout?.on("data", (chunk) => {
20753
- const text16 = chunk.toString();
20752
+ subprocess.stdout?.on("data", (chunk2) => {
20753
+ const text16 = chunk2.toString();
20754
20754
  stdoutBuffer += text16;
20755
20755
  process.stdout.write(text16);
20756
20756
  heartbeat.activity();
20757
20757
  });
20758
- subprocess.stderr?.on("data", (chunk) => {
20759
- const text16 = chunk.toString();
20758
+ subprocess.stderr?.on("data", (chunk2) => {
20759
+ const text16 = chunk2.toString();
20760
20760
  stderrBuffer += text16;
20761
20761
  process.stderr.write(text16);
20762
20762
  heartbeat.activity();
@@ -43226,8 +43226,401 @@ Response format (JSON only, no prose):
43226
43226
  p26.outro(" Spec saved \u2014 starting sprints");
43227
43227
  return spec;
43228
43228
  }
43229
-
43230
- // src/runtime/multi-agent.ts
43229
+ var LEGACY_ROLE_MAPPINGS = [
43230
+ { legacy: "explore", role: "researcher", reason: "read-only codebase exploration" },
43231
+ { legacy: "researcher", role: "researcher", reason: "legacy executor role" },
43232
+ { legacy: "plan", role: "planner", reason: "task planning" },
43233
+ { legacy: "planner", role: "planner", reason: "legacy executor role" },
43234
+ { legacy: "architect", role: "architect", reason: "architecture design" },
43235
+ { legacy: "editor", role: "editor", reason: "implementation edits" },
43236
+ { legacy: "debug", role: "coder", reason: "debugging maps to coding capability" },
43237
+ { legacy: "coder", role: "coder", reason: "legacy executor role" },
43238
+ { legacy: "test", role: "tester", reason: "test authoring/execution" },
43239
+ { legacy: "tester", role: "tester", reason: "legacy executor role" },
43240
+ { legacy: "tdd", role: "tester", reason: "test-first implementation" },
43241
+ { legacy: "e2e", role: "tester", reason: "end-to-end testing" },
43242
+ { legacy: "review", role: "reviewer", reason: "code review" },
43243
+ { legacy: "reviewer", role: "reviewer", reason: "legacy executor role" },
43244
+ { legacy: "refactor", role: "optimizer", reason: "structure optimization" },
43245
+ { legacy: "optimizer", role: "optimizer", reason: "legacy executor role" },
43246
+ { legacy: "security", role: "security", reason: "security analysis" },
43247
+ { legacy: "qa", role: "qa", reason: "quality assurance" },
43248
+ { legacy: "integrator", role: "integrator", reason: "integration coordination" },
43249
+ { legacy: "pm", role: "pm", reason: "product/project coordination" },
43250
+ { legacy: "docs", role: "docs", reason: "documentation" },
43251
+ { legacy: "database", role: "database", reason: "database work" }
43252
+ ];
43253
+ var LEGACY_ROLE_MAP = new Map(LEGACY_ROLE_MAPPINGS.map((mapping) => [mapping.legacy, mapping]));
43254
+ function mapLegacyAgentRole(legacyRole, fallback = "coder") {
43255
+ return LEGACY_ROLE_MAP.get(legacyRole)?.role ?? fallback;
43256
+ }
43257
+ function assertProvenance(provenance) {
43258
+ if (!provenance.workflowRunId) {
43259
+ throw new Error("Shared workspace writes require workflowRunId provenance.");
43260
+ }
43261
+ }
43262
+ function snapshotFromRecords(records, role) {
43263
+ const includeSensitive = role === void 0 || role === "security" || role === "integrator" || role === "pm";
43264
+ const facts = /* @__PURE__ */ new Map();
43265
+ const decisions = /* @__PURE__ */ new Map();
43266
+ const risks = /* @__PURE__ */ new Map();
43267
+ const files = /* @__PURE__ */ new Map();
43268
+ const testResults = /* @__PURE__ */ new Map();
43269
+ const artifacts = [];
43270
+ for (const record of records) {
43271
+ if (!includeSensitive && (record.kind === "risk" || record.provenance.risk === "secrets-sensitive")) {
43272
+ continue;
43273
+ }
43274
+ switch (record.kind) {
43275
+ case "fact":
43276
+ facts.set(record.key, record.value);
43277
+ break;
43278
+ case "decision":
43279
+ decisions.set(record.key, record.value);
43280
+ break;
43281
+ case "risk":
43282
+ risks.set(record.key, record.value);
43283
+ break;
43284
+ case "file":
43285
+ files.set(record.key, record.value);
43286
+ break;
43287
+ case "testResult":
43288
+ testResults.set(record.key, record.value);
43289
+ break;
43290
+ case "artifact":
43291
+ if (isAgentArtifact(record.value)) {
43292
+ if (includeSensitive || record.value.kind !== "riskReport") {
43293
+ artifacts.push(cloneArtifact(record.value));
43294
+ }
43295
+ }
43296
+ break;
43297
+ }
43298
+ }
43299
+ return {
43300
+ facts: Object.fromEntries(facts),
43301
+ decisions: Object.fromEntries(decisions),
43302
+ risks: Object.fromEntries(risks),
43303
+ files: Object.fromEntries(files),
43304
+ testResults: Object.fromEntries(testResults),
43305
+ artifacts
43306
+ };
43307
+ }
43308
+ var InMemorySharedWorkspaceStore = class {
43309
+ records = [];
43310
+ write(input) {
43311
+ assertProvenance(input.provenance);
43312
+ const record = {
43313
+ id: input.id ?? `state-${randomUUID()}`,
43314
+ kind: input.kind,
43315
+ key: input.key,
43316
+ value: cloneUnknown(input.value),
43317
+ provenance: { ...input.provenance },
43318
+ createdAt: input.createdAt ?? (/* @__PURE__ */ new Date()).toISOString()
43319
+ };
43320
+ this.records.push(record);
43321
+ return cloneRecord(record);
43322
+ }
43323
+ list() {
43324
+ return this.records.map(cloneRecord);
43325
+ }
43326
+ snapshot() {
43327
+ return snapshotFromRecords(this.records);
43328
+ }
43329
+ readForRole(role) {
43330
+ return snapshotFromRecords(this.records, role);
43331
+ }
43332
+ clear() {
43333
+ this.records = [];
43334
+ }
43335
+ };
43336
+ function createAgentTraceContext(input = {}) {
43337
+ return {
43338
+ traceId: input.traceId ?? `trace-${randomUUID()}`,
43339
+ spanId: input.spanId ?? `span-${randomUUID()}`,
43340
+ parentSpanId: input.parentSpanId,
43341
+ workflowRunId: input.workflowRunId,
43342
+ agentRunId: input.agentRunId,
43343
+ taskId: input.taskId,
43344
+ toolCallId: input.toolCallId
43345
+ };
43346
+ }
43347
+ var AgentGraphEngine = class {
43348
+ eventLog;
43349
+ sharedState;
43350
+ nodeExecutor;
43351
+ gateEvaluator;
43352
+ trace;
43353
+ constructor(options = {}) {
43354
+ this.eventLog = options.eventLog;
43355
+ this.sharedState = options.sharedState ?? new InMemorySharedWorkspaceStore();
43356
+ this.nodeExecutor = options.nodeExecutor ?? (options.allowSimulated ? dryRunAgentGraphNodeExecutor : missingAgentGraphNodeExecutor);
43357
+ this.gateEvaluator = options.gateEvaluator ?? defaultAgentGateEvaluator;
43358
+ this.trace = options.trace ?? createAgentTraceContext();
43359
+ }
43360
+ async run(input) {
43361
+ const validation = validateAgentGraph(input.graph);
43362
+ if (!validation.valid) {
43363
+ throw new Error(
43364
+ `Invalid agent graph: ${validation.issues.map((issue) => issue.message).join("; ")}`
43365
+ );
43366
+ }
43367
+ const startedAt = (/* @__PURE__ */ new Date()).toISOString();
43368
+ const nodeResults = /* @__PURE__ */ new Map();
43369
+ const artifacts = [];
43370
+ const graphTrace = createAgentTraceContext({
43371
+ ...this.trace,
43372
+ workflowRunId: input.workflowRunId
43373
+ });
43374
+ this.eventLog?.record("agent.graph.started", {
43375
+ workflowRunId: input.workflowRunId,
43376
+ trace: graphTrace,
43377
+ levels: validation.levels
43378
+ });
43379
+ try {
43380
+ for (const level of validation.levels) {
43381
+ const batches = chunk(level, input.graph.parallelism ?? level.length);
43382
+ for (const batch of batches) {
43383
+ const levelResults = await Promise.all(
43384
+ batch.map(
43385
+ (nodeId) => this.executeNode({
43386
+ node: input.graph.nodes.find((candidate) => candidate.id === nodeId),
43387
+ graph: input.graph,
43388
+ workflowRunId: input.workflowRunId,
43389
+ input: input.input,
43390
+ graphTrace,
43391
+ nodeResults
43392
+ })
43393
+ )
43394
+ );
43395
+ for (const result2 of levelResults) {
43396
+ nodeResults.set(result2.taskId, result2);
43397
+ artifacts.push(...result2.artifacts.map(cloneArtifact));
43398
+ }
43399
+ }
43400
+ }
43401
+ const completedAt = (/* @__PURE__ */ new Date()).toISOString();
43402
+ const result = {
43403
+ id: input.workflowRunId,
43404
+ status: "completed",
43405
+ nodeResults: Object.fromEntries(nodeResults),
43406
+ artifacts,
43407
+ stateSnapshot: this.sharedState.snapshot(),
43408
+ trace: graphTrace,
43409
+ startedAt,
43410
+ completedAt
43411
+ };
43412
+ this.eventLog?.record("agent.graph.completed", {
43413
+ workflowRunId: input.workflowRunId,
43414
+ trace: graphTrace,
43415
+ nodeCount: nodeResults.size
43416
+ });
43417
+ return result;
43418
+ } catch (error) {
43419
+ const completedAt = (/* @__PURE__ */ new Date()).toISOString();
43420
+ const message = error instanceof Error ? error.message : String(error);
43421
+ this.eventLog?.record("agent.graph.failed", {
43422
+ workflowRunId: input.workflowRunId,
43423
+ trace: graphTrace,
43424
+ error: message
43425
+ });
43426
+ return {
43427
+ id: input.workflowRunId,
43428
+ status: "failed",
43429
+ nodeResults: Object.fromEntries(nodeResults),
43430
+ artifacts,
43431
+ stateSnapshot: this.sharedState.snapshot(),
43432
+ trace: graphTrace,
43433
+ startedAt,
43434
+ completedAt,
43435
+ error: message
43436
+ };
43437
+ }
43438
+ }
43439
+ async executeNode(input) {
43440
+ const skipReason = shouldSkipNode(input.node, input.graph, input.input, input.nodeResults);
43441
+ if (skipReason) {
43442
+ const completedAt = (/* @__PURE__ */ new Date()).toISOString();
43443
+ const task = graphNodeToTask(input.node, input.input);
43444
+ const skipped = normalizeAgentRunResult({
43445
+ id: `${input.workflowRunId}-${input.node.id}-skipped`,
43446
+ taskId: task.id,
43447
+ role: task.role,
43448
+ success: true,
43449
+ status: "cancelled",
43450
+ output: `Skipped node '${input.node.id}': ${skipReason}`,
43451
+ startedAt: completedAt,
43452
+ completedAt,
43453
+ durationMs: 0,
43454
+ metadata: {
43455
+ workflowRunId: input.workflowRunId,
43456
+ nodeId: input.node.id,
43457
+ skipped: true,
43458
+ skipReason
43459
+ }
43460
+ });
43461
+ this.eventLog?.record("agent.completed", {
43462
+ workflowRunId: input.workflowRunId,
43463
+ nodeId: input.node.id,
43464
+ agentRunId: skipped.id,
43465
+ taskId: task.id,
43466
+ role: skipped.role,
43467
+ skipped: true,
43468
+ reason: skipReason,
43469
+ trace: input.graphTrace
43470
+ });
43471
+ return skipped;
43472
+ }
43473
+ const attempts = input.node.retryPolicy?.maxAttempts ?? 1;
43474
+ let lastResult;
43475
+ for (let attempt = 1; attempt <= attempts; attempt++) {
43476
+ const task = graphNodeToTask(input.node, input.input);
43477
+ const trace = createAgentTraceContext({
43478
+ traceId: input.graphTrace.traceId,
43479
+ parentSpanId: input.graphTrace.spanId,
43480
+ workflowRunId: input.workflowRunId,
43481
+ taskId: task.id
43482
+ });
43483
+ this.eventLog?.record("agent.started", {
43484
+ workflowRunId: input.workflowRunId,
43485
+ nodeId: input.node.id,
43486
+ taskId: task.id,
43487
+ role: task.role,
43488
+ attempt,
43489
+ trace
43490
+ });
43491
+ const result = await runWithOptionalTimeout(
43492
+ this.nodeExecutor({
43493
+ node: input.node,
43494
+ task,
43495
+ attempt,
43496
+ workflowRunId: input.workflowRunId,
43497
+ trace,
43498
+ dependencyResults: input.nodeResults,
43499
+ sharedState: this.sharedState,
43500
+ eventLog: this.eventLog ?? NULL_EVENT_LOG
43501
+ }),
43502
+ input.node.timeoutMs,
43503
+ () => normalizeAgentRunResult({
43504
+ id: `${input.workflowRunId}-${input.node.id}-attempt-${attempt}-timeout`,
43505
+ taskId: task.id,
43506
+ role: task.role,
43507
+ success: false,
43508
+ status: "timeout",
43509
+ output: "",
43510
+ startedAt: (/* @__PURE__ */ new Date()).toISOString(),
43511
+ completedAt: (/* @__PURE__ */ new Date()).toISOString(),
43512
+ durationMs: input.node.timeoutMs ?? 0,
43513
+ error: `Node '${input.node.id}' timed out after ${input.node.timeoutMs}ms.`,
43514
+ metadata: {
43515
+ workflowRunId: input.workflowRunId,
43516
+ nodeId: input.node.id,
43517
+ trace,
43518
+ timeoutMs: input.node.timeoutMs
43519
+ }
43520
+ })
43521
+ );
43522
+ lastResult = result;
43523
+ for (const artifact of result.artifacts) {
43524
+ const record = this.sharedState.write({
43525
+ kind: "artifact",
43526
+ key: artifact.id,
43527
+ value: artifact,
43528
+ provenance: {
43529
+ workflowRunId: input.workflowRunId,
43530
+ agentRunId: result.id,
43531
+ nodeId: input.node.id,
43532
+ taskId: task.id,
43533
+ risk: input.node.risk
43534
+ }
43535
+ });
43536
+ this.eventLog?.record("shared_state.updated", {
43537
+ workflowRunId: input.workflowRunId,
43538
+ nodeId: input.node.id,
43539
+ agentRunId: result.id,
43540
+ recordId: record.id,
43541
+ kind: record.kind,
43542
+ key: record.key,
43543
+ trace
43544
+ });
43545
+ this.eventLog?.record("agent.artifact.created", {
43546
+ workflowRunId: input.workflowRunId,
43547
+ nodeId: input.node.id,
43548
+ agentRunId: result.id,
43549
+ artifactId: artifact.id,
43550
+ kind: artifact.kind,
43551
+ trace
43552
+ });
43553
+ }
43554
+ if (result.success) {
43555
+ await this.evaluateNodeGates(input.graph, input.node, result, input.workflowRunId, trace);
43556
+ this.eventLog?.record("agent.completed", {
43557
+ workflowRunId: input.workflowRunId,
43558
+ nodeId: input.node.id,
43559
+ agentRunId: result.id,
43560
+ taskId: task.id,
43561
+ role: result.role,
43562
+ attempt,
43563
+ trace
43564
+ });
43565
+ this.eventLog?.record("checkpoint.created", {
43566
+ workflowRunId: input.workflowRunId,
43567
+ nodeId: input.node.id,
43568
+ agentRunId: result.id,
43569
+ taskId: task.id,
43570
+ attempt,
43571
+ trace
43572
+ });
43573
+ return result;
43574
+ }
43575
+ this.eventLog?.record("agent.failed", {
43576
+ workflowRunId: input.workflowRunId,
43577
+ nodeId: input.node.id,
43578
+ agentRunId: result.id,
43579
+ taskId: task.id,
43580
+ role: result.role,
43581
+ attempt,
43582
+ error: result.error,
43583
+ trace
43584
+ });
43585
+ if (attempt < attempts && input.node.retryPolicy?.backoffMs) {
43586
+ await new Promise((resolve4) => setTimeout(resolve4, input.node.retryPolicy.backoffMs));
43587
+ }
43588
+ }
43589
+ throw new Error(
43590
+ `Node '${input.node.id}' failed after ${attempts} attempt(s): ${lastResult?.error ?? "unknown error"}`
43591
+ );
43592
+ }
43593
+ async evaluateNodeGates(graph, node, result, workflowRunId, trace) {
43594
+ for (const gateId of node.gates ?? []) {
43595
+ const gate = graph.gates?.find((candidate) => candidate.id === gateId);
43596
+ if (!gate) continue;
43597
+ const evaluation = await this.gateEvaluator({
43598
+ gate,
43599
+ node,
43600
+ result,
43601
+ workflowRunId,
43602
+ trace,
43603
+ sharedState: this.sharedState,
43604
+ eventLog: this.eventLog ?? NULL_EVENT_LOG
43605
+ });
43606
+ const eventType = evaluation.passed ? "workflow.gate.passed" : "workflow.gate.failed";
43607
+ this.eventLog?.record(eventType, {
43608
+ workflowRunId,
43609
+ nodeId: node.id,
43610
+ gateId: gate.id,
43611
+ kind: gate.kind,
43612
+ required: gate.required,
43613
+ reason: evaluation.reason,
43614
+ trace
43615
+ });
43616
+ if (!evaluation.passed && gate.required) {
43617
+ throw new Error(
43618
+ `Required gate '${gate.id}' failed for node '${node.id}': ${evaluation.reason ?? "no reason"}`
43619
+ );
43620
+ }
43621
+ }
43622
+ }
43623
+ };
43231
43624
  function createAgentArtifact(input) {
43232
43625
  return {
43233
43626
  ...input,
@@ -43359,6 +43752,192 @@ function buildExecutionLevels(graph, issues) {
43359
43752
  }
43360
43753
  return levels;
43361
43754
  }
43755
+ var NULL_EVENT_LOG = {
43756
+ record(type, data = {}) {
43757
+ return {
43758
+ id: `event-${randomUUID()}`,
43759
+ type,
43760
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
43761
+ data
43762
+ };
43763
+ },
43764
+ list() {
43765
+ return [];
43766
+ },
43767
+ count() {
43768
+ return 0;
43769
+ },
43770
+ clear() {
43771
+ }
43772
+ };
43773
+ function graphNodeToTask(node, workflowInput) {
43774
+ return {
43775
+ id: node.id,
43776
+ role: node.agentRole ?? "coder",
43777
+ objective: node.description,
43778
+ context: {
43779
+ workflowInput,
43780
+ condition: node.condition
43781
+ },
43782
+ dependencies: node.dependsOn,
43783
+ constraints: node.requiredTools?.map((tool) => `Requires tool: ${tool}`)
43784
+ };
43785
+ }
43786
+ async function dryRunAgentGraphNodeExecutor(execution) {
43787
+ const startedAt = (/* @__PURE__ */ new Date()).toISOString();
43788
+ const dependencyOutputs = Object.fromEntries(
43789
+ [...execution.dependencyResults.entries()].map(([id, result]) => [
43790
+ id,
43791
+ { success: result.success, output: result.output }
43792
+ ])
43793
+ );
43794
+ const output = [
43795
+ `Node '${execution.node.id}' executed by ${execution.task.role}.`,
43796
+ `Objective: ${execution.task.objective}`,
43797
+ Object.keys(dependencyOutputs).length > 0 ? `Dependencies: ${JSON.stringify(dependencyOutputs)}` : "Dependencies: none"
43798
+ ].join("\n");
43799
+ return normalizeAgentRunResult({
43800
+ id: `${execution.workflowRunId}-${execution.node.id}-attempt-${execution.attempt}`,
43801
+ taskId: execution.task.id,
43802
+ role: execution.task.role,
43803
+ success: true,
43804
+ output,
43805
+ startedAt,
43806
+ completedAt: (/* @__PURE__ */ new Date()).toISOString(),
43807
+ turns: 0,
43808
+ toolsUsed: [],
43809
+ durationMs: 0,
43810
+ metadata: {
43811
+ workflowRunId: execution.workflowRunId,
43812
+ nodeId: execution.node.id,
43813
+ trace: execution.trace,
43814
+ simulated: true
43815
+ }
43816
+ });
43817
+ }
43818
+ async function missingAgentGraphNodeExecutor(execution) {
43819
+ const completedAt = (/* @__PURE__ */ new Date()).toISOString();
43820
+ return normalizeAgentRunResult({
43821
+ id: `${execution.workflowRunId}-${execution.node.id}-missing-executor`,
43822
+ taskId: execution.task.id,
43823
+ role: execution.task.role,
43824
+ success: false,
43825
+ output: "",
43826
+ startedAt: completedAt,
43827
+ completedAt,
43828
+ durationMs: 0,
43829
+ error: "AgentGraphEngine requires a nodeExecutor. Pass a real executor or set allowSimulated: true for dry-run/demo workflows.",
43830
+ metadata: {
43831
+ workflowRunId: execution.workflowRunId,
43832
+ nodeId: execution.node.id,
43833
+ trace: execution.trace,
43834
+ missingExecutor: true
43835
+ }
43836
+ });
43837
+ }
43838
+ async function defaultAgentGateEvaluator(input) {
43839
+ if (!input.result.success) {
43840
+ return { passed: false, reason: "Agent result was not successful." };
43841
+ }
43842
+ if (input.gate.kind === "tests" || input.gate.kind === "coverage" || input.gate.kind === "security" || input.gate.kind === "quality-score" || input.gate.kind === "human-approval") {
43843
+ return {
43844
+ passed: false,
43845
+ reason: `Gate '${input.gate.kind}' requires an explicit evaluator.`
43846
+ };
43847
+ }
43848
+ return { passed: true };
43849
+ }
43850
+ function chunk(items, size) {
43851
+ const safeSize = Math.max(1, size);
43852
+ const result = [];
43853
+ for (let index = 0; index < items.length; index += safeSize) {
43854
+ result.push(items.slice(index, index + safeSize));
43855
+ }
43856
+ return result;
43857
+ }
43858
+ async function runWithOptionalTimeout(promise, timeoutMs, onTimeout) {
43859
+ if (!timeoutMs || timeoutMs <= 0) return promise;
43860
+ return Promise.race([
43861
+ promise,
43862
+ new Promise((resolve4) => {
43863
+ setTimeout(() => resolve4(onTimeout()), timeoutMs);
43864
+ })
43865
+ ]);
43866
+ }
43867
+ function shouldSkipNode(node, graph, workflowInput, dependencyResults) {
43868
+ const nodeCondition = evaluateGraphCondition(node.condition, workflowInput, dependencyResults);
43869
+ if (!nodeCondition.passed) return nodeCondition.reason;
43870
+ for (const edge of graph.edges ?? []) {
43871
+ if (edge.to !== node.id || !edge.condition) continue;
43872
+ const edgeCondition = evaluateGraphCondition(edge.condition, workflowInput, dependencyResults);
43873
+ if (!edgeCondition.passed) {
43874
+ return `edge '${edge.from}' -> '${edge.to}' condition '${edge.condition}' was false`;
43875
+ }
43876
+ }
43877
+ return void 0;
43878
+ }
43879
+ function evaluateGraphCondition(condition, workflowInput, dependencyResults) {
43880
+ if (!condition || condition === "always") return { passed: true };
43881
+ if (condition === "never") return { passed: false, reason: "condition 'never' was false" };
43882
+ if (condition.startsWith("!input.")) {
43883
+ const path65 = condition.slice("!input.".length);
43884
+ return {
43885
+ passed: !readPath(workflowInput, path65),
43886
+ reason: `condition '${condition}' was false`
43887
+ };
43888
+ }
43889
+ if (condition.startsWith("input.")) {
43890
+ const path65 = condition.slice("input.".length);
43891
+ return {
43892
+ passed: Boolean(readPath(workflowInput, path65)),
43893
+ reason: `condition '${condition}' was false`
43894
+ };
43895
+ }
43896
+ if (condition.startsWith("dependency.") && condition.endsWith(".success")) {
43897
+ const id = condition.slice("dependency.".length, -".success".length);
43898
+ return {
43899
+ passed: dependencyResults.get(id)?.success === true,
43900
+ reason: `condition '${condition}' was false`
43901
+ };
43902
+ }
43903
+ if (condition.startsWith("dependency.") && condition.endsWith(".failed")) {
43904
+ const id = condition.slice("dependency.".length, -".failed".length);
43905
+ return {
43906
+ passed: dependencyResults.get(id)?.success === false,
43907
+ reason: `condition '${condition}' was false`
43908
+ };
43909
+ }
43910
+ return {
43911
+ passed: false,
43912
+ reason: `Unsupported graph condition '${condition}'.`
43913
+ };
43914
+ }
43915
+ function readPath(input, path65) {
43916
+ return path65.split(".").reduce((current, segment) => {
43917
+ if (current && typeof current === "object" && segment in current) {
43918
+ return current[segment];
43919
+ }
43920
+ return void 0;
43921
+ }, input);
43922
+ }
43923
+ function cloneUnknown(value) {
43924
+ if (value === void 0 || value === null) return value;
43925
+ try {
43926
+ return JSON.parse(JSON.stringify(value));
43927
+ } catch {
43928
+ return value;
43929
+ }
43930
+ }
43931
+ function cloneRecord(record) {
43932
+ return {
43933
+ ...record,
43934
+ value: cloneUnknown(record.value),
43935
+ provenance: { ...record.provenance }
43936
+ };
43937
+ }
43938
+ function isAgentArtifact(value) {
43939
+ return typeof value === "object" && value !== null && "id" in value && "kind" in value && "content" in value && "createdAt" in value;
43940
+ }
43362
43941
  function cloneArtifact(artifact) {
43363
43942
  return {
43364
43943
  ...artifact,
@@ -43366,14 +43945,524 @@ function cloneArtifact(artifact) {
43366
43945
  };
43367
43946
  }
43368
43947
 
43948
+ // src/runtime/context.ts
43949
+ function createRuntimeRequestContext(input = {}) {
43950
+ return {
43951
+ surface: input.surface ?? "api",
43952
+ tenant: input.tenant ? { ...input.tenant, metadata: { ...input.tenant.metadata } } : void 0,
43953
+ user: input.user ? {
43954
+ ...input.user,
43955
+ roles: [...input.user.roles ?? []],
43956
+ groups: [...input.user.groups ?? []],
43957
+ metadata: { ...input.user.metadata }
43958
+ } : void 0,
43959
+ channel: input.channel,
43960
+ correlationId: input.correlationId,
43961
+ policy: input.policy ? cloneRuntimePolicy(input.policy) : void 0,
43962
+ metadata: { ...input.metadata }
43963
+ };
43964
+ }
43965
+ function mergeRuntimePolicy(base, override) {
43966
+ if (!base && !override) return void 0;
43967
+ return {
43968
+ ...base,
43969
+ ...override,
43970
+ allowedTools: override?.allowedTools ? [...override.allowedTools] : base?.allowedTools ? [...base.allowedTools] : void 0,
43971
+ requireHumanApprovalFor: override?.requireHumanApprovalFor ? [...override.requireHumanApprovalFor] : base?.requireHumanApprovalFor ? [...base.requireHumanApprovalFor] : void 0,
43972
+ dataBoundary: { ...base?.dataBoundary, ...override?.dataBoundary },
43973
+ costBudget: { ...base?.costBudget, ...override?.costBudget },
43974
+ retention: { ...base?.retention, ...override?.retention },
43975
+ rateLimit: { ...base?.rateLimit, ...override?.rateLimit }
43976
+ };
43977
+ }
43978
+ function runtimeContextToMetadata(context) {
43979
+ if (!context) return {};
43980
+ return {
43981
+ surface: context.surface,
43982
+ channel: context.channel,
43983
+ correlationId: context.correlationId,
43984
+ tenantId: context.tenant?.id,
43985
+ tenantName: context.tenant?.name,
43986
+ userId: context.user?.id,
43987
+ userRoles: context.user?.roles,
43988
+ dataClassification: context.policy?.dataBoundary?.classification
43989
+ };
43990
+ }
43991
+ function evaluateRuntimeToolPolicy(policy, input) {
43992
+ if (policy?.allowedTools && !policy.allowedTools.includes(input.toolName)) {
43993
+ return {
43994
+ allowed: false,
43995
+ reason: `Runtime policy does not allow tool: ${input.toolName}`,
43996
+ risk: input.risk
43997
+ };
43998
+ }
43999
+ if (policy?.maxToolRisk && riskRank(input.risk) > riskRank(policy.maxToolRisk)) {
44000
+ return {
44001
+ allowed: false,
44002
+ reason: `Runtime policy allows tools up to ${policy.maxToolRisk} risk; ${input.toolName} is ${input.risk}.`,
44003
+ risk: input.risk
44004
+ };
44005
+ }
44006
+ if (policy?.requireHumanApprovalFor?.includes(input.risk) && input.confirmed !== true) {
44007
+ return {
44008
+ allowed: false,
44009
+ requiresConfirmation: true,
44010
+ reason: `Runtime policy requires human approval for ${input.risk} tools.`,
44011
+ risk: input.risk
44012
+ };
44013
+ }
44014
+ return { allowed: true, risk: input.risk };
44015
+ }
44016
+ function evaluateRuntimeRiskPolicy(policy, input) {
44017
+ if (policy?.maxToolRisk && riskRank(input.risk) > riskRank(policy.maxToolRisk)) {
44018
+ return {
44019
+ allowed: false,
44020
+ reason: `Runtime policy allows work up to ${policy.maxToolRisk} risk; ${input.subject} is ${input.risk}.`,
44021
+ risk: input.risk
44022
+ };
44023
+ }
44024
+ if (policy?.requireHumanApprovalFor?.includes(input.risk) && input.confirmed !== true) {
44025
+ return {
44026
+ allowed: false,
44027
+ requiresConfirmation: true,
44028
+ reason: `Runtime policy requires human approval for ${input.risk} work.`,
44029
+ risk: input.risk
44030
+ };
44031
+ }
44032
+ return { allowed: true, risk: input.risk };
44033
+ }
44034
+ function assertRuntimeUsageWithinPolicy(policy, usage) {
44035
+ const budget = policy?.costBudget;
44036
+ if (!budget) return;
44037
+ if (budget.maxInputTokens !== void 0 && (usage.inputTokens ?? 0) > budget.maxInputTokens) {
44038
+ throw new Error(
44039
+ `Runtime policy input token budget exceeded: ${usage.inputTokens ?? 0}/${budget.maxInputTokens}`
44040
+ );
44041
+ }
44042
+ if (budget.maxOutputTokens !== void 0 && (usage.outputTokens ?? 0) > budget.maxOutputTokens) {
44043
+ throw new Error(
44044
+ `Runtime policy output token budget exceeded: ${usage.outputTokens ?? 0}/${budget.maxOutputTokens}`
44045
+ );
44046
+ }
44047
+ }
44048
+ function cloneRuntimePolicy(policy) {
44049
+ return mergeRuntimePolicy(void 0, policy) ?? {};
44050
+ }
44051
+ function riskRank(risk) {
44052
+ switch (risk) {
44053
+ case "read-only":
44054
+ return 0;
44055
+ case "network":
44056
+ return 1;
44057
+ case "write":
44058
+ return 2;
44059
+ case "destructive":
44060
+ return 3;
44061
+ case "secrets-sensitive":
44062
+ return 4;
44063
+ }
44064
+ }
44065
+ var InMemoryEventLog = class {
44066
+ events = [];
44067
+ record(type, data = {}) {
44068
+ const event = {
44069
+ id: randomUUID(),
44070
+ type,
44071
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
44072
+ data
44073
+ };
44074
+ this.events.push(event);
44075
+ return event;
44076
+ }
44077
+ list() {
44078
+ return [...this.events];
44079
+ }
44080
+ count() {
44081
+ return this.events.length;
44082
+ }
44083
+ clear() {
44084
+ this.events = [];
44085
+ }
44086
+ };
44087
+ var FileEventLog = class {
44088
+ constructor(filePath) {
44089
+ this.filePath = filePath;
44090
+ try {
44091
+ mkdirSync(dirname(filePath), { recursive: true });
44092
+ } catch {
44093
+ this.writable = false;
44094
+ }
44095
+ }
44096
+ filePath;
44097
+ memory = new InMemoryEventLog();
44098
+ writable = true;
44099
+ record(type, data = {}) {
44100
+ const event = this.memory.record(type, data);
44101
+ if (this.writable) {
44102
+ try {
44103
+ appendFileSync(this.filePath, JSON.stringify(event) + "\n", "utf-8");
44104
+ } catch {
44105
+ this.writable = false;
44106
+ }
44107
+ }
44108
+ return event;
44109
+ }
44110
+ list() {
44111
+ if (!this.writable) return this.memory.list();
44112
+ try {
44113
+ const raw = readFileSync(this.filePath, "utf-8");
44114
+ return raw.split("\n").filter(Boolean).flatMap((line) => {
44115
+ try {
44116
+ return [JSON.parse(line)];
44117
+ } catch {
44118
+ return [];
44119
+ }
44120
+ });
44121
+ } catch {
44122
+ return this.memory.list();
44123
+ }
44124
+ }
44125
+ count() {
44126
+ return this.list().length;
44127
+ }
44128
+ clear() {
44129
+ this.memory.clear();
44130
+ if (this.writable) {
44131
+ try {
44132
+ writeFileSync(this.filePath, "", "utf-8");
44133
+ } catch {
44134
+ this.writable = false;
44135
+ }
44136
+ }
44137
+ }
44138
+ };
44139
+ function createEventLog() {
44140
+ return new InMemoryEventLog();
44141
+ }
44142
+ function createFileEventLog(filePath) {
44143
+ return new FileEventLog(filePath);
44144
+ }
44145
+
44146
+ // src/runtime/agent-modes.ts
44147
+ var AGENT_MODES = {
44148
+ ask: {
44149
+ id: "ask",
44150
+ label: "Ask",
44151
+ description: "Answer questions and explain code without modifying files.",
44152
+ readOnly: true,
44153
+ preferredTools: ["read_file", "grep", "glob", "codebase_map", "lsp_definition"],
44154
+ requiresVerification: false
44155
+ },
44156
+ plan: {
44157
+ id: "plan",
44158
+ label: "Plan",
44159
+ description: "Explore and produce an implementation plan with read-only tools.",
44160
+ readOnly: true,
44161
+ preferredTools: ["read_file", "grep", "glob", "codebase_map", "lsp_workspace_symbols"],
44162
+ requiresVerification: false
44163
+ },
44164
+ build: {
44165
+ id: "build",
44166
+ label: "Build",
44167
+ description: "Implement code changes and verify them.",
44168
+ readOnly: false,
44169
+ preferredTools: ["read_file", "edit_file", "write_file", "bash_exec", "run_tests"],
44170
+ requiresVerification: true
44171
+ },
44172
+ debug: {
44173
+ id: "debug",
44174
+ label: "Debug",
44175
+ description: "Reproduce failures, trace root cause, patch, and verify.",
44176
+ readOnly: false,
44177
+ preferredTools: ["bash_exec", "read_file", "grep", "lsp_references", "edit_file"],
44178
+ requiresVerification: true
44179
+ },
44180
+ review: {
44181
+ id: "review",
44182
+ label: "Review",
44183
+ description: "Inspect code quality, security, behavior changes, and test gaps.",
44184
+ readOnly: true,
44185
+ preferredTools: ["git_diff", "read_file", "grep", "review_code", "calculate_quality"],
44186
+ requiresVerification: false
44187
+ },
44188
+ architect: {
44189
+ id: "architect",
44190
+ label: "Architect",
44191
+ description: "Design architecture and split work for architect/editor execution.",
44192
+ readOnly: true,
44193
+ preferredTools: ["codebase_map", "lsp_workspace_symbols", "grep", "create_agent_plan"],
44194
+ requiresVerification: false
44195
+ }
44196
+ };
44197
+ function getAgentMode(mode) {
44198
+ return AGENT_MODES[mode];
44199
+ }
44200
+ function listAgentModes() {
44201
+ return Object.values(AGENT_MODES);
44202
+ }
44203
+ function isAgentMode(value) {
44204
+ return value in AGENT_MODES;
44205
+ }
44206
+
44207
+ // src/runtime/permission-policy.ts
44208
+ var READ_ONLY_CATEGORIES = /* @__PURE__ */ new Set(["search", "web", "document"]);
44209
+ var WRITE_CATEGORIES = /* @__PURE__ */ new Set(["file", "git", "test", "build", "memory"]);
44210
+ var READ_ONLY_TOOL_NAMES = /* @__PURE__ */ new Set([
44211
+ "glob",
44212
+ "read_file",
44213
+ "list_dir",
44214
+ "tree",
44215
+ "grep",
44216
+ "find_in_file",
44217
+ "semantic_search",
44218
+ "codebase_map",
44219
+ "repo_context",
44220
+ "lsp_status",
44221
+ "lsp_document_symbols",
44222
+ "lsp_workspace_symbols",
44223
+ "lsp_definition",
44224
+ "lsp_references",
44225
+ "git_status",
44226
+ "git_log",
44227
+ "git_diff",
44228
+ "git_show",
44229
+ "git_branch",
44230
+ "recall_memory",
44231
+ "list_memories",
44232
+ "list_checkpoints",
44233
+ "checkAgentCapability"
44234
+ ]);
44235
+ var WRITE_CAPABLE_TOOL_NAMES = /* @__PURE__ */ new Set(["run_linter"]);
44236
+ var DESTRUCTIVE_TOOL_NAMES = /* @__PURE__ */ new Set([
44237
+ "bash_exec",
44238
+ "write_file",
44239
+ "edit_file",
44240
+ "delete_file",
44241
+ "restore_checkpoint",
44242
+ "git_commit",
44243
+ "git_push",
44244
+ "request_human_escalation"
44245
+ ]);
44246
+ function riskForTool(tool) {
44247
+ if (READ_ONLY_TOOL_NAMES.has(tool.name)) return "read-only";
44248
+ if (DESTRUCTIVE_TOOL_NAMES.has(tool.name)) return "destructive";
44249
+ if (WRITE_CAPABLE_TOOL_NAMES.has(tool.name)) return "write";
44250
+ if (tool.category === "web") return "network";
44251
+ if (WRITE_CATEGORIES.has(tool.category)) return "write";
44252
+ if (tool.category === "quality") return "write";
44253
+ return "read-only";
44254
+ }
44255
+ var DefaultPermissionPolicy = class {
44256
+ canExecuteTool(mode, tool) {
44257
+ const definition = getAgentMode(mode);
44258
+ const risk = riskForTool(tool);
44259
+ const readOnlyTool = READ_ONLY_TOOL_NAMES.has(tool.name) || READ_ONLY_CATEGORIES.has(tool.category);
44260
+ if (definition.readOnly && !readOnlyTool) {
44261
+ return {
44262
+ allowed: false,
44263
+ reason: `${definition.label} mode is read-only; ${tool.name} is a ${tool.category} tool.`,
44264
+ risk
44265
+ };
44266
+ }
44267
+ if (risk === "destructive") {
44268
+ return {
44269
+ allowed: true,
44270
+ requiresConfirmation: true,
44271
+ reason: `${tool.name} can change repository state and should be confirmed.`,
44272
+ risk
44273
+ };
44274
+ }
44275
+ return { allowed: true, risk };
44276
+ }
44277
+ canExecuteToolInput(mode, tool, input) {
44278
+ if (tool.name === "spawnSimpleAgent") {
44279
+ const risk = riskForSpawnedAgent(input);
44280
+ const definition2 = getAgentMode(mode);
44281
+ if (definition2.readOnly && risk !== "read-only" && risk !== "network") {
44282
+ return {
44283
+ allowed: false,
44284
+ reason: `${definition2.label} mode is read-only; spawnSimpleAgent with this role can perform ${risk} work.`,
44285
+ risk
44286
+ };
44287
+ }
44288
+ return {
44289
+ allowed: true,
44290
+ requiresConfirmation: risk === "destructive" || risk === "secrets-sensitive",
44291
+ risk
44292
+ };
44293
+ }
44294
+ if (tool.name !== "run_linter") {
44295
+ return this.canExecuteTool(mode, tool);
44296
+ }
44297
+ const definition = getAgentMode(mode);
44298
+ const fixEnabled = input["fix"] === true;
44299
+ const decision = fixEnabled ? { allowed: true, risk: "write" } : { allowed: true, risk: "read-only" };
44300
+ if (definition.readOnly && fixEnabled) {
44301
+ return {
44302
+ allowed: false,
44303
+ reason: `${definition.label} mode is read-only; run_linter with fix=true can modify files.`,
44304
+ risk: "write"
44305
+ };
44306
+ }
44307
+ return decision;
44308
+ }
44309
+ };
44310
+ function createPermissionPolicy() {
44311
+ return new DefaultPermissionPolicy();
44312
+ }
44313
+ function riskForSpawnedAgent(input) {
44314
+ const type = typeof input["type"] === "string" ? input["type"] : void 0;
44315
+ const role = typeof input["role"] === "string" ? input["role"] : void 0;
44316
+ const resolved = type ?? role;
44317
+ switch (resolved) {
44318
+ case "explore":
44319
+ case "plan":
44320
+ case "review":
44321
+ case "architect":
44322
+ case "security":
44323
+ case "docs":
44324
+ case "researcher":
44325
+ case "reviewer":
44326
+ case "planner":
44327
+ return "read-only";
44328
+ case "database":
44329
+ return "secrets-sensitive";
44330
+ case "test":
44331
+ case "tdd":
44332
+ case "e2e":
44333
+ case "tester":
44334
+ return "destructive";
44335
+ case "debug":
44336
+ case "refactor":
44337
+ case "coder":
44338
+ case "optimizer":
44339
+ return "write";
44340
+ default:
44341
+ return "read-only";
44342
+ }
44343
+ }
44344
+
44345
+ // src/runtime/runtime-tool-executor.ts
44346
+ var RuntimeToolExecutor = class {
44347
+ toolRegistry;
44348
+ eventLog;
44349
+ permissionPolicy;
44350
+ defaultMode;
44351
+ runtimePolicy;
44352
+ constructor(options) {
44353
+ this.toolRegistry = options.toolRegistry;
44354
+ this.eventLog = options.eventLog ?? createEventLog();
44355
+ this.permissionPolicy = options.permissionPolicy ?? createPermissionPolicy();
44356
+ this.defaultMode = options.mode ?? "ask";
44357
+ this.runtimePolicy = options.runtimePolicy;
44358
+ }
44359
+ async execute(input) {
44360
+ const startedAt = performance.now();
44361
+ const mode = input.mode ?? this.defaultMode;
44362
+ const allowedTools = input.allowedTools ? new Set(input.allowedTools) : void 0;
44363
+ if (allowedTools && !allowedTools.has(input.toolName)) {
44364
+ const decision2 = {
44365
+ allowed: false,
44366
+ reason: `Tool '${input.toolName}' is not available to this agent.`,
44367
+ risk: "read-only"
44368
+ };
44369
+ return this.block(input, mode, decision2, startedAt);
44370
+ }
44371
+ const tool = this.toolRegistry.get(input.toolName);
44372
+ if (!tool) {
44373
+ const decision2 = {
44374
+ allowed: false,
44375
+ reason: "Tool not registered.",
44376
+ risk: "read-only"
44377
+ };
44378
+ return this.block(input, mode, decision2, startedAt);
44379
+ }
44380
+ const decision = this.permissionPolicy.canExecuteToolInput ? this.permissionPolicy.canExecuteToolInput(mode, tool, input.input) : this.permissionPolicy.canExecuteTool(mode, tool);
44381
+ const runtimeDecision = decision.allowed ? evaluateRuntimeToolPolicy(this.runtimePolicy, {
44382
+ toolName: input.toolName,
44383
+ risk: decision.risk,
44384
+ confirmed: input.confirmed
44385
+ }) : void 0;
44386
+ if (!decision.allowed || runtimeDecision?.allowed === false || decision.requiresConfirmation && input.confirmed !== true) {
44387
+ const reason = runtimeDecision?.reason ?? decision.reason ?? (decision.requiresConfirmation ? "Tool requires explicit runtime confirmation." : "Tool is not allowed.");
44388
+ return this.block(
44389
+ input,
44390
+ mode,
44391
+ {
44392
+ ...decision,
44393
+ allowed: false,
44394
+ reason,
44395
+ requiresConfirmation: runtimeDecision?.requiresConfirmation ?? decision.requiresConfirmation,
44396
+ risk: runtimeDecision?.risk ?? decision.risk
44397
+ },
44398
+ startedAt,
44399
+ { runtimePolicyBlocked: runtimeDecision ? !runtimeDecision.allowed : false }
44400
+ );
44401
+ }
44402
+ this.eventLog.record("agent.tool.called", {
44403
+ mode,
44404
+ tool: input.toolName,
44405
+ risk: decision.risk,
44406
+ metadata: input.metadata
44407
+ });
44408
+ this.eventLog.record("tool.started", {
44409
+ mode,
44410
+ tool: input.toolName,
44411
+ risk: decision.risk,
44412
+ runtimeApi: true,
44413
+ metadataKeys: Object.keys(input.metadata ?? {}).sort()
44414
+ });
44415
+ const result = await this.toolRegistry.execute(input.toolName, input.input);
44416
+ this.eventLog.record("tool.completed", {
44417
+ mode,
44418
+ tool: input.toolName,
44419
+ success: result.success,
44420
+ duration: result.duration,
44421
+ runtimeApi: true
44422
+ });
44423
+ return {
44424
+ toolName: input.toolName,
44425
+ success: result.success,
44426
+ output: result.data,
44427
+ error: result.error,
44428
+ duration: result.duration,
44429
+ decision
44430
+ };
44431
+ }
44432
+ block(input, mode, decision, startedAt, extraData = {}) {
44433
+ this.eventLog.record("tool.blocked", {
44434
+ mode,
44435
+ tool: input.toolName,
44436
+ reason: decision.reason,
44437
+ risk: decision.risk,
44438
+ requiresConfirmation: decision.requiresConfirmation,
44439
+ runtimeApi: true,
44440
+ metadata: input.metadata,
44441
+ ...extraData
44442
+ });
44443
+ return {
44444
+ toolName: input.toolName,
44445
+ success: false,
44446
+ error: decision.reason ?? "Tool is not allowed.",
44447
+ duration: performance.now() - startedAt,
44448
+ decision
44449
+ };
44450
+ }
44451
+ };
44452
+ function createRuntimeToolExecutor(options) {
44453
+ return new RuntimeToolExecutor(options);
44454
+ }
44455
+
43369
44456
  // src/agents/executor.ts
43370
44457
  var AgentExecutor = class {
43371
- constructor(provider, toolRegistry) {
44458
+ constructor(provider, toolRegistry, runtimeToolExecutor) {
43372
44459
  this.provider = provider;
43373
44460
  this.toolRegistry = toolRegistry;
44461
+ this.runtimeToolExecutor = runtimeToolExecutor ?? createRuntimeToolExecutor({ toolRegistry, mode: "ask" });
43374
44462
  }
43375
44463
  provider;
43376
44464
  toolRegistry;
44465
+ runtimeToolExecutor;
43377
44466
  /**
43378
44467
  * Execute an agent on a task with multi-turn tool use
43379
44468
  */
@@ -43441,11 +44530,21 @@ var AgentExecutor = class {
43441
44530
  for (const toolCall of response.toolCalls) {
43442
44531
  toolsUsed.add(toolCall.name);
43443
44532
  try {
43444
- const result = await this.toolRegistry.execute(toolCall.name, toolCall.input);
44533
+ const result = await this.runtimeToolExecutor.execute({
44534
+ toolName: toolCall.name,
44535
+ input: toolCall.input,
44536
+ allowedTools: agent.allowedTools.length > 0 ? agent.allowedTools : void 0,
44537
+ mode: runtimeModeForAgent(agent.role),
44538
+ metadata: {
44539
+ agentRole: agent.role,
44540
+ taskId: task.id,
44541
+ toolCallId: toolCall.id
44542
+ }
44543
+ });
43445
44544
  toolResults.push({
43446
44545
  type: "tool_result",
43447
44546
  tool_use_id: toolCall.id,
43448
- content: result.success ? JSON.stringify(result.data) : `Error: ${result.error}`,
44547
+ content: result.success ? JSON.stringify(result.output) : `Error: ${result.error}`,
43449
44548
  is_error: !result.success
43450
44549
  });
43451
44550
  } catch (error) {
@@ -43547,7 +44646,7 @@ Complete this task autonomously using the available tools. When done, provide a
43547
44646
  }
43548
44647
  };
43549
44648
  function normalizeRole(role) {
43550
- return role === "researcher" || role === "architect" || role === "editor" || role === "coder" || role === "tester" || role === "reviewer" || role === "optimizer" || role === "planner" ? role : "coder";
44649
+ return mapLegacyAgentRole(role);
43551
44650
  }
43552
44651
  var AGENT_ROLES = {
43553
44652
  researcher: {
@@ -43656,6 +44755,22 @@ Use tools to analyze requirements and explore the codebase.`,
43656
44755
  allowedTools: ["read_file", "grep", "glob", "codebase_map"]
43657
44756
  }
43658
44757
  };
44758
+ function runtimeModeForAgent(role) {
44759
+ switch (role) {
44760
+ case "researcher":
44761
+ case "planner":
44762
+ return "plan";
44763
+ case "architect":
44764
+ return "architect";
44765
+ case "reviewer":
44766
+ return "review";
44767
+ case "tester":
44768
+ case "editor":
44769
+ case "coder":
44770
+ case "optimizer":
44771
+ return "build";
44772
+ }
44773
+ }
43659
44774
  var DEFAULTS = {
43660
44775
  maxConcurrency: os4__default.cpus().length,
43661
44776
  minConcurrency: 1,
@@ -45975,16 +47090,18 @@ var AgentManager = class extends EventEmitter {
45975
47090
  abortControllers = /* @__PURE__ */ new Map();
45976
47091
  provider;
45977
47092
  toolRegistry;
47093
+ runtimeToolExecutor;
45978
47094
  logger = getLogger();
45979
47095
  /**
45980
47096
  * Create a new AgentManager
45981
47097
  * @param provider - LLM provider for agent execution
45982
47098
  * @param toolRegistry - Tool registry for agent tool access
45983
47099
  */
45984
- constructor(provider, toolRegistry) {
47100
+ constructor(provider, toolRegistry, runtimeToolExecutor) {
45985
47101
  super();
45986
47102
  this.provider = provider;
45987
47103
  this.toolRegistry = toolRegistry;
47104
+ this.runtimeToolExecutor = runtimeToolExecutor ?? createRuntimeToolExecutor({ toolRegistry, mode: "ask" });
45988
47105
  }
45989
47106
  /**
45990
47107
  * Spawn a new subagent for a specific task
@@ -46299,11 +47416,20 @@ var AgentManager = class extends EventEmitter {
46299
47416
  continue;
46300
47417
  }
46301
47418
  try {
46302
- const result = await this.toolRegistry.execute(toolCall.name, toolCall.input);
47419
+ const result = await this.runtimeToolExecutor.execute({
47420
+ toolName: toolCall.name,
47421
+ input: toolCall.input,
47422
+ allowedTools: config.tools,
47423
+ mode: runtimeModeForAgentType(config.type),
47424
+ metadata: {
47425
+ agentType: config.type,
47426
+ toolCallId: toolCall.id
47427
+ }
47428
+ });
46303
47429
  results.push({
46304
47430
  type: "tool_result",
46305
47431
  tool_use_id: toolCall.id,
46306
- content: result.success ? String(result.data ?? "Success") : `Error: ${result.error}`,
47432
+ content: result.success ? String(result.output ?? "Success") : `Error: ${result.error}`,
46307
47433
  is_error: !result.success
46308
47434
  });
46309
47435
  } catch (error) {
@@ -46366,28 +47492,27 @@ var AgentManager = class extends EventEmitter {
46366
47492
  }
46367
47493
  };
46368
47494
  function agentTypeToRuntimeRole(type) {
47495
+ return mapLegacyAgentRole(type);
47496
+ }
47497
+ function runtimeModeForAgentType(type) {
46369
47498
  switch (type) {
46370
47499
  case "explore":
46371
- return "researcher";
46372
47500
  case "plan":
46373
- return "planner";
46374
- case "test":
46375
- case "e2e":
46376
- case "tdd":
46377
- return "tester";
46378
- case "debug":
46379
- case "refactor":
46380
- return "coder";
47501
+ case "docs":
47502
+ return "plan";
46381
47503
  case "review":
46382
- return "reviewer";
47504
+ case "security":
47505
+ return "review";
46383
47506
  case "architect":
46384
47507
  return "architect";
46385
- case "security":
46386
- return "security";
46387
- case "docs":
46388
- return "docs";
47508
+ case "debug":
47509
+ return "debug";
47510
+ case "test":
47511
+ case "tdd":
47512
+ case "e2e":
47513
+ case "refactor":
46389
47514
  case "database":
46390
- return "database";
47515
+ return "build";
46391
47516
  }
46392
47517
  }
46393
47518
 
@@ -46434,7 +47559,7 @@ var AGENT_TYPES = [
46434
47559
  "docs",
46435
47560
  "database"
46436
47561
  ];
46437
- var LEGACY_ROLE_MAP = {
47562
+ var LEGACY_ROLE_MAP2 = {
46438
47563
  researcher: "explore",
46439
47564
  coder: "debug",
46440
47565
  // "debug" has write + bash + read — closest to general coding
@@ -46454,7 +47579,7 @@ var SpawnSimpleAgentSchema = z.object({
46454
47579
  });
46455
47580
  function resolveAgentType(input) {
46456
47581
  if (input.type) return input.type;
46457
- if (input.role && input.role in LEGACY_ROLE_MAP) return LEGACY_ROLE_MAP[input.role];
47582
+ if (input.role && input.role in LEGACY_ROLE_MAP2) return LEGACY_ROLE_MAP2[input.role];
46458
47583
  return "explore";
46459
47584
  }
46460
47585
  var spawnSimpleAgentTool = defineTool({
@@ -46996,14 +48121,14 @@ ${message}
46996
48121
  const subprocess = execa(pm, cmdArgs, options);
46997
48122
  let stdoutBuffer = "";
46998
48123
  let stderrBuffer = "";
46999
- subprocess.stdout?.on("data", (chunk) => {
47000
- const text16 = chunk.toString();
48124
+ subprocess.stdout?.on("data", (chunk2) => {
48125
+ const text16 = chunk2.toString();
47001
48126
  stdoutBuffer += text16;
47002
48127
  process.stdout.write(text16);
47003
48128
  heartbeat.activity();
47004
48129
  });
47005
- subprocess.stderr?.on("data", (chunk) => {
47006
- const text16 = chunk.toString();
48130
+ subprocess.stderr?.on("data", (chunk2) => {
48131
+ const text16 = chunk2.toString();
47007
48132
  stderrBuffer += text16;
47008
48133
  process.stderr.write(text16);
47009
48134
  heartbeat.activity();
@@ -47121,14 +48246,14 @@ ${message}
47121
48246
  const subprocess = execa(pm, cmdArgs, options);
47122
48247
  let stdoutBuffer = "";
47123
48248
  let stderrBuffer = "";
47124
- subprocess.stdout?.on("data", (chunk) => {
47125
- const text16 = chunk.toString();
48249
+ subprocess.stdout?.on("data", (chunk2) => {
48250
+ const text16 = chunk2.toString();
47126
48251
  stdoutBuffer += text16;
47127
48252
  process.stdout.write(text16);
47128
48253
  heartbeat.activity();
47129
48254
  });
47130
- subprocess.stderr?.on("data", (chunk) => {
47131
- const text16 = chunk.toString();
48255
+ subprocess.stderr?.on("data", (chunk2) => {
48256
+ const text16 = chunk2.toString();
47132
48257
  stderrBuffer += text16;
47133
48258
  process.stderr.write(text16);
47134
48259
  heartbeat.activity();
@@ -47223,14 +48348,14 @@ ${message}
47223
48348
  const subprocess = execa("make", cmdArgs, options);
47224
48349
  let stdoutBuffer = "";
47225
48350
  let stderrBuffer = "";
47226
- subprocess.stdout?.on("data", (chunk) => {
47227
- const text16 = chunk.toString();
48351
+ subprocess.stdout?.on("data", (chunk2) => {
48352
+ const text16 = chunk2.toString();
47228
48353
  stdoutBuffer += text16;
47229
48354
  process.stdout.write(text16);
47230
48355
  heartbeat.activity();
47231
48356
  });
47232
- subprocess.stderr?.on("data", (chunk) => {
47233
- const text16 = chunk.toString();
48357
+ subprocess.stderr?.on("data", (chunk2) => {
48358
+ const text16 = chunk2.toString();
47234
48359
  stderrBuffer += text16;
47235
48360
  process.stderr.write(text16);
47236
48361
  heartbeat.activity();
@@ -47326,14 +48451,14 @@ ${message}
47326
48451
  const subprocess = execa("npx", ["tsc", ...cmdArgs], options);
47327
48452
  let stdoutBuffer = "";
47328
48453
  let stderrBuffer = "";
47329
- subprocess.stdout?.on("data", (chunk) => {
47330
- const text16 = chunk.toString();
48454
+ subprocess.stdout?.on("data", (chunk2) => {
48455
+ const text16 = chunk2.toString();
47331
48456
  stdoutBuffer += text16;
47332
48457
  process.stdout.write(text16);
47333
48458
  heartbeat.activity();
47334
48459
  });
47335
- subprocess.stderr?.on("data", (chunk) => {
47336
- const text16 = chunk.toString();
48460
+ subprocess.stderr?.on("data", (chunk2) => {
48461
+ const text16 = chunk2.toString();
47337
48462
  stderrBuffer += text16;
47338
48463
  process.stderr.write(text16);
47339
48464
  heartbeat.activity();
@@ -47430,14 +48555,14 @@ ${message}
47430
48555
  });
47431
48556
  let stdoutBuffer = "";
47432
48557
  let stderrBuffer = "";
47433
- subprocess.stdout?.on("data", (chunk) => {
47434
- const text16 = chunk.toString();
48558
+ subprocess.stdout?.on("data", (chunk2) => {
48559
+ const text16 = chunk2.toString();
47435
48560
  stdoutBuffer += text16;
47436
48561
  process.stdout.write(text16);
47437
48562
  heartbeat.activity();
47438
48563
  });
47439
- subprocess.stderr?.on("data", (chunk) => {
47440
- const text16 = chunk.toString();
48564
+ subprocess.stderr?.on("data", (chunk2) => {
48565
+ const text16 = chunk2.toString();
47441
48566
  stderrBuffer += text16;
47442
48567
  process.stderr.write(text16);
47443
48568
  heartbeat.activity();
@@ -47517,14 +48642,14 @@ ${message}
47517
48642
  });
47518
48643
  let stdoutBuffer = "";
47519
48644
  let stderrBuffer = "";
47520
- subprocess.stdout?.on("data", (chunk) => {
47521
- const text16 = chunk.toString();
48645
+ subprocess.stdout?.on("data", (chunk2) => {
48646
+ const text16 = chunk2.toString();
47522
48647
  stdoutBuffer += text16;
47523
48648
  process.stdout.write(text16);
47524
48649
  heartbeat.activity();
47525
48650
  });
47526
- subprocess.stderr?.on("data", (chunk) => {
47527
- const text16 = chunk.toString();
48651
+ subprocess.stderr?.on("data", (chunk2) => {
48652
+ const text16 = chunk2.toString();
47528
48653
  stderrBuffer += text16;
47529
48654
  process.stderr.write(text16);
47530
48655
  heartbeat.activity();
@@ -49346,13 +50471,13 @@ Examples:
49346
50471
  const content = await fs41.readFile(fullPath, "utf-8");
49347
50472
  if (content.length > 1e5) continue;
49348
50473
  const fileChunks = chunkContent(content, DEFAULT_CHUNK_SIZE);
49349
- for (const chunk of fileChunks) {
49350
- const vector = await getEmbedding(chunk.text);
50474
+ for (const chunk2 of fileChunks) {
50475
+ const vector = await getEmbedding(chunk2.text);
49351
50476
  chunks.push({
49352
50477
  file,
49353
- startLine: chunk.startLine,
49354
- endLine: chunk.endLine,
49355
- text: chunk.text,
50478
+ startLine: chunk2.startLine,
50479
+ endLine: chunk2.endLine,
50480
+ text: chunk2.text,
49356
50481
  vector,
49357
50482
  mtime: stat2.mtimeMs
49358
50483
  });
@@ -49386,9 +50511,9 @@ Examples:
49386
50511
  }
49387
50512
  }
49388
50513
  const queryVector = await getEmbedding(query);
49389
- const scored = index.chunks.map((chunk) => ({
49390
- chunk,
49391
- score: cosineSimilarity(queryVector, chunk.vector)
50514
+ const scored = index.chunks.map((chunk2) => ({
50515
+ chunk: chunk2,
50516
+ score: cosineSimilarity(queryVector, chunk2.vector)
49392
50517
  }));
49393
50518
  const filtered = scored.filter((s) => s.score >= effectiveThreshold).sort((a, b) => b.score - a.score).slice(0, effectiveMaxResults);
49394
50519
  const results = filtered.map((s) => {
@@ -50261,7 +51386,7 @@ async function validateCode(code, filePath, _language) {
50261
51386
  const errors = [];
50262
51387
  const warnings = [];
50263
51388
  try {
50264
- const ast = parse$1(code, {
51389
+ const ast = parse(code, {
50265
51390
  loc: true,
50266
51391
  range: true,
50267
51392
  comment: true,
@@ -50388,7 +51513,7 @@ async function analyzeFile(filePath, includeAst = false) {
50388
51513
  const exports$1 = [];
50389
51514
  let ast;
50390
51515
  try {
50391
- ast = parse$1(content, {
51516
+ ast = parse(content, {
50392
51517
  loc: true,
50393
51518
  range: true,
50394
51519
  comment: true,
@@ -52866,69 +53991,6 @@ var repoMapCommand = {
52866
53991
  return false;
52867
53992
  }
52868
53993
  };
52869
-
52870
- // src/runtime/agent-modes.ts
52871
- var AGENT_MODES = {
52872
- ask: {
52873
- id: "ask",
52874
- label: "Ask",
52875
- description: "Answer questions and explain code without modifying files.",
52876
- readOnly: true,
52877
- preferredTools: ["read_file", "grep", "glob", "codebase_map", "lsp_definition"],
52878
- requiresVerification: false
52879
- },
52880
- plan: {
52881
- id: "plan",
52882
- label: "Plan",
52883
- description: "Explore and produce an implementation plan with read-only tools.",
52884
- readOnly: true,
52885
- preferredTools: ["read_file", "grep", "glob", "codebase_map", "lsp_workspace_symbols"],
52886
- requiresVerification: false
52887
- },
52888
- build: {
52889
- id: "build",
52890
- label: "Build",
52891
- description: "Implement code changes and verify them.",
52892
- readOnly: false,
52893
- preferredTools: ["read_file", "edit_file", "write_file", "bash_exec", "run_tests"],
52894
- requiresVerification: true
52895
- },
52896
- debug: {
52897
- id: "debug",
52898
- label: "Debug",
52899
- description: "Reproduce failures, trace root cause, patch, and verify.",
52900
- readOnly: false,
52901
- preferredTools: ["bash_exec", "read_file", "grep", "lsp_references", "edit_file"],
52902
- requiresVerification: true
52903
- },
52904
- review: {
52905
- id: "review",
52906
- label: "Review",
52907
- description: "Inspect code quality, security, behavior changes, and test gaps.",
52908
- readOnly: true,
52909
- preferredTools: ["git_diff", "read_file", "grep", "review_code", "calculate_quality"],
52910
- requiresVerification: false
52911
- },
52912
- architect: {
52913
- id: "architect",
52914
- label: "Architect",
52915
- description: "Design architecture and split work for architect/editor execution.",
52916
- readOnly: true,
52917
- preferredTools: ["codebase_map", "lsp_workspace_symbols", "grep", "create_agent_plan"],
52918
- requiresVerification: false
52919
- }
52920
- };
52921
- function getAgentMode(mode) {
52922
- return AGENT_MODES[mode];
52923
- }
52924
- function listAgentModes() {
52925
- return Object.values(AGENT_MODES);
52926
- }
52927
- function isAgentMode(value) {
52928
- return value in AGENT_MODES;
52929
- }
52930
-
52931
- // src/cli/repl/commands/mode.ts
52932
53994
  function currentMode(session) {
52933
53995
  return session.agentMode ?? (session.planMode ? "plan" : "build");
52934
53996
  }
@@ -54367,17 +55429,17 @@ function resetLineBuffer() {
54367
55429
  stopStreamingIndicator();
54368
55430
  resetBlockStore();
54369
55431
  }
54370
- function renderStreamChunk(chunk) {
54371
- if (chunk.type === "text" && chunk.text) {
54372
- lineBuffer += chunk.text;
54373
- rawMarkdownBuffer += chunk.text;
55432
+ function renderStreamChunk(chunk2) {
55433
+ if (chunk2.type === "text" && chunk2.text) {
55434
+ lineBuffer += chunk2.text;
55435
+ rawMarkdownBuffer += chunk2.text;
54374
55436
  let newlineIndex;
54375
55437
  while ((newlineIndex = lineBuffer.indexOf("\n")) !== -1) {
54376
55438
  const line = lineBuffer.slice(0, newlineIndex);
54377
55439
  lineBuffer = lineBuffer.slice(newlineIndex + 1);
54378
55440
  processAndOutputLine(line);
54379
55441
  }
54380
- } else if (chunk.type === "done") {
55442
+ } else if (chunk2.type === "done") {
54381
55443
  flushLineBuffer();
54382
55444
  }
54383
55445
  }
@@ -55571,22 +56633,22 @@ ${tail}`;
55571
56633
  content: `[System: ${reason} Do not call tools. Either explain the exact blocker and ask the user for the smallest missing input, or, if the task is already complete, summarize it briefly. Do not return an empty response.]`
55572
56634
  }
55573
56635
  ];
55574
- for await (const chunk of provider.streamWithTools(finalMessages, {
56636
+ for await (const chunk2 of provider.streamWithTools(finalMessages, {
55575
56637
  tools: [],
55576
56638
  maxTokens: session.config.provider.maxTokens,
55577
56639
  signal: options.signal
55578
56640
  // Omit thinking for the final explanation turn to avoid unnecessary cost
55579
56641
  })) {
55580
56642
  if (options.signal?.aborted) break;
55581
- if (chunk.type === "text" && chunk.text) {
56643
+ if (chunk2.type === "text" && chunk2.text) {
55582
56644
  if (!explanationThinkingEnded) {
55583
56645
  options.onThinkingEnd?.();
55584
56646
  explanationThinkingEnded = true;
55585
56647
  }
55586
- explanation += chunk.text;
55587
- options.onStream?.(chunk);
56648
+ explanation += chunk2.text;
56649
+ options.onStream?.(chunk2);
55588
56650
  }
55589
- if (chunk.type === "done") break;
56651
+ if (chunk2.type === "done") break;
55590
56652
  }
55591
56653
  } catch {
55592
56654
  } finally {
@@ -55627,7 +56689,7 @@ ${tail}`;
55627
56689
  lastStopReason = void 0;
55628
56690
  const toolCallBuilders = /* @__PURE__ */ new Map();
55629
56691
  try {
55630
- for await (const chunk of provider.streamWithTools(messages, {
56692
+ for await (const chunk2 of provider.streamWithTools(messages, {
55631
56693
  tools,
55632
56694
  maxTokens: session.config.provider.maxTokens,
55633
56695
  signal: options.signal,
@@ -55637,56 +56699,56 @@ ${tail}`;
55637
56699
  break;
55638
56700
  }
55639
56701
  try {
55640
- if (chunk.type === "text" && chunk.text) {
56702
+ if (chunk2.type === "text" && chunk2.text) {
55641
56703
  if (!thinkingEnded) {
55642
56704
  options.onThinkingEnd?.();
55643
56705
  thinkingEnded = true;
55644
56706
  }
55645
- responseContent += chunk.text;
55646
- finalContent += chunk.text;
55647
- iterationTextChunks.push(chunk);
56707
+ responseContent += chunk2.text;
56708
+ finalContent += chunk2.text;
56709
+ iterationTextChunks.push(chunk2);
55648
56710
  }
55649
- if (chunk.type === "tool_use_start" && chunk.toolCall) {
56711
+ if (chunk2.type === "tool_use_start" && chunk2.toolCall) {
55650
56712
  flushLineBuffer();
55651
56713
  if (!thinkingEnded) {
55652
56714
  options.onThinkingEnd?.();
55653
56715
  thinkingEnded = true;
55654
56716
  }
55655
- const id = chunk.toolCall.id ?? `tool_${toolCallBuilders.size}`;
55656
- const toolName = chunk.toolCall.name ?? "";
56717
+ const id = chunk2.toolCall.id ?? `tool_${toolCallBuilders.size}`;
56718
+ const toolName = chunk2.toolCall.name ?? "";
55657
56719
  toolCallBuilders.set(id, {
55658
56720
  id,
55659
56721
  name: toolName,
55660
56722
  input: {},
55661
- geminiThoughtSignature: chunk.toolCall.geminiThoughtSignature
56723
+ geminiThoughtSignature: chunk2.toolCall.geminiThoughtSignature
55662
56724
  });
55663
56725
  if (toolName) {
55664
56726
  options.onToolPreparing?.(toolName);
55665
56727
  }
55666
56728
  }
55667
- if (chunk.type === "tool_use_end" && chunk.toolCall) {
55668
- const id = chunk.toolCall.id ?? "";
56729
+ if (chunk2.type === "tool_use_end" && chunk2.toolCall) {
56730
+ const id = chunk2.toolCall.id ?? "";
55669
56731
  const builder = toolCallBuilders.get(id);
55670
56732
  if (builder) {
55671
56733
  const finalToolCall = {
55672
56734
  id: builder.id,
55673
- name: chunk.toolCall.name ?? builder.name,
55674
- input: chunk.toolCall.input ?? builder.input,
55675
- geminiThoughtSignature: chunk.toolCall.geminiThoughtSignature ?? builder.geminiThoughtSignature
56735
+ name: chunk2.toolCall.name ?? builder.name,
56736
+ input: chunk2.toolCall.input ?? builder.input,
56737
+ geminiThoughtSignature: chunk2.toolCall.geminiThoughtSignature ?? builder.geminiThoughtSignature
55676
56738
  };
55677
56739
  collectedToolCalls.push(finalToolCall);
55678
- } else if (chunk.toolCall.id && chunk.toolCall.name) {
56740
+ } else if (chunk2.toolCall.id && chunk2.toolCall.name) {
55679
56741
  collectedToolCalls.push({
55680
- id: chunk.toolCall.id,
55681
- name: chunk.toolCall.name,
55682
- input: chunk.toolCall.input ?? {},
55683
- geminiThoughtSignature: chunk.toolCall.geminiThoughtSignature
56742
+ id: chunk2.toolCall.id,
56743
+ name: chunk2.toolCall.name,
56744
+ input: chunk2.toolCall.input ?? {},
56745
+ geminiThoughtSignature: chunk2.toolCall.geminiThoughtSignature
55684
56746
  });
55685
56747
  }
55686
56748
  }
55687
- if (chunk.type === "done") {
55688
- if (chunk.stopReason) {
55689
- lastStopReason = chunk.stopReason;
56749
+ if (chunk2.type === "done") {
56750
+ if (chunk2.stopReason) {
56751
+ lastStopReason = chunk2.stopReason;
55690
56752
  }
55691
56753
  if (!thinkingEnded) {
55692
56754
  options.onThinkingEnd?.();
@@ -56169,17 +57231,17 @@ ${ITERATION_LIMIT_SUMMARY_PROMPT}` : ITERATION_LIMIT_SUMMARY_PROMPT
56169
57231
  if (stuckInErrorLoop) {
56170
57232
  try {
56171
57233
  const finalMessages = getConversationContext(session, toolRegistry);
56172
- for await (const chunk of provider.streamWithTools(finalMessages, {
57234
+ for await (const chunk2 of provider.streamWithTools(finalMessages, {
56173
57235
  tools: [],
56174
57236
  maxTokens: session.config.provider.maxTokens,
56175
57237
  signal: options.signal
56176
57238
  })) {
56177
57239
  if (options.signal?.aborted) break;
56178
- if (chunk.type === "text" && chunk.text) {
56179
- finalContent += chunk.text;
56180
- options.onStream?.(chunk);
57240
+ if (chunk2.type === "text" && chunk2.text) {
57241
+ finalContent += chunk2.text;
57242
+ options.onStream?.(chunk2);
56181
57243
  }
56182
- if (chunk.type === "done") break;
57244
+ if (chunk2.type === "done") break;
56183
57245
  }
56184
57246
  } catch {
56185
57247
  }
@@ -56200,21 +57262,21 @@ ${ITERATION_LIMIT_SUMMARY_PROMPT}` : ITERATION_LIMIT_SUMMARY_PROMPT
56200
57262
  options.onThinkingStart?.();
56201
57263
  try {
56202
57264
  const finalMessages = getConversationContext(session, toolRegistry);
56203
- for await (const chunk of provider.streamWithTools(finalMessages, {
57265
+ for await (const chunk2 of provider.streamWithTools(finalMessages, {
56204
57266
  tools: [],
56205
57267
  maxTokens: session.config.provider.maxTokens,
56206
57268
  signal: options.signal
56207
57269
  })) {
56208
57270
  if (options.signal?.aborted) break;
56209
- if (chunk.type === "text" && chunk.text) {
57271
+ if (chunk2.type === "text" && chunk2.text) {
56210
57272
  if (!summaryThinkingEnded) {
56211
57273
  options.onThinkingEnd?.();
56212
57274
  summaryThinkingEnded = true;
56213
57275
  }
56214
- finalContent += chunk.text;
56215
- options.onStream?.(chunk);
57276
+ finalContent += chunk2.text;
57277
+ options.onStream?.(chunk2);
56216
57278
  }
56217
- if (chunk.type === "done") break;
57279
+ if (chunk2.type === "done") break;
56218
57280
  }
56219
57281
  } catch {
56220
57282
  const notice = `
@@ -56365,15 +57427,15 @@ function createReplayProvider(turns) {
56365
57427
  async *stream() {
56366
57428
  const chunks = turns[Math.min(callIndex, turns.length - 1)] ?? [{ type: "done" }];
56367
57429
  callIndex++;
56368
- for (const chunk of chunks) {
56369
- yield chunk;
57430
+ for (const chunk2 of chunks) {
57431
+ yield chunk2;
56370
57432
  }
56371
57433
  },
56372
57434
  async *streamWithTools() {
56373
57435
  const chunks = turns[Math.min(callIndex, turns.length - 1)] ?? [{ type: "done" }];
56374
57436
  callIndex++;
56375
- for (const chunk of chunks) {
56376
- yield chunk;
57437
+ for (const chunk2 of chunks) {
57438
+ yield chunk2;
56377
57439
  }
56378
57440
  },
56379
57441
  countTokens(text16) {
@@ -56389,9 +57451,9 @@ function createReplayProvider(turns) {
56389
57451
  }
56390
57452
  function collectToolNames(stream) {
56391
57453
  const names = /* @__PURE__ */ new Set();
56392
- for (const chunk of stream) {
56393
- if ((chunk.type === "tool_use_start" || chunk.type === "tool_use_end") && chunk.toolCall?.name) {
56394
- names.add(chunk.toolCall.name);
57454
+ for (const chunk2 of stream) {
57455
+ if ((chunk2.type === "tool_use_start" || chunk2.type === "tool_use_end") && chunk2.toolCall?.name) {
57456
+ names.add(chunk2.toolCall.name);
56395
57457
  }
56396
57458
  }
56397
57459
  return Array.from(names);
@@ -57635,6 +58697,7 @@ init_providers();
57635
58697
 
57636
58698
  // src/runtime/agent-runtime.ts
57637
58699
  init_env();
58700
+ init_registry4();
57638
58701
 
57639
58702
  // src/runtime/default-turn-runner.ts
57640
58703
  var DefaultRuntimeTurnRunner = class {
@@ -57668,178 +58731,6 @@ var DefaultRuntimeTurnRunner = class {
57668
58731
  function createDefaultRuntimeTurnRunner() {
57669
58732
  return new DefaultRuntimeTurnRunner();
57670
58733
  }
57671
- var InMemoryEventLog = class {
57672
- events = [];
57673
- record(type, data = {}) {
57674
- const event = {
57675
- id: randomUUID(),
57676
- type,
57677
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
57678
- data
57679
- };
57680
- this.events.push(event);
57681
- return event;
57682
- }
57683
- list() {
57684
- return [...this.events];
57685
- }
57686
- count() {
57687
- return this.events.length;
57688
- }
57689
- clear() {
57690
- this.events = [];
57691
- }
57692
- };
57693
- var FileEventLog = class {
57694
- constructor(filePath) {
57695
- this.filePath = filePath;
57696
- try {
57697
- mkdirSync(dirname(filePath), { recursive: true });
57698
- } catch {
57699
- this.writable = false;
57700
- }
57701
- }
57702
- filePath;
57703
- memory = new InMemoryEventLog();
57704
- writable = true;
57705
- record(type, data = {}) {
57706
- const event = this.memory.record(type, data);
57707
- if (this.writable) {
57708
- try {
57709
- appendFileSync(this.filePath, JSON.stringify(event) + "\n", "utf-8");
57710
- } catch {
57711
- this.writable = false;
57712
- }
57713
- }
57714
- return event;
57715
- }
57716
- list() {
57717
- if (!this.writable) return this.memory.list();
57718
- try {
57719
- const raw = readFileSync(this.filePath, "utf-8");
57720
- return raw.split("\n").filter(Boolean).flatMap((line) => {
57721
- try {
57722
- return [JSON.parse(line)];
57723
- } catch {
57724
- return [];
57725
- }
57726
- });
57727
- } catch {
57728
- return this.memory.list();
57729
- }
57730
- }
57731
- count() {
57732
- return this.list().length;
57733
- }
57734
- clear() {
57735
- this.memory.clear();
57736
- if (this.writable) {
57737
- try {
57738
- writeFileSync(this.filePath, "", "utf-8");
57739
- } catch {
57740
- this.writable = false;
57741
- }
57742
- }
57743
- }
57744
- };
57745
- function createEventLog() {
57746
- return new InMemoryEventLog();
57747
- }
57748
- function createFileEventLog(filePath) {
57749
- return new FileEventLog(filePath);
57750
- }
57751
-
57752
- // src/runtime/permission-policy.ts
57753
- var READ_ONLY_CATEGORIES = /* @__PURE__ */ new Set(["search", "web", "document"]);
57754
- var WRITE_CATEGORIES = /* @__PURE__ */ new Set(["file", "git", "test", "build", "memory"]);
57755
- var READ_ONLY_TOOL_NAMES = /* @__PURE__ */ new Set([
57756
- "glob",
57757
- "read_file",
57758
- "list_dir",
57759
- "tree",
57760
- "grep",
57761
- "find_in_file",
57762
- "semantic_search",
57763
- "codebase_map",
57764
- "repo_context",
57765
- "lsp_status",
57766
- "lsp_document_symbols",
57767
- "lsp_workspace_symbols",
57768
- "lsp_definition",
57769
- "lsp_references",
57770
- "git_status",
57771
- "git_log",
57772
- "git_diff",
57773
- "git_show",
57774
- "git_branch",
57775
- "recall_memory",
57776
- "list_memories",
57777
- "list_checkpoints",
57778
- "spawnSimpleAgent",
57779
- "checkAgentCapability"
57780
- ]);
57781
- var WRITE_CAPABLE_TOOL_NAMES = /* @__PURE__ */ new Set(["run_linter"]);
57782
- var DESTRUCTIVE_TOOL_NAMES = /* @__PURE__ */ new Set([
57783
- "bash_exec",
57784
- "write_file",
57785
- "edit_file",
57786
- "delete_file",
57787
- "restore_checkpoint",
57788
- "git_commit",
57789
- "git_push",
57790
- "request_human_escalation"
57791
- ]);
57792
- function riskForTool(tool) {
57793
- if (READ_ONLY_TOOL_NAMES.has(tool.name)) return "read-only";
57794
- if (DESTRUCTIVE_TOOL_NAMES.has(tool.name)) return "destructive";
57795
- if (WRITE_CAPABLE_TOOL_NAMES.has(tool.name)) return "write";
57796
- if (tool.category === "web") return "network";
57797
- if (WRITE_CATEGORIES.has(tool.category)) return "write";
57798
- if (tool.category === "quality") return "write";
57799
- return "read-only";
57800
- }
57801
- var DefaultPermissionPolicy = class {
57802
- canExecuteTool(mode, tool) {
57803
- const definition = getAgentMode(mode);
57804
- const risk = riskForTool(tool);
57805
- const readOnlyTool = READ_ONLY_TOOL_NAMES.has(tool.name) || READ_ONLY_CATEGORIES.has(tool.category);
57806
- if (definition.readOnly && !readOnlyTool) {
57807
- return {
57808
- allowed: false,
57809
- reason: `${definition.label} mode is read-only; ${tool.name} is a ${tool.category} tool.`,
57810
- risk
57811
- };
57812
- }
57813
- if (risk === "destructive") {
57814
- return {
57815
- allowed: true,
57816
- requiresConfirmation: true,
57817
- reason: `${tool.name} can change repository state and should be confirmed.`,
57818
- risk
57819
- };
57820
- }
57821
- return { allowed: true, risk };
57822
- }
57823
- canExecuteToolInput(mode, tool, input) {
57824
- if (tool.name !== "run_linter") {
57825
- return this.canExecuteTool(mode, tool);
57826
- }
57827
- const definition = getAgentMode(mode);
57828
- const fixEnabled = input["fix"] === true;
57829
- const decision = fixEnabled ? { allowed: true, risk: "write" } : { allowed: true, risk: "read-only" };
57830
- if (definition.readOnly && fixEnabled) {
57831
- return {
57832
- allowed: false,
57833
- reason: `${definition.label} mode is read-only; run_linter with fix=true can modify files.`,
57834
- risk: "write"
57835
- };
57836
- }
57837
- return decision;
57838
- }
57839
- };
57840
- function createPermissionPolicy() {
57841
- return new DefaultPermissionPolicy();
57842
- }
57843
58734
 
57844
58735
  // src/runtime/provider-registry.ts
57845
58736
  init_providers();
@@ -58006,6 +58897,109 @@ var WorkflowCatalog = class {
58006
58897
  }
58007
58898
  };
58008
58899
  var DEFAULT_WORKFLOWS = [
58900
+ {
58901
+ id: "enterprise-rag-answer",
58902
+ name: "Enterprise RAG Answer",
58903
+ description: "Retrieve tenant-scoped knowledge, draft a cited answer, and review for policy compliance.",
58904
+ inputSchema: "question: string; tenantId: string; userId?: string",
58905
+ outputKind: "json",
58906
+ replayable: true,
58907
+ checks: ["retrieval citations", "policy review", "answer quality"],
58908
+ steps: [],
58909
+ parallelism: 2,
58910
+ gates: [
58911
+ {
58912
+ id: "quality",
58913
+ kind: "quality-score",
58914
+ description: "Answer meets tenant quality and citation requirements.",
58915
+ required: true
58916
+ }
58917
+ ],
58918
+ nodes: [
58919
+ {
58920
+ id: "retrieve",
58921
+ agentRole: "researcher",
58922
+ description: "Retrieve tenant-scoped sources and produce citations.",
58923
+ requiredTools: ["knowledge_search"],
58924
+ risk: "read-only",
58925
+ timeoutMs: 3e4
58926
+ },
58927
+ {
58928
+ id: "draft-answer",
58929
+ agentRole: "docs",
58930
+ description: "Draft a concise answer grounded only in retrieved sources.",
58931
+ dependsOn: ["retrieve"],
58932
+ risk: "read-only",
58933
+ timeoutMs: 3e4
58934
+ },
58935
+ {
58936
+ id: "policy-review",
58937
+ agentRole: "reviewer",
58938
+ description: "Review citations, data boundary, and unsupported claims.",
58939
+ dependsOn: ["draft-answer"],
58940
+ gates: ["quality"],
58941
+ risk: "read-only",
58942
+ timeoutMs: 3e4
58943
+ }
58944
+ ]
58945
+ },
58946
+ {
58947
+ id: "whatsapp-support-assistant",
58948
+ name: "WhatsApp Support Assistant",
58949
+ description: "Handle a WhatsApp customer message with retrieval, support draft, and optional escalation.",
58950
+ inputSchema: "message: string; phoneNumber: string; tenantId: string",
58951
+ outputKind: "json",
58952
+ replayable: true,
58953
+ checks: ["retrieval citations", "support policy", "human escalation when needed"],
58954
+ steps: [],
58955
+ parallelism: 2,
58956
+ gates: [
58957
+ {
58958
+ id: "human-escalation",
58959
+ kind: "human-approval",
58960
+ description: "Human review is required before sensitive or external follow-up.",
58961
+ required: false
58962
+ }
58963
+ ],
58964
+ nodes: [
58965
+ {
58966
+ id: "classify-message",
58967
+ agentRole: "planner",
58968
+ description: "Classify intent, urgency, and required data boundary.",
58969
+ risk: "read-only",
58970
+ timeoutMs: 15e3
58971
+ },
58972
+ {
58973
+ id: "retrieve-context",
58974
+ agentRole: "researcher",
58975
+ description: "Retrieve tenant support knowledge relevant to the customer message.",
58976
+ dependsOn: ["classify-message"],
58977
+ requiredTools: ["knowledge_search"],
58978
+ risk: "read-only",
58979
+ timeoutMs: 3e4
58980
+ },
58981
+ {
58982
+ id: "draft-response",
58983
+ agentRole: "docs",
58984
+ description: "Draft a WhatsApp-safe response with concise citations for audit.",
58985
+ dependsOn: ["retrieve-context"],
58986
+ requiredTools: ["create_support_draft"],
58987
+ risk: "read-only",
58988
+ timeoutMs: 3e4
58989
+ },
58990
+ {
58991
+ id: "escalate-if-needed",
58992
+ agentRole: "integrator",
58993
+ description: "Create a human escalation request when classification requires it.",
58994
+ dependsOn: ["draft-response"],
58995
+ requiredTools: ["request_human_escalation"],
58996
+ gates: ["human-escalation"],
58997
+ condition: "input.requiresEscalation",
58998
+ risk: "network",
58999
+ timeoutMs: 3e4
59000
+ }
59001
+ ]
59002
+ },
58009
59003
  {
58010
59004
  id: "architect-editor-verifier",
58011
59005
  name: "Architect / Editor / Verifier",
@@ -58146,19 +59140,28 @@ function createWorkflowCatalog(workflows) {
58146
59140
 
58147
59141
  // src/runtime/workflow-engine.ts
58148
59142
  var WorkflowEngine = class {
58149
- constructor(catalog = createWorkflowCatalog(), eventLog = createEventLog()) {
59143
+ constructor(catalog = createWorkflowCatalog(), eventLog = createEventLog(), options = {}) {
58150
59144
  this.catalog = catalog;
58151
59145
  this.eventLog = eventLog;
59146
+ this.sharedState = options.sharedState ?? new InMemorySharedWorkspaceStore();
59147
+ this.nodeExecutor = options.nodeExecutor;
59148
+ this.runtimePolicy = options.runtimePolicy;
58152
59149
  }
58153
59150
  catalog;
58154
59151
  eventLog;
58155
59152
  handlers = /* @__PURE__ */ new Map();
59153
+ sharedState;
59154
+ runtimePolicy;
59155
+ nodeExecutor;
58156
59156
  registerHandler(workflowId, handler) {
58157
59157
  if (!this.catalog.get(workflowId)) {
58158
59158
  throw new Error(`Unknown workflow: ${workflowId}`);
58159
59159
  }
58160
59160
  this.handlers.set(workflowId, handler);
58161
59161
  }
59162
+ registerNodeExecutor(executor) {
59163
+ this.nodeExecutor = executor;
59164
+ }
58162
59165
  createPlan(workflowId, input) {
58163
59166
  return this.catalog.createPlan(workflowId, input, this.eventLog);
58164
59167
  }
@@ -58168,23 +59171,37 @@ var WorkflowEngine = class {
58168
59171
  throw new Error(`Unknown workflow: ${request.workflowId}`);
58169
59172
  }
58170
59173
  const handler = this.handlers.get(request.workflowId);
58171
- if (!handler) {
58172
- throw new Error(`No handler registered for workflow: ${request.workflowId}`);
58173
- }
58174
59174
  const plan = request.plan ?? this.createPlan(request.workflowId, request.input);
58175
59175
  const startedAt = (/* @__PURE__ */ new Date()).toISOString();
58176
59176
  const runId = `${request.workflowId}-run-${Date.now().toString(36)}`;
59177
+ const trace = createAgentTraceContext({ workflowRunId: runId });
58177
59178
  this.eventLog.record("workflow.started", {
58178
59179
  workflowId: request.workflowId,
58179
59180
  planId: plan.id,
58180
- runId
59181
+ runId,
59182
+ trace
58181
59183
  });
58182
59184
  try {
58183
- const output = await handler(request.input, {
59185
+ const graph = workflowToAgentGraph(workflow);
59186
+ assertWorkflowAllowedByRuntimePolicy(graph, this.runtimePolicy);
59187
+ const graphResult = handler ? void 0 : await new AgentGraphEngine({
59188
+ eventLog: this.eventLog,
59189
+ sharedState: this.sharedState,
59190
+ nodeExecutor: this.nodeExecutor,
59191
+ trace
59192
+ }).run({
59193
+ workflowRunId: runId,
59194
+ graph,
59195
+ input: request.input
59196
+ });
59197
+ const output = graphResult ?? await handler(request.input, {
58184
59198
  workflow,
58185
59199
  plan,
58186
59200
  eventLog: this.eventLog
58187
59201
  });
59202
+ if (graphResult?.status === "failed") {
59203
+ throw new Error(graphResult.error ?? "Workflow graph failed");
59204
+ }
58188
59205
  const completedAt = (/* @__PURE__ */ new Date()).toISOString();
58189
59206
  const result = {
58190
59207
  id: runId,
@@ -58192,12 +59209,15 @@ var WorkflowEngine = class {
58192
59209
  status: "completed",
58193
59210
  output,
58194
59211
  startedAt,
58195
- completedAt
59212
+ completedAt,
59213
+ graphResult,
59214
+ trace
58196
59215
  };
58197
59216
  this.eventLog.record("workflow.completed", {
58198
59217
  workflowId: request.workflowId,
58199
59218
  planId: plan.id,
58200
- runId
59219
+ runId,
59220
+ trace
58201
59221
  });
58202
59222
  return result;
58203
59223
  } catch (error) {
@@ -58207,7 +59227,8 @@ var WorkflowEngine = class {
58207
59227
  workflowId: request.workflowId,
58208
59228
  planId: plan.id,
58209
59229
  runId,
58210
- error: message
59230
+ error: message,
59231
+ trace
58211
59232
  });
58212
59233
  return {
58213
59234
  id: runId,
@@ -58216,13 +59237,37 @@ var WorkflowEngine = class {
58216
59237
  output: null,
58217
59238
  startedAt,
58218
59239
  completedAt,
58219
- error: message
59240
+ error: message,
59241
+ trace
58220
59242
  };
58221
59243
  }
58222
59244
  }
58223
59245
  };
58224
- function createWorkflowEngine(catalog, eventLog) {
58225
- return new WorkflowEngine(catalog, eventLog);
59246
+ function assertWorkflowAllowedByRuntimePolicy(graph, policy) {
59247
+ if (!policy) return;
59248
+ for (const node of graph.nodes) {
59249
+ const risk = node.risk ?? "read-only";
59250
+ const riskDecision = evaluateRuntimeRiskPolicy(policy, {
59251
+ subject: `workflow node ${node.id}`,
59252
+ risk
59253
+ });
59254
+ if (!riskDecision.allowed) {
59255
+ throw new Error(
59256
+ `Workflow node ${node.id} is blocked by runtime policy: ${riskDecision.reason}`
59257
+ );
59258
+ }
59259
+ for (const toolName of node.requiredTools ?? []) {
59260
+ const decision = evaluateRuntimeToolPolicy(policy, { toolName, risk });
59261
+ if (!decision.allowed) {
59262
+ throw new Error(
59263
+ `Workflow node ${node.id} is blocked by runtime policy: ${decision.reason}`
59264
+ );
59265
+ }
59266
+ }
59267
+ }
59268
+ }
59269
+ function createWorkflowEngine(catalog, eventLog, options) {
59270
+ return new WorkflowEngine(catalog, eventLog, options);
58226
59271
  }
58227
59272
 
58228
59273
  // src/runtime/agent-runtime.ts
@@ -58230,15 +59275,17 @@ var AgentRuntime = class {
58230
59275
  constructor(options) {
58231
59276
  this.options = options;
58232
59277
  this.providerRegistry = createProviderRegistry();
58233
- this.toolRegistry = options.toolRegistry ?? createFullToolRegistry();
59278
+ this.toolRegistry = options.toolRegistry ?? new ToolRegistry();
58234
59279
  this.sessionStore = options.sessionStore;
58235
59280
  this.runtimeSessionStore = options.runtimeSessionStore ?? createRuntimeSessionStore();
58236
59281
  this.eventLog = options.eventLog ?? (options.eventLogPath ? createFileEventLog(options.eventLogPath) : createEventLog());
58237
- this.workflowEngine = options.workflowEngine ?? createWorkflowEngine(void 0, this.eventLog);
58238
59282
  this.permissionPolicy = options.permissionPolicy ?? createPermissionPolicy();
58239
59283
  this.turnRunner = options.turnRunner ?? createDefaultRuntimeTurnRunner();
58240
59284
  this.providerType = options.providerType;
58241
59285
  this.model = options.model ?? options.providerConfig?.model ?? getDefaultModel(options.providerType);
59286
+ this.runtimeContext = options.runtimeContext ? createRuntimeRequestContext(options.runtimeContext) : void 0;
59287
+ this.runtimePolicy = mergeRuntimePolicy(this.runtimeContext?.policy, options.runtimePolicy);
59288
+ this.workflowEngine = options.workflowEngine ?? createWorkflowEngine(void 0, this.eventLog, { runtimePolicy: this.runtimePolicy });
58242
59289
  }
58243
59290
  options;
58244
59291
  providerRegistry;
@@ -58252,6 +59299,8 @@ var AgentRuntime = class {
58252
59299
  providerType;
58253
59300
  model;
58254
59301
  provider;
59302
+ runtimeContext;
59303
+ runtimePolicy;
58255
59304
  async initialize() {
58256
59305
  const providerInjected = Boolean(this.options.provider);
58257
59306
  const provider = this.options.provider ?? await this.providerRegistry.createProvider(this.providerType, {
@@ -58282,8 +59331,8 @@ var AgentRuntime = class {
58282
59331
  }
58283
59332
  publishToGlobalBridge(provider) {
58284
59333
  if (this.options.publishToGlobalBridge !== true) return;
58285
- setAgentProvider(provider);
58286
- setAgentToolRegistry(this.toolRegistry);
59334
+ this.options.legacyAgentBridge?.setAgentProvider(provider);
59335
+ this.options.legacyAgentBridge?.setAgentToolRegistry(this.toolRegistry);
58287
59336
  }
58288
59337
  snapshot() {
58289
59338
  const capability = this.providerRegistry.getCapability(this.providerType, this.getModel());
@@ -58298,14 +59347,25 @@ var AgentRuntime = class {
58298
59347
  count: toolNames.length,
58299
59348
  names: toolNames
58300
59349
  },
58301
- modes: listAgentModes()
59350
+ modes: listAgentModes(),
59351
+ context: this.runtimeContext,
59352
+ policy: this.runtimePolicy
58302
59353
  };
58303
59354
  }
58304
59355
  createSession(options = {}) {
58305
- const session = this.runtimeSessionStore.create(options);
59356
+ const session = this.runtimeSessionStore.create({
59357
+ ...options,
59358
+ metadata: {
59359
+ ...runtimeContextToMetadata(this.runtimeContext),
59360
+ ...options.metadata
59361
+ }
59362
+ });
58306
59363
  this.eventLog.record("session.created", {
58307
59364
  sessionId: session.id,
58308
59365
  mode: session.mode,
59366
+ ...session.metadata["tenantId"] ? { tenantId: session.metadata["tenantId"] } : {},
59367
+ ...session.metadata["surface"] ? { surface: session.metadata["surface"] } : {},
59368
+ ...session.metadata["correlationId"] ? { correlationId: session.metadata["correlationId"] } : {},
58309
59369
  metadataKeys: Object.keys(session.metadata).sort()
58310
59370
  });
58311
59371
  return session;
@@ -58342,6 +59402,7 @@ var AgentRuntime = class {
58342
59402
  permissionPolicy: this.permissionPolicy,
58343
59403
  eventLog: this.eventLog
58344
59404
  });
59405
+ assertRuntimeUsageWithinPolicy(this.runtimePolicy, result.usage);
58345
59406
  const updatedSession = this.runtimeSessionStore.update({
58346
59407
  ...effectiveSession,
58347
59408
  messages: [
@@ -58400,7 +59461,7 @@ var AgentRuntime = class {
58400
59461
  let completed = false;
58401
59462
  let failed = false;
58402
59463
  try {
58403
- for await (const chunk of provider.stream(messages, {
59464
+ for await (const chunk2 of provider.stream(messages, {
58404
59465
  model: input.options?.model,
58405
59466
  maxTokens: input.options?.maxTokens,
58406
59467
  temperature: input.options?.temperature,
@@ -58410,25 +59471,17 @@ var AgentRuntime = class {
58410
59471
  signal: input.options?.signal,
58411
59472
  thinking: input.options?.thinking
58412
59473
  })) {
58413
- if (chunk.type === "text" && chunk.text) {
58414
- content += chunk.text;
59474
+ if (chunk2.type === "text" && chunk2.text) {
59475
+ content += chunk2.text;
58415
59476
  yield {
58416
59477
  type: "text",
58417
59478
  sessionId: effectiveSession.id,
58418
- text: chunk.text
59479
+ text: chunk2.text
58419
59480
  };
58420
59481
  }
58421
59482
  }
58422
- const updatedSession = this.runtimeSessionStore.update({
58423
- ...effectiveSession,
58424
- messages: [
58425
- ...effectiveSession.messages,
58426
- { role: "user", content: input.content },
58427
- { role: "assistant", content }
58428
- ]
58429
- });
58430
59483
  const result = {
58431
- sessionId: updatedSession.id,
59484
+ sessionId: effectiveSession.id,
58432
59485
  content,
58433
59486
  usage: {
58434
59487
  inputTokens: provider.countTokens(input.content),
@@ -58436,8 +59489,19 @@ var AgentRuntime = class {
58436
59489
  estimated: true
58437
59490
  },
58438
59491
  model: input.options?.model ?? this.getModel(),
58439
- mode: updatedSession.mode
59492
+ mode: effectiveSession.mode
58440
59493
  };
59494
+ assertRuntimeUsageWithinPolicy(this.runtimePolicy, result.usage);
59495
+ const updatedSession = this.runtimeSessionStore.update({
59496
+ ...effectiveSession,
59497
+ messages: [
59498
+ ...effectiveSession.messages,
59499
+ { role: "user", content: input.content },
59500
+ { role: "assistant", content }
59501
+ ]
59502
+ });
59503
+ result.sessionId = updatedSession.id;
59504
+ result.mode = updatedSession.mode;
58441
59505
  this.eventLog.record("session.updated", {
58442
59506
  sessionId: updatedSession.id,
58443
59507
  messages: updatedSession.messages.length
@@ -58525,15 +59589,22 @@ var AgentRuntime = class {
58525
59589
  };
58526
59590
  }
58527
59591
  const decision = this.permissionPolicy.canExecuteToolInput ? this.permissionPolicy.canExecuteToolInput(mode, tool, input.input) : this.permissionPolicy.canExecuteTool(mode, tool);
58528
- if (!decision.allowed || decision.requiresConfirmation && input.confirmed !== true) {
58529
- const reason = decision.reason ?? (decision.requiresConfirmation ? "Tool requires explicit runtime confirmation." : "Tool is not allowed.");
59592
+ const runtimeDecision = decision.allowed ? evaluateRuntimeToolPolicy(this.runtimePolicy, {
59593
+ toolName: input.toolName,
59594
+ risk: decision.risk,
59595
+ confirmed: input.confirmed
59596
+ }) : void 0;
59597
+ const effectiveDecision = runtimeDecision ?? decision;
59598
+ if (!decision.allowed || !effectiveDecision.allowed || decision.requiresConfirmation && input.confirmed !== true) {
59599
+ const reason = effectiveDecision.reason ?? decision.reason ?? (decision.requiresConfirmation ? "Tool requires explicit runtime confirmation." : "Tool is not allowed.");
58530
59600
  this.eventLog.record("tool.blocked", {
58531
59601
  sessionId: input.sessionId,
58532
59602
  mode,
58533
59603
  tool: input.toolName,
58534
59604
  reason,
58535
- risk: decision.risk,
58536
- requiresConfirmation: decision.requiresConfirmation,
59605
+ risk: effectiveDecision.risk,
59606
+ requiresConfirmation: effectiveDecision.requiresConfirmation ?? decision.requiresConfirmation,
59607
+ runtimePolicyBlocked: runtimeDecision ? !runtimeDecision.allowed : false,
58537
59608
  runtimeApi: true
58538
59609
  });
58539
59610
  return {
@@ -58541,14 +59612,20 @@ var AgentRuntime = class {
58541
59612
  success: false,
58542
59613
  error: reason,
58543
59614
  duration: performance.now() - startedAt,
58544
- decision
59615
+ decision: {
59616
+ ...decision,
59617
+ allowed: false,
59618
+ reason,
59619
+ requiresConfirmation: effectiveDecision.requiresConfirmation ?? decision.requiresConfirmation,
59620
+ risk: effectiveDecision.risk
59621
+ }
58545
59622
  };
58546
59623
  }
58547
59624
  this.eventLog.record("tool.started", {
58548
59625
  sessionId: input.sessionId,
58549
59626
  mode,
58550
59627
  tool: input.toolName,
58551
- risk: decision.risk,
59628
+ risk: effectiveDecision.risk,
58552
59629
  runtimeApi: true,
58553
59630
  metadataKeys: Object.keys(input.metadata ?? {}).sort()
58554
59631
  });
@@ -58567,7 +59644,11 @@ var AgentRuntime = class {
58567
59644
  output: result.data,
58568
59645
  error: result.error,
58569
59646
  duration: result.duration,
58570
- decision
59647
+ decision: {
59648
+ ...decision,
59649
+ risk: effectiveDecision.risk,
59650
+ requiresConfirmation: decision.requiresConfirmation
59651
+ }
58571
59652
  };
58572
59653
  }
58573
59654
  assertToolAllowed(mode, toolName, input) {
@@ -58581,12 +59662,24 @@ var AgentRuntime = class {
58581
59662
  return false;
58582
59663
  }
58583
59664
  const decision = input && this.permissionPolicy.canExecuteToolInput ? this.permissionPolicy.canExecuteToolInput(mode, tool, input) : this.permissionPolicy.canExecuteTool(mode, tool);
58584
- this.eventLog.record(decision.allowed ? "tool.allowed" : "tool.blocked", {
59665
+ const runtimeDecision = decision.allowed ? evaluateRuntimeToolPolicy(this.runtimePolicy, {
59666
+ toolName,
59667
+ risk: decision.risk,
59668
+ confirmed: false
59669
+ }) : void 0;
59670
+ const allowed = decision.allowed && runtimeDecision?.allowed !== false;
59671
+ this.eventLog.record(allowed ? "tool.allowed" : "tool.blocked", {
58585
59672
  mode,
58586
59673
  tool: toolName,
58587
- ...decision
59674
+ ...decision,
59675
+ ...runtimeDecision && !runtimeDecision.allowed ? {
59676
+ allowed: false,
59677
+ reason: runtimeDecision.reason,
59678
+ requiresConfirmation: runtimeDecision.requiresConfirmation,
59679
+ runtimePolicyBlocked: true
59680
+ } : {}
58588
59681
  });
58589
- return decision.allowed;
59682
+ return allowed;
58590
59683
  }
58591
59684
  };
58592
59685
  async function createAgentRuntime(options) {
@@ -59264,8 +60357,10 @@ async function startRepl(options = {}) {
59264
60357
  providerType: internalProviderId,
59265
60358
  model: session.config.provider.model || void 0,
59266
60359
  provider,
60360
+ toolRegistry: createFullToolRegistry(),
59267
60361
  eventLogPath: path39__default.join(projectPath, ".coco", "events", `${session.id}.jsonl`),
59268
- publishToGlobalBridge: true
60362
+ publishToGlobalBridge: true,
60363
+ legacyAgentBridge: { setAgentProvider, setAgentToolRegistry }
59269
60364
  });
59270
60365
  session.runtime = runtime;
59271
60366
  const toolRegistry = runtime.toolRegistry;
@@ -59853,12 +60948,12 @@ ${imagePrompts}`.trim() : imagePrompts;
59853
60948
  let lastToolGroup = null;
59854
60949
  await ensureRequestedMcpConnections(extractMessageText(effectiveMessage));
59855
60950
  const result = await executeAgentTurn(session, effectiveMessage, provider, toolRegistry, {
59856
- onStream: (chunk) => {
60951
+ onStream: (chunk2) => {
59857
60952
  if (!streamStarted) {
59858
60953
  streamStarted = true;
59859
60954
  clearSpinner();
59860
60955
  }
59861
- renderStreamChunk(chunk);
60956
+ renderStreamChunk(chunk2);
59862
60957
  },
59863
60958
  onToolStart: (tc, index, total) => {
59864
60959
  const desc = getToolRunningDescription(
@@ -60489,9 +61584,9 @@ async function readStdin() {
60489
61584
  const timeout = setTimeout(() => {
60490
61585
  resolve4("");
60491
61586
  }, 5e3);
60492
- process.stdin.on("data", (chunk) => {
61587
+ process.stdin.on("data", (chunk2) => {
60493
61588
  clearTimeout(timeout);
60494
- chunks.push(Buffer.from(chunk));
61589
+ chunks.push(Buffer.from(chunk2));
60495
61590
  });
60496
61591
  process.stdin.on("end", () => {
60497
61592
  clearTimeout(timeout);
@@ -60540,9 +61635,11 @@ ${stdinContent}
60540
61635
  providerType,
60541
61636
  model: session.config.provider.model || void 0,
60542
61637
  provider,
61638
+ toolRegistry: createFullToolRegistry(),
60543
61639
  eventLogPath: path39__default.join(options.projectPath, ".coco", "events", `${session.id}.jsonl`),
60544
61640
  turnRunner: options.useRuntimeRunner ? createToolCallingRuntimeTurnRunner() : void 0,
60545
- publishToGlobalBridge: true
61641
+ publishToGlobalBridge: true,
61642
+ legacyAgentBridge: { setAgentProvider, setAgentToolRegistry }
60546
61643
  });
60547
61644
  session.runtime = runtime;
60548
61645
  const toolRegistry = runtime.toolRegistry;
@@ -60581,9 +61678,9 @@ ${stdinContent}
60581
61678
  const result = await executeAgentTurn(session, task, provider, toolRegistry, {
60582
61679
  skipConfirmation: true,
60583
61680
  // No interactive confirmations in headless mode
60584
- onStream: (chunk) => {
60585
- if (options.outputFormat === "text" && chunk.type === "text" && chunk.text) {
60586
- process.stdout.write(chunk.text);
61681
+ onStream: (chunk2) => {
61682
+ if (options.outputFormat === "text" && chunk2.type === "text" && chunk2.text) {
61683
+ process.stdout.write(chunk2.text);
60587
61684
  }
60588
61685
  }
60589
61686
  });