@corbat-tech/coco 2.35.0 → 2.37.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,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
- import { execFileSync, execSync, spawn, execFile, exec } from 'child_process';
2
+ import { execFileSync, spawn, execSync, execFile, exec } from 'child_process';
3
3
  import { setGlobalDispatcher, EnvHttpProxyAgent } from 'undici';
4
4
  import * as fs5 from 'fs';
5
- import fs5__default, { accessSync, readFileSync, constants as constants$1 } from 'fs';
5
+ import fs5__default, { accessSync, mkdirSync, appendFileSync, readFileSync, writeFileSync, constants as constants$1 } from 'fs';
6
6
  import * as path39 from 'path';
7
7
  import path39__default, { join, dirname, resolve, basename } from 'path';
8
8
  import { URL as URL$1, fileURLToPath } from 'url';
@@ -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 as parse$1 } from 'yaml';
26
+ import { parse } 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 } from '@typescript-eslint/typescript-estree';
45
+ import { parse as parse$1 } 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';
@@ -893,8 +893,8 @@ async function configExists(configPath, scope = "any") {
893
893
  }
894
894
  return false;
895
895
  }
896
- function getConfigValue(config, path63) {
897
- const keys = path63.split(".");
896
+ function getConfigValue(config, path65) {
897
+ const keys = path65.split(".");
898
898
  let current = config;
899
899
  for (const key of keys) {
900
900
  if (current === null || current === void 0 || typeof current !== "object") {
@@ -956,6 +956,10 @@ function getCatalogDefaultModel(provider) {
956
956
  function getCatalogModel(provider, modelId) {
957
957
  return getProviderCatalogEntry(provider).models.find((modelEntry) => modelEntry.id === modelId);
958
958
  }
959
+ function getCatalogRecommendedModel(provider) {
960
+ const entry = getProviderCatalogEntry(provider);
961
+ return entry.models.find((modelEntry) => modelEntry.recommended) ?? entry.models[0];
962
+ }
959
963
  function getCatalogContextWindow(provider, modelId, fallback) {
960
964
  if (!modelId) return fallback;
961
965
  const exact = getCatalogModel(provider, modelId);
@@ -9496,9 +9500,9 @@ async function migrateGlobalConfig(oldDir, newConfigPath) {
9496
9500
  );
9497
9501
  }
9498
9502
  }
9499
- async function fileExists(path63) {
9503
+ async function fileExists(path65) {
9500
9504
  try {
9501
- await access(path63);
9505
+ await access(path65);
9502
9506
  return true;
9503
9507
  } catch {
9504
9508
  return false;
@@ -9881,8 +9885,8 @@ var init_registry = __esm({
9881
9885
  /**
9882
9886
  * Ensure directory exists
9883
9887
  */
9884
- async ensureDir(path63) {
9885
- await mkdir(dirname(path63), { recursive: true });
9888
+ async ensureDir(path65) {
9889
+ await mkdir(dirname(path65), { recursive: true });
9886
9890
  }
9887
9891
  };
9888
9892
  }
@@ -10057,7 +10061,7 @@ function parseSkillMarkdown(raw) {
10057
10061
  const frontmatter = normalized.slice(3, closeIndex).trim();
10058
10062
  const afterMarkerStart = closeIndex + closeMarker.length;
10059
10063
  const contentStart = normalized[afterMarkerStart] === "\n" ? afterMarkerStart + 1 : afterMarkerStart;
10060
- const parsed = frontmatter.length > 0 ? parse$1(frontmatter) : {};
10064
+ const parsed = frontmatter.length > 0 ? parse(frontmatter) : {};
10061
10065
  return {
10062
10066
  data: parsed && typeof parsed === "object" ? parsed : {},
10063
10067
  content: normalized.slice(contentStart)
@@ -11563,9 +11567,9 @@ function createEmptyMemoryContext() {
11563
11567
  errors: []
11564
11568
  };
11565
11569
  }
11566
- function createMissingMemoryFile(path63, level) {
11570
+ function createMissingMemoryFile(path65, level) {
11567
11571
  return {
11568
- path: path63,
11572
+ path: path65,
11569
11573
  level,
11570
11574
  content: "",
11571
11575
  sections: [],
@@ -13126,8 +13130,8 @@ __export(trust_store_exports, {
13126
13130
  saveTrustStore: () => saveTrustStore,
13127
13131
  updateLastAccessed: () => updateLastAccessed
13128
13132
  });
13129
- async function ensureDir(path63) {
13130
- await mkdir(dirname(path63), { recursive: true });
13133
+ async function ensureDir(path65) {
13134
+ await mkdir(dirname(path65), { recursive: true });
13131
13135
  }
13132
13136
  async function loadTrustStore(storePath = TRUST_STORE_PATH) {
13133
13137
  try {
@@ -13212,8 +13216,8 @@ function canPerformOperation(store, projectPath, operation) {
13212
13216
  };
13213
13217
  return permissions[level]?.includes(operation) ?? false;
13214
13218
  }
13215
- function normalizePath(path63) {
13216
- return join(path63);
13219
+ function normalizePath(path65) {
13220
+ return join(path65);
13217
13221
  }
13218
13222
  function createTrustStore(storePath = TRUST_STORE_PATH) {
13219
13223
  let store = null;
@@ -13569,12 +13573,12 @@ function humanizeError(message, toolName) {
13569
13573
  return msg;
13570
13574
  }
13571
13575
  if (/ENOENT/i.test(msg)) {
13572
- const path63 = extractQuotedPath(msg);
13573
- return path63 ? `File or directory not found: ${path63}` : "File or directory not found";
13576
+ const path65 = extractQuotedPath(msg);
13577
+ return path65 ? `File or directory not found: ${path65}` : "File or directory not found";
13574
13578
  }
13575
13579
  if (/EACCES/i.test(msg)) {
13576
- const path63 = extractQuotedPath(msg);
13577
- return path63 ? `Permission denied: ${path63}` : "Permission denied \u2014 check file permissions";
13580
+ const path65 = extractQuotedPath(msg);
13581
+ return path65 ? `Permission denied: ${path65}` : "Permission denied \u2014 check file permissions";
13578
13582
  }
13579
13583
  if (/EISDIR/i.test(msg)) {
13580
13584
  return "Expected a file but found a directory at the specified path";
@@ -14516,9 +14520,9 @@ var init_diff_renderer = __esm({
14516
14520
  getTerminalWidth = () => process.stdout.columns || 80;
14517
14521
  }
14518
14522
  });
14519
- async function fileExists4(path63) {
14523
+ async function fileExists4(path65) {
14520
14524
  try {
14521
- await access(path63);
14525
+ await access(path65);
14522
14526
  return true;
14523
14527
  } catch {
14524
14528
  return false;
@@ -15461,7 +15465,7 @@ var init_complexity = __esm({
15461
15465
  * Analyze single file
15462
15466
  */
15463
15467
  async analyzeFile(file, content) {
15464
- const ast = parse(content, {
15468
+ const ast = parse$1(content, {
15465
15469
  loc: true,
15466
15470
  range: true,
15467
15471
  comment: false,
@@ -16058,7 +16062,7 @@ var init_completeness = __esm({
16058
16062
  for (const file of files) {
16059
16063
  try {
16060
16064
  const content = await readFile(file, "utf-8");
16061
- const ast = parse(content, {
16065
+ const ast = parse$1(content, {
16062
16066
  loc: true,
16063
16067
  range: true,
16064
16068
  jsx: file.endsWith(".tsx") || file.endsWith(".jsx")
@@ -16271,7 +16275,7 @@ var init_robustness = __esm({
16271
16275
  for (const file of targetFiles) {
16272
16276
  try {
16273
16277
  const content = await readFile(file, "utf-8");
16274
- const ast = parse(content, {
16278
+ const ast = parse$1(content, {
16275
16279
  loc: true,
16276
16280
  range: true,
16277
16281
  jsx: file.endsWith(".tsx") || file.endsWith(".jsx")
@@ -16564,7 +16568,7 @@ var init_documentation = __esm({
16564
16568
  for (const file of targetFiles) {
16565
16569
  try {
16566
16570
  const content = await readFile(file, "utf-8");
16567
- const ast = parse(content, {
16571
+ const ast = parse$1(content, {
16568
16572
  loc: true,
16569
16573
  range: true,
16570
16574
  comment: true,
@@ -16942,7 +16946,7 @@ var init_readability = __esm({
16942
16946
  for (const file of targetFiles) {
16943
16947
  try {
16944
16948
  const content = await readFile(file, "utf-8");
16945
- const ast = parse(content, {
16949
+ const ast = parse$1(content, {
16946
16950
  loc: true,
16947
16951
  range: true,
16948
16952
  jsx: file.endsWith(".tsx") || file.endsWith(".jsx")
@@ -17100,7 +17104,7 @@ var init_maintainability = __esm({
17100
17104
  try {
17101
17105
  const content = await readFile(file, "utf-8");
17102
17106
  const lineCount = countLines(content);
17103
- const ast = parse(content, {
17107
+ const ast = parse$1(content, {
17104
17108
  loc: true,
17105
17109
  range: true,
17106
17110
  jsx: file.endsWith(".tsx") || file.endsWith(".jsx")
@@ -26985,8 +26989,8 @@ Generated by Corbat-Coco v0.1.0
26985
26989
 
26986
26990
  // src/cli/commands/init.ts
26987
26991
  function registerInitCommand(program2) {
26988
- program2.command("init").description("Initialize a new Corbat-Coco project").argument("[path]", "Project directory path", ".").option("-t, --template <template>", "Project template to use").option("-y, --yes", "Skip prompts and use defaults").option("--skip-discovery", "Skip the discovery phase (use existing spec)").action(async (path63, options) => {
26989
- await runInit(path63, options);
26992
+ program2.command("init").description("Initialize a new Corbat-Coco project").argument("[path]", "Project directory path", ".").option("-t, --template <template>", "Project template to use").option("-y, --yes", "Skip prompts and use defaults").option("--skip-discovery", "Skip the discovery phase (use existing spec)").action(async (path65, options) => {
26993
+ await runInit(path65, options);
26990
26994
  });
26991
26995
  }
26992
26996
  async function runInit(projectPath, options) {
@@ -27065,18 +27069,18 @@ async function gatherProjectInfo() {
27065
27069
  language
27066
27070
  };
27067
27071
  }
27068
- function getDefaultProjectInfo(path63) {
27069
- const name = path63 === "." ? "my-project" : path63.split("/").pop() || "my-project";
27072
+ function getDefaultProjectInfo(path65) {
27073
+ const name = path65 === "." ? "my-project" : path65.split("/").pop() || "my-project";
27070
27074
  return {
27071
27075
  name,
27072
27076
  description: "",
27073
27077
  language: "typescript"
27074
27078
  };
27075
27079
  }
27076
- async function checkExistingProject(path63) {
27080
+ async function checkExistingProject(path65) {
27077
27081
  try {
27078
27082
  const fs57 = await import('fs/promises');
27079
- await fs57.access(`${path63}/.coco`);
27083
+ await fs57.access(`${path65}/.coco`);
27080
27084
  return true;
27081
27085
  } catch {
27082
27086
  return false;
@@ -30577,20 +30581,20 @@ async function createCliPhaseContext(projectPath, _onUserInput) {
30577
30581
  },
30578
30582
  tools: {
30579
30583
  file: {
30580
- async read(path63) {
30584
+ async read(path65) {
30581
30585
  const fs57 = await import('fs/promises');
30582
- return fs57.readFile(path63, "utf-8");
30586
+ return fs57.readFile(path65, "utf-8");
30583
30587
  },
30584
- async write(path63, content) {
30588
+ async write(path65, content) {
30585
30589
  const fs57 = await import('fs/promises');
30586
30590
  const nodePath = await import('path');
30587
- await fs57.mkdir(nodePath.dirname(path63), { recursive: true });
30588
- await fs57.writeFile(path63, content, "utf-8");
30591
+ await fs57.mkdir(nodePath.dirname(path65), { recursive: true });
30592
+ await fs57.writeFile(path65, content, "utf-8");
30589
30593
  },
30590
- async exists(path63) {
30594
+ async exists(path65) {
30591
30595
  const fs57 = await import('fs/promises');
30592
30596
  try {
30593
- await fs57.access(path63);
30597
+ await fs57.access(path65);
30594
30598
  return true;
30595
30599
  } catch {
30596
30600
  return false;
@@ -30946,10 +30950,10 @@ function getPhaseStatusForPhase(phase) {
30946
30950
  }
30947
30951
  async function loadProjectState(cwd, config) {
30948
30952
  const fs57 = await import('fs/promises');
30949
- const path63 = await import('path');
30950
- const statePath = path63.join(cwd, ".coco", "state.json");
30951
- const backlogPath = path63.join(cwd, ".coco", "planning", "backlog.json");
30952
- const checkpointDir = path63.join(cwd, ".coco", "checkpoints");
30953
+ const path65 = await import('path');
30954
+ const statePath = path65.join(cwd, ".coco", "state.json");
30955
+ const backlogPath = path65.join(cwd, ".coco", "planning", "backlog.json");
30956
+ const checkpointDir = path65.join(cwd, ".coco", "checkpoints");
30953
30957
  let currentPhase = "idle";
30954
30958
  let metrics;
30955
30959
  let sprint;
@@ -32521,8 +32525,8 @@ async function saveConfig2(config) {
32521
32525
  await fs57.mkdir(dir, { recursive: true });
32522
32526
  await fs57.writeFile(CONFIG_PATH, JSON.stringify(config, null, 2));
32523
32527
  }
32524
- function getNestedValue(obj, path63) {
32525
- const keys = path63.split(".");
32528
+ function getNestedValue(obj, path65) {
32529
+ const keys = path65.split(".");
32526
32530
  let current = obj;
32527
32531
  for (const key of keys) {
32528
32532
  if (current === null || current === void 0 || typeof current !== "object") {
@@ -32532,8 +32536,8 @@ function getNestedValue(obj, path63) {
32532
32536
  }
32533
32537
  return current;
32534
32538
  }
32535
- function setNestedValue(obj, path63, value) {
32536
- const keys = path63.split(".");
32539
+ function setNestedValue(obj, path65, value) {
32540
+ const keys = path65.split(".");
32537
32541
  let current = obj;
32538
32542
  for (let i = 0; i < keys.length - 1; i++) {
32539
32543
  const key = keys[i];
@@ -33565,9 +33569,9 @@ function registerCheckCommand(program2) {
33565
33569
  // src/swarm/spec-parser.ts
33566
33570
  async function parseSwarmSpec(filePath) {
33567
33571
  const fs57 = await import('fs/promises');
33568
- const path63 = await import('path');
33572
+ const path65 = await import('path');
33569
33573
  const rawContent = await fs57.readFile(filePath, "utf-8");
33570
- const ext = path63.extname(filePath).toLowerCase();
33574
+ const ext = path65.extname(filePath).toLowerCase();
33571
33575
  if (ext === ".yaml" || ext === ".yml") {
33572
33576
  return parseYamlSpec(rawContent);
33573
33577
  }
@@ -33897,8 +33901,8 @@ var DEFAULT_AGENT_CONFIG = {
33897
33901
  };
33898
33902
  async function loadAgentConfig(projectPath) {
33899
33903
  const fs57 = await import('fs/promises');
33900
- const path63 = await import('path');
33901
- const configPath = path63.join(projectPath, ".coco", "swarm", "agents.json");
33904
+ const path65 = await import('path');
33905
+ const configPath = path65.join(projectPath, ".coco", "swarm", "agents.json");
33902
33906
  try {
33903
33907
  const raw = await fs57.readFile(configPath, "utf-8");
33904
33908
  const parsed = JSON.parse(raw);
@@ -34089,16 +34093,16 @@ async function createBoard(projectPath, spec) {
34089
34093
  }
34090
34094
  async function loadBoard(projectPath) {
34091
34095
  const fs57 = await import('fs/promises');
34092
- const path63 = await import('path');
34093
- const boardPath = path63.join(projectPath, ".coco", "swarm", "task-board.json");
34096
+ const path65 = await import('path');
34097
+ const boardPath = path65.join(projectPath, ".coco", "swarm", "task-board.json");
34094
34098
  const raw = await fs57.readFile(boardPath, "utf-8");
34095
34099
  return JSON.parse(raw);
34096
34100
  }
34097
34101
  async function saveBoard(projectPath, board) {
34098
34102
  const fs57 = await import('fs/promises');
34099
- const path63 = await import('path');
34100
- const boardDir = path63.join(projectPath, ".coco", "swarm");
34101
- const boardPath = path63.join(boardDir, "task-board.json");
34103
+ const path65 = await import('path');
34104
+ const boardDir = path65.join(projectPath, ".coco", "swarm");
34105
+ const boardPath = path65.join(boardDir, "task-board.json");
34102
34106
  await fs57.mkdir(boardDir, { recursive: true });
34103
34107
  await fs57.writeFile(boardPath, JSON.stringify(board, null, 2), "utf-8");
34104
34108
  }
@@ -34266,9 +34270,9 @@ async function defaultPromptHandler(q) {
34266
34270
  }
34267
34271
  async function writeAssumptionsFile(projectPath, projectName, questions, assumptions) {
34268
34272
  const fs57 = await import('fs/promises');
34269
- const path63 = await import('path');
34270
- const swarmDir = path63.join(projectPath, ".coco", "swarm");
34271
- const assumptionsPath = path63.join(swarmDir, "assumptions.md");
34273
+ const path65 = await import('path');
34274
+ const swarmDir = path65.join(projectPath, ".coco", "swarm");
34275
+ const assumptionsPath = path65.join(swarmDir, "assumptions.md");
34272
34276
  await fs57.mkdir(swarmDir, { recursive: true });
34273
34277
  const now = (/* @__PURE__ */ new Date()).toISOString();
34274
34278
  const content = [
@@ -34292,9 +34296,9 @@ async function writeAssumptionsFile(projectPath, projectName, questions, assumpt
34292
34296
  // src/swarm/events.ts
34293
34297
  async function appendSwarmEvent(projectPath, event) {
34294
34298
  const fs57 = await import('fs/promises');
34295
- const path63 = await import('path');
34296
- const eventsDir = path63.join(projectPath, ".coco", "swarm");
34297
- const eventsFile = path63.join(eventsDir, "events.jsonl");
34299
+ const path65 = await import('path');
34300
+ const eventsDir = path65.join(projectPath, ".coco", "swarm");
34301
+ const eventsFile = path65.join(eventsDir, "events.jsonl");
34298
34302
  await fs57.mkdir(eventsDir, { recursive: true });
34299
34303
  await fs57.appendFile(eventsFile, JSON.stringify(event) + "\n", "utf-8");
34300
34304
  }
@@ -34305,9 +34309,9 @@ function createEventId() {
34305
34309
  // src/swarm/knowledge.ts
34306
34310
  async function appendKnowledge(projectPath, entry) {
34307
34311
  const fs57 = await import('fs/promises');
34308
- const path63 = await import('path');
34309
- const knowledgeDir = path63.join(projectPath, ".coco", "swarm");
34310
- const knowledgeFile = path63.join(knowledgeDir, "knowledge.jsonl");
34312
+ const path65 = await import('path');
34313
+ const knowledgeDir = path65.join(projectPath, ".coco", "swarm");
34314
+ const knowledgeFile = path65.join(knowledgeDir, "knowledge.jsonl");
34311
34315
  await fs57.mkdir(knowledgeDir, { recursive: true });
34312
34316
  await fs57.appendFile(knowledgeFile, JSON.stringify(entry) + "\n", "utf-8");
34313
34317
  }
@@ -34614,10 +34618,10 @@ async function runSwarmLifecycle(options) {
34614
34618
  async function stageInit(ctx) {
34615
34619
  const { projectPath, spec } = ctx.options;
34616
34620
  const fs57 = await import('fs/promises');
34617
- const path63 = await import('path');
34618
- await fs57.mkdir(path63.join(projectPath, ".coco", "swarm"), { recursive: true });
34621
+ const path65 = await import('path');
34622
+ await fs57.mkdir(path65.join(projectPath, ".coco", "swarm"), { recursive: true });
34619
34623
  await fs57.mkdir(ctx.options.outputPath, { recursive: true });
34620
- const specSummaryPath = path63.join(projectPath, ".coco", "swarm", "spec-summary.json");
34624
+ const specSummaryPath = path65.join(projectPath, ".coco", "swarm", "spec-summary.json");
34621
34625
  const specSummary = {
34622
34626
  projectName: spec.projectName,
34623
34627
  description: spec.description,
@@ -34689,8 +34693,8 @@ async function stagePlan(ctx) {
34689
34693
  ]);
34690
34694
  await createBoard(projectPath, spec);
34691
34695
  const fs57 = await import('fs/promises');
34692
- const path63 = await import('path');
34693
- const planPath = path63.join(projectPath, ".coco", "swarm", "plan.json");
34696
+ const path65 = await import('path');
34697
+ const planPath = path65.join(projectPath, ".coco", "swarm", "plan.json");
34694
34698
  await fs57.writeFile(
34695
34699
  planPath,
34696
34700
  JSON.stringify({ pm: pmResult, architect: archResult, bestPractices: bpResult }, null, 2),
@@ -34907,7 +34911,7 @@ async function stageIntegrate(ctx) {
34907
34911
  async function stageOutput(ctx) {
34908
34912
  const { projectPath, outputPath } = ctx.options;
34909
34913
  const fs57 = await import('fs/promises');
34910
- const path63 = await import('path');
34914
+ const path65 = await import('path');
34911
34915
  const board = await loadBoard(projectPath);
34912
34916
  const featureResults = Array.from(ctx.featureResults.values());
34913
34917
  const summary = {
@@ -34922,7 +34926,7 @@ async function stageOutput(ctx) {
34922
34926
  globalScore: computeGlobalScore(featureResults)
34923
34927
  };
34924
34928
  await fs57.mkdir(outputPath, { recursive: true });
34925
- const summaryPath = path63.join(outputPath, "swarm-summary.json");
34929
+ const summaryPath = path65.join(outputPath, "swarm-summary.json");
34926
34930
  await fs57.writeFile(summaryPath, JSON.stringify(summary, null, 2), "utf-8");
34927
34931
  const passed = summary.globalScore >= ctx.options.minScore;
34928
34932
  await emitGate(projectPath, "global-score", passed, `Global score: ${summary.globalScore}`);
@@ -35269,8 +35273,8 @@ var SwarmOrchestrator = class {
35269
35273
  noQuestions = false,
35270
35274
  onProgress
35271
35275
  } = options;
35272
- const path63 = await import('path');
35273
- const projectPath = path63.dirname(path63.resolve(specFile));
35276
+ const path65 = await import('path');
35277
+ const projectPath = path65.dirname(path65.resolve(specFile));
35274
35278
  onProgress?.("init", `Parsing spec file: ${specFile}`);
35275
35279
  const spec = await parseSwarmSpec(specFile);
35276
35280
  onProgress?.("init", `Initializing provider: ${providerType}`);
@@ -35281,7 +35285,7 @@ var SwarmOrchestrator = class {
35281
35285
  await runSwarmLifecycle({
35282
35286
  spec,
35283
35287
  projectPath,
35284
- outputPath: path63.resolve(outputPath),
35288
+ outputPath: path65.resolve(outputPath),
35285
35289
  provider,
35286
35290
  agentConfig,
35287
35291
  minScore,
@@ -39219,8 +39223,8 @@ async function listTrustedProjects2(trustStore) {
39219
39223
  p26.log.message("");
39220
39224
  for (const project of projects) {
39221
39225
  const level = project.approvalLevel.toUpperCase().padEnd(5);
39222
- const path63 = project.path.length > 50 ? "..." + project.path.slice(-47) : project.path;
39223
- p26.log.message(` [${level}] ${path63}`);
39226
+ const path65 = project.path.length > 50 ? "..." + project.path.slice(-47) : project.path;
39227
+ p26.log.message(` [${level}] ${path65}`);
39224
39228
  p26.log.message(` Last accessed: ${new Date(project.lastAccessed).toLocaleString()}`);
39225
39229
  }
39226
39230
  p26.log.message("");
@@ -40451,8 +40455,8 @@ function displayRewindResult(result) {
40451
40455
  const fileName = filePath.split("/").pop() ?? filePath;
40452
40456
  console.log(`${chalk.green(String.fromCodePoint(10003))} Restored: ${fileName}`);
40453
40457
  }
40454
- for (const { path: path63, error } of result.filesFailed) {
40455
- const fileName = path63.split("/").pop() ?? path63;
40458
+ for (const { path: path65, error } of result.filesFailed) {
40459
+ const fileName = path65.split("/").pop() ?? path65;
40456
40460
  console.log(`${chalk.red(String.fromCodePoint(10007))} Failed: ${fileName} (${error})`);
40457
40461
  }
40458
40462
  if (result.conversationRestored) {
@@ -49993,7 +49997,7 @@ async function validateCode(code, filePath, _language) {
49993
49997
  const errors = [];
49994
49998
  const warnings = [];
49995
49999
  try {
49996
- const ast = parse(code, {
50000
+ const ast = parse$1(code, {
49997
50001
  loc: true,
49998
50002
  range: true,
49999
50003
  comment: true,
@@ -50120,7 +50124,7 @@ async function analyzeFile(filePath, includeAst = false) {
50120
50124
  const exports$1 = [];
50121
50125
  let ast;
50122
50126
  try {
50123
- ast = parse(content, {
50127
+ ast = parse$1(content, {
50124
50128
  loc: true,
50125
50129
  range: true,
50126
50130
  comment: true,
@@ -52599,7 +52603,7 @@ var repoMapCommand = {
52599
52603
  }
52600
52604
  };
52601
52605
 
52602
- // src/cli/repl/modes.ts
52606
+ // src/runtime/agent-modes.ts
52603
52607
  var AGENT_MODES = {
52604
52608
  ask: {
52605
52609
  id: "ask",
@@ -54880,8 +54884,8 @@ function formatToolSummary(toolName, input) {
54880
54884
  case "grep":
54881
54885
  case "search_files": {
54882
54886
  const pattern = String(input.pattern || "");
54883
- const path63 = input.path ? ` in ${input.path}` : "";
54884
- return `"${pattern}"${path63}`;
54887
+ const path65 = input.path ? ` in ${input.path}` : "";
54888
+ return `"${pattern}"${path65}`;
54885
54889
  }
54886
54890
  case "bash_exec": {
54887
54891
  const cmd = String(input.command || "");
@@ -54902,8 +54906,8 @@ function formatToolSummary(toolName, input) {
54902
54906
  function formatUrl(url) {
54903
54907
  try {
54904
54908
  const u = new URL(url);
54905
- const path63 = u.pathname.replace(/\/$/, "");
54906
- const display = path63 ? `${u.hostname} \u203A ${path63.slice(1)}` : u.hostname;
54909
+ const path65 = u.pathname.replace(/\/$/, "");
54910
+ const display = path65 ? `${u.hostname} \u203A ${path65.slice(1)}` : u.hostname;
54907
54911
  const max = Math.max(getTerminalWidth2() - 20, 50);
54908
54912
  return display.length > max ? display.slice(0, max - 1) + "\u2026" : display;
54909
54913
  } catch {
@@ -55083,6 +55087,12 @@ var RepeatedOutputSuppressor = class {
55083
55087
  // src/cli/repl/agent-loop.ts
55084
55088
  async function executeAgentTurn(session, userMessage, provider, toolRegistry, options = {}) {
55085
55089
  resetLineBuffer();
55090
+ session.runtime?.eventLog.record("turn.started", {
55091
+ sessionId: session.id,
55092
+ provider: session.config.provider.type,
55093
+ model: session.config.provider.model,
55094
+ mode: session.agentMode ?? (session.planMode ? "plan" : "build")
55095
+ });
55086
55096
  const messageSnapshot = session.messages.length;
55087
55097
  addMessage(session, { role: "user", content: userMessage });
55088
55098
  const executedTools = [];
@@ -55099,6 +55109,15 @@ async function executeAgentTurn(session, userMessage, provider, toolRegistry, op
55099
55109
  const readOnlyModeEnabled = session.planMode === true || activeMode?.readOnly === true;
55100
55110
  const strictPlanModeEnabled = readOnlyModeEnabled && session.config.agent.planModeStrict === true;
55101
55111
  const outputOffloadObservationEnabled = session.config.agent.outputOffload === true;
55112
+ const recordToolSkipped = (toolCall, reason) => {
55113
+ session.runtime?.eventLog.record("tool.skipped", {
55114
+ sessionId: session.id,
55115
+ tool: toolCall.name,
55116
+ toolCallId: toolCall.id,
55117
+ reason
55118
+ });
55119
+ options.onToolSkipped?.(toolCall, reason);
55120
+ };
55102
55121
  const buildQualityMetrics = () => computeTurnQualityMetrics({
55103
55122
  iterationsUsed: iteration,
55104
55123
  maxIterations,
@@ -55110,7 +55129,7 @@ async function executeAgentTurn(session, userMessage, provider, toolRegistry, op
55110
55129
  });
55111
55130
  const abortReturn = () => {
55112
55131
  session.messages.length = messageSnapshot;
55113
- return {
55132
+ const result2 = {
55114
55133
  content: finalContent,
55115
55134
  toolCalls: executedTools,
55116
55135
  usage: { inputTokens: totalInputTokens, outputTokens: totalOutputTokens },
@@ -55119,6 +55138,14 @@ async function executeAgentTurn(session, userMessage, provider, toolRegistry, op
55119
55138
  partialContent: finalContent || void 0,
55120
55139
  abortReason: "user_cancel"
55121
55140
  };
55141
+ session.runtime?.eventLog.record("turn.completed", {
55142
+ sessionId: session.id,
55143
+ aborted: true,
55144
+ toolsExecuted: executedTools.length,
55145
+ inputTokens: totalInputTokens,
55146
+ outputTokens: totalOutputTokens
55147
+ });
55148
+ return result2;
55122
55149
  };
55123
55150
  const allTools = toolRegistry.getToolDefinitionsForLLM();
55124
55151
  const tools = readOnlyModeEnabled ? strictPlanModeEnabled ? filterStrictPlanModeTools(allTools) : filterReadOnlyTools(allTools) : allTools;
@@ -55441,10 +55468,20 @@ ${tail}`;
55441
55468
  return abortReturn();
55442
55469
  }
55443
55470
  if (classification.kind === "provider_non_retryable") {
55471
+ session.runtime?.eventLog.record("turn.failed", {
55472
+ sessionId: session.id,
55473
+ error: classification.original instanceof Error ? classification.original.message : String(classification.original),
55474
+ toolsExecuted: executedTools.length
55475
+ });
55444
55476
  throw classification.original;
55445
55477
  }
55446
55478
  hadTurnError = true;
55447
55479
  const errorMsg = classification.message;
55480
+ session.runtime?.eventLog.record("turn.failed", {
55481
+ sessionId: session.id,
55482
+ error: errorMsg,
55483
+ toolsExecuted: executedTools.length
55484
+ });
55448
55485
  addMessage(session, {
55449
55486
  role: "assistant",
55450
55487
  content: `[Error during streaming: ${errorMsg}]`
@@ -55550,7 +55587,7 @@ ${tail}`;
55550
55587
  toolCall.id,
55551
55588
  `User explicitly requested MCP, but the model selected '${toolCall.name}' instead. Use an MCP tool (${availableMcpToolNames.join(", ")}) for this service access.`
55552
55589
  );
55553
- options.onToolSkipped?.(toolCall, "Use MCP tool instead of generic fetch");
55590
+ recordToolSkipped(toolCall, "Use MCP tool instead of generic fetch");
55554
55591
  continue;
55555
55592
  }
55556
55593
  if (shouldBlockShellMcpInspection(toolCall)) {
@@ -55558,7 +55595,7 @@ ${tail}`;
55558
55595
  toolCall.id,
55559
55596
  "Use the native mcp_list_servers tool to inspect configured and connected MCP services in this session. Do not shell out to `coco mcp ...` for runtime MCP diagnosis unless the user explicitly asked for the CLI command."
55560
55597
  );
55561
- options.onToolSkipped?.(toolCall, "Use mcp_list_servers instead of coco mcp CLI");
55598
+ recordToolSkipped(toolCall, "Use mcp_list_servers instead of coco mcp CLI");
55562
55599
  continue;
55563
55600
  }
55564
55601
  if (strictPlanModeEnabled && !STRICT_PLAN_MODE_ALLOWED_TOOLS.has(toolCall.name)) {
@@ -55566,7 +55603,7 @@ ${tail}`;
55566
55603
  toolCall.id,
55567
55604
  `Blocked by strict plan mode: tool '${toolCall.name}' is not read-only`
55568
55605
  );
55569
- options.onToolSkipped?.(toolCall, "Blocked by strict plan mode");
55606
+ recordToolSkipped(toolCall, "Blocked by strict plan mode");
55570
55607
  continue;
55571
55608
  }
55572
55609
  const trustPattern = getTrustPattern(toolCall.name, toolCall.input);
@@ -55579,7 +55616,7 @@ ${tail}`;
55579
55616
  } catch (confirmError) {
55580
55617
  options.onAfterConfirmation?.();
55581
55618
  declinedTools.set(toolCall.id, "Confirmation failed");
55582
- options.onToolSkipped?.(
55619
+ recordToolSkipped(
55583
55620
  toolCall,
55584
55621
  `Confirmation failed: ${confirmError instanceof Error ? confirmError.message : String(confirmError)}`
55585
55622
  );
@@ -55598,7 +55635,7 @@ ${tail}`;
55598
55635
  switch (confirmResult) {
55599
55636
  case "no":
55600
55637
  declinedTools.set(toolCall.id, "User declined");
55601
- options.onToolSkipped?.(toolCall, "User declined");
55638
+ recordToolSkipped(toolCall, "User declined");
55602
55639
  continue;
55603
55640
  case "abort":
55604
55641
  turnAborted = true;
@@ -55628,15 +55665,33 @@ ${tail}`;
55628
55665
  onToolStart: (toolCall, _index, _total) => {
55629
55666
  const originalIndex = response.toolCalls.findIndex((tc) => tc.id === toolCall.id) + 1;
55630
55667
  options.onToolStart?.(toolCall, originalIndex, totalTools);
55668
+ session.runtime?.eventLog.record("tool.started", {
55669
+ sessionId: session.id,
55670
+ tool: toolCall.name,
55671
+ toolCallId: toolCall.id,
55672
+ index: originalIndex,
55673
+ total: totalTools
55674
+ });
55675
+ },
55676
+ onToolEnd: (result2) => {
55677
+ session.runtime?.eventLog.record("tool.completed", {
55678
+ sessionId: session.id,
55679
+ tool: result2.name,
55680
+ toolCallId: result2.id,
55681
+ success: result2.result.success,
55682
+ duration: result2.duration
55683
+ });
55684
+ options.onToolEnd?.(result2);
55685
+ },
55686
+ onToolSkipped: (toolCall, reason) => {
55687
+ recordToolSkipped(toolCall, reason);
55631
55688
  },
55632
- onToolEnd: options.onToolEnd,
55633
- onToolSkipped: options.onToolSkipped,
55634
55689
  signal: options.signal,
55635
55690
  onPathAccessDenied: async (dirPath) => {
55636
55691
  options.onBeforeConfirmation?.();
55637
- const result = await promptAllowPath(dirPath);
55692
+ const result2 = await promptAllowPath(dirPath);
55638
55693
  options.onAfterConfirmation?.();
55639
- return result;
55694
+ return result2;
55640
55695
  },
55641
55696
  // Pass hooks through so PreToolUse/PostToolUse hooks fire during execution
55642
55697
  hookRegistry: options.hookRegistry,
@@ -55910,13 +55965,21 @@ I have reached the maximum iteration limit (${maxIterations}). The task may be i
55910
55965
  }
55911
55966
  }
55912
55967
  options.onStream?.({ type: "done" });
55913
- return {
55968
+ const result = {
55914
55969
  content: finalContent,
55915
55970
  toolCalls: executedTools,
55916
55971
  usage: { inputTokens: totalInputTokens, outputTokens: totalOutputTokens },
55917
55972
  quality: buildQualityMetrics(),
55918
55973
  aborted: false
55919
55974
  };
55975
+ session.runtime?.eventLog.record("turn.completed", {
55976
+ sessionId: session.id,
55977
+ aborted: false,
55978
+ toolsExecuted: executedTools.length,
55979
+ inputTokens: totalInputTokens,
55980
+ outputTokens: totalOutputTokens
55981
+ });
55982
+ return result;
55920
55983
  }
55921
55984
  function formatAbortSummary(executedTools) {
55922
55985
  if (executedTools.length === 0) return null;
@@ -56307,6 +56370,9 @@ var statsCommand = {
56307
56370
  console.log(` Model: ${chalk.cyan(session.config.provider.model)}`);
56308
56371
  console.log(` Endpoint: ${chalk.yellow(runtime.endpoint)}`);
56309
56372
  console.log(` Mode: ${session.agentMode ?? (session.planMode ? "plan" : "build")}`);
56373
+ if (session.runtime) {
56374
+ console.log(` Runtime events: ${chalk.yellow(String(session.runtime.eventLog.count()))}`);
56375
+ }
56310
56376
  console.log();
56311
56377
  console.log(chalk.dim(" Messages:"));
56312
56378
  console.log(chalk.dim(` user: ${userMessages}`));
@@ -57302,6 +57368,937 @@ function createSpinner(message) {
57302
57368
  // src/cli/repl/index.ts
57303
57369
  init_error_resilience();
57304
57370
  init_providers();
57371
+
57372
+ // src/runtime/agent-runtime.ts
57373
+ init_env();
57374
+
57375
+ // src/runtime/default-turn-runner.ts
57376
+ var DefaultRuntimeTurnRunner = class {
57377
+ async run(input, context) {
57378
+ const messages = [
57379
+ ...context.session.messages,
57380
+ {
57381
+ role: "user",
57382
+ content: input.content
57383
+ }
57384
+ ];
57385
+ const response = await context.provider.chat(messages, {
57386
+ model: input.options?.model,
57387
+ maxTokens: input.options?.maxTokens,
57388
+ temperature: input.options?.temperature,
57389
+ stopSequences: input.options?.stopSequences,
57390
+ system: context.session.instructions ?? input.options?.system,
57391
+ timeout: input.options?.timeout,
57392
+ signal: input.options?.signal,
57393
+ thinking: input.options?.thinking
57394
+ });
57395
+ return {
57396
+ sessionId: context.session.id,
57397
+ content: response.content,
57398
+ usage: response.usage,
57399
+ model: response.model,
57400
+ mode: context.session.mode
57401
+ };
57402
+ }
57403
+ };
57404
+ function createDefaultRuntimeTurnRunner() {
57405
+ return new DefaultRuntimeTurnRunner();
57406
+ }
57407
+ var InMemoryEventLog = class {
57408
+ events = [];
57409
+ record(type, data = {}) {
57410
+ const event = {
57411
+ id: randomUUID(),
57412
+ type,
57413
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
57414
+ data
57415
+ };
57416
+ this.events.push(event);
57417
+ return event;
57418
+ }
57419
+ list() {
57420
+ return [...this.events];
57421
+ }
57422
+ count() {
57423
+ return this.events.length;
57424
+ }
57425
+ clear() {
57426
+ this.events = [];
57427
+ }
57428
+ };
57429
+ var FileEventLog = class {
57430
+ constructor(filePath) {
57431
+ this.filePath = filePath;
57432
+ try {
57433
+ mkdirSync(dirname(filePath), { recursive: true });
57434
+ } catch {
57435
+ this.writable = false;
57436
+ }
57437
+ }
57438
+ filePath;
57439
+ memory = new InMemoryEventLog();
57440
+ writable = true;
57441
+ record(type, data = {}) {
57442
+ const event = this.memory.record(type, data);
57443
+ if (this.writable) {
57444
+ try {
57445
+ appendFileSync(this.filePath, JSON.stringify(event) + "\n", "utf-8");
57446
+ } catch {
57447
+ this.writable = false;
57448
+ }
57449
+ }
57450
+ return event;
57451
+ }
57452
+ list() {
57453
+ if (!this.writable) return this.memory.list();
57454
+ try {
57455
+ const raw = readFileSync(this.filePath, "utf-8");
57456
+ return raw.split("\n").filter(Boolean).flatMap((line) => {
57457
+ try {
57458
+ return [JSON.parse(line)];
57459
+ } catch {
57460
+ return [];
57461
+ }
57462
+ });
57463
+ } catch {
57464
+ return this.memory.list();
57465
+ }
57466
+ }
57467
+ count() {
57468
+ return this.list().length;
57469
+ }
57470
+ clear() {
57471
+ this.memory.clear();
57472
+ if (this.writable) {
57473
+ try {
57474
+ writeFileSync(this.filePath, "", "utf-8");
57475
+ } catch {
57476
+ this.writable = false;
57477
+ }
57478
+ }
57479
+ }
57480
+ };
57481
+ function createEventLog() {
57482
+ return new InMemoryEventLog();
57483
+ }
57484
+ function createFileEventLog(filePath) {
57485
+ return new FileEventLog(filePath);
57486
+ }
57487
+
57488
+ // src/runtime/permission-policy.ts
57489
+ var READ_ONLY_CATEGORIES = /* @__PURE__ */ new Set(["search", "web", "document"]);
57490
+ var WRITE_CATEGORIES = /* @__PURE__ */ new Set(["file", "git", "test", "build", "memory"]);
57491
+ var READ_ONLY_TOOL_NAMES = /* @__PURE__ */ new Set([
57492
+ "glob",
57493
+ "read_file",
57494
+ "list_dir",
57495
+ "tree",
57496
+ "grep",
57497
+ "find_in_file",
57498
+ "semantic_search",
57499
+ "codebase_map",
57500
+ "repo_context",
57501
+ "lsp_status",
57502
+ "lsp_document_symbols",
57503
+ "lsp_workspace_symbols",
57504
+ "lsp_definition",
57505
+ "lsp_references",
57506
+ "git_status",
57507
+ "git_log",
57508
+ "git_diff",
57509
+ "git_show",
57510
+ "git_branch",
57511
+ "recall_memory",
57512
+ "list_memories",
57513
+ "list_checkpoints",
57514
+ "spawnSimpleAgent",
57515
+ "checkAgentCapability"
57516
+ ]);
57517
+ var WRITE_CAPABLE_TOOL_NAMES = /* @__PURE__ */ new Set(["run_linter"]);
57518
+ var DESTRUCTIVE_TOOL_NAMES = /* @__PURE__ */ new Set([
57519
+ "bash_exec",
57520
+ "write_file",
57521
+ "edit_file",
57522
+ "delete_file",
57523
+ "restore_checkpoint",
57524
+ "git_commit",
57525
+ "git_push"
57526
+ ]);
57527
+ function riskForTool(tool) {
57528
+ if (READ_ONLY_TOOL_NAMES.has(tool.name)) return "read-only";
57529
+ if (DESTRUCTIVE_TOOL_NAMES.has(tool.name)) return "destructive";
57530
+ if (WRITE_CAPABLE_TOOL_NAMES.has(tool.name)) return "write";
57531
+ if (tool.category === "web") return "network";
57532
+ if (WRITE_CATEGORIES.has(tool.category)) return "write";
57533
+ if (tool.category === "quality") return "write";
57534
+ return "read-only";
57535
+ }
57536
+ var DefaultPermissionPolicy = class {
57537
+ canExecuteTool(mode, tool) {
57538
+ const definition = getAgentMode(mode);
57539
+ const risk = riskForTool(tool);
57540
+ const readOnlyTool = READ_ONLY_TOOL_NAMES.has(tool.name) || READ_ONLY_CATEGORIES.has(tool.category);
57541
+ if (definition.readOnly && !readOnlyTool) {
57542
+ return {
57543
+ allowed: false,
57544
+ reason: `${definition.label} mode is read-only; ${tool.name} is a ${tool.category} tool.`,
57545
+ risk
57546
+ };
57547
+ }
57548
+ if (risk === "destructive") {
57549
+ return {
57550
+ allowed: true,
57551
+ requiresConfirmation: true,
57552
+ reason: `${tool.name} can change repository state and should be confirmed.`,
57553
+ risk
57554
+ };
57555
+ }
57556
+ return { allowed: true, risk };
57557
+ }
57558
+ canExecuteToolInput(mode, tool, input) {
57559
+ if (tool.name !== "run_linter") {
57560
+ return this.canExecuteTool(mode, tool);
57561
+ }
57562
+ const definition = getAgentMode(mode);
57563
+ const fixEnabled = input["fix"] === true;
57564
+ const decision = fixEnabled ? { allowed: true, risk: "write" } : { allowed: true, risk: "read-only" };
57565
+ if (definition.readOnly && fixEnabled) {
57566
+ return {
57567
+ allowed: false,
57568
+ reason: `${definition.label} mode is read-only; run_linter with fix=true can modify files.`,
57569
+ risk: "write"
57570
+ };
57571
+ }
57572
+ return decision;
57573
+ }
57574
+ };
57575
+ function createPermissionPolicy() {
57576
+ return new DefaultPermissionPolicy();
57577
+ }
57578
+
57579
+ // src/runtime/provider-registry.ts
57580
+ init_providers();
57581
+ init_catalog();
57582
+ init_runtime_capabilities();
57583
+ var ProviderRegistry = class {
57584
+ listProviders() {
57585
+ return Object.values(PROVIDER_CATALOG);
57586
+ }
57587
+ getProvider(provider) {
57588
+ return getProviderCatalogEntry(provider);
57589
+ }
57590
+ listModels(provider) {
57591
+ return this.getProvider(provider).models;
57592
+ }
57593
+ getModel(provider, model2) {
57594
+ return getCatalogModel(provider, model2);
57595
+ }
57596
+ getDefaultModel(provider) {
57597
+ return getCatalogDefaultModel(provider);
57598
+ }
57599
+ getRecommendedModel(provider) {
57600
+ return getCatalogRecommendedModel(provider);
57601
+ }
57602
+ getCapability(provider, model2) {
57603
+ return getProviderRuntimeCapability(provider, model2);
57604
+ }
57605
+ async createProvider(provider, config = {}) {
57606
+ return createProvider(provider, config);
57607
+ }
57608
+ async probe(provider, model2, checkAvailability) {
57609
+ return probeProviderRuntimeCapability(provider, model2, checkAvailability);
57610
+ }
57611
+ };
57612
+ function createProviderRegistry() {
57613
+ return new ProviderRegistry();
57614
+ }
57615
+ function createSessionId() {
57616
+ return `rt_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;
57617
+ }
57618
+ function cloneSession(session) {
57619
+ return structuredClone(session);
57620
+ }
57621
+ var InMemoryRuntimeSessionStore = class {
57622
+ sessions = /* @__PURE__ */ new Map();
57623
+ create(options = {}) {
57624
+ const now = (/* @__PURE__ */ new Date()).toISOString();
57625
+ const session = {
57626
+ id: options.id ?? createSessionId(),
57627
+ createdAt: now,
57628
+ updatedAt: now,
57629
+ mode: options.mode ?? "ask",
57630
+ messages: options.messages ? options.messages.map((message) => ({ ...message })) : [],
57631
+ instructions: options.instructions,
57632
+ metadata: { ...options.metadata }
57633
+ };
57634
+ this.sessions.set(session.id, cloneSession(session));
57635
+ return cloneSession(session);
57636
+ }
57637
+ get(id) {
57638
+ const session = this.sessions.get(id);
57639
+ return session ? cloneSession(session) : void 0;
57640
+ }
57641
+ update(session) {
57642
+ const updated = {
57643
+ ...session,
57644
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
57645
+ messages: session.messages.map((message) => ({ ...message })),
57646
+ metadata: { ...session.metadata }
57647
+ };
57648
+ this.sessions.set(updated.id, cloneSession(updated));
57649
+ return cloneSession(updated);
57650
+ }
57651
+ list() {
57652
+ return [...this.sessions.values()].map(cloneSession);
57653
+ }
57654
+ delete(id) {
57655
+ return this.sessions.delete(id);
57656
+ }
57657
+ };
57658
+ function createRuntimeSessionStore() {
57659
+ return new InMemoryRuntimeSessionStore();
57660
+ }
57661
+
57662
+ // src/runtime/workflow-registry.ts
57663
+ function cloneWorkflow(workflow) {
57664
+ return {
57665
+ ...workflow,
57666
+ checks: [...workflow.checks],
57667
+ steps: workflow.steps.map((step) => ({
57668
+ ...step,
57669
+ requiredTools: [...step.requiredTools]
57670
+ }))
57671
+ };
57672
+ }
57673
+ var WorkflowCatalog = class {
57674
+ workflows = /* @__PURE__ */ new Map();
57675
+ constructor(workflows = DEFAULT_WORKFLOWS) {
57676
+ for (const workflow of workflows) {
57677
+ this.register(workflow);
57678
+ }
57679
+ }
57680
+ register(workflow) {
57681
+ this.workflows.set(workflow.id, cloneWorkflow(workflow));
57682
+ }
57683
+ get(id) {
57684
+ const workflow = this.workflows.get(id);
57685
+ return workflow ? cloneWorkflow(workflow) : void 0;
57686
+ }
57687
+ list() {
57688
+ return [...this.workflows.values()].map(cloneWorkflow).sort((a, b) => a.id.localeCompare(b.id));
57689
+ }
57690
+ createPlan(workflowId, input, eventLog) {
57691
+ const workflow = this.get(workflowId);
57692
+ if (!workflow) {
57693
+ throw new Error(`Unknown workflow: ${workflowId}`);
57694
+ }
57695
+ const plan = {
57696
+ id: `${workflowId}-${Date.now().toString(36)}`,
57697
+ workflowId,
57698
+ input,
57699
+ status: "planned",
57700
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
57701
+ };
57702
+ eventLog?.record("workflow.planned", {
57703
+ workflowId,
57704
+ planId: plan.id,
57705
+ replayable: workflow.replayable,
57706
+ checks: workflow.checks
57707
+ });
57708
+ return plan;
57709
+ }
57710
+ };
57711
+ var DEFAULT_WORKFLOWS = [
57712
+ {
57713
+ id: "architect-editor-verifier",
57714
+ name: "Architect / Editor / Verifier",
57715
+ description: "Plan read-only, apply approved changes, then verify and summarize risks.",
57716
+ inputSchema: "task: string; approvedPlan?: string",
57717
+ outputKind: "patch",
57718
+ replayable: true,
57719
+ checks: ["pnpm check", "diff summary", "review risks"],
57720
+ steps: [
57721
+ {
57722
+ id: "architect",
57723
+ description: "Inspect context and produce a read-only implementation plan.",
57724
+ requiredTools: ["repo_context", "read_file", "git_diff"],
57725
+ risk: "read-only"
57726
+ },
57727
+ {
57728
+ id: "editor",
57729
+ description: "Apply the approved plan without reinterpreting the objective.",
57730
+ requiredTools: ["read_file", "edit_file", "write_file"],
57731
+ risk: "write"
57732
+ },
57733
+ {
57734
+ id: "verifier",
57735
+ description: "Run checks, review diff, and report residual risk.",
57736
+ requiredTools: ["bash_exec", "git_diff", "review_code"],
57737
+ risk: "destructive"
57738
+ }
57739
+ ]
57740
+ },
57741
+ {
57742
+ id: "provider-diagnosis",
57743
+ name: "Provider Diagnosis",
57744
+ description: "Probe provider/model capabilities, endpoint strategy, credentials, and fallbacks.",
57745
+ inputSchema: "provider?: string; model?: string; live?: boolean",
57746
+ outputKind: "json",
57747
+ replayable: true,
57748
+ checks: ["provider capability matrix", "optional live probe"],
57749
+ steps: [
57750
+ {
57751
+ id: "capability",
57752
+ description: "Resolve catalog metadata and runtime endpoint strategy.",
57753
+ requiredTools: [],
57754
+ risk: "read-only"
57755
+ },
57756
+ {
57757
+ id: "fallbacks",
57758
+ description: "Suggest fallback provider/model choices when unsupported.",
57759
+ requiredTools: [],
57760
+ risk: "read-only"
57761
+ }
57762
+ ]
57763
+ },
57764
+ {
57765
+ id: "review-pr",
57766
+ name: "Review PR",
57767
+ description: "Review a branch or PR read-only and emit severity-ranked findings.",
57768
+ inputSchema: "target: string",
57769
+ outputKind: "markdown",
57770
+ replayable: true,
57771
+ checks: ["git diff", "tests gap review", "security review"],
57772
+ steps: [
57773
+ {
57774
+ id: "collect-diff",
57775
+ description: "Collect PR diff and related context.",
57776
+ requiredTools: ["git_diff", "repo_context"],
57777
+ risk: "read-only"
57778
+ },
57779
+ {
57780
+ id: "findings",
57781
+ description: "Produce prioritized findings with file and line references.",
57782
+ requiredTools: ["read_file", "review_code"],
57783
+ risk: "read-only"
57784
+ }
57785
+ ]
57786
+ },
57787
+ {
57788
+ id: "best-of-n",
57789
+ name: "Best Of N",
57790
+ description: "Run multiple isolated attempts, score them, and select a winning patch.",
57791
+ inputSchema: "task: string; attempts: number",
57792
+ outputKind: "patch",
57793
+ replayable: true,
57794
+ checks: ["worktree isolation", "checks pass", "diff risk score"],
57795
+ steps: [
57796
+ {
57797
+ id: "fanout",
57798
+ description: "Create isolated attempts in temporary worktrees.",
57799
+ requiredTools: ["git_status", "bash_exec"],
57800
+ risk: "destructive"
57801
+ },
57802
+ {
57803
+ id: "score",
57804
+ description: "Run checks and compare quality, cost, latency, and diff risk.",
57805
+ requiredTools: ["bash_exec", "git_diff"],
57806
+ risk: "destructive"
57807
+ },
57808
+ {
57809
+ id: "apply-winner",
57810
+ description: "Apply the winning patch only if conservative checks pass.",
57811
+ requiredTools: ["git_diff", "edit_file"],
57812
+ risk: "write"
57813
+ }
57814
+ ]
57815
+ },
57816
+ {
57817
+ id: "release",
57818
+ name: "Release",
57819
+ description: "Follow the project release skill: changelog, version bump, PR, merge, tag, publish verify.",
57820
+ inputSchema: "bump?: patch|minor|major",
57821
+ outputKind: "release",
57822
+ replayable: true,
57823
+ checks: ["pnpm check", "PR checks", "release.yml", "npm view"],
57824
+ steps: [
57825
+ {
57826
+ id: "preflight",
57827
+ description: "Verify branch, clean tree, GitHub auth, and remote state.",
57828
+ requiredTools: ["git_status", "bash_exec"],
57829
+ risk: "destructive"
57830
+ },
57831
+ {
57832
+ id: "version",
57833
+ description: "Update changelog and package versions using the release skill.",
57834
+ requiredTools: ["read_file", "edit_file", "bash_exec"],
57835
+ risk: "destructive"
57836
+ },
57837
+ {
57838
+ id: "publish",
57839
+ description: "Merge release PR, tag main, and verify release workflow outputs.",
57840
+ requiredTools: ["bash_exec"],
57841
+ risk: "destructive"
57842
+ }
57843
+ ]
57844
+ }
57845
+ ];
57846
+ function createWorkflowCatalog(workflows) {
57847
+ return new WorkflowCatalog(workflows);
57848
+ }
57849
+
57850
+ // src/runtime/workflow-engine.ts
57851
+ var WorkflowEngine = class {
57852
+ constructor(catalog = createWorkflowCatalog(), eventLog = createEventLog()) {
57853
+ this.catalog = catalog;
57854
+ this.eventLog = eventLog;
57855
+ }
57856
+ catalog;
57857
+ eventLog;
57858
+ handlers = /* @__PURE__ */ new Map();
57859
+ registerHandler(workflowId, handler) {
57860
+ if (!this.catalog.get(workflowId)) {
57861
+ throw new Error(`Unknown workflow: ${workflowId}`);
57862
+ }
57863
+ this.handlers.set(workflowId, handler);
57864
+ }
57865
+ createPlan(workflowId, input) {
57866
+ return this.catalog.createPlan(workflowId, input, this.eventLog);
57867
+ }
57868
+ async run(request) {
57869
+ const workflow = this.catalog.get(request.workflowId);
57870
+ if (!workflow) {
57871
+ throw new Error(`Unknown workflow: ${request.workflowId}`);
57872
+ }
57873
+ const handler = this.handlers.get(request.workflowId);
57874
+ if (!handler) {
57875
+ throw new Error(`No handler registered for workflow: ${request.workflowId}`);
57876
+ }
57877
+ const plan = request.plan ?? this.createPlan(request.workflowId, request.input);
57878
+ const startedAt = (/* @__PURE__ */ new Date()).toISOString();
57879
+ const runId = `${request.workflowId}-run-${Date.now().toString(36)}`;
57880
+ this.eventLog.record("workflow.started", {
57881
+ workflowId: request.workflowId,
57882
+ planId: plan.id,
57883
+ runId
57884
+ });
57885
+ try {
57886
+ const output = await handler(request.input, {
57887
+ workflow,
57888
+ plan,
57889
+ eventLog: this.eventLog
57890
+ });
57891
+ const completedAt = (/* @__PURE__ */ new Date()).toISOString();
57892
+ const result = {
57893
+ id: runId,
57894
+ workflowId: request.workflowId,
57895
+ status: "completed",
57896
+ output,
57897
+ startedAt,
57898
+ completedAt
57899
+ };
57900
+ this.eventLog.record("workflow.completed", {
57901
+ workflowId: request.workflowId,
57902
+ planId: plan.id,
57903
+ runId
57904
+ });
57905
+ return result;
57906
+ } catch (error) {
57907
+ const completedAt = (/* @__PURE__ */ new Date()).toISOString();
57908
+ const message = error instanceof Error ? error.message : String(error);
57909
+ this.eventLog.record("workflow.failed", {
57910
+ workflowId: request.workflowId,
57911
+ planId: plan.id,
57912
+ runId,
57913
+ error: message
57914
+ });
57915
+ return {
57916
+ id: runId,
57917
+ workflowId: request.workflowId,
57918
+ status: "failed",
57919
+ output: null,
57920
+ startedAt,
57921
+ completedAt,
57922
+ error: message
57923
+ };
57924
+ }
57925
+ }
57926
+ };
57927
+ function createWorkflowEngine(catalog, eventLog) {
57928
+ return new WorkflowEngine(catalog, eventLog);
57929
+ }
57930
+
57931
+ // src/runtime/agent-runtime.ts
57932
+ var AgentRuntime = class {
57933
+ constructor(options) {
57934
+ this.options = options;
57935
+ this.providerRegistry = createProviderRegistry();
57936
+ this.toolRegistry = options.toolRegistry ?? createFullToolRegistry();
57937
+ this.sessionStore = options.sessionStore;
57938
+ this.runtimeSessionStore = options.runtimeSessionStore ?? createRuntimeSessionStore();
57939
+ this.eventLog = options.eventLog ?? (options.eventLogPath ? createFileEventLog(options.eventLogPath) : createEventLog());
57940
+ this.workflowEngine = options.workflowEngine ?? createWorkflowEngine(void 0, this.eventLog);
57941
+ this.permissionPolicy = options.permissionPolicy ?? createPermissionPolicy();
57942
+ this.turnRunner = options.turnRunner ?? createDefaultRuntimeTurnRunner();
57943
+ this.providerType = options.providerType;
57944
+ this.model = options.model ?? options.providerConfig?.model ?? getDefaultModel(options.providerType);
57945
+ }
57946
+ options;
57947
+ providerRegistry;
57948
+ toolRegistry;
57949
+ sessionStore;
57950
+ runtimeSessionStore;
57951
+ workflowEngine;
57952
+ permissionPolicy;
57953
+ eventLog;
57954
+ turnRunner;
57955
+ providerType;
57956
+ model;
57957
+ provider;
57958
+ async initialize() {
57959
+ const providerInjected = Boolean(this.options.provider);
57960
+ const provider = this.options.provider ?? await this.providerRegistry.createProvider(this.providerType, {
57961
+ ...this.options.providerConfig,
57962
+ model: this.getModel()
57963
+ });
57964
+ this.provider = provider;
57965
+ this.publishToGlobalBridge(provider);
57966
+ this.eventLog.record(providerInjected ? "provider.attached" : "provider.created", {
57967
+ provider: this.providerType,
57968
+ model: this.getModel(),
57969
+ createdByRuntime: !providerInjected
57970
+ });
57971
+ this.eventLog.record("runtime.initialized", { snapshot: this.snapshot() });
57972
+ }
57973
+ getModel() {
57974
+ return this.model;
57975
+ }
57976
+ updateProvider(providerType, model2, provider) {
57977
+ this.providerType = providerType;
57978
+ this.model = model2 ?? getDefaultModel(providerType);
57979
+ this.provider = provider;
57980
+ this.publishToGlobalBridge(provider);
57981
+ this.eventLog.record("provider.updated", {
57982
+ provider: this.providerType,
57983
+ model: this.model
57984
+ });
57985
+ }
57986
+ publishToGlobalBridge(provider) {
57987
+ if (this.options.publishToGlobalBridge !== true) return;
57988
+ setAgentProvider(provider);
57989
+ setAgentToolRegistry(this.toolRegistry);
57990
+ }
57991
+ snapshot() {
57992
+ const capability = this.providerRegistry.getCapability(this.providerType, this.getModel());
57993
+ const toolNames = this.toolRegistry.getAll().map((tool) => tool.name).sort();
57994
+ return {
57995
+ provider: {
57996
+ type: this.providerType,
57997
+ model: this.getModel(),
57998
+ capability
57999
+ },
58000
+ tools: {
58001
+ count: toolNames.length,
58002
+ names: toolNames
58003
+ },
58004
+ modes: listAgentModes()
58005
+ };
58006
+ }
58007
+ createSession(options = {}) {
58008
+ const session = this.runtimeSessionStore.create(options);
58009
+ this.eventLog.record("session.created", {
58010
+ sessionId: session.id,
58011
+ mode: session.mode,
58012
+ metadataKeys: Object.keys(session.metadata).sort()
58013
+ });
58014
+ return session;
58015
+ }
58016
+ getSession(sessionId) {
58017
+ return this.runtimeSessionStore.get(sessionId);
58018
+ }
58019
+ listSessions() {
58020
+ return this.runtimeSessionStore.list();
58021
+ }
58022
+ async runTurn(input) {
58023
+ const provider = this.provider;
58024
+ if (!provider) {
58025
+ throw new Error("Runtime provider is not initialized.");
58026
+ }
58027
+ const session = input.sessionId ? this.runtimeSessionStore.get(input.sessionId) : this.createSession({ mode: input.mode, metadata: input.metadata });
58028
+ if (!session) {
58029
+ throw new Error(`Runtime session not found: ${input.sessionId}`);
58030
+ }
58031
+ const effectiveSession = input.mode && input.mode !== session.mode ? { ...session, mode: input.mode } : session;
58032
+ this.eventLog.record("turn.started", {
58033
+ sessionId: effectiveSession.id,
58034
+ provider: this.providerType,
58035
+ model: this.getModel(),
58036
+ mode: effectiveSession.mode,
58037
+ runtimeApi: true
58038
+ });
58039
+ try {
58040
+ const result = await this.turnRunner.run(input, {
58041
+ runtime: this,
58042
+ session: effectiveSession,
58043
+ provider,
58044
+ toolRegistry: this.toolRegistry,
58045
+ permissionPolicy: this.permissionPolicy,
58046
+ eventLog: this.eventLog
58047
+ });
58048
+ const updatedSession = this.runtimeSessionStore.update({
58049
+ ...effectiveSession,
58050
+ messages: [
58051
+ ...effectiveSession.messages,
58052
+ { role: "user", content: input.content },
58053
+ { role: "assistant", content: result.content }
58054
+ ]
58055
+ });
58056
+ this.eventLog.record("session.updated", {
58057
+ sessionId: updatedSession.id,
58058
+ messages: updatedSession.messages.length
58059
+ });
58060
+ this.eventLog.record("turn.completed", {
58061
+ sessionId: updatedSession.id,
58062
+ inputTokens: result.usage.inputTokens,
58063
+ outputTokens: result.usage.outputTokens,
58064
+ model: result.model,
58065
+ runtimeApi: true
58066
+ });
58067
+ return { ...result, sessionId: updatedSession.id, mode: updatedSession.mode };
58068
+ } catch (error) {
58069
+ this.eventLog.record("turn.failed", {
58070
+ sessionId: effectiveSession.id,
58071
+ error: error instanceof Error ? error.message : String(error),
58072
+ runtimeApi: true
58073
+ });
58074
+ throw error;
58075
+ }
58076
+ }
58077
+ async *streamTurn(input) {
58078
+ const provider = this.provider;
58079
+ if (!provider) {
58080
+ throw new Error("Runtime provider is not initialized.");
58081
+ }
58082
+ const session = input.sessionId ? this.runtimeSessionStore.get(input.sessionId) : this.createSession({ mode: input.mode, metadata: input.metadata });
58083
+ if (!session) {
58084
+ throw new Error(`Runtime session not found: ${input.sessionId}`);
58085
+ }
58086
+ const effectiveSession = input.mode && input.mode !== session.mode ? { ...session, mode: input.mode } : session;
58087
+ const messages = [
58088
+ ...effectiveSession.messages,
58089
+ {
58090
+ role: "user",
58091
+ content: input.content
58092
+ }
58093
+ ];
58094
+ this.eventLog.record("turn.started", {
58095
+ sessionId: effectiveSession.id,
58096
+ provider: this.providerType,
58097
+ model: this.getModel(),
58098
+ mode: effectiveSession.mode,
58099
+ streaming: true,
58100
+ runtimeApi: true
58101
+ });
58102
+ let content = "";
58103
+ let completed = false;
58104
+ let failed = false;
58105
+ try {
58106
+ for await (const chunk of provider.stream(messages, {
58107
+ model: input.options?.model,
58108
+ maxTokens: input.options?.maxTokens,
58109
+ temperature: input.options?.temperature,
58110
+ stopSequences: input.options?.stopSequences,
58111
+ system: effectiveSession.instructions ?? input.options?.system,
58112
+ timeout: input.options?.timeout,
58113
+ signal: input.options?.signal,
58114
+ thinking: input.options?.thinking
58115
+ })) {
58116
+ if (chunk.type === "text" && chunk.text) {
58117
+ content += chunk.text;
58118
+ yield {
58119
+ type: "text",
58120
+ sessionId: effectiveSession.id,
58121
+ text: chunk.text
58122
+ };
58123
+ }
58124
+ }
58125
+ const updatedSession = this.runtimeSessionStore.update({
58126
+ ...effectiveSession,
58127
+ messages: [
58128
+ ...effectiveSession.messages,
58129
+ { role: "user", content: input.content },
58130
+ { role: "assistant", content }
58131
+ ]
58132
+ });
58133
+ const result = {
58134
+ sessionId: updatedSession.id,
58135
+ content,
58136
+ usage: {
58137
+ inputTokens: provider.countTokens(input.content),
58138
+ outputTokens: provider.countTokens(content),
58139
+ estimated: true
58140
+ },
58141
+ model: input.options?.model ?? this.getModel(),
58142
+ mode: updatedSession.mode
58143
+ };
58144
+ this.eventLog.record("session.updated", {
58145
+ sessionId: updatedSession.id,
58146
+ messages: updatedSession.messages.length
58147
+ });
58148
+ this.eventLog.record("turn.completed", {
58149
+ sessionId: updatedSession.id,
58150
+ inputTokens: result.usage.inputTokens,
58151
+ outputTokens: result.usage.outputTokens,
58152
+ model: result.model,
58153
+ streaming: true,
58154
+ runtimeApi: true
58155
+ });
58156
+ completed = true;
58157
+ yield { type: "done", sessionId: updatedSession.id, result };
58158
+ } catch (error) {
58159
+ failed = true;
58160
+ const message = error instanceof Error ? error.message : String(error);
58161
+ this.eventLog.record("turn.failed", {
58162
+ sessionId: effectiveSession.id,
58163
+ error: message,
58164
+ streaming: true,
58165
+ runtimeApi: true
58166
+ });
58167
+ yield {
58168
+ type: "error",
58169
+ sessionId: effectiveSession.id,
58170
+ error: message
58171
+ };
58172
+ } finally {
58173
+ if (!completed && !failed) {
58174
+ this.eventLog.record("turn.cancelled", {
58175
+ sessionId: effectiveSession.id,
58176
+ outputTokens: provider.countTokens(content),
58177
+ streaming: true,
58178
+ runtimeApi: true
58179
+ });
58180
+ }
58181
+ }
58182
+ }
58183
+ async executeTool(input) {
58184
+ const startedAt = performance.now();
58185
+ const session = input.sessionId ? this.getSession(input.sessionId) : void 0;
58186
+ if (input.sessionId && !session) {
58187
+ const decision2 = {
58188
+ allowed: false,
58189
+ reason: `Runtime session not found: ${input.sessionId}`,
58190
+ risk: "read-only"
58191
+ };
58192
+ this.eventLog.record("tool.blocked", {
58193
+ sessionId: input.sessionId,
58194
+ mode: input.mode ?? "ask",
58195
+ tool: input.toolName,
58196
+ reason: decision2.reason,
58197
+ runtimeApi: true
58198
+ });
58199
+ return {
58200
+ toolName: input.toolName,
58201
+ success: false,
58202
+ error: decision2.reason,
58203
+ duration: performance.now() - startedAt,
58204
+ decision: decision2
58205
+ };
58206
+ }
58207
+ const mode = input.mode ?? session?.mode ?? "ask";
58208
+ const tool = this.toolRegistry.get(input.toolName);
58209
+ if (!tool) {
58210
+ const decision2 = {
58211
+ allowed: false,
58212
+ reason: "Tool not registered.",
58213
+ risk: "read-only"
58214
+ };
58215
+ this.eventLog.record("tool.blocked", {
58216
+ sessionId: input.sessionId,
58217
+ mode,
58218
+ tool: input.toolName,
58219
+ reason: decision2.reason,
58220
+ runtimeApi: true
58221
+ });
58222
+ return {
58223
+ toolName: input.toolName,
58224
+ success: false,
58225
+ error: decision2.reason,
58226
+ duration: performance.now() - startedAt,
58227
+ decision: decision2
58228
+ };
58229
+ }
58230
+ const decision = this.permissionPolicy.canExecuteToolInput ? this.permissionPolicy.canExecuteToolInput(mode, tool, input.input) : this.permissionPolicy.canExecuteTool(mode, tool);
58231
+ if (!decision.allowed || decision.requiresConfirmation && input.confirmed !== true) {
58232
+ const reason = decision.reason ?? (decision.requiresConfirmation ? "Tool requires explicit runtime confirmation." : "Tool is not allowed.");
58233
+ this.eventLog.record("tool.blocked", {
58234
+ sessionId: input.sessionId,
58235
+ mode,
58236
+ tool: input.toolName,
58237
+ reason,
58238
+ risk: decision.risk,
58239
+ requiresConfirmation: decision.requiresConfirmation,
58240
+ runtimeApi: true
58241
+ });
58242
+ return {
58243
+ toolName: input.toolName,
58244
+ success: false,
58245
+ error: reason,
58246
+ duration: performance.now() - startedAt,
58247
+ decision
58248
+ };
58249
+ }
58250
+ this.eventLog.record("tool.started", {
58251
+ sessionId: input.sessionId,
58252
+ mode,
58253
+ tool: input.toolName,
58254
+ risk: decision.risk,
58255
+ runtimeApi: true,
58256
+ metadataKeys: Object.keys(input.metadata ?? {}).sort()
58257
+ });
58258
+ const result = await this.toolRegistry.execute(input.toolName, input.input);
58259
+ this.eventLog.record("tool.completed", {
58260
+ sessionId: input.sessionId,
58261
+ mode,
58262
+ tool: input.toolName,
58263
+ success: result.success,
58264
+ duration: result.duration,
58265
+ runtimeApi: true
58266
+ });
58267
+ return {
58268
+ toolName: input.toolName,
58269
+ success: result.success,
58270
+ output: result.data,
58271
+ error: result.error,
58272
+ duration: result.duration,
58273
+ decision
58274
+ };
58275
+ }
58276
+ assertToolAllowed(mode, toolName, input) {
58277
+ const tool = this.toolRegistry.get(toolName);
58278
+ if (!tool) {
58279
+ this.eventLog.record("tool.blocked", {
58280
+ mode,
58281
+ tool: toolName,
58282
+ reason: "Tool not registered."
58283
+ });
58284
+ return false;
58285
+ }
58286
+ const decision = input && this.permissionPolicy.canExecuteToolInput ? this.permissionPolicy.canExecuteToolInput(mode, tool, input) : this.permissionPolicy.canExecuteTool(mode, tool);
58287
+ this.eventLog.record(decision.allowed ? "tool.allowed" : "tool.blocked", {
58288
+ mode,
58289
+ tool: toolName,
58290
+ ...decision
58291
+ });
58292
+ return decision.allowed;
58293
+ }
58294
+ };
58295
+ async function createAgentRuntime(options) {
58296
+ const runtime = new AgentRuntime(options);
58297
+ await runtime.initialize();
58298
+ return runtime;
58299
+ }
58300
+
58301
+ // src/cli/repl/index.ts
57305
58302
  init_version();
57306
58303
  init_trust_store();
57307
58304
 
@@ -57854,9 +58851,15 @@ async function startRepl(options = {}) {
57854
58851
  loadFullAccessPreference2(),
57855
58852
  loadFullPowerRiskPreference2()
57856
58853
  ]);
57857
- const toolRegistry = createFullToolRegistry();
57858
- setAgentProvider(provider);
57859
- setAgentToolRegistry(toolRegistry);
58854
+ const runtime = await createAgentRuntime({
58855
+ providerType: internalProviderId,
58856
+ model: session.config.provider.model || void 0,
58857
+ provider,
58858
+ eventLogPath: path39__default.join(projectPath, ".coco", "events", `${session.id}.jsonl`),
58859
+ publishToGlobalBridge: true
58860
+ });
58861
+ session.runtime = runtime;
58862
+ const toolRegistry = runtime.toolRegistry;
57860
58863
  try {
57861
58864
  const { createUnifiedSkillRegistry: createUnifiedSkillRegistry2 } = await Promise.resolve().then(() => (init_skills(), skills_exports));
57862
58865
  const { getBuiltinSkillsForDiscovery: getBuiltinSkillsForDiscovery2 } = await Promise.resolve().then(() => (init_skills2(), skills_exports2));
@@ -58040,7 +59043,7 @@ async function startRepl(options = {}) {
58040
59043
  let consecutiveErrors = 0;
58041
59044
  const AUTO_SWITCH_THRESHOLD = 2;
58042
59045
  const autoSwitchHistory = /* @__PURE__ */ new Set();
58043
- const enableAutoSwitchProvider = session.config.agent.enableAutoSwitchProvider === true;
59046
+ const enableAutoSwitchProvider = session.config.agent?.enableAutoSwitchProvider === true;
58044
59047
  const buildReplayMessage = (message) => {
58045
59048
  if (typeof message === "string") {
58046
59049
  const trimmed = message.trim();
@@ -58143,7 +59146,8 @@ async function startRepl(options = {}) {
58143
59146
  provider = nextProvider;
58144
59147
  session.config.provider.type = candidate;
58145
59148
  session.config.provider.model = getDefaultModel(candidate);
58146
- setAgentProvider(provider);
59149
+ runtime.updateProvider(nextInternalId, session.config.provider.model, provider);
59150
+ session.runtime = runtime;
58147
59151
  initializeContextManager(session, provider);
58148
59152
  llmClassifier = createLLMClassifier2(provider);
58149
59153
  autoSwitchHistory.add(edge);
@@ -58205,7 +59209,12 @@ async function startRepl(options = {}) {
58205
59209
  project: session.config.provider.project ?? process.env["VERTEX_PROJECT"] ?? process.env["GOOGLE_CLOUD_PROJECT"] ?? process.env["GCLOUD_PROJECT"],
58206
59210
  location: session.config.provider.location ?? process.env["VERTEX_LOCATION"] ?? process.env["GOOGLE_CLOUD_LOCATION"]
58207
59211
  });
58208
- setAgentProvider(provider);
59212
+ runtime.updateProvider(
59213
+ newInternalId,
59214
+ session.config.provider.model || void 0,
59215
+ provider
59216
+ );
59217
+ session.runtime = runtime;
58209
59218
  initializeContextManager(session, provider);
58210
59219
  } catch (err) {
58211
59220
  session.config.provider.type = prevProviderType;
@@ -59118,9 +60127,15 @@ ${stdinContent}
59118
60127
  const provider = await createProvider(providerType, {
59119
60128
  model: session.config.provider.model || void 0
59120
60129
  });
59121
- const toolRegistry = createFullToolRegistry();
59122
- setAgentProvider(provider);
59123
- setAgentToolRegistry(toolRegistry);
60130
+ const runtime = await createAgentRuntime({
60131
+ providerType,
60132
+ model: session.config.provider.model || void 0,
60133
+ provider,
60134
+ eventLogPath: path39__default.join(options.projectPath, ".coco", "events", `${session.id}.jsonl`),
60135
+ publishToGlobalBridge: true
60136
+ });
60137
+ session.runtime = runtime;
60138
+ const toolRegistry = runtime.toolRegistry;
59124
60139
  await loadAllowedPaths(options.projectPath);
59125
60140
  await initializeContextManager(session, provider);
59126
60141
  const result = await executeAgentTurn(session, task, provider, toolRegistry, {