@corbat-tech/coco 2.39.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';
@@ -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,
@@ -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")
@@ -43310,7 +43310,7 @@ var InMemorySharedWorkspaceStore = class {
43310
43310
  write(input) {
43311
43311
  assertProvenance(input.provenance);
43312
43312
  const record = {
43313
- id: `state-${randomUUID()}`,
43313
+ id: input.id ?? `state-${randomUUID()}`,
43314
43314
  kind: input.kind,
43315
43315
  key: input.key,
43316
43316
  value: cloneUnknown(input.value),
@@ -43353,7 +43353,7 @@ var AgentGraphEngine = class {
43353
43353
  constructor(options = {}) {
43354
43354
  this.eventLog = options.eventLog;
43355
43355
  this.sharedState = options.sharedState ?? new InMemorySharedWorkspaceStore();
43356
- this.nodeExecutor = options.nodeExecutor ?? defaultAgentGraphNodeExecutor;
43356
+ this.nodeExecutor = options.nodeExecutor ?? (options.allowSimulated ? dryRunAgentGraphNodeExecutor : missingAgentGraphNodeExecutor);
43357
43357
  this.gateEvaluator = options.gateEvaluator ?? defaultAgentGateEvaluator;
43358
43358
  this.trace = options.trace ?? createAgentTraceContext();
43359
43359
  }
@@ -43437,6 +43437,39 @@ var AgentGraphEngine = class {
43437
43437
  }
43438
43438
  }
43439
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
+ }
43440
43473
  const attempts = input.node.retryPolicy?.maxAttempts ?? 1;
43441
43474
  let lastResult;
43442
43475
  for (let attempt = 1; attempt <= attempts; attempt++) {
@@ -43455,19 +43488,40 @@ var AgentGraphEngine = class {
43455
43488
  attempt,
43456
43489
  trace
43457
43490
  });
43458
- const result = await this.nodeExecutor({
43459
- node: input.node,
43460
- task,
43461
- attempt,
43462
- workflowRunId: input.workflowRunId,
43463
- trace,
43464
- dependencyResults: input.nodeResults,
43465
- sharedState: this.sharedState,
43466
- eventLog: this.eventLog ?? NULL_EVENT_LOG
43467
- });
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
+ );
43468
43522
  lastResult = result;
43469
43523
  for (const artifact of result.artifacts) {
43470
- this.sharedState.write({
43524
+ const record = this.sharedState.write({
43471
43525
  kind: "artifact",
43472
43526
  key: artifact.id,
43473
43527
  value: artifact,
@@ -43479,6 +43533,15 @@ var AgentGraphEngine = class {
43479
43533
  risk: input.node.risk
43480
43534
  }
43481
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
+ });
43482
43545
  this.eventLog?.record("agent.artifact.created", {
43483
43546
  workflowRunId: input.workflowRunId,
43484
43547
  nodeId: input.node.id,
@@ -43499,6 +43562,14 @@ var AgentGraphEngine = class {
43499
43562
  attempt,
43500
43563
  trace
43501
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
+ });
43502
43573
  return result;
43503
43574
  }
43504
43575
  this.eventLog?.record("agent.failed", {
@@ -43712,7 +43783,7 @@ function graphNodeToTask(node, workflowInput) {
43712
43783
  constraints: node.requiredTools?.map((tool) => `Requires tool: ${tool}`)
43713
43784
  };
43714
43785
  }
43715
- async function defaultAgentGraphNodeExecutor(execution) {
43786
+ async function dryRunAgentGraphNodeExecutor(execution) {
43716
43787
  const startedAt = (/* @__PURE__ */ new Date()).toISOString();
43717
43788
  const dependencyOutputs = Object.fromEntries(
43718
43789
  [...execution.dependencyResults.entries()].map(([id, result]) => [
@@ -43744,10 +43815,36 @@ async function defaultAgentGraphNodeExecutor(execution) {
43744
43815
  }
43745
43816
  });
43746
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
+ }
43747
43838
  async function defaultAgentGateEvaluator(input) {
43748
43839
  if (!input.result.success) {
43749
43840
  return { passed: false, reason: "Agent result was not successful." };
43750
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
+ }
43751
43848
  return { passed: true };
43752
43849
  }
43753
43850
  function chunk(items, size) {
@@ -43758,6 +43855,71 @@ function chunk(items, size) {
43758
43855
  }
43759
43856
  return result;
43760
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
+ }
43761
43923
  function cloneUnknown(value) {
43762
43924
  if (value === void 0 || value === null) return value;
43763
43925
  try {
@@ -43783,14 +43945,524 @@ function cloneArtifact(artifact) {
43783
43945
  };
43784
43946
  }
43785
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
+
43786
44456
  // src/agents/executor.ts
43787
44457
  var AgentExecutor = class {
43788
- constructor(provider, toolRegistry) {
44458
+ constructor(provider, toolRegistry, runtimeToolExecutor) {
43789
44459
  this.provider = provider;
43790
44460
  this.toolRegistry = toolRegistry;
44461
+ this.runtimeToolExecutor = runtimeToolExecutor ?? createRuntimeToolExecutor({ toolRegistry, mode: "ask" });
43791
44462
  }
43792
44463
  provider;
43793
44464
  toolRegistry;
44465
+ runtimeToolExecutor;
43794
44466
  /**
43795
44467
  * Execute an agent on a task with multi-turn tool use
43796
44468
  */
@@ -43858,11 +44530,21 @@ var AgentExecutor = class {
43858
44530
  for (const toolCall of response.toolCalls) {
43859
44531
  toolsUsed.add(toolCall.name);
43860
44532
  try {
43861
- 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
+ });
43862
44544
  toolResults.push({
43863
44545
  type: "tool_result",
43864
44546
  tool_use_id: toolCall.id,
43865
- content: result.success ? JSON.stringify(result.data) : `Error: ${result.error}`,
44547
+ content: result.success ? JSON.stringify(result.output) : `Error: ${result.error}`,
43866
44548
  is_error: !result.success
43867
44549
  });
43868
44550
  } catch (error) {
@@ -44073,6 +44755,22 @@ Use tools to analyze requirements and explore the codebase.`,
44073
44755
  allowedTools: ["read_file", "grep", "glob", "codebase_map"]
44074
44756
  }
44075
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
+ }
44076
44774
  var DEFAULTS = {
44077
44775
  maxConcurrency: os4__default.cpus().length,
44078
44776
  minConcurrency: 1,
@@ -46392,16 +47090,18 @@ var AgentManager = class extends EventEmitter {
46392
47090
  abortControllers = /* @__PURE__ */ new Map();
46393
47091
  provider;
46394
47092
  toolRegistry;
47093
+ runtimeToolExecutor;
46395
47094
  logger = getLogger();
46396
47095
  /**
46397
47096
  * Create a new AgentManager
46398
47097
  * @param provider - LLM provider for agent execution
46399
47098
  * @param toolRegistry - Tool registry for agent tool access
46400
47099
  */
46401
- constructor(provider, toolRegistry) {
47100
+ constructor(provider, toolRegistry, runtimeToolExecutor) {
46402
47101
  super();
46403
47102
  this.provider = provider;
46404
47103
  this.toolRegistry = toolRegistry;
47104
+ this.runtimeToolExecutor = runtimeToolExecutor ?? createRuntimeToolExecutor({ toolRegistry, mode: "ask" });
46405
47105
  }
46406
47106
  /**
46407
47107
  * Spawn a new subagent for a specific task
@@ -46716,11 +47416,20 @@ var AgentManager = class extends EventEmitter {
46716
47416
  continue;
46717
47417
  }
46718
47418
  try {
46719
- 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
+ });
46720
47429
  results.push({
46721
47430
  type: "tool_result",
46722
47431
  tool_use_id: toolCall.id,
46723
- content: result.success ? String(result.data ?? "Success") : `Error: ${result.error}`,
47432
+ content: result.success ? String(result.output ?? "Success") : `Error: ${result.error}`,
46724
47433
  is_error: !result.success
46725
47434
  });
46726
47435
  } catch (error) {
@@ -46785,6 +47494,27 @@ var AgentManager = class extends EventEmitter {
46785
47494
  function agentTypeToRuntimeRole(type) {
46786
47495
  return mapLegacyAgentRole(type);
46787
47496
  }
47497
+ function runtimeModeForAgentType(type) {
47498
+ switch (type) {
47499
+ case "explore":
47500
+ case "plan":
47501
+ case "docs":
47502
+ return "plan";
47503
+ case "review":
47504
+ case "security":
47505
+ return "review";
47506
+ case "architect":
47507
+ return "architect";
47508
+ case "debug":
47509
+ return "debug";
47510
+ case "test":
47511
+ case "tdd":
47512
+ case "e2e":
47513
+ case "refactor":
47514
+ case "database":
47515
+ return "build";
47516
+ }
47517
+ }
46788
47518
 
46789
47519
  // src/agents/provider-bridge.ts
46790
47520
  var agentProvider = null;
@@ -50656,7 +51386,7 @@ async function validateCode(code, filePath, _language) {
50656
51386
  const errors = [];
50657
51387
  const warnings = [];
50658
51388
  try {
50659
- const ast = parse$1(code, {
51389
+ const ast = parse(code, {
50660
51390
  loc: true,
50661
51391
  range: true,
50662
51392
  comment: true,
@@ -50783,7 +51513,7 @@ async function analyzeFile(filePath, includeAst = false) {
50783
51513
  const exports$1 = [];
50784
51514
  let ast;
50785
51515
  try {
50786
- ast = parse$1(content, {
51516
+ ast = parse(content, {
50787
51517
  loc: true,
50788
51518
  range: true,
50789
51519
  comment: true,
@@ -53261,69 +53991,6 @@ var repoMapCommand = {
53261
53991
  return false;
53262
53992
  }
53263
53993
  };
53264
-
53265
- // src/runtime/agent-modes.ts
53266
- var AGENT_MODES = {
53267
- ask: {
53268
- id: "ask",
53269
- label: "Ask",
53270
- description: "Answer questions and explain code without modifying files.",
53271
- readOnly: true,
53272
- preferredTools: ["read_file", "grep", "glob", "codebase_map", "lsp_definition"],
53273
- requiresVerification: false
53274
- },
53275
- plan: {
53276
- id: "plan",
53277
- label: "Plan",
53278
- description: "Explore and produce an implementation plan with read-only tools.",
53279
- readOnly: true,
53280
- preferredTools: ["read_file", "grep", "glob", "codebase_map", "lsp_workspace_symbols"],
53281
- requiresVerification: false
53282
- },
53283
- build: {
53284
- id: "build",
53285
- label: "Build",
53286
- description: "Implement code changes and verify them.",
53287
- readOnly: false,
53288
- preferredTools: ["read_file", "edit_file", "write_file", "bash_exec", "run_tests"],
53289
- requiresVerification: true
53290
- },
53291
- debug: {
53292
- id: "debug",
53293
- label: "Debug",
53294
- description: "Reproduce failures, trace root cause, patch, and verify.",
53295
- readOnly: false,
53296
- preferredTools: ["bash_exec", "read_file", "grep", "lsp_references", "edit_file"],
53297
- requiresVerification: true
53298
- },
53299
- review: {
53300
- id: "review",
53301
- label: "Review",
53302
- description: "Inspect code quality, security, behavior changes, and test gaps.",
53303
- readOnly: true,
53304
- preferredTools: ["git_diff", "read_file", "grep", "review_code", "calculate_quality"],
53305
- requiresVerification: false
53306
- },
53307
- architect: {
53308
- id: "architect",
53309
- label: "Architect",
53310
- description: "Design architecture and split work for architect/editor execution.",
53311
- readOnly: true,
53312
- preferredTools: ["codebase_map", "lsp_workspace_symbols", "grep", "create_agent_plan"],
53313
- requiresVerification: false
53314
- }
53315
- };
53316
- function getAgentMode(mode) {
53317
- return AGENT_MODES[mode];
53318
- }
53319
- function listAgentModes() {
53320
- return Object.values(AGENT_MODES);
53321
- }
53322
- function isAgentMode(value) {
53323
- return value in AGENT_MODES;
53324
- }
53325
-
53326
- // src/cli/repl/commands/mode.ts
53327
53994
  function currentMode(session) {
53328
53995
  return session.agentMode ?? (session.planMode ? "plan" : "build");
53329
53996
  }
@@ -58030,6 +58697,7 @@ init_providers();
58030
58697
 
58031
58698
  // src/runtime/agent-runtime.ts
58032
58699
  init_env();
58700
+ init_registry4();
58033
58701
 
58034
58702
  // src/runtime/default-turn-runner.ts
58035
58703
  var DefaultRuntimeTurnRunner = class {
@@ -58063,224 +58731,6 @@ var DefaultRuntimeTurnRunner = class {
58063
58731
  function createDefaultRuntimeTurnRunner() {
58064
58732
  return new DefaultRuntimeTurnRunner();
58065
58733
  }
58066
- var InMemoryEventLog = class {
58067
- events = [];
58068
- record(type, data = {}) {
58069
- const event = {
58070
- id: randomUUID(),
58071
- type,
58072
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
58073
- data
58074
- };
58075
- this.events.push(event);
58076
- return event;
58077
- }
58078
- list() {
58079
- return [...this.events];
58080
- }
58081
- count() {
58082
- return this.events.length;
58083
- }
58084
- clear() {
58085
- this.events = [];
58086
- }
58087
- };
58088
- var FileEventLog = class {
58089
- constructor(filePath) {
58090
- this.filePath = filePath;
58091
- try {
58092
- mkdirSync(dirname(filePath), { recursive: true });
58093
- } catch {
58094
- this.writable = false;
58095
- }
58096
- }
58097
- filePath;
58098
- memory = new InMemoryEventLog();
58099
- writable = true;
58100
- record(type, data = {}) {
58101
- const event = this.memory.record(type, data);
58102
- if (this.writable) {
58103
- try {
58104
- appendFileSync(this.filePath, JSON.stringify(event) + "\n", "utf-8");
58105
- } catch {
58106
- this.writable = false;
58107
- }
58108
- }
58109
- return event;
58110
- }
58111
- list() {
58112
- if (!this.writable) return this.memory.list();
58113
- try {
58114
- const raw = readFileSync(this.filePath, "utf-8");
58115
- return raw.split("\n").filter(Boolean).flatMap((line) => {
58116
- try {
58117
- return [JSON.parse(line)];
58118
- } catch {
58119
- return [];
58120
- }
58121
- });
58122
- } catch {
58123
- return this.memory.list();
58124
- }
58125
- }
58126
- count() {
58127
- return this.list().length;
58128
- }
58129
- clear() {
58130
- this.memory.clear();
58131
- if (this.writable) {
58132
- try {
58133
- writeFileSync(this.filePath, "", "utf-8");
58134
- } catch {
58135
- this.writable = false;
58136
- }
58137
- }
58138
- }
58139
- };
58140
- function createEventLog() {
58141
- return new InMemoryEventLog();
58142
- }
58143
- function createFileEventLog(filePath) {
58144
- return new FileEventLog(filePath);
58145
- }
58146
-
58147
- // src/runtime/permission-policy.ts
58148
- var READ_ONLY_CATEGORIES = /* @__PURE__ */ new Set(["search", "web", "document"]);
58149
- var WRITE_CATEGORIES = /* @__PURE__ */ new Set(["file", "git", "test", "build", "memory"]);
58150
- var READ_ONLY_TOOL_NAMES = /* @__PURE__ */ new Set([
58151
- "glob",
58152
- "read_file",
58153
- "list_dir",
58154
- "tree",
58155
- "grep",
58156
- "find_in_file",
58157
- "semantic_search",
58158
- "codebase_map",
58159
- "repo_context",
58160
- "lsp_status",
58161
- "lsp_document_symbols",
58162
- "lsp_workspace_symbols",
58163
- "lsp_definition",
58164
- "lsp_references",
58165
- "git_status",
58166
- "git_log",
58167
- "git_diff",
58168
- "git_show",
58169
- "git_branch",
58170
- "recall_memory",
58171
- "list_memories",
58172
- "list_checkpoints",
58173
- "checkAgentCapability"
58174
- ]);
58175
- var WRITE_CAPABLE_TOOL_NAMES = /* @__PURE__ */ new Set(["run_linter"]);
58176
- var DESTRUCTIVE_TOOL_NAMES = /* @__PURE__ */ new Set([
58177
- "bash_exec",
58178
- "write_file",
58179
- "edit_file",
58180
- "delete_file",
58181
- "restore_checkpoint",
58182
- "git_commit",
58183
- "git_push",
58184
- "request_human_escalation"
58185
- ]);
58186
- function riskForTool(tool) {
58187
- if (READ_ONLY_TOOL_NAMES.has(tool.name)) return "read-only";
58188
- if (DESTRUCTIVE_TOOL_NAMES.has(tool.name)) return "destructive";
58189
- if (WRITE_CAPABLE_TOOL_NAMES.has(tool.name)) return "write";
58190
- if (tool.category === "web") return "network";
58191
- if (WRITE_CATEGORIES.has(tool.category)) return "write";
58192
- if (tool.category === "quality") return "write";
58193
- return "read-only";
58194
- }
58195
- var DefaultPermissionPolicy = class {
58196
- canExecuteTool(mode, tool) {
58197
- const definition = getAgentMode(mode);
58198
- const risk = riskForTool(tool);
58199
- const readOnlyTool = READ_ONLY_TOOL_NAMES.has(tool.name) || READ_ONLY_CATEGORIES.has(tool.category);
58200
- if (definition.readOnly && !readOnlyTool) {
58201
- return {
58202
- allowed: false,
58203
- reason: `${definition.label} mode is read-only; ${tool.name} is a ${tool.category} tool.`,
58204
- risk
58205
- };
58206
- }
58207
- if (risk === "destructive") {
58208
- return {
58209
- allowed: true,
58210
- requiresConfirmation: true,
58211
- reason: `${tool.name} can change repository state and should be confirmed.`,
58212
- risk
58213
- };
58214
- }
58215
- return { allowed: true, risk };
58216
- }
58217
- canExecuteToolInput(mode, tool, input) {
58218
- if (tool.name === "spawnSimpleAgent") {
58219
- const risk = riskForSpawnedAgent(input);
58220
- const definition2 = getAgentMode(mode);
58221
- if (definition2.readOnly && risk !== "read-only" && risk !== "network") {
58222
- return {
58223
- allowed: false,
58224
- reason: `${definition2.label} mode is read-only; spawnSimpleAgent with this role can perform ${risk} work.`,
58225
- risk
58226
- };
58227
- }
58228
- return {
58229
- allowed: true,
58230
- requiresConfirmation: risk === "destructive" || risk === "secrets-sensitive",
58231
- risk
58232
- };
58233
- }
58234
- if (tool.name !== "run_linter") {
58235
- return this.canExecuteTool(mode, tool);
58236
- }
58237
- const definition = getAgentMode(mode);
58238
- const fixEnabled = input["fix"] === true;
58239
- const decision = fixEnabled ? { allowed: true, risk: "write" } : { allowed: true, risk: "read-only" };
58240
- if (definition.readOnly && fixEnabled) {
58241
- return {
58242
- allowed: false,
58243
- reason: `${definition.label} mode is read-only; run_linter with fix=true can modify files.`,
58244
- risk: "write"
58245
- };
58246
- }
58247
- return decision;
58248
- }
58249
- };
58250
- function createPermissionPolicy() {
58251
- return new DefaultPermissionPolicy();
58252
- }
58253
- function riskForSpawnedAgent(input) {
58254
- const type = typeof input["type"] === "string" ? input["type"] : void 0;
58255
- const role = typeof input["role"] === "string" ? input["role"] : void 0;
58256
- const resolved = type ?? role;
58257
- switch (resolved) {
58258
- case "explore":
58259
- case "plan":
58260
- case "review":
58261
- case "architect":
58262
- case "security":
58263
- case "docs":
58264
- case "researcher":
58265
- case "reviewer":
58266
- case "planner":
58267
- return "read-only";
58268
- case "database":
58269
- return "secrets-sensitive";
58270
- case "test":
58271
- case "tdd":
58272
- case "e2e":
58273
- case "tester":
58274
- return "destructive";
58275
- case "debug":
58276
- case "refactor":
58277
- case "coder":
58278
- case "optimizer":
58279
- return "write";
58280
- default:
58281
- return "read-only";
58282
- }
58283
- }
58284
58734
 
58285
58735
  // src/runtime/provider-registry.ts
58286
58736
  init_providers();
@@ -58447,6 +58897,109 @@ var WorkflowCatalog = class {
58447
58897
  }
58448
58898
  };
58449
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
+ },
58450
59003
  {
58451
59004
  id: "architect-editor-verifier",
58452
59005
  name: "Architect / Editor / Verifier",
@@ -58592,11 +59145,13 @@ var WorkflowEngine = class {
58592
59145
  this.eventLog = eventLog;
58593
59146
  this.sharedState = options.sharedState ?? new InMemorySharedWorkspaceStore();
58594
59147
  this.nodeExecutor = options.nodeExecutor;
59148
+ this.runtimePolicy = options.runtimePolicy;
58595
59149
  }
58596
59150
  catalog;
58597
59151
  eventLog;
58598
59152
  handlers = /* @__PURE__ */ new Map();
58599
59153
  sharedState;
59154
+ runtimePolicy;
58600
59155
  nodeExecutor;
58601
59156
  registerHandler(workflowId, handler) {
58602
59157
  if (!this.catalog.get(workflowId)) {
@@ -58627,6 +59182,8 @@ var WorkflowEngine = class {
58627
59182
  trace
58628
59183
  });
58629
59184
  try {
59185
+ const graph = workflowToAgentGraph(workflow);
59186
+ assertWorkflowAllowedByRuntimePolicy(graph, this.runtimePolicy);
58630
59187
  const graphResult = handler ? void 0 : await new AgentGraphEngine({
58631
59188
  eventLog: this.eventLog,
58632
59189
  sharedState: this.sharedState,
@@ -58634,7 +59191,7 @@ var WorkflowEngine = class {
58634
59191
  trace
58635
59192
  }).run({
58636
59193
  workflowRunId: runId,
58637
- graph: workflowToAgentGraph(workflow),
59194
+ graph,
58638
59195
  input: request.input
58639
59196
  });
58640
59197
  const output = graphResult ?? await handler(request.input, {
@@ -58686,6 +59243,29 @@ var WorkflowEngine = class {
58686
59243
  }
58687
59244
  }
58688
59245
  };
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
+ }
58689
59269
  function createWorkflowEngine(catalog, eventLog, options) {
58690
59270
  return new WorkflowEngine(catalog, eventLog, options);
58691
59271
  }
@@ -58695,15 +59275,17 @@ var AgentRuntime = class {
58695
59275
  constructor(options) {
58696
59276
  this.options = options;
58697
59277
  this.providerRegistry = createProviderRegistry();
58698
- this.toolRegistry = options.toolRegistry ?? createFullToolRegistry();
59278
+ this.toolRegistry = options.toolRegistry ?? new ToolRegistry();
58699
59279
  this.sessionStore = options.sessionStore;
58700
59280
  this.runtimeSessionStore = options.runtimeSessionStore ?? createRuntimeSessionStore();
58701
59281
  this.eventLog = options.eventLog ?? (options.eventLogPath ? createFileEventLog(options.eventLogPath) : createEventLog());
58702
- this.workflowEngine = options.workflowEngine ?? createWorkflowEngine(void 0, this.eventLog);
58703
59282
  this.permissionPolicy = options.permissionPolicy ?? createPermissionPolicy();
58704
59283
  this.turnRunner = options.turnRunner ?? createDefaultRuntimeTurnRunner();
58705
59284
  this.providerType = options.providerType;
58706
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 });
58707
59289
  }
58708
59290
  options;
58709
59291
  providerRegistry;
@@ -58717,6 +59299,8 @@ var AgentRuntime = class {
58717
59299
  providerType;
58718
59300
  model;
58719
59301
  provider;
59302
+ runtimeContext;
59303
+ runtimePolicy;
58720
59304
  async initialize() {
58721
59305
  const providerInjected = Boolean(this.options.provider);
58722
59306
  const provider = this.options.provider ?? await this.providerRegistry.createProvider(this.providerType, {
@@ -58747,8 +59331,8 @@ var AgentRuntime = class {
58747
59331
  }
58748
59332
  publishToGlobalBridge(provider) {
58749
59333
  if (this.options.publishToGlobalBridge !== true) return;
58750
- setAgentProvider(provider);
58751
- setAgentToolRegistry(this.toolRegistry);
59334
+ this.options.legacyAgentBridge?.setAgentProvider(provider);
59335
+ this.options.legacyAgentBridge?.setAgentToolRegistry(this.toolRegistry);
58752
59336
  }
58753
59337
  snapshot() {
58754
59338
  const capability = this.providerRegistry.getCapability(this.providerType, this.getModel());
@@ -58763,14 +59347,25 @@ var AgentRuntime = class {
58763
59347
  count: toolNames.length,
58764
59348
  names: toolNames
58765
59349
  },
58766
- modes: listAgentModes()
59350
+ modes: listAgentModes(),
59351
+ context: this.runtimeContext,
59352
+ policy: this.runtimePolicy
58767
59353
  };
58768
59354
  }
58769
59355
  createSession(options = {}) {
58770
- 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
+ });
58771
59363
  this.eventLog.record("session.created", {
58772
59364
  sessionId: session.id,
58773
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"] } : {},
58774
59369
  metadataKeys: Object.keys(session.metadata).sort()
58775
59370
  });
58776
59371
  return session;
@@ -58807,6 +59402,7 @@ var AgentRuntime = class {
58807
59402
  permissionPolicy: this.permissionPolicy,
58808
59403
  eventLog: this.eventLog
58809
59404
  });
59405
+ assertRuntimeUsageWithinPolicy(this.runtimePolicy, result.usage);
58810
59406
  const updatedSession = this.runtimeSessionStore.update({
58811
59407
  ...effectiveSession,
58812
59408
  messages: [
@@ -58884,16 +59480,8 @@ var AgentRuntime = class {
58884
59480
  };
58885
59481
  }
58886
59482
  }
58887
- const updatedSession = this.runtimeSessionStore.update({
58888
- ...effectiveSession,
58889
- messages: [
58890
- ...effectiveSession.messages,
58891
- { role: "user", content: input.content },
58892
- { role: "assistant", content }
58893
- ]
58894
- });
58895
59483
  const result = {
58896
- sessionId: updatedSession.id,
59484
+ sessionId: effectiveSession.id,
58897
59485
  content,
58898
59486
  usage: {
58899
59487
  inputTokens: provider.countTokens(input.content),
@@ -58901,8 +59489,19 @@ var AgentRuntime = class {
58901
59489
  estimated: true
58902
59490
  },
58903
59491
  model: input.options?.model ?? this.getModel(),
58904
- mode: updatedSession.mode
59492
+ mode: effectiveSession.mode
58905
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;
58906
59505
  this.eventLog.record("session.updated", {
58907
59506
  sessionId: updatedSession.id,
58908
59507
  messages: updatedSession.messages.length
@@ -58990,15 +59589,22 @@ var AgentRuntime = class {
58990
59589
  };
58991
59590
  }
58992
59591
  const decision = this.permissionPolicy.canExecuteToolInput ? this.permissionPolicy.canExecuteToolInput(mode, tool, input.input) : this.permissionPolicy.canExecuteTool(mode, tool);
58993
- if (!decision.allowed || decision.requiresConfirmation && input.confirmed !== true) {
58994
- 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.");
58995
59600
  this.eventLog.record("tool.blocked", {
58996
59601
  sessionId: input.sessionId,
58997
59602
  mode,
58998
59603
  tool: input.toolName,
58999
59604
  reason,
59000
- risk: decision.risk,
59001
- requiresConfirmation: decision.requiresConfirmation,
59605
+ risk: effectiveDecision.risk,
59606
+ requiresConfirmation: effectiveDecision.requiresConfirmation ?? decision.requiresConfirmation,
59607
+ runtimePolicyBlocked: runtimeDecision ? !runtimeDecision.allowed : false,
59002
59608
  runtimeApi: true
59003
59609
  });
59004
59610
  return {
@@ -59006,14 +59612,20 @@ var AgentRuntime = class {
59006
59612
  success: false,
59007
59613
  error: reason,
59008
59614
  duration: performance.now() - startedAt,
59009
- decision
59615
+ decision: {
59616
+ ...decision,
59617
+ allowed: false,
59618
+ reason,
59619
+ requiresConfirmation: effectiveDecision.requiresConfirmation ?? decision.requiresConfirmation,
59620
+ risk: effectiveDecision.risk
59621
+ }
59010
59622
  };
59011
59623
  }
59012
59624
  this.eventLog.record("tool.started", {
59013
59625
  sessionId: input.sessionId,
59014
59626
  mode,
59015
59627
  tool: input.toolName,
59016
- risk: decision.risk,
59628
+ risk: effectiveDecision.risk,
59017
59629
  runtimeApi: true,
59018
59630
  metadataKeys: Object.keys(input.metadata ?? {}).sort()
59019
59631
  });
@@ -59032,7 +59644,11 @@ var AgentRuntime = class {
59032
59644
  output: result.data,
59033
59645
  error: result.error,
59034
59646
  duration: result.duration,
59035
- decision
59647
+ decision: {
59648
+ ...decision,
59649
+ risk: effectiveDecision.risk,
59650
+ requiresConfirmation: decision.requiresConfirmation
59651
+ }
59036
59652
  };
59037
59653
  }
59038
59654
  assertToolAllowed(mode, toolName, input) {
@@ -59046,12 +59662,24 @@ var AgentRuntime = class {
59046
59662
  return false;
59047
59663
  }
59048
59664
  const decision = input && this.permissionPolicy.canExecuteToolInput ? this.permissionPolicy.canExecuteToolInput(mode, tool, input) : this.permissionPolicy.canExecuteTool(mode, tool);
59049
- 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", {
59050
59672
  mode,
59051
59673
  tool: toolName,
59052
- ...decision
59674
+ ...decision,
59675
+ ...runtimeDecision && !runtimeDecision.allowed ? {
59676
+ allowed: false,
59677
+ reason: runtimeDecision.reason,
59678
+ requiresConfirmation: runtimeDecision.requiresConfirmation,
59679
+ runtimePolicyBlocked: true
59680
+ } : {}
59053
59681
  });
59054
- return decision.allowed;
59682
+ return allowed;
59055
59683
  }
59056
59684
  };
59057
59685
  async function createAgentRuntime(options) {
@@ -59729,8 +60357,10 @@ async function startRepl(options = {}) {
59729
60357
  providerType: internalProviderId,
59730
60358
  model: session.config.provider.model || void 0,
59731
60359
  provider,
60360
+ toolRegistry: createFullToolRegistry(),
59732
60361
  eventLogPath: path39__default.join(projectPath, ".coco", "events", `${session.id}.jsonl`),
59733
- publishToGlobalBridge: true
60362
+ publishToGlobalBridge: true,
60363
+ legacyAgentBridge: { setAgentProvider, setAgentToolRegistry }
59734
60364
  });
59735
60365
  session.runtime = runtime;
59736
60366
  const toolRegistry = runtime.toolRegistry;
@@ -61005,9 +61635,11 @@ ${stdinContent}
61005
61635
  providerType,
61006
61636
  model: session.config.provider.model || void 0,
61007
61637
  provider,
61638
+ toolRegistry: createFullToolRegistry(),
61008
61639
  eventLogPath: path39__default.join(options.projectPath, ".coco", "events", `${session.id}.jsonl`),
61009
61640
  turnRunner: options.useRuntimeRunner ? createToolCallingRuntimeTurnRunner() : void 0,
61010
- publishToGlobalBridge: true
61641
+ publishToGlobalBridge: true,
61642
+ legacyAgentBridge: { setAgentProvider, setAgentToolRegistry }
61011
61643
  });
61012
61644
  session.runtime = runtime;
61013
61645
  const toolRegistry = runtime.toolRegistry;