@akanjs/cli 3.0.0-beta.16 → 3.0.0-beta.17

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.
@@ -1,7 +1,9 @@
1
1
  // @bun
2
2
  import {
3
- SubagentPool2
4
- } from "./index-jgrnpt6y.js";
3
+ SubagentPool2,
4
+ akanCodePaths2,
5
+ McpServerConfig
6
+ } from "./index-qt8dqgnf.js";
5
7
  import {
6
8
  stripAnsi
7
9
  } from "./index-7md2g9vw.js";
@@ -9,7 +11,7 @@ import {
9
11
  akanCodeModel2,
10
12
  akanCodeModelSupportsImages2,
11
13
  akanCodeModelWarnings2
12
- } from "./index-wfwknnje.js";
14
+ } from "./index-jwrpsrg3.js";
13
15
 
14
16
  // pkgs/@akanjs/devkit/codeAgent/agent/CodeAgent.ts
15
17
  import {
@@ -639,31 +641,12 @@ class MailToolPack2 {
639
641
  }
640
642
 
641
643
  // pkgs/@akanjs/devkit/codeAgent/tools/McpToolPack.ts
642
- import { existsSync as existsSync5, readFileSync } from "fs";
643
- import { codeAgentClip, codeAgentOutputChars } from "akanjs/common";
644
+ import {
645
+ codeAgentClip,
646
+ codeAgentOutputChars
647
+ } from "akanjs/common";
644
648
  import { Type as Type3 } from "typebox";
645
649
 
646
- // pkgs/@akanjs/devkit/codeAgent/agent/akanCodePaths.ts
647
- import { existsSync as existsSync4 } from "fs";
648
- import { homedir as homedir2 } from "os";
649
- import path4 from "path";
650
- var builtinSkillsDir = () => {
651
- const candidates = [path4.join(import.meta.dir, "skills"), path4.join(import.meta.dir, "..", "skills")];
652
- return candidates.find((candidate) => existsSync4(candidate));
653
- };
654
- var akanCodePaths2 = {
655
- workspaceDir: (workspaceRoot) => path4.join(workspaceRoot, ".akan", "code"),
656
- sessionsDir: (workspaceRoot) => path4.join(workspaceRoot, ".akan", "code", "sessions"),
657
- extensionsDir: (workspaceRoot) => path4.join(workspaceRoot, ".akan", "code", "extensions"),
658
- skillsDir: (workspaceRoot) => path4.join(workspaceRoot, ".akan", "code", "skills"),
659
- mailDir: (workspaceRoot) => path4.join(workspaceRoot, ".akan", "code", "mail"),
660
- builtinSkillsDir,
661
- mcpFile: (workspaceRoot) => path4.join(workspaceRoot, ".akan", "code", "mcp.json"),
662
- globalDir: () => path4.join(homedir2(), ".akan", "code"),
663
- authFile: () => path4.join(homedir2(), ".akan", "code", "auth.json"),
664
- modelsFile: () => path4.join(homedir2(), ".akan", "code", "models.json")
665
- };
666
-
667
650
  // pkgs/@akanjs/devkit/codeAgent/tools/McpClient.ts
668
651
  var protocolVersion = "2025-06-18";
669
652
 
@@ -804,29 +787,34 @@ class McpClient2 {
804
787
 
805
788
  // pkgs/@akanjs/devkit/codeAgent/tools/McpToolPack.ts
806
789
  class McpToolPack2 {
807
- #options;
808
790
  #clients = [];
809
- constructor(options) {
810
- this.#options = options;
811
- }
791
+ #status = [];
792
+ constructor() {}
812
793
  static async connect(options) {
813
794
  const refs = McpToolPack2.#refs(options);
814
795
  if (!refs.length)
815
796
  return;
816
- const pack = new McpToolPack2(options);
797
+ const pack = new McpToolPack2;
817
798
  for (const ref of refs) {
799
+ const base = { name: ref.name, transport: ref.transport, target: McpServerConfig.targetOf(ref) };
818
800
  try {
819
801
  const client = await new McpClient2(ref).connect();
820
- pack.#clients.push({ client, tools: await client.listTools() });
802
+ const tools = await client.listTools();
803
+ pack.#clients.push({ client, tools });
804
+ pack.#status.push({ ...base, tools: tools.map((tool) => McpToolPack2.#nameOf(ref.name, tool.name)) });
821
805
  } catch (error) {
822
806
  options.onNotice?.(`MCP server "${ref.name}" is unavailable: ${String(error)}`);
807
+ pack.#status.push({ ...base, tools: [], error: String(error) });
823
808
  }
824
809
  }
825
- return pack.#clients.length ? pack : undefined;
810
+ return pack;
826
811
  }
827
812
  get toolNames() {
828
813
  return this.#clients.flatMap(({ client, tools }) => tools.map((tool) => McpToolPack2.#nameOf(client.ref.name, tool.name)));
829
814
  }
815
+ get status() {
816
+ return this.#status;
817
+ }
830
818
  extension() {
831
819
  return { name: "akan-mcp", factory: (pi) => this.#register(pi) };
832
820
  }
@@ -863,29 +851,7 @@ class McpToolPack2 {
863
851
  if (options.profile.tools.mcp === "off")
864
852
  return [];
865
853
  const declared = Array.isArray(options.profile.tools.mcp) ? options.profile.tools.mcp : [];
866
- return [...McpToolPack2.#fromFile(options.workspaceRoot), ...declared];
867
- }
868
- static #fromFile(workspaceRoot) {
869
- const file = akanCodePaths2.mcpFile(workspaceRoot);
870
- if (!existsSync5(file))
871
- return [];
872
- try {
873
- const parsed = JSON.parse(readFileSync(file, "utf8"));
874
- const entries = Object.entries(parsed.mcpServers ?? parsed.servers ?? {});
875
- return entries.filter(([, entry]) => !entry.disabled).map(([name, entry]) => {
876
- const transport = entry.url ? "http" : "stdio";
877
- return {
878
- name,
879
- transport,
880
- ...entry.command ? { command: entry.command } : {},
881
- ...entry.args ? { args: entry.args } : {},
882
- ...entry.url ? { url: entry.url } : {},
883
- ...entry.env ? { env: entry.env } : {}
884
- };
885
- });
886
- } catch {
887
- return [];
888
- }
854
+ return [...McpServerConfig.read(options.workspaceRoot), ...declared];
889
855
  }
890
856
  }
891
857
 
@@ -1098,6 +1064,7 @@ class AkanCodePlugins2 {
1098
1064
  ...options.onNotice ? { onNotice: options.onNotice } : {}
1099
1065
  });
1100
1066
  const dispose = () => mcp?.close();
1067
+ const mcpStatus = mcp?.status ?? [];
1101
1068
  const web = new WebToolPack2({ profile: options.profile });
1102
1069
  const webExtension = web.extension();
1103
1070
  const sessions = new SessionToolPack2({
@@ -1113,6 +1080,7 @@ class AkanCodePlugins2 {
1113
1080
  return {
1114
1081
  extensions: [mcp?.extension(), webExtension, sessionExtension, mailExtension].filter((entry) => !!entry),
1115
1082
  toolNames: [...mcp?.toolNames ?? [], ...web.names(), ...sessions.names(), ...mail.names()],
1083
+ mcp: mcpStatus,
1116
1084
  dispose
1117
1085
  };
1118
1086
  const readOnly = !options.profile.tools.builtin.includes("write");
@@ -1127,7 +1095,8 @@ class AkanCodePlugins2 {
1127
1095
  cwd: options.cwd,
1128
1096
  parent: options.profile,
1129
1097
  depth: options.depth,
1130
- ...options.onNotice ? { onNotice: options.onNotice } : {}
1098
+ ...options.onNotice ? { onNotice: options.onNotice } : {},
1099
+ ...options.onAgents ? { onAgents: options.onAgents } : {}
1131
1100
  });
1132
1101
  if (subagent)
1133
1102
  extensions.push(subagent);
@@ -1155,6 +1124,7 @@ class AkanCodePlugins2 {
1155
1124
  ...sessions.names(),
1156
1125
  ...mail.names()
1157
1126
  ],
1127
+ mcp: mcpStatus,
1158
1128
  dispose
1159
1129
  };
1160
1130
  }
@@ -1184,36 +1154,31 @@ class AkanCodePlugins2 {
1184
1154
  }
1185
1155
 
1186
1156
  // pkgs/@akanjs/devkit/codeAgent/agent/AkanCodeServices.ts
1187
- import { existsSync as existsSync9, mkdirSync as mkdirSync2 } from "fs";
1188
- import {
1189
- AuthStorage,
1190
- ModelRegistry,
1191
- SessionManager as SessionManager2,
1192
- SettingsManager
1193
- } from "@earendil-works/pi-coding-agent";
1157
+ import { existsSync as existsSync7, mkdirSync } from "fs";
1158
+ import { ModelRuntime, SessionManager as SessionManager2, SettingsManager } from "@earendil-works/pi-coding-agent";
1194
1159
 
1195
1160
  // pkgs/@akanjs/devkit/codeAgent/tools/AkanEnvKeys.ts
1196
- import { existsSync as existsSync6, readFileSync as readFileSync2 } from "fs";
1197
- import path5 from "path";
1161
+ import { existsSync as existsSync4, readFileSync } from "fs";
1162
+ import path4 from "path";
1198
1163
 
1199
1164
  class AkanEnvKeys2 {
1200
- static apply(authStorage, workspaceRoot) {
1165
+ static async apply(runtime, workspaceRoot) {
1201
1166
  const applied = [];
1202
1167
  for (const [name, value] of AkanEnvKeys2.#entries(workspaceRoot)) {
1203
1168
  const provider = AkanEnvKeys2.#providerOf(name);
1204
1169
  if (!provider || !value)
1205
1170
  continue;
1206
- authStorage.setRuntimeApiKey(provider, value);
1171
+ await runtime.setRuntimeApiKey(provider, value);
1207
1172
  applied.push(provider);
1208
1173
  }
1209
1174
  return applied;
1210
1175
  }
1211
1176
  static #entries(workspaceRoot) {
1212
1177
  const fromProcess = Object.entries(process.env).filter(([, value]) => typeof value === "string");
1213
- const file = path5.join(workspaceRoot, ".env");
1214
- if (!existsSync6(file))
1178
+ const file = path4.join(workspaceRoot, ".env");
1179
+ if (!existsSync4(file))
1215
1180
  return fromProcess;
1216
- const fromFile = readFileSync2(file, "utf8").split(`
1181
+ const fromFile = readFileSync(file, "utf8").split(`
1217
1182
  `).map((line) => line.trim()).filter((line) => line && !line.startsWith("#") && line.includes("=")).map((line) => {
1218
1183
  const index = line.indexOf("=");
1219
1184
  return [
@@ -1229,89 +1194,82 @@ class AkanEnvKeys2 {
1229
1194
  }
1230
1195
  }
1231
1196
 
1232
- // pkgs/@akanjs/devkit/codeAgent/agent/AkanAuthStorageBackend.ts
1233
- import {
1234
- closeSync,
1235
- existsSync as existsSync7,
1236
- mkdirSync,
1237
- openSync,
1238
- readFileSync as readFileSync3,
1239
- renameSync,
1240
- unlinkSync,
1241
- writeFileSync
1242
- } from "fs";
1243
- import path6 from "path";
1197
+ // pkgs/@akanjs/devkit/codeAgent/agent/AkanContextFiles.ts
1198
+ import { existsSync as existsSync5, readdirSync, readFileSync as readFileSync2, statSync as statSync2 } from "fs";
1199
+ import path5 from "path";
1244
1200
 
1245
- class AkanAuthStorageBackend2 {
1246
- #authPath;
1247
- #lockPath;
1248
- constructor(authPath) {
1249
- this.#authPath = authPath;
1250
- this.#lockPath = `${authPath}.lock`;
1251
- }
1252
- withLock(fn) {
1253
- this.#acquire();
1254
- try {
1255
- const { result, next } = fn(this.#read());
1256
- if (next !== undefined)
1257
- this.#write(next);
1258
- return result;
1259
- } finally {
1260
- this.#release();
1201
+ class AkanContextFiles {
1202
+ static #frontmatter = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?/;
1203
+ static extend(base, options) {
1204
+ const seen = new Set(base.map((file) => file.path));
1205
+ const contents = new Set(base.map((file) => file.content.trim()));
1206
+ const added = [];
1207
+ for (const file of [...AkanContextFiles.#claude(base), ...AkanContextFiles.#cursor(options)]) {
1208
+ if (seen.has(file.path) || contents.has(file.content.trim()) || !file.content.trim())
1209
+ continue;
1210
+ seen.add(file.path);
1211
+ contents.add(file.content.trim());
1212
+ added.push(file);
1261
1213
  }
1214
+ return [...base, ...added];
1262
1215
  }
1263
- async withLockAsync(fn) {
1264
- this.#acquire();
1265
- try {
1266
- const { result, next } = await fn(this.#read());
1267
- if (next !== undefined)
1268
- this.#write(next);
1269
- return result;
1270
- } finally {
1271
- this.#release();
1216
+ static #claude(base) {
1217
+ const files = [];
1218
+ for (const file of base) {
1219
+ if (!/^AGENTS\.(md|MD)$/.test(path5.basename(file.path)))
1220
+ continue;
1221
+ for (const name of ["CLAUDE.md", "CLAUDE.MD"]) {
1222
+ const candidate = path5.join(path5.dirname(file.path), name);
1223
+ const content = AkanContextFiles.#read(candidate);
1224
+ if (content !== undefined)
1225
+ files.push({ path: candidate, content });
1226
+ }
1272
1227
  }
1273
- }
1274
- #read() {
1275
- if (!existsSync7(this.#authPath))
1276
- return;
1277
- const text = readFileSync3(this.#authPath, "utf8");
1278
- return text.trim() ? text : undefined;
1279
- }
1280
- #write(next) {
1281
- mkdirSync(path6.dirname(this.#authPath), { recursive: true, mode: 448 });
1282
- const temp = `${this.#authPath}.${process.pid}.tmp`;
1283
- writeFileSync(temp, next, { mode: 384 });
1284
- renameSync(temp, this.#authPath);
1285
- }
1286
- #acquire() {
1287
- mkdirSync(path6.dirname(this.#lockPath), { recursive: true, mode: 448 });
1288
- const deadline = Date.now() + 5000;
1289
- for (;; ) {
1290
- try {
1291
- closeSync(openSync(this.#lockPath, "wx"));
1292
- return;
1293
- } catch {
1294
- if (this.#lockIsStale() || Date.now() > deadline) {
1295
- try {
1296
- unlinkSync(this.#lockPath);
1297
- } catch {}
1228
+ return files;
1229
+ }
1230
+ static #cursor(options) {
1231
+ const files = [];
1232
+ const roots = [...new Set([options.workspaceRoot, options.cwd])];
1233
+ for (const root of roots) {
1234
+ const legacy = AkanContextFiles.#read(path5.join(root, ".cursorrules"));
1235
+ if (legacy !== undefined)
1236
+ files.push({ path: path5.join(root, ".cursorrules"), content: legacy });
1237
+ for (const file of AkanContextFiles.#mdcFiles(path5.join(root, ".cursor", "rules"))) {
1238
+ const raw = AkanContextFiles.#read(file);
1239
+ if (raw === undefined)
1298
1240
  continue;
1299
- }
1300
- Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 20);
1241
+ const body = AkanContextFiles.#applied(raw);
1242
+ if (body !== undefined)
1243
+ files.push({ path: file, content: body });
1301
1244
  }
1302
1245
  }
1246
+ return files;
1247
+ }
1248
+ static #applied(raw) {
1249
+ const match = AkanContextFiles.#frontmatter.exec(raw);
1250
+ if (!match)
1251
+ return raw;
1252
+ if (!/^\s*alwaysApply\s*:\s*true\s*$/m.test(match[1] ?? ""))
1253
+ return;
1254
+ return raw.slice(match[0].length);
1303
1255
  }
1304
- #lockIsStale() {
1256
+ static #mdcFiles(dir) {
1257
+ if (!existsSync5(dir))
1258
+ return [];
1305
1259
  try {
1306
- return Date.now() - Bun.file(this.#lockPath).lastModified > 30000;
1260
+ return readdirSync(dir, { recursive: true, withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".mdc")).map((entry) => path5.join(entry.parentPath ?? dir, entry.name)).sort();
1307
1261
  } catch {
1308
- return true;
1262
+ return [];
1309
1263
  }
1310
1264
  }
1311
- #release() {
1265
+ static #read(file) {
1312
1266
  try {
1313
- unlinkSync(this.#lockPath);
1314
- } catch {}
1267
+ if (!existsSync5(file) || !statSync2(file).isFile())
1268
+ return;
1269
+ return readFileSync2(file, "utf8").replace(/^\uFEFF/, "");
1270
+ } catch {
1271
+ return;
1272
+ }
1315
1273
  }
1316
1274
  }
1317
1275
 
@@ -1339,26 +1297,26 @@ var akanSystemPrompt2 = (profile) => {
1339
1297
  };
1340
1298
 
1341
1299
  // pkgs/@akanjs/devkit/codeAgent/agent/CodeSessionIndex.ts
1342
- import { existsSync as existsSync8, readdirSync, readFileSync as readFileSync4, statSync as statSync2 } from "fs";
1343
- import path7 from "path";
1300
+ import { existsSync as existsSync6, readdirSync as readdirSync2, readFileSync as readFileSync3, statSync as statSync3 } from "fs";
1301
+ import path6 from "path";
1344
1302
 
1345
1303
  class CodeSessionIndex2 {
1346
1304
  static readLimit = 512 * 1024;
1347
1305
  static list(dir, limit = 30) {
1348
- if (!existsSync8(dir))
1306
+ if (!existsSync6(dir))
1349
1307
  return [];
1350
- const files = readdirSync(dir).filter((entry) => entry.endsWith(".jsonl")).map((entry) => path7.join(dir, entry)).map((file) => ({ file, updatedAt: CodeSessionIndex2.#mtime(file) })).sort((left, right) => right.updatedAt - left.updatedAt).slice(0, limit);
1308
+ const files = readdirSync2(dir).filter((entry) => entry.endsWith(".jsonl")).map((entry) => path6.join(dir, entry)).map((file) => ({ file, updatedAt: CodeSessionIndex2.#mtime(file) })).sort((left, right) => right.updatedAt - left.updatedAt).slice(0, limit);
1351
1309
  return files.map((entry) => CodeSessionIndex2.#read(entry.file, entry.updatedAt)).filter((entry) => !!entry);
1352
1310
  }
1353
1311
  static fileOf(dir, id) {
1354
- if (!existsSync8(dir))
1312
+ if (!existsSync6(dir))
1355
1313
  return;
1356
- const match = readdirSync(dir).find((entry) => entry.endsWith(`${id}.jsonl`) || entry === `${id}.jsonl`);
1357
- return match ? path7.join(dir, match) : undefined;
1314
+ const match = readdirSync2(dir).find((entry) => entry.endsWith(`${id}.jsonl`) || entry === `${id}.jsonl`);
1315
+ return match ? path6.join(dir, match) : undefined;
1358
1316
  }
1359
1317
  static #mtime(file) {
1360
1318
  try {
1361
- return statSync2(file).mtimeMs;
1319
+ return statSync3(file).mtimeMs;
1362
1320
  } catch {
1363
1321
  return 0;
1364
1322
  }
@@ -1389,9 +1347,9 @@ class CodeSessionIndex2 {
1389
1347
  }
1390
1348
  static #lines(file) {
1391
1349
  try {
1392
- if (statSync2(file).size > CodeSessionIndex2.readLimit)
1350
+ if (statSync3(file).size > CodeSessionIndex2.readLimit)
1393
1351
  return [];
1394
- return readFileSync4(file, "utf8").split(`
1352
+ return readFileSync3(file, "utf8").split(`
1395
1353
  `).filter((line) => !!line.trim());
1396
1354
  } catch {
1397
1355
  return [];
@@ -1419,20 +1377,20 @@ class AkanCodeServices2 {
1419
1377
  quietStartup: true
1420
1378
  });
1421
1379
  }
1422
- static auth(workspaceRoot) {
1423
- mkdirSync2(akanCodePaths2.globalDir(), { recursive: true, mode: 448 });
1424
- const authStorage = AuthStorage.fromStorage(new AkanAuthStorageBackend2(akanCodePaths2.authFile()));
1425
- AkanEnvKeys2.apply(authStorage, workspaceRoot);
1426
- return authStorage;
1427
- }
1428
- static models(authStorage) {
1429
- return ModelRegistry.create(authStorage, akanCodePaths2.modelsFile());
1380
+ static async runtime(workspaceRoot) {
1381
+ mkdirSync(akanCodePaths2.globalDir(), { recursive: true, mode: 448 });
1382
+ const runtime = await ModelRuntime.create({
1383
+ authPath: akanCodePaths2.authFile(),
1384
+ modelsPath: akanCodePaths2.modelsFile()
1385
+ });
1386
+ await AkanEnvKeys2.apply(runtime, workspaceRoot);
1387
+ return runtime;
1430
1388
  }
1431
1389
  static sessions(workspaceRoot, cwd, profile, resume) {
1432
1390
  if (profile.session.store !== "file")
1433
1391
  return SessionManager2.inMemory(cwd);
1434
1392
  const dir = akanCodePaths2.sessionsDir(workspaceRoot);
1435
- mkdirSync2(dir, { recursive: true });
1393
+ mkdirSync(dir, { recursive: true });
1436
1394
  const manager = SessionManager2.create(cwd, dir);
1437
1395
  if (!resume)
1438
1396
  return manager;
@@ -1446,16 +1404,19 @@ class AkanCodeServices2 {
1446
1404
  if (!profile.context.skills)
1447
1405
  return [];
1448
1406
  const workspace = akanCodePaths2.skillsDir(workspaceRoot);
1449
- return [akanCodePaths2.builtinSkillsDir(), existsSync9(workspace) ? workspace : undefined].filter((dir) => !!dir);
1407
+ return [akanCodePaths2.builtinSkillsDir(), existsSync7(workspace) ? workspace : undefined].filter((dir) => !!dir);
1450
1408
  }
1451
1409
  static resourceOptions(options) {
1452
- const present = (dir) => existsSync9(dir) ? [dir] : [];
1410
+ const present = (dir) => existsSync7(dir) ? [dir] : [];
1453
1411
  return {
1454
1412
  noExtensions: true,
1455
1413
  noSkills: true,
1456
1414
  noPromptTemplates: true,
1457
1415
  noThemes: true,
1458
1416
  noContextFiles: !options.profile.context.projectFiles,
1417
+ agentsFilesOverride: ({ agentsFiles }) => ({
1418
+ agentsFiles: options.profile.context.projectFiles ? AkanContextFiles.extend(agentsFiles, { workspaceRoot: options.workspaceRoot, cwd: options.cwd }) : agentsFiles
1419
+ }),
1459
1420
  appendSystemPrompt: [akanSystemPrompt2(options.profile)],
1460
1421
  additionalExtensionPaths: present(akanCodePaths2.extensionsDir(options.workspaceRoot)),
1461
1422
  additionalSkillPaths: AkanCodeServices2.#skillPaths(options.profile, options.workspaceRoot),
@@ -1733,7 +1694,7 @@ class CodeAgentEventMapper2 {
1733
1694
  }
1734
1695
 
1735
1696
  // pkgs/@akanjs/devkit/codeAgent/agent/CodeAgentGate.ts
1736
- import path8 from "path";
1697
+ import path7 from "path";
1737
1698
  var writeTools = new Set(["write", "edit"]);
1738
1699
  var commandTools = new Set(["bash"]);
1739
1700
 
@@ -1772,9 +1733,9 @@ class CodeAgentGate2 {
1772
1733
  return `The command names "${hit}", which the profile's deny list covers. Ask the user for the value instead of reading the file.`;
1773
1734
  }
1774
1735
  #deniedReason(target) {
1775
- const absolute = path8.isAbsolute(target) ? target : path8.resolve(this.#profile.paths.root, target);
1776
- const relative = path8.relative(this.#profile.paths.root, absolute);
1777
- if (relative.startsWith("..") || path8.isAbsolute(relative))
1736
+ const absolute = path7.isAbsolute(target) ? target : path7.resolve(this.#profile.paths.root, target);
1737
+ const relative = path7.relative(this.#profile.paths.root, absolute);
1738
+ if (relative.startsWith("..") || path7.isAbsolute(relative))
1778
1739
  return `Path is outside the agent root (${this.#profile.paths.root}).`;
1779
1740
  if (this.#deny.some((glob) => glob.match(absolute) || glob.match(relative)))
1780
1741
  return "Path is on the profile's deny list (secrets and environment files are never readable).";
@@ -1864,15 +1825,15 @@ class CodeAgentUi2 {
1864
1825
  // pkgs/@akanjs/devkit/codeAgent/agent/CodeMailbox.ts
1865
1826
  import {
1866
1827
  appendFileSync,
1867
- existsSync as existsSync10,
1868
- mkdirSync as mkdirSync3,
1869
- readdirSync as readdirSync2,
1870
- readFileSync as readFileSync5,
1828
+ existsSync as existsSync8,
1829
+ mkdirSync as mkdirSync2,
1830
+ readdirSync as readdirSync3,
1831
+ readFileSync as readFileSync4,
1871
1832
  rmSync,
1872
- statSync as statSync3,
1873
- writeFileSync as writeFileSync2
1833
+ statSync as statSync4,
1834
+ writeFileSync
1874
1835
  } from "fs";
1875
- import path9 from "path";
1836
+ import path8 from "path";
1876
1837
 
1877
1838
  class CodeMailbox2 {
1878
1839
  static staleMs = 20000;
@@ -1892,11 +1853,11 @@ class CodeMailbox2 {
1892
1853
  this.#name = name;
1893
1854
  }
1894
1855
  get inbox() {
1895
- return path9.join(this.#dir, "inbox", `${this.#id}.jsonl`);
1856
+ return path8.join(this.#dir, "inbox", `${this.#id}.jsonl`);
1896
1857
  }
1897
1858
  open(cwd, onMail) {
1898
- mkdirSync3(path9.join(this.#dir, "live"), { recursive: true });
1899
- mkdirSync3(path9.join(this.#dir, "inbox"), { recursive: true });
1859
+ mkdirSync2(path8.join(this.#dir, "live"), { recursive: true });
1860
+ mkdirSync2(path8.join(this.#dir, "inbox"), { recursive: true });
1900
1861
  this.#read = CodeMailbox2.#lines(this.inbox).length;
1901
1862
  this.beat(cwd);
1902
1863
  this.#beat = setInterval(() => this.beat(cwd), CodeMailbox2.beatMs);
@@ -1913,7 +1874,7 @@ class CodeMailbox2 {
1913
1874
  this.#beat = null;
1914
1875
  this.#poll = null;
1915
1876
  try {
1916
- rmSync(path9.join(this.#dir, "live", `${this.#id}.json`), { force: true });
1877
+ rmSync(path8.join(this.#dir, "live", `${this.#id}.json`), { force: true });
1917
1878
  } catch {}
1918
1879
  }
1919
1880
  rename(name, cwd) {
@@ -1923,15 +1884,15 @@ class CodeMailbox2 {
1923
1884
  beat(cwd) {
1924
1885
  const peer = { id: this.#id, name: this.#name, cwd, pid: process.pid, at: Date.now() };
1925
1886
  try {
1926
- writeFileSync2(path9.join(this.#dir, "live", `${this.#id}.json`), JSON.stringify(peer));
1887
+ writeFileSync(path8.join(this.#dir, "live", `${this.#id}.json`), JSON.stringify(peer));
1927
1888
  } catch {}
1928
1889
  }
1929
1890
  peers() {
1930
- const dir = path9.join(this.#dir, "live");
1931
- if (!existsSync10(dir))
1891
+ const dir = path8.join(this.#dir, "live");
1892
+ if (!existsSync8(dir))
1932
1893
  return [];
1933
1894
  const now = Date.now();
1934
- return readdirSync2(dir).filter((entry) => entry.endsWith(".json")).map((entry) => CodeMailbox2.#peer(path9.join(dir, entry))).filter((peer) => !!peer && peer.id !== this.#id && now - peer.at < CodeMailbox2.staleMs).sort((left, right) => right.at - left.at);
1895
+ return readdirSync3(dir).filter((entry) => entry.endsWith(".json")).map((entry) => CodeMailbox2.#peer(path8.join(dir, entry))).filter((peer) => !!peer && peer.id !== this.#id && now - peer.at < CodeMailbox2.staleMs).sort((left, right) => right.at - left.at);
1935
1896
  }
1936
1897
  find(target) {
1937
1898
  const needle = target.trim().toLowerCase();
@@ -1949,8 +1910,8 @@ class CodeMailbox2 {
1949
1910
  throw new Error(`Too many messages: ${CodeMailbox2.sendsPerMinute} a minute is the ceiling.`);
1950
1911
  this.#sent.push(now);
1951
1912
  const mail = { at: now, from: this.#id, fromName: this.#name, text };
1952
- mkdirSync3(path9.join(this.#dir, "inbox"), { recursive: true });
1953
- appendFileSync(path9.join(this.#dir, "inbox", `${to}.jsonl`), `${JSON.stringify(mail)}
1913
+ mkdirSync2(path8.join(this.#dir, "inbox"), { recursive: true });
1914
+ appendFileSync(path8.join(this.#dir, "inbox", `${to}.jsonl`), `${JSON.stringify(mail)}
1954
1915
  `);
1955
1916
  }
1956
1917
  #drain() {
@@ -1963,15 +1924,15 @@ class CodeMailbox2 {
1963
1924
  }
1964
1925
  static #peer(file) {
1965
1926
  try {
1966
- const peer = JSON.parse(readFileSync5(file, "utf8"));
1967
- return typeof peer.id === "string" ? { ...peer, at: peer.at || statSync3(file).mtimeMs } : undefined;
1927
+ const peer = JSON.parse(readFileSync4(file, "utf8"));
1928
+ return typeof peer.id === "string" ? { ...peer, at: peer.at || statSync4(file).mtimeMs } : undefined;
1968
1929
  } catch {
1969
1930
  return;
1970
1931
  }
1971
1932
  }
1972
1933
  static #lines(file) {
1973
1934
  try {
1974
- return readFileSync5(file, "utf8").split(`
1935
+ return readFileSync4(file, "utf8").split(`
1975
1936
  `).filter((line) => !!line.trim());
1976
1937
  } catch {
1977
1938
  return [];
@@ -1988,15 +1949,15 @@ class CodeMailbox2 {
1988
1949
 
1989
1950
  // pkgs/@akanjs/devkit/codeAgent/agent/CodeSessionFork.ts
1990
1951
  import { randomBytes } from "crypto";
1991
- import { readFileSync as readFileSync6, writeFileSync as writeFileSync3 } from "fs";
1992
- import path10 from "path";
1952
+ import { readFileSync as readFileSync5, writeFileSync as writeFileSync2 } from "fs";
1953
+ import path9 from "path";
1993
1954
  import { codeAgentSessionName } from "akanjs/common";
1994
1955
  class CodeSessionFork2 {
1995
1956
  static fork(dir, id, name) {
1996
1957
  const source = CodeSessionIndex2.fileOf(dir, id);
1997
1958
  if (!source)
1998
1959
  throw new Error(`No stored session ${id} in ${dir}`);
1999
- const lines = readFileSync6(source, "utf8").split(`
1960
+ const lines = readFileSync5(source, "utf8").split(`
2000
1961
  `).filter((line) => !!line.trim());
2001
1962
  if (!lines.length)
2002
1963
  throw new Error(`Session ${id} has nothing in it to fork`);
@@ -2009,8 +1970,8 @@ class CodeSessionFork2 {
2009
1970
  first.id = forked;
2010
1971
  first.timestamp = at.toISOString();
2011
1972
  records.push(CodeSessionFork2.#named(records, name ?? CodeSessionFork2.#nameOf(records), at));
2012
- const file = path10.join(dir, `${at.toISOString().replace(/[:.]/g, "-")}_${forked}.jsonl`);
2013
- writeFileSync3(file, `${records.map((record) => JSON.stringify(record)).join(`
1973
+ const file = path9.join(dir, `${at.toISOString().replace(/[:.]/g, "-")}_${forked}.jsonl`);
1974
+ writeFileSync2(file, `${records.map((record) => JSON.stringify(record)).join(`
2014
1975
  `)}
2015
1976
  `);
2016
1977
  return { id: forked, file };
@@ -2052,6 +2013,8 @@ class CodeAgent2 {
2052
2013
  #disposed = false;
2053
2014
  #sessionDir;
2054
2015
  #mailbox;
2016
+ #mcp = [];
2017
+ #workspaceRoot = "";
2055
2018
  #replay = [];
2056
2019
  #replayFrom = 0;
2057
2020
  #lastContextTokens;
@@ -2064,9 +2027,8 @@ class CodeAgent2 {
2064
2027
  const cwd = options.cwd ?? workspaceRoot;
2065
2028
  const agent = new CodeAgent2(options.profile);
2066
2029
  const settingsManager = AkanCodeServices2.settings();
2067
- const authStorage = AkanCodeServices2.auth(workspaceRoot);
2068
- const modelRegistry = AkanCodeServices2.models(authStorage);
2069
- const model = await akanCodeModel2(modelRegistry, options.model);
2030
+ const modelRuntime = await AkanCodeServices2.runtime(workspaceRoot);
2031
+ const model = await akanCodeModel2(modelRuntime, options.model);
2070
2032
  const compaction = DEFAULT_COMPACTION_SETTINGS;
2071
2033
  const modelWarnings = akanCodeModelWarnings2(model, compaction.reserveTokens + compaction.keepRecentTokens);
2072
2034
  const akan = await AkanCodePlugins2.build({
@@ -2078,7 +2040,8 @@ class CodeAgent2 {
2078
2040
  depth: options.depth ?? 0,
2079
2041
  currentSessionId: () => agent.sessionId,
2080
2042
  mailbox: () => agent.#mailbox,
2081
- onNotice: (message) => agent.#emit({ type: "notice", level: "warning", message })
2043
+ onNotice: (message) => agent.#emit({ type: "notice", level: "warning", message }),
2044
+ onAgents: (agents) => agent.#emit({ type: "subagent", agents })
2082
2045
  });
2083
2046
  const resourceLoader = new DefaultResourceLoader({
2084
2047
  cwd,
@@ -2095,8 +2058,7 @@ class CodeAgent2 {
2095
2058
  const { session } = await createAgentSession({
2096
2059
  cwd,
2097
2060
  agentDir: akanCodePaths2.globalDir(),
2098
- authStorage,
2099
- modelRegistry,
2061
+ modelRuntime,
2100
2062
  settingsManager,
2101
2063
  resourceLoader,
2102
2064
  model,
@@ -2106,6 +2068,8 @@ class CodeAgent2 {
2106
2068
  customTools: options.customTools
2107
2069
  });
2108
2070
  agent.#disposePlugins = akan.dispose;
2071
+ agent.#mcp = akan.mcp;
2072
+ agent.#workspaceRoot = workspaceRoot;
2109
2073
  if (options.profile.session.store === "file")
2110
2074
  agent.#sessionDir = akanCodePaths2.sessionsDir(workspaceRoot);
2111
2075
  await agent.#attach(session, options.mode ?? "print");
@@ -2125,6 +2089,12 @@ class CodeAgent2 {
2125
2089
  sessions() {
2126
2090
  return this.#sessionDir ? CodeSessionIndex2.list(this.#sessionDir) : [];
2127
2091
  }
2092
+ get workspaceRoot() {
2093
+ return this.#workspaceRoot;
2094
+ }
2095
+ mcpServers() {
2096
+ return this.#mcp;
2097
+ }
2128
2098
  peers() {
2129
2099
  return this.#mailbox?.peers() ?? [];
2130
2100
  }
@@ -2281,7 +2251,7 @@ Continue the task.`);
2281
2251
  }
2282
2252
  async setModel(ref) {
2283
2253
  const session = this.#require();
2284
- const model = await akanCodeModel2(session.modelRegistry, ref);
2254
+ const model = await akanCodeModel2(session.modelRuntime, ref);
2285
2255
  if (!model)
2286
2256
  throw new Error(`Unknown model: ${ref.provider}/${ref.id}`);
2287
2257
  await session.setModel(model);
@@ -2431,4 +2401,4 @@ Continue the task.`);
2431
2401
  }
2432
2402
  }
2433
2403
 
2434
- export { AkanEditScope2, DevLogFeedback2, PreviewChrome2, PreviewView2, PreviewFeedback2, TurnFeedback2, AkanCli2, AkanVerifier2, VerifyFeedback2, AkanToolPack2, MailToolPack2, akanCodePaths2, McpClient2, McpToolPack2, SessionToolPack2, WebToolPack2, AkanCodePlugins2, AkanEnvKeys2, AkanAuthStorageBackend2, akanSystemPrompt2, CodeSessionIndex2, AkanCodeServices2, CodeAgentAsks2, CodeAgentEventMapper2, CodeAgentGate2, CodeAgentUi2, CodeMailbox2, CodeSessionFork2, CodeAgent2 };
2404
+ export { AkanEditScope2, DevLogFeedback2, PreviewChrome2, PreviewView2, PreviewFeedback2, TurnFeedback2, AkanCli2, AkanVerifier2, VerifyFeedback2, AkanToolPack2, MailToolPack2, McpClient2, McpToolPack2, SessionToolPack2, WebToolPack2, AkanCodePlugins2, AkanEnvKeys2, akanSystemPrompt2, CodeSessionIndex2, AkanCodeServices2, CodeAgentAsks2, CodeAgentEventMapper2, CodeAgentGate2, CodeAgentUi2, CodeMailbox2, CodeSessionFork2, CodeAgent2 };