@akanjs/cli 3.0.0-beta.19 → 3.0.0-beta.20

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.
Files changed (95) hide show
  1. package/.build-stamp +1 -1
  2. package/{CodeAgent-6cm97kay.js → CodeAgent-awv258wb.js} +2 -2
  3. package/{CodeTui-za4jsm41.js → CodeTui-1nqh35ez.js} +20 -22
  4. package/TunnelShare-scf4e4pd.js +9 -0
  5. package/{agent.command-e0wpbbyg.js → agent.command-1s9ag7sb.js} +8 -9
  6. package/akanCode.js +4 -4
  7. package/{application.command-8wyxqc8q.js → application.command-49hwy6va.js} +25 -56
  8. package/{applicationBuildRunner-n9gzaxd0.js → applicationBuildRunner-ybyp97pv.js} +33 -59
  9. package/{applicationReleasePackager-vpggfqgq.js → applicationReleasePackager-esnrphw8.js} +40 -60
  10. package/buildBatch.proc.js +19 -24
  11. package/{capacitorApp-q3z0qht0.js → capacitorApp-1synz4en.js} +3 -4
  12. package/{cloud.command-4zwa5dsx.js → cloud.command-d7rqtzt9.js} +16 -26
  13. package/cloud.script-bkbpcr96.js +19 -0
  14. package/{code.command-468c9d7s.js → code.command-nn48xzej.js} +22 -37
  15. package/context.command-s3mcmvpa.js +48 -0
  16. package/context.runner-k99nb5pk.js +21 -0
  17. package/{dependencyScanner-0z2h2tks.js → dependencyScanner-ye2e6pdz.js} +2 -2
  18. package/{devTui-ffjsarqa.js → devTui-q7k7bakd.js} +5 -9
  19. package/fileSys-5ngz93ga.js +9 -0
  20. package/{guideline.command-vhw13pqr.js → guideline.command-sct4qnt5.js} +4 -5
  21. package/guidelines/conventions/conventions.instruction.md +5 -1
  22. package/guidelines/mcpRule/mcpRule.instruction.md +7 -5
  23. package/incrementalBuilder.proc.js +30 -48
  24. package/{index-s5rhm04y.js → index-0bq14vr1.js} +1 -1
  25. package/{index-10dkrrww.js → index-13ffe9wp.js} +4 -4
  26. package/{index-srmay5jw.js → index-22d57v4c.js} +84 -67
  27. package/{index-53176s7j.js → index-31yr441d.js} +10 -17
  28. package/index-3hx1z96c.js +87 -0
  29. package/{index-4m929vvn.js → index-3sq321ak.js} +10 -18
  30. package/{index-bhtmj233.js → index-3t7g9e4r.js} +41 -78
  31. package/{index-q0y2jq9j.js → index-5b6tavv3.js} +6 -3
  32. package/{index-47pj3aee.js → index-5e0n4hqx.js} +11 -12
  33. package/{index-7ep8qtvp.js → index-5pc1qrbv.js} +5 -8
  34. package/{index-esk82rvk.js → index-8mna0947.js} +34 -71
  35. package/{index-sq2dzkzm.js → index-8sf7wmdr.js} +6 -6
  36. package/{index-crmeqnmf.js → index-9d9bgcx4.js} +283 -722
  37. package/{index-bwf965h6.js → index-ahemdr5n.js} +6 -6
  38. package/{index-ab0c38ea.js → index-as7xmyz8.js} +20 -20
  39. package/{index-bc88j1ry.js → index-axzjaqve.js} +94 -142
  40. package/{index-3d9y066c.js → index-bjwxs904.js} +9 -8
  41. package/{index-667w0yah.js → index-c6eggbee.js} +2 -5
  42. package/{index-a1w6934z.js → index-ddxvdd1p.js} +169 -305
  43. package/{index-92zztqy1.js → index-dy0jx9ay.js} +2 -17
  44. package/{index-22xtgmhn.js → index-dzf3r49a.js} +1 -1
  45. package/{index-89hy31kf.js → index-fgq75haa.js} +172 -287
  46. package/{index-by5gpp8x.js → index-hj6w4ka1.js} +2 -1
  47. package/{index-hwkygn9s.js → index-khpfpcsd.js} +302 -33
  48. package/{index-vqx8bdxz.js → index-mxav6j3c.js} +78 -231
  49. package/{index-2446k7b4.js → index-myhc3c1j.js} +512 -588
  50. package/{index-3jrp517k.js → index-nv5976x3.js} +45 -128
  51. package/{index-zqgj2rt2.js → index-przybvy5.js} +69 -147
  52. package/{index-n3cv0tm4.js → index-smme4r47.js} +1 -1
  53. package/{index-qdgzsnhg.js → index-w2zdcw3k.js} +110 -231
  54. package/{index-14zrtgfa.js → index-wa5jbxj1.js} +6 -39
  55. package/{index-bftkz6cp.js → index-ww4z397j.js} +198 -555
  56. package/{index-kwaq3n9n.js → index-xqjwd384.js} +4 -7
  57. package/{index-txr7dj2g.js → index-xqpzbab5.js} +106 -240
  58. package/{index-e4v6vhxq.js → index-xsjh6nzh.js} +178 -165
  59. package/{index-18zybgkc.js → index-ygn77a5w.js} +47 -99
  60. package/{index-9d6nvkz2.js → index-ztp3e73t.js} +79 -35
  61. package/index.js +23 -24
  62. package/{library.command-cqr175dy.js → library.command-1gx04jgn.js} +4 -5
  63. package/{localRegistry.command-49z55qqz.js → localRegistry.command-zndxj1q6.js} +21 -42
  64. package/{module.command-9p8mm3b0.js → module.command-3waddk95.js} +6 -7
  65. package/{package.command-wxyz909t.js → package.command-zrc7br1y.js} +5 -6
  66. package/package.json +2 -2
  67. package/{page.command-gsrsfqqs.js → page.command-vpjgardh.js} +4 -5
  68. package/{primitive.command-ns1mptje.js → primitive.command-sz84tk4t.js} +9 -20
  69. package/{prompter-1f8d9pcc.js → prompter-ptaa3nk0.js} +2 -2
  70. package/{quality.command-e76k2q9k.js → quality.command-g869hafs.js} +129 -363
  71. package/{recipeScanner-fpagtgc1.js → recipeScanner-4b69ybe0.js} +1 -1
  72. package/{repair.command-pkrsm3cw.js → repair.command-chsnjvvv.js} +11 -35
  73. package/{scalar.command-0cpt3fc8.js → scalar.command-2v21newx.js} +5 -6
  74. package/skills/akan-code/SKILL.md +12 -4
  75. package/{subspace.command-fktpwp0g.js → subspace.command-ckcbwfp1.js} +39 -58
  76. package/templates/appSample/srvkit/{AuthGuard.ts → guards.ts} +3 -3
  77. package/templates/appSample/srvkit/{SessionInternalArg.ts → internalArgs.ts} +3 -3
  78. package/templates/client.ts +7 -30
  79. package/templates/lib/__lib/lib.dictionary.ts +0 -2
  80. package/templates/lib/__lib/lib.document.ts +0 -2
  81. package/templates/lib/sig.ts +8 -30
  82. package/templates/server.ts +0 -2
  83. package/{tunnel.command-d5jy9gk8.js → tunnel.command-kd2yr4fx.js} +5 -6
  84. package/{typeChecker-3xgrzc2v.js → typeChecker-px49mezc.js} +1 -1
  85. package/typecheck.proc.js +1 -1
  86. package/workflow.command-44252cqv.js +79 -0
  87. package/{workspace.command-gv84eh1p.js → workspace.command-fqcztt5p.js} +72 -107
  88. package/TunnelShare-2j6s511d.js +0 -9
  89. package/cloud.script-fwx3vb34.js +0 -20
  90. package/context.command-dsnw0jby.js +0 -80
  91. package/context.runner-rs4rj15d.js +0 -22
  92. package/devTuiView-1q1mdgrv.js +0 -9
  93. package/getDirname-dr3jz1xg.js +0 -7
  94. package/index-6wwzs1bc.js +0 -7
  95. package/workflow.command-6tkcysmx.js +0 -105
@@ -4,7 +4,7 @@ import {
4
4
  akanCodePaths2,
5
5
  McpServerConfig,
6
6
  McpSignIn
7
- } from "./index-9d6nvkz2.js";
7
+ } from "./index-ztp3e73t.js";
8
8
  import {
9
9
  stripAnsi
10
10
  } from "./index-7md2g9vw.js";
@@ -13,7 +13,7 @@ import {
13
13
  akanCodeModel2,
14
14
  akanCodeModelSupportsImages2,
15
15
  akanCodeModelWarnings2
16
- } from "./index-667w0yah.js";
16
+ } from "./index-c6eggbee.js";
17
17
 
18
18
  // pkgs/@akanjs/devkit/codeAgent/agent/CodeAgent.ts
19
19
  import {
@@ -36,7 +36,7 @@ var empty = { paths: [], apps: [], libs: [], needsSync: false, touchesTsx: false
36
36
 
37
37
  class AkanEditScope2 {
38
38
  static async since(cwd, baseline) {
39
- const current = await AkanEditScope2.#status(cwd);
39
+ const current = await AkanEditScope2.baseline(cwd);
40
40
  const changed = [...current].filter((line) => !baseline.has(line));
41
41
  if (!changed.length)
42
42
  return empty;
@@ -51,9 +51,6 @@ class AkanEditScope2 {
51
51
  };
52
52
  }
53
53
  static async baseline(cwd) {
54
- return await AkanEditScope2.#status(cwd);
55
- }
56
- static async#status(cwd) {
57
54
  const proc = Bun.spawn(["git", "status", "--porcelain=v1", "--untracked-files=all"], {
58
55
  cwd,
59
56
  stdout: "pipe",
@@ -514,7 +511,7 @@ class AkanToolPack2 {
514
511
  return { name: "akan-tools", factory: async (pi) => await this.#register(pi) };
515
512
  }
516
513
  async names() {
517
- const { ContextRunner } = await import("./context.runner-rs4rj15d.js");
514
+ const { ContextRunner } = await import("./context.runner-k99nb5pk.js");
518
515
  return [
519
516
  ...new ContextRunner().listMcpTools(this.#options.mode).map((tool) => tool.name),
520
517
  AkanToolPack2.verifyToolName
@@ -522,7 +519,7 @@ class AkanToolPack2 {
522
519
  }
523
520
  static verifyToolName = "akan_verify";
524
521
  async#register(pi) {
525
- const { ContextRunner } = await import("./context.runner-rs4rj15d.js");
522
+ const { ContextRunner } = await import("./context.runner-k99nb5pk.js");
526
523
  const runner = new ContextRunner;
527
524
  const guidelineNames = await AkanToolPack2.#guidelineNames();
528
525
  for (const tool of runner.listMcpTools(this.#options.mode, { guidelineNames })) {
@@ -537,7 +534,8 @@ class AkanToolPack2 {
537
534
  const result = await runner.callMcpTool(this.#options.workspace, tool.name, params ?? {}, {
538
535
  mode: this.#options.mode
539
536
  });
540
- return { content: [{ type: "text", text: AkanToolPack2.#render(result) }], details: undefined };
537
+ const text = typeof result === "string" ? result : JSON.stringify(result, null, 2);
538
+ return { content: [{ type: "text", text }], details: undefined };
541
539
  }
542
540
  });
543
541
  }
@@ -564,17 +562,12 @@ class AkanToolPack2 {
564
562
  }
565
563
  static async#guidelineNames() {
566
564
  try {
567
- const { Prompter } = await import("./prompter-1f8d9pcc.js");
565
+ const { Prompter } = await import("./prompter-ptaa3nk0.js");
568
566
  return await Prompter.listGuidelines();
569
567
  } catch {
570
568
  return [];
571
569
  }
572
570
  }
573
- static #render(result) {
574
- if (typeof result === "string")
575
- return result;
576
- return JSON.stringify(result, null, 2);
577
- }
578
571
  }
579
572
 
580
573
  // pkgs/@akanjs/devkit/codeAgent/tools/AskToolPack.ts
@@ -885,24 +878,27 @@ class McpClient2 {
885
878
  class McpToolPack2 {
886
879
  #clients = [];
887
880
  #status = [];
888
- constructor() {}
881
+ #onNotice;
882
+ constructor(onNotice) {
883
+ this.#onNotice = onNotice;
884
+ }
889
885
  static async connect(options) {
890
886
  const refs = McpToolPack2.#refs(options);
891
887
  if (!refs.length)
892
888
  return;
893
- const pack = new McpToolPack2;
889
+ const pack = new McpToolPack2(options.onNotice);
894
890
  for (const ref of refs) {
895
891
  const base = { name: ref.name, transport: ref.transport, target: McpServerConfig.targetOf(ref) };
896
892
  const token = ref.transport === "http" ? await McpSignIn.token(ref, options.onNotice) : undefined;
897
893
  try {
898
- const client = await new McpClient2(ref, token).connect();
899
- const tools = await client.listTools();
900
- pack.#clients.push({ client, tools });
901
- pack.#status.push({
894
+ const opened = await McpToolPack2.#openRefreshing(ref, token, options.onNotice);
895
+ const status = {
902
896
  ...base,
903
- tools: tools.map((tool) => McpToolPack2.#nameOf(ref.name, tool.name)),
904
- auth: token ? "authorized" : "none"
905
- });
897
+ tools: opened.tools.map((tool) => McpToolPack2.#nameOf(ref.name, tool.name)),
898
+ auth: opened.token ? "authorized" : "none"
899
+ };
900
+ pack.#clients.push({ ...opened, status, renewing: undefined, refused: undefined });
901
+ pack.#status.push(status);
906
902
  } catch (error) {
907
903
  if (error instanceof McpUnauthorized2) {
908
904
  options.onNotice?.(`MCP server "${ref.name}" needs signing in \u2014 /mcp login ${ref.name}`);
@@ -915,6 +911,22 @@ class McpToolPack2 {
915
911
  }
916
912
  return pack;
917
913
  }
914
+ static async#openRefreshing(ref, token, onNotice) {
915
+ try {
916
+ return await McpToolPack2.#open(ref, token);
917
+ } catch (error) {
918
+ if (!(error instanceof McpUnauthorized2) || !token)
919
+ throw error;
920
+ const retry = await McpSignIn.retryToken(ref, token, onNotice);
921
+ if (!retry)
922
+ throw error;
923
+ return await McpToolPack2.#open(ref, retry);
924
+ }
925
+ }
926
+ static async#open(ref, token) {
927
+ const client = await new McpClient2(ref, token).connect();
928
+ return { client, tools: await client.listTools(), token };
929
+ }
918
930
  get toolNames() {
919
931
  return this.#clients.flatMap(({ client, tools }) => tools.map((tool) => McpToolPack2.#nameOf(client.ref.name, tool.name)));
920
932
  }
@@ -929,18 +941,18 @@ class McpToolPack2 {
929
941
  client.close();
930
942
  }
931
943
  #register(pi) {
932
- for (const { client, tools } of this.#clients)
933
- for (const tool of tools) {
934
- const name = McpToolPack2.#nameOf(client.ref.name, tool.name);
944
+ for (const server of this.#clients)
945
+ for (const tool of server.tools) {
946
+ const name = McpToolPack2.#nameOf(server.client.ref.name, tool.name);
935
947
  const description = tool.description ?? tool.name;
936
948
  pi.registerTool({
937
949
  name,
938
- label: `${client.ref.name}: ${tool.name}`,
950
+ label: `${server.client.ref.name}: ${tool.name}`,
939
951
  description,
940
952
  promptSnippet: `${name}: ${description.split(".")[0] ?? description}`,
941
953
  parameters: Type4.Unsafe(tool.inputSchema),
942
954
  execute: async (_id, params) => {
943
- const result = await client.callTool(tool.name, params ?? {});
955
+ const result = await this.#call(server, tool.name, params ?? {});
944
956
  return {
945
957
  content: [{ type: "text", text: codeAgentClip(result.text, codeAgentOutputChars) }],
946
958
  details: undefined,
@@ -950,6 +962,59 @@ class McpToolPack2 {
950
962
  });
951
963
  }
952
964
  }
965
+ async#call(server, tool, args) {
966
+ const client = server.client;
967
+ try {
968
+ return await client.callTool(tool, args);
969
+ } catch (error) {
970
+ if (!(error instanceof McpUnauthorized2))
971
+ throw error;
972
+ }
973
+ const renewed = await this.#renewed(server, client);
974
+ try {
975
+ if (renewed)
976
+ return await renewed.callTool(tool, args);
977
+ } catch (error) {
978
+ if (!(error instanceof McpUnauthorized2))
979
+ throw error;
980
+ McpToolPack2.#refuse(server, renewed);
981
+ }
982
+ throw new Error(`MCP server "${client.ref.name}" needs signing in \u2014 /mcp login ${client.ref.name}`);
983
+ }
984
+ static #refuse(server, client) {
985
+ server.refused = client;
986
+ server.status.auth = "required";
987
+ }
988
+ async#renewed(server, refused) {
989
+ if (server.client === refused && server.refused !== refused)
990
+ server.renewing ??= this.#renew(server, refused).finally(() => {
991
+ server.renewing = undefined;
992
+ });
993
+ if (server.renewing)
994
+ return await server.renewing;
995
+ return server.client === server.refused ? undefined : server.client;
996
+ }
997
+ async#renew(server, refused) {
998
+ const token = server.token ? await McpSignIn.retryToken(refused.ref, server.token, this.#onNotice) : undefined;
999
+ const client = token ? await McpToolPack2.#reopen(refused.ref, token) : undefined;
1000
+ if (!client) {
1001
+ McpToolPack2.#refuse(server, refused);
1002
+ return;
1003
+ }
1004
+ refused.close();
1005
+ server.client = client;
1006
+ server.token = token;
1007
+ return client;
1008
+ }
1009
+ static async#reopen(ref, token) {
1010
+ try {
1011
+ return await new McpClient2(ref, token).connect();
1012
+ } catch (error) {
1013
+ if (error instanceof McpUnauthorized2)
1014
+ return;
1015
+ throw error;
1016
+ }
1017
+ }
953
1018
  static #nameOf(server, tool) {
954
1019
  return `mcp__${server.replace(/[^a-zA-Z0-9_]/g, "_")}__${tool}`;
955
1020
  }
@@ -1172,32 +1237,27 @@ class AkanCodePlugins2 {
1172
1237
  const dispose = () => mcp?.close();
1173
1238
  const mcpStatus = mcp?.status ?? [];
1174
1239
  const web = new WebToolPack2({ profile: options.profile });
1175
- const webExtension = web.extension();
1176
1240
  const sessions = new SessionToolPack2({
1177
1241
  workspaceRoot: options.workspace.workspaceRoot,
1178
1242
  cwd: options.cwd,
1179
1243
  profile: options.profile,
1180
1244
  currentSessionId: options.currentSessionId
1181
1245
  });
1182
- const sessionExtension = sessions.extension();
1183
1246
  const mail = new MailToolPack2({ profile: options.profile, mailbox: options.mailbox });
1184
- const mailExtension = mail.extension();
1185
1247
  const onAsk = options.onAsk;
1186
1248
  const ask = onAsk ? new AskToolPack({ profile: options.profile, ask: onAsk }) : undefined;
1187
- const askExtension = ask?.extension();
1249
+ const shared = {
1250
+ extensions: [mcp?.extension(), web.extension(), sessions.extension(), mail.extension(), ask?.extension()].filter((entry) => !!entry),
1251
+ toolNames: [
1252
+ ...mcp?.toolNames ?? [],
1253
+ ...web.names(),
1254
+ ...sessions.names(),
1255
+ ...mail.names(),
1256
+ ...ask?.names() ?? []
1257
+ ]
1258
+ };
1188
1259
  if (!options.profile.tools.akan)
1189
- return {
1190
- extensions: [mcp?.extension(), webExtension, sessionExtension, mailExtension, askExtension].filter((entry) => !!entry),
1191
- toolNames: [
1192
- ...mcp?.toolNames ?? [],
1193
- ...web.names(),
1194
- ...sessions.names(),
1195
- ...mail.names(),
1196
- ...ask?.names() ?? []
1197
- ],
1198
- mcp: mcpStatus,
1199
- dispose
1200
- };
1260
+ return { ...shared, mcp: mcpStatus, dispose };
1201
1261
  const readOnly = !options.profile.tools.builtin.includes("write");
1202
1262
  const pack = new AkanToolPack2({
1203
1263
  workspace: options.workspace,
@@ -1210,6 +1270,7 @@ class AkanCodePlugins2 {
1210
1270
  cwd: options.cwd,
1211
1271
  parent: options.profile,
1212
1272
  depth: options.depth,
1273
+ ...options.subagentSpend ? { spend: options.subagentSpend } : {},
1213
1274
  ...options.onNotice ? { onNotice: options.onNotice } : {},
1214
1275
  ...options.onAgents ? { onAgents: options.onAgents } : {}
1215
1276
  });
@@ -1221,27 +1282,9 @@ class AkanCodePlugins2 {
1221
1282
  budget: options.profile.limits.feedback,
1222
1283
  ...options.onNotice ? { onNotice: options.onNotice } : {}
1223
1284
  }).extension());
1224
- if (mcp)
1225
- extensions.push(mcp.extension());
1226
- if (webExtension)
1227
- extensions.push(webExtension);
1228
- if (sessionExtension)
1229
- extensions.push(sessionExtension);
1230
- if (mailExtension)
1231
- extensions.push(mailExtension);
1232
- if (askExtension)
1233
- extensions.push(askExtension);
1234
1285
  return {
1235
- extensions,
1236
- toolNames: [
1237
- ...await pack.names(),
1238
- ...subagent ? [SubagentPool2.toolName] : [],
1239
- ...mcp?.toolNames ?? [],
1240
- ...web.names(),
1241
- ...sessions.names(),
1242
- ...mail.names(),
1243
- ...ask?.names() ?? []
1244
- ],
1286
+ extensions: [...extensions, ...shared.extensions],
1287
+ toolNames: [...await pack.names(), ...subagent ? [SubagentPool2.toolName] : [], ...shared.toolNames],
1245
1288
  mcp: mcpStatus,
1246
1289
  dispose
1247
1290
  };
@@ -1420,9 +1463,38 @@ var akanSystemPrompt2 = (profile) => {
1420
1463
  };
1421
1464
 
1422
1465
  // pkgs/@akanjs/devkit/codeAgent/agent/CodeSessionIndex.ts
1423
- import { existsSync as existsSync6, readdirSync as readdirSync2, readFileSync as readFileSync3, statSync as statSync3 } from "fs";
1466
+ import { existsSync as existsSync6, readdirSync as readdirSync2, statSync as statSync4 } from "fs";
1424
1467
  import path6 from "path";
1425
1468
 
1469
+ // pkgs/@akanjs/devkit/codeAgent/agent/jsonLines.ts
1470
+ import { closeSync, openSync, readFileSync as readFileSync3, readSync, statSync as statSync3 } from "fs";
1471
+ var readHead = (file, maxBytes) => {
1472
+ const fd = openSync(file, "r");
1473
+ try {
1474
+ const head = Buffer.alloc(maxBytes);
1475
+ return head.subarray(0, readSync(fd, head, 0, maxBytes, 0)).toString("utf8");
1476
+ } finally {
1477
+ closeSync(fd);
1478
+ }
1479
+ };
1480
+ var readJsonLines = (file, maxBytes) => {
1481
+ try {
1482
+ const text = maxBytes !== undefined && statSync3(file).size > maxBytes ? readHead(file, maxBytes) : readFileSync3(file, "utf8");
1483
+ return text.split(`
1484
+ `).filter((line) => !!line.trim());
1485
+ } catch {
1486
+ return [];
1487
+ }
1488
+ };
1489
+ var parseJsonLine = (line) => {
1490
+ try {
1491
+ return JSON.parse(line);
1492
+ } catch {
1493
+ return;
1494
+ }
1495
+ };
1496
+
1497
+ // pkgs/@akanjs/devkit/codeAgent/agent/CodeSessionIndex.ts
1426
1498
  class CodeSessionIndex2 {
1427
1499
  static readLimit = 512 * 1024;
1428
1500
  static list(dir, limit = 30) {
@@ -1439,18 +1511,18 @@ class CodeSessionIndex2 {
1439
1511
  }
1440
1512
  static #mtime(file) {
1441
1513
  try {
1442
- return statSync3(file).mtimeMs;
1514
+ return statSync4(file).mtimeMs;
1443
1515
  } catch {
1444
1516
  return 0;
1445
1517
  }
1446
1518
  }
1447
1519
  static #read(file, updatedAt) {
1448
- const lines = CodeSessionIndex2.#lines(file);
1520
+ const lines = readJsonLines(file, CodeSessionIndex2.readLimit);
1449
1521
  if (!lines.length)
1450
1522
  return;
1451
1523
  const entry = { id: "", file, name: undefined, opening: "", updatedAt, turns: 0 };
1452
1524
  for (const line of lines) {
1453
- const record = CodeSessionIndex2.#parse(line);
1525
+ const record = parseJsonLine(line);
1454
1526
  if (!record)
1455
1527
  continue;
1456
1528
  if (record.type === "session" && typeof record.id === "string")
@@ -1468,23 +1540,6 @@ class CodeSessionIndex2 {
1468
1540
  }
1469
1541
  return entry.id ? entry : undefined;
1470
1542
  }
1471
- static #lines(file) {
1472
- try {
1473
- if (statSync3(file).size > CodeSessionIndex2.readLimit)
1474
- return [];
1475
- return readFileSync3(file, "utf8").split(`
1476
- `).filter((line) => !!line.trim());
1477
- } catch {
1478
- return [];
1479
- }
1480
- }
1481
- static #parse(line) {
1482
- try {
1483
- return JSON.parse(line);
1484
- } catch {
1485
- return;
1486
- }
1487
- }
1488
1543
  static #text(content) {
1489
1544
  const text = typeof content === "string" ? content : Array.isArray(content) ? content.map((part) => typeof part === "object" && part && ("text" in part) ? String(part.text) : "").join(" ") : "";
1490
1545
  return text.replace(/\s+/g, " ").trim();
@@ -1503,19 +1558,14 @@ class AkanCodeServices2 {
1503
1558
  }
1504
1559
  static async runtime(workspaceRoot, proxy = null) {
1505
1560
  mkdirSync(akanCodePaths2.globalDir(), { recursive: true, mode: 448 });
1506
- if (proxy) {
1507
- const runtime = await ModelRuntime.create({
1508
- authPath: path7.join(mkdtempSync(path7.join(tmpdir(), "akan-code-proxy-")), "auth.json"),
1509
- modelsPath: akanCodePaths2.modelsFile()
1510
- });
1511
- await proxy.apply(runtime);
1512
- return runtime;
1513
- }
1514
1561
  const runtime = await ModelRuntime.create({
1515
- authPath: akanCodePaths2.authFile(),
1562
+ authPath: proxy ? path7.join(mkdtempSync(path7.join(tmpdir(), "akan-code-proxy-")), "auth.json") : akanCodePaths2.authFile(),
1516
1563
  modelsPath: akanCodePaths2.modelsFile()
1517
1564
  });
1518
- await AkanEnvKeys2.apply(runtime, workspaceRoot);
1565
+ if (proxy)
1566
+ await proxy.apply(runtime);
1567
+ else
1568
+ await AkanEnvKeys2.apply(runtime, workspaceRoot);
1519
1569
  return runtime;
1520
1570
  }
1521
1571
  static sessions(workspaceRoot, cwd, profile, resume) {
@@ -1582,7 +1632,7 @@ class CodeAgentAsks2 {
1582
1632
  }
1583
1633
  openQuestion(question) {
1584
1634
  this.#question?.deferred.resolve("");
1585
- const deferred = CodeAgentAsks2.#defer();
1635
+ const deferred = Promise.withResolvers();
1586
1636
  this.#question = { question, deferred };
1587
1637
  return deferred.promise;
1588
1638
  }
@@ -1595,7 +1645,7 @@ class CodeAgentAsks2 {
1595
1645
  return true;
1596
1646
  }
1597
1647
  openApproval(id) {
1598
- const deferred = CodeAgentAsks2.#defer();
1648
+ const deferred = Promise.withResolvers();
1599
1649
  this.#approvals.set(id, deferred);
1600
1650
  return deferred.promise;
1601
1651
  }
@@ -1614,13 +1664,6 @@ class CodeAgentAsks2 {
1614
1664
  deferred.resolve(false);
1615
1665
  this.#approvals.clear();
1616
1666
  }
1617
- static #defer() {
1618
- let resolve = () => {};
1619
- const promise = new Promise((r) => {
1620
- resolve = r;
1621
- });
1622
- return { resolve, promise };
1623
- }
1624
1667
  }
1625
1668
 
1626
1669
  // pkgs/@akanjs/devkit/codeAgent/agent/CodeAgentEventMapper.ts
@@ -1629,6 +1672,16 @@ import {
1629
1672
  codeAgentLabelChars,
1630
1673
  codeAgentOutputChars as codeAgentOutputChars4
1631
1674
  } from "akanjs/common";
1675
+
1676
+ // pkgs/@akanjs/devkit/codeAgent/agent/stringArg.ts
1677
+ var stringArg = (args, key) => {
1678
+ if (!args || typeof args !== "object")
1679
+ return;
1680
+ const value = args[key];
1681
+ return typeof value === "string" && value ? value : undefined;
1682
+ };
1683
+
1684
+ // pkgs/@akanjs/devkit/codeAgent/agent/CodeAgentEventMapper.ts
1632
1685
  var toolOps = {
1633
1686
  read: "read",
1634
1687
  write: "write",
@@ -1772,7 +1825,7 @@ class CodeAgentEventMapper2 {
1772
1825
  return "done";
1773
1826
  }
1774
1827
  #summary(toolCallId, name, args) {
1775
- const path = CodeAgentEventMapper2.#pathOf(args);
1828
+ const path = stringArg(args, "path");
1776
1829
  return {
1777
1830
  toolCallId,
1778
1831
  name,
@@ -1798,12 +1851,6 @@ class CodeAgentEventMapper2 {
1798
1851
  return [];
1799
1852
  return [{ type: "message", turnId: this.#turnId, role: message.role, text }];
1800
1853
  }
1801
- static #pathOf(args) {
1802
- if (!args || typeof args !== "object")
1803
- return;
1804
- const value = args.path;
1805
- return typeof value === "string" && value ? value : undefined;
1806
- }
1807
1854
  static #renderArgs(args) {
1808
1855
  if (!args || typeof args !== "object")
1809
1856
  return "";
@@ -1855,13 +1902,13 @@ class CodeAgentGate2 {
1855
1902
  this.#deniedFragments = [...new Set((profile.paths.deny ?? []).map(CodeAgentGate2.#fragmentOf).filter(Boolean))];
1856
1903
  }
1857
1904
  verdict(toolName, args) {
1858
- const target = CodeAgentGate2.#pathOf(args);
1905
+ const target = stringArg(args, "path");
1859
1906
  if (target) {
1860
1907
  const denied = this.#deniedReason(target);
1861
1908
  if (denied)
1862
1909
  return { block: denied };
1863
1910
  }
1864
- const command = CodeAgentGate2.#commandOf(args);
1911
+ const command = stringArg(args, "command");
1865
1912
  if (command) {
1866
1913
  const denied = this.#deniedCommandReason(command);
1867
1914
  if (denied)
@@ -1906,23 +1953,11 @@ class CodeAgentGate2 {
1906
1953
  const trimmed = pattern.replace(/^\*\*\//, "").replace(/\/\*\*$/, "/").replace(/^\*+/, "");
1907
1954
  return trimmed.includes("*") ? "" : trimmed;
1908
1955
  }
1909
- static #commandOf(args) {
1910
- if (!args || typeof args !== "object")
1911
- return;
1912
- const value = args.command;
1913
- return typeof value === "string" && value ? value : undefined;
1914
- }
1915
- static #pathOf(args) {
1916
- if (!args || typeof args !== "object")
1917
- return;
1918
- const value = args.path;
1919
- return typeof value === "string" && value ? value : undefined;
1920
- }
1921
1956
  static #summarize(toolName, args) {
1922
1957
  const record = args ?? {};
1923
1958
  if (toolName === "bash")
1924
1959
  return `run: ${String(record.command ?? "").slice(0, 200)}`;
1925
- const target = CodeAgentGate2.#pathOf(args);
1960
+ const target = stringArg(args, "path");
1926
1961
  return target ? `${toolName} ${target}` : toolName;
1927
1962
  }
1928
1963
  }
@@ -2106,11 +2141,10 @@ import {
2106
2141
  readdirSync as readdirSync3,
2107
2142
  readFileSync as readFileSync5,
2108
2143
  rmSync as rmSync2,
2109
- statSync as statSync4,
2144
+ statSync as statSync5,
2110
2145
  writeFileSync as writeFileSync2
2111
2146
  } from "fs";
2112
2147
  import path10 from "path";
2113
-
2114
2148
  class CodeMailbox2 {
2115
2149
  static staleMs = 20000;
2116
2150
  static beatMs = 5000;
@@ -2134,7 +2168,7 @@ class CodeMailbox2 {
2134
2168
  open(cwd, onMail) {
2135
2169
  mkdirSync3(path10.join(this.#dir, "live"), { recursive: true });
2136
2170
  mkdirSync3(path10.join(this.#dir, "inbox"), { recursive: true });
2137
- this.#read = CodeMailbox2.#lines(this.inbox).length;
2171
+ this.#read = readJsonLines(this.inbox).length;
2138
2172
  this.beat(cwd);
2139
2173
  this.#beat = setInterval(() => this.beat(cwd), CodeMailbox2.beatMs);
2140
2174
  this.#poll = setInterval(() => {
@@ -2191,32 +2225,17 @@ class CodeMailbox2 {
2191
2225
  `);
2192
2226
  }
2193
2227
  #drain() {
2194
- const lines = CodeMailbox2.#lines(this.inbox);
2228
+ const lines = readJsonLines(this.inbox);
2195
2229
  if (lines.length <= this.#read)
2196
2230
  return [];
2197
2231
  const fresh = lines.slice(this.#read);
2198
2232
  this.#read = lines.length;
2199
- return fresh.map((line) => CodeMailbox2.#parse(line)).filter((mail) => !!mail?.text && typeof mail.from === "string");
2233
+ return fresh.map((line) => parseJsonLine(line)).filter((mail) => !!mail?.text && typeof mail.from === "string");
2200
2234
  }
2201
2235
  static #peer(file) {
2202
2236
  try {
2203
2237
  const peer = JSON.parse(readFileSync5(file, "utf8"));
2204
- return typeof peer.id === "string" ? { ...peer, at: peer.at || statSync4(file).mtimeMs } : undefined;
2205
- } catch {
2206
- return;
2207
- }
2208
- }
2209
- static #lines(file) {
2210
- try {
2211
- return readFileSync5(file, "utf8").split(`
2212
- `).filter((line) => !!line.trim());
2213
- } catch {
2214
- return [];
2215
- }
2216
- }
2217
- static #parse(line) {
2218
- try {
2219
- return JSON.parse(line);
2238
+ return typeof peer.id === "string" ? { ...peer, at: peer.at || statSync5(file).mtimeMs } : undefined;
2220
2239
  } catch {
2221
2240
  return;
2222
2241
  }
@@ -2239,7 +2258,7 @@ class CodeSessionFork2 {
2239
2258
  throw new Error(`Session ${id} has nothing in it to fork`);
2240
2259
  const at = new Date;
2241
2260
  const forked = Bun.randomUUIDv7();
2242
- const records = lines.map((line) => CodeSessionFork2.#parse(line)).filter((record) => !!record);
2261
+ const records = lines.map((line) => parseJsonLine(line)).filter((record) => !!record);
2243
2262
  const first = records.find((record) => record.type === "session");
2244
2263
  if (!first)
2245
2264
  throw new Error(`Session ${id} carries no session record`);
@@ -2267,13 +2286,6 @@ class CodeSessionFork2 {
2267
2286
  const current = typeof named?.name === "string" ? named.name : "";
2268
2287
  return codeAgentSessionName(current ? `${current} fork` : "fork");
2269
2288
  }
2270
- static #parse(line) {
2271
- try {
2272
- return JSON.parse(line);
2273
- } catch {
2274
- return;
2275
- }
2276
- }
2277
2289
  }
2278
2290
 
2279
2291
  // pkgs/@akanjs/devkit/codeAgent/agent/CodeAgent.ts
@@ -2315,6 +2327,7 @@ class CodeAgent2 {
2315
2327
  apps: options.apps ?? [],
2316
2328
  canSeeImages: akanCodeModelSupportsImages2(model),
2317
2329
  depth: options.depth ?? 0,
2330
+ ...options.subagentSpend ? { subagentSpend: options.subagentSpend } : {},
2318
2331
  currentSessionId: () => agent.sessionId,
2319
2332
  mailbox: () => agent.#mailbox,
2320
2333
  onNotice: (message) => agent.#emit({ type: "notice", level: "warning", message }),
@@ -2395,7 +2408,7 @@ class CodeAgent2 {
2395
2408
  this.#mailbox.open(cwd, (mail) => {
2396
2409
  const from = `${mail.fromName} (${mail.from.slice(0, 8)})`;
2397
2410
  this.#emit({ type: "notice", level: "info", message: `message from ${from}` });
2398
- this.prompt(`Message from another session \u2014 ${from}:
2411
+ this.#prompt(`Message from another session \u2014 ${from}:
2399
2412
  ${mail.text}`).catch((error) => this.#emit({ type: "notice", level: "error", message: String(error) }));
2400
2413
  });
2401
2414
  }
@@ -2465,6 +2478,10 @@ ${mail.text}`).catch((error) => this.#emit({ type: "notice", level: "error", mes
2465
2478
  return { ...base, frames: this.#replay.filter((event) => event.seq > sinceSeq) };
2466
2479
  }
2467
2480
  async prompt(message, images) {
2481
+ this.#suspended.clear();
2482
+ await this.#prompt(message, images);
2483
+ }
2484
+ async#prompt(message, images) {
2468
2485
  const session = this.#require();
2469
2486
  if (!session.sessionName && message.trim())
2470
2487
  this.setName(codeAgentSessionName2(message));
@@ -2493,7 +2510,7 @@ ${mail.text}`).catch((error) => this.#emit({ type: "notice", level: "error", mes
2493
2510
  return false;
2494
2511
  const suspendedRendered = codeAgentRenderAnswer(suspended, answer);
2495
2512
  this.#emit({ type: "question_resolved", questionId, answer, rendered: suspendedRendered });
2496
- await this.prompt(`The user answered: ${suspendedRendered}
2513
+ await this.#prompt(`The user answered: ${suspendedRendered}
2497
2514
  Continue the task.`);
2498
2515
  return true;
2499
2516
  }
@@ -2508,7 +2525,7 @@ Continue the task.`);
2508
2525
  return false;
2509
2526
  this.#emit({ type: "approval_resolved", approvalId, approved });
2510
2527
  if (approved)
2511
- await this.prompt("The user approved the pending action. Retry it and continue.");
2528
+ await this.#prompt("The user approved the pending action. Retry it and continue.");
2512
2529
  return true;
2513
2530
  }
2514
2531
  async compact(instructions) {
@@ -2583,7 +2600,8 @@ Continue the task.`);
2583
2600
  session.subscribe((event) => {
2584
2601
  for (const body of this.#mapper.map(event))
2585
2602
  this.#emit(body);
2586
- this.#emitContextUsage(event.type);
2603
+ if (event.type === "agent_end" || event.type === "compaction_end")
2604
+ this.#emitContextNow();
2587
2605
  });
2588
2606
  await session.bindExtensions({
2589
2607
  mode,
@@ -2606,11 +2624,6 @@ Continue the task.`);
2606
2624
  };
2607
2625
  }));
2608
2626
  }
2609
- #emitContextUsage(eventType) {
2610
- if (eventType !== "agent_end" && eventType !== "compaction_end")
2611
- return;
2612
- this.#emitContextNow();
2613
- }
2614
2627
  #emitContextNow() {
2615
2628
  const usage = this.#session?.getContextUsage();
2616
2629
  if (usage?.tokens == null)