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

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 (75) hide show
  1. package/.build-stamp +1 -1
  2. package/{CodeAgent-0035exh3.js → CodeAgent-6cm97kay.js} +2 -2
  3. package/{CodeAgentRpcHost-qvwfv0n9.js → CodeAgentRpcHost-p7h6n2hp.js} +1 -1
  4. package/CodeAgentRpcListener-7p7z5dd7.js +97 -0
  5. package/{CodeTui-eweg1hep.js → CodeTui-za4jsm41.js} +1 -1
  6. package/{TunnelShare-r5tc2qk5.js → TunnelShare-2j6s511d.js} +2 -2
  7. package/{agent.command-65zqfkg0.js → agent.command-e0wpbbyg.js} +5 -5
  8. package/akanCode.js +4 -4
  9. package/{application.command-2wcj5da3.js → application.command-8wyxqc8q.js} +15 -9
  10. package/{applicationBuildRunner-m0hhgwsx.js → applicationBuildRunner-n9gzaxd0.js} +31 -7
  11. package/{applicationReleasePackager-vykfzgx3.js → applicationReleasePackager-vpggfqgq.js} +1 -1
  12. package/buildBatch.proc.js +3 -3
  13. package/{capacitorApp-2daqhb5h.js → capacitorApp-q3z0qht0.js} +2 -2
  14. package/{cloud.command-960bgbf4.js → cloud.command-4zwa5dsx.js} +34 -12
  15. package/cloud.script-fwx3vb34.js +20 -0
  16. package/{code.command-4feh3ef7.js → code.command-468c9d7s.js} +41 -19
  17. package/commandManifest.json +1 -1
  18. package/{context.command-kzehkx48.js → context.command-dsnw0jby.js} +13 -13
  19. package/context.runner-rs4rj15d.js +22 -0
  20. package/{dependencyScanner-shs82ynp.js → dependencyScanner-0z2h2tks.js} +1 -1
  21. package/{guideline.command-3w2g20x4.js → guideline.command-vhw13pqr.js} +2 -2
  22. package/guidelines/agentRule/agentRule.instruction.md +27 -10
  23. package/guidelines/conventions/conventions.instruction.md +16 -4
  24. package/guidelines/queryRule/queryRule.instruction.md +16 -6
  25. package/guidelines/runtimeRule/runtimeRule.instruction.md +74 -0
  26. package/incrementalBuilder.proc.js +3 -2
  27. package/{index-dw943k93.js → index-10dkrrww.js} +4 -4
  28. package/{index-rpgxs245.js → index-18zybgkc.js} +2 -2
  29. package/{index-mt2154s2.js → index-22xtgmhn.js} +1 -1
  30. package/{index-yw6g3bbv.js → index-2446k7b4.js} +1 -1
  31. package/{index-cjw1sj1x.js → index-3jrp517k.js} +10 -10
  32. package/{index-q9c3c0hy.js → index-4m929vvn.js} +2 -2
  33. package/{index-ef228gzf.js → index-53176s7j.js} +3 -3
  34. package/{index-jwrpsrg3.js → index-667w0yah.js} +1 -1
  35. package/{index-6q589y9t.js → index-7ep8qtvp.js} +2 -2
  36. package/{index-w8kmx1b6.js → index-89hy31kf.js} +30 -7
  37. package/{index-jd01kj5r.js → index-9d6nvkz2.js} +1 -1
  38. package/{index-zq0mr3hh.js → index-a1w6934z.js} +3 -3
  39. package/{index-sbfk9daf.js → index-ab0c38ea.js} +4 -4
  40. package/index-bc88j1ry.js +1166 -0
  41. package/{index-h94faz96.js → index-bftkz6cp.js} +274 -60
  42. package/{index-kcxmv48c.js → index-bhtmj233.js} +4 -1
  43. package/{index-m41ptvat.js → index-bwf965h6.js} +3 -3
  44. package/{index-bwxpk2cj.js → index-crmeqnmf.js} +52 -26
  45. package/{index-8k16atqy.js → index-d2242ksy.js} +23 -6
  46. package/{index-jwexzh42.js → index-e4v6vhxq.js} +222 -56
  47. package/{index-pn8mhpps.js → index-esk82rvk.js} +4 -4
  48. package/{index-4r42ext5.js → index-kwaq3n9n.js} +1 -1
  49. package/{index-gm76f0qb.js → index-n3cv0tm4.js} +1 -1
  50. package/{index-ycy302an.js → index-qdgzsnhg.js} +1 -1
  51. package/{index-wcg582a8.js → index-sq2dzkzm.js} +35 -10
  52. package/{index-myj01w9r.js → index-srmay5jw.js} +15 -2
  53. package/{index-zmj143x7.js → index-txr7dj2g.js} +3 -3
  54. package/{index-erfc1x40.js → index-vqx8bdxz.js} +1 -1
  55. package/{index-d9fjz06h.js → index-zqgj2rt2.js} +4 -4
  56. package/index.js +21 -21
  57. package/{library.command-fp0nhr62.js → library.command-cqr175dy.js} +3 -3
  58. package/{localRegistry.command-8y0ecxb9.js → localRegistry.command-49z55qqz.js} +9 -9
  59. package/{module.command-kqkn48t2.js → module.command-9p8mm3b0.js} +5 -5
  60. package/{package.command-qverjh22.js → package.command-wxyz909t.js} +4 -4
  61. package/package.json +2 -2
  62. package/{page.command-94bwhd0g.js → page.command-gsrsfqqs.js} +3 -3
  63. package/{primitive.command-2ydvtah2.js → primitive.command-ns1mptje.js} +6 -6
  64. package/{quality.command-fa0gth4p.js → quality.command-e76k2q9k.js} +17 -15
  65. package/{repair.command-4qng2hpm.js → repair.command-pkrsm3cw.js} +5 -5
  66. package/{scalar.command-pb2y95sh.js → scalar.command-0cpt3fc8.js} +4 -4
  67. package/{subspace.command-vkxmwp74.js → subspace.command-fktpwp0g.js} +20 -10
  68. package/templates/appSample/lib/task/task.signal.test.ts +1 -1
  69. package/templates/localDev/docker-compose.yaml.template +3 -14
  70. package/{tunnel.command-02cvp9nf.js → tunnel.command-d5jy9gk8.js} +4 -4
  71. package/{workflow.command-132txnrh.js → workflow.command-6tkcysmx.js} +9 -9
  72. package/{workspace.command-d5wkswek.js → workspace.command-gv84eh1p.js} +24 -23
  73. package/cloud.script-qhcnqt1n.js +0 -20
  74. package/context.runner-z0rrcz7b.js +0 -22
  75. package/index-3hpxeys1.js +0 -462
@@ -4,20 +4,20 @@ import {
4
4
  akanCodePaths2,
5
5
  McpServerConfig,
6
6
  McpSignIn
7
- } from "./index-jd01kj5r.js";
7
+ } from "./index-9d6nvkz2.js";
8
8
  import {
9
9
  stripAnsi
10
10
  } from "./index-7md2g9vw.js";
11
11
  import {
12
+ akanCodeDefaultModel2,
12
13
  akanCodeModel2,
13
14
  akanCodeModelSupportsImages2,
14
15
  akanCodeModelWarnings2
15
- } from "./index-jwrpsrg3.js";
16
+ } from "./index-667w0yah.js";
16
17
 
17
18
  // pkgs/@akanjs/devkit/codeAgent/agent/CodeAgent.ts
18
19
  import {
19
20
  createAgentSession,
20
- DEFAULT_COMPACTION_SETTINGS,
21
21
  DefaultResourceLoader
22
22
  } from "@earendil-works/pi-coding-agent";
23
23
  import {
@@ -514,7 +514,7 @@ class AkanToolPack2 {
514
514
  return { name: "akan-tools", factory: async (pi) => await this.#register(pi) };
515
515
  }
516
516
  async names() {
517
- const { ContextRunner } = await import("./context.runner-z0rrcz7b.js");
517
+ const { ContextRunner } = await import("./context.runner-rs4rj15d.js");
518
518
  return [
519
519
  ...new ContextRunner().listMcpTools(this.#options.mode).map((tool) => tool.name),
520
520
  AkanToolPack2.verifyToolName
@@ -522,7 +522,7 @@ class AkanToolPack2 {
522
522
  }
523
523
  static verifyToolName = "akan_verify";
524
524
  async#register(pi) {
525
- const { ContextRunner } = await import("./context.runner-z0rrcz7b.js");
525
+ const { ContextRunner } = await import("./context.runner-rs4rj15d.js");
526
526
  const runner = new ContextRunner;
527
527
  const guidelineNames = await AkanToolPack2.#guidelineNames();
528
528
  for (const tool of runner.listMcpTools(this.#options.mode, { guidelineNames })) {
@@ -1272,7 +1272,9 @@ class AkanCodePlugins2 {
1272
1272
  }
1273
1273
 
1274
1274
  // pkgs/@akanjs/devkit/codeAgent/agent/AkanCodeServices.ts
1275
- import { existsSync as existsSync7, mkdirSync } from "fs";
1275
+ import { existsSync as existsSync7, mkdirSync, mkdtempSync } from "fs";
1276
+ import { tmpdir } from "os";
1277
+ import path7 from "path";
1276
1278
  import { ModelRuntime, SessionManager as SessionManager2, SettingsManager } from "@earendil-works/pi-coding-agent";
1277
1279
 
1278
1280
  // pkgs/@akanjs/devkit/codeAgent/tools/AkanEnvKeys.ts
@@ -1495,11 +1497,20 @@ class AkanCodeServices2 {
1495
1497
  return SettingsManager.inMemory({
1496
1498
  enableInstallTelemetry: false,
1497
1499
  enableAnalytics: false,
1498
- quietStartup: true
1500
+ quietStartup: true,
1501
+ compaction: { reserveTokens: 32768 }
1499
1502
  });
1500
1503
  }
1501
- static async runtime(workspaceRoot) {
1504
+ static async runtime(workspaceRoot, proxy = null) {
1502
1505
  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
+ }
1503
1514
  const runtime = await ModelRuntime.create({
1504
1515
  authPath: akanCodePaths2.authFile(),
1505
1516
  modelsPath: akanCodePaths2.modelsFile()
@@ -1508,7 +1519,7 @@ class AkanCodeServices2 {
1508
1519
  return runtime;
1509
1520
  }
1510
1521
  static sessions(workspaceRoot, cwd, profile, resume) {
1511
- if (profile.session.store !== "file")
1522
+ if (profile.session.store === "memory")
1512
1523
  return SessionManager2.inMemory(cwd);
1513
1524
  const dir = akanCodePaths2.sessionsDir(workspaceRoot);
1514
1525
  mkdirSync(dir, { recursive: true });
@@ -1555,6 +1566,7 @@ class CodeAgentAsks2 {
1555
1566
  #question;
1556
1567
  #approvals = new Map;
1557
1568
  #nextId = 0;
1569
+ #epoch = Date.now().toString(36);
1558
1570
  get pendingQuestionId() {
1559
1571
  return this.#question?.question.questionId;
1560
1572
  }
@@ -1566,7 +1578,7 @@ class CodeAgentAsks2 {
1566
1578
  }
1567
1579
  nextId(prefix) {
1568
1580
  this.#nextId += 1;
1569
- return `${prefix}${this.#nextId}`;
1581
+ return `${prefix}${this.#epoch}.${this.#nextId}`;
1570
1582
  }
1571
1583
  openQuestion(question) {
1572
1584
  this.#question?.deferred.resolve("");
@@ -1675,7 +1687,15 @@ class CodeAgentEventMapper2 {
1675
1687
  case "compaction_start":
1676
1688
  return [{ type: "compaction", phase: "start", reason: event.reason }];
1677
1689
  case "compaction_end":
1678
- return [{ type: "compaction", phase: "end", reason: event.reason }];
1690
+ return [
1691
+ {
1692
+ type: "compaction",
1693
+ phase: "end",
1694
+ reason: event.reason,
1695
+ ...event.errorMessage ? { error: event.errorMessage } : {},
1696
+ ...event.aborted ? { aborted: true } : {}
1697
+ }
1698
+ ];
1679
1699
  case "auto_retry_start":
1680
1700
  return [
1681
1701
  {
@@ -1819,7 +1839,7 @@ class CodeAgentEventMapper2 {
1819
1839
  }
1820
1840
 
1821
1841
  // pkgs/@akanjs/devkit/codeAgent/agent/CodeAgentGate.ts
1822
- import path7 from "path";
1842
+ import path8 from "path";
1823
1843
  var writeTools = new Set(["write", "edit"]);
1824
1844
  var commandTools = new Set(["bash"]);
1825
1845
 
@@ -1858,9 +1878,9 @@ class CodeAgentGate2 {
1858
1878
  return `The command names "${hit}", which the profile's deny list covers. Ask the user for the value instead of reading the file.`;
1859
1879
  }
1860
1880
  #deniedReason(target) {
1861
- const absolute = path7.isAbsolute(target) ? target : path7.resolve(this.#profile.paths.root, target);
1862
- const relative = path7.relative(this.#profile.paths.root, absolute);
1863
- if (relative.startsWith("..") || path7.isAbsolute(relative))
1881
+ const absolute = path8.isAbsolute(target) ? target : path8.resolve(this.#profile.paths.root, target);
1882
+ const relative = path8.relative(this.#profile.paths.root, absolute);
1883
+ if (relative.startsWith("..") || path8.isAbsolute(relative))
1864
1884
  return `Path is outside the agent root (${this.#profile.paths.root}).`;
1865
1885
  if (this.#deny.some((glob) => glob.match(absolute) || glob.match(relative)))
1866
1886
  return "Path is on the profile's deny list (secrets and environment files are never readable).";
@@ -1907,6 +1927,137 @@ class CodeAgentGate2 {
1907
1927
  }
1908
1928
  }
1909
1929
 
1930
+ // pkgs/@akanjs/devkit/codeAgent/agent/CodeAgentProxy.ts
1931
+ import { readFile } from "fs/promises";
1932
+ class CodeAgentProxy {
1933
+ static placeholderKey = "akan-code-proxy";
1934
+ baseUrl;
1935
+ providers;
1936
+ #tokenFile;
1937
+ #token;
1938
+ constructor({ baseUrl, providers, tokenFile, token }) {
1939
+ this.baseUrl = baseUrl.replace(/\/+$/, "");
1940
+ this.providers = providers;
1941
+ this.#tokenFile = tokenFile;
1942
+ this.#token = token;
1943
+ if (!tokenFile && !token)
1944
+ throw new Error("AKAN_CODE_PROXY_URL needs AKAN_CODE_PROXY_TOKEN_FILE or AKAN_CODE_PROXY_TOKEN");
1945
+ }
1946
+ static fromEnv(profile) {
1947
+ const baseUrl = process.env.AKAN_CODE_PROXY_URL?.trim() || profile?.network.proxyBaseUrl;
1948
+ if (!baseUrl)
1949
+ return null;
1950
+ const providers = (process.env.AKAN_CODE_PROXY_PROVIDERS ?? akanCodeDefaultModel2.provider).split(",").map((provider) => provider.trim()).filter(Boolean);
1951
+ return new CodeAgentProxy({
1952
+ baseUrl,
1953
+ providers,
1954
+ tokenFile: process.env.AKAN_CODE_PROXY_TOKEN_FILE?.trim() || undefined,
1955
+ token: process.env.AKAN_CODE_PROXY_TOKEN?.trim() || undefined
1956
+ });
1957
+ }
1958
+ baseUrlFor(provider) {
1959
+ return this.baseUrl.replaceAll("{provider}", provider);
1960
+ }
1961
+ async token() {
1962
+ if (!this.#tokenFile)
1963
+ return this.#token ?? "";
1964
+ const token = (await readFile(this.#tokenFile, "utf8")).trim();
1965
+ if (!token)
1966
+ throw new Error(`${this.#tokenFile} is empty`);
1967
+ return token;
1968
+ }
1969
+ async apply(runtime) {
1970
+ const target = runtime;
1971
+ const original = target.prepareRequest?.bind(runtime);
1972
+ if (!original)
1973
+ throw new Error("The model runtime no longer exposes prepareRequest; update CodeAgentProxy");
1974
+ for (const provider of this.providers)
1975
+ await runtime.setRuntimeApiKey(provider, CodeAgentProxy.placeholderKey);
1976
+ target.prepareRequest = async (model, options = {}) => {
1977
+ const apiKey = await this.token();
1978
+ const prepared = await original(model, { ...options, apiKey });
1979
+ return {
1980
+ ...prepared,
1981
+ model: { ...prepared.model, baseUrl: this.baseUrlFor(prepared.model.provider) },
1982
+ options: { ...prepared.options, apiKey }
1983
+ };
1984
+ };
1985
+ }
1986
+ }
1987
+
1988
+ // pkgs/@akanjs/devkit/codeAgent/agent/CodeAgentSuspended.ts
1989
+ import { existsSync as existsSync8, mkdirSync as mkdirSync2, readFileSync as readFileSync4, rmSync, writeFileSync } from "fs";
1990
+ import path9 from "path";
1991
+
1992
+ class CodeAgentSuspended {
1993
+ #file;
1994
+ #state;
1995
+ constructor(file) {
1996
+ this.#file = file;
1997
+ this.#state = CodeAgentSuspended.#read(file);
1998
+ }
1999
+ static fileOf(sessionDir, sessionId) {
2000
+ return sessionDir ? path9.join(sessionDir, `${sessionId}.suspended.json`) : null;
2001
+ }
2002
+ get question() {
2003
+ return this.#state.question;
2004
+ }
2005
+ get approvals() {
2006
+ return this.#state.approvals;
2007
+ }
2008
+ setQuestion(question) {
2009
+ this.#state = { ...this.#state, question };
2010
+ this.#save();
2011
+ }
2012
+ addApproval(request) {
2013
+ this.#state = { ...this.#state, approvals: [...this.#state.approvals, request] };
2014
+ this.#save();
2015
+ }
2016
+ takeQuestion(questionId) {
2017
+ const question = this.#state.question;
2018
+ if (question?.questionId !== questionId)
2019
+ return;
2020
+ this.#state = { approvals: this.#state.approvals };
2021
+ this.#save();
2022
+ return question;
2023
+ }
2024
+ takeApproval(approvalId) {
2025
+ const request = this.#state.approvals.find((approval) => approval.approvalId === approvalId);
2026
+ if (!request)
2027
+ return;
2028
+ this.#state = { ...this.#state, approvals: this.#state.approvals.filter((approval) => approval !== request) };
2029
+ this.#save();
2030
+ return request;
2031
+ }
2032
+ clear() {
2033
+ if (!this.#state.question && !this.#state.approvals.length)
2034
+ return;
2035
+ this.#state = { approvals: [] };
2036
+ this.#save();
2037
+ }
2038
+ #save() {
2039
+ if (!this.#file)
2040
+ return;
2041
+ if (!this.#state.question && !this.#state.approvals.length) {
2042
+ rmSync(this.#file, { force: true });
2043
+ return;
2044
+ }
2045
+ mkdirSync2(path9.dirname(this.#file), { recursive: true });
2046
+ writeFileSync(this.#file, `${JSON.stringify(this.#state)}
2047
+ `);
2048
+ }
2049
+ static #read(file) {
2050
+ if (!file || !existsSync8(file))
2051
+ return { approvals: [] };
2052
+ try {
2053
+ const parsed = JSON.parse(readFileSync4(file, "utf8"));
2054
+ return { ...parsed.question ? { question: parsed.question } : {}, approvals: parsed.approvals ?? [] };
2055
+ } catch {
2056
+ return { approvals: [] };
2057
+ }
2058
+ }
2059
+ }
2060
+
1910
2061
  // pkgs/@akanjs/devkit/codeAgent/agent/CodeAgentUi.ts
1911
2062
  class CodeAgentUi2 {
1912
2063
  #handlers;
@@ -1950,15 +2101,15 @@ class CodeAgentUi2 {
1950
2101
  // pkgs/@akanjs/devkit/codeAgent/agent/CodeMailbox.ts
1951
2102
  import {
1952
2103
  appendFileSync,
1953
- existsSync as existsSync8,
1954
- mkdirSync as mkdirSync2,
2104
+ existsSync as existsSync9,
2105
+ mkdirSync as mkdirSync3,
1955
2106
  readdirSync as readdirSync3,
1956
- readFileSync as readFileSync4,
1957
- rmSync,
2107
+ readFileSync as readFileSync5,
2108
+ rmSync as rmSync2,
1958
2109
  statSync as statSync4,
1959
- writeFileSync
2110
+ writeFileSync as writeFileSync2
1960
2111
  } from "fs";
1961
- import path8 from "path";
2112
+ import path10 from "path";
1962
2113
 
1963
2114
  class CodeMailbox2 {
1964
2115
  static staleMs = 20000;
@@ -1978,11 +2129,11 @@ class CodeMailbox2 {
1978
2129
  this.#name = name;
1979
2130
  }
1980
2131
  get inbox() {
1981
- return path8.join(this.#dir, "inbox", `${this.#id}.jsonl`);
2132
+ return path10.join(this.#dir, "inbox", `${this.#id}.jsonl`);
1982
2133
  }
1983
2134
  open(cwd, onMail) {
1984
- mkdirSync2(path8.join(this.#dir, "live"), { recursive: true });
1985
- mkdirSync2(path8.join(this.#dir, "inbox"), { recursive: true });
2135
+ mkdirSync3(path10.join(this.#dir, "live"), { recursive: true });
2136
+ mkdirSync3(path10.join(this.#dir, "inbox"), { recursive: true });
1986
2137
  this.#read = CodeMailbox2.#lines(this.inbox).length;
1987
2138
  this.beat(cwd);
1988
2139
  this.#beat = setInterval(() => this.beat(cwd), CodeMailbox2.beatMs);
@@ -1999,7 +2150,7 @@ class CodeMailbox2 {
1999
2150
  this.#beat = null;
2000
2151
  this.#poll = null;
2001
2152
  try {
2002
- rmSync(path8.join(this.#dir, "live", `${this.#id}.json`), { force: true });
2153
+ rmSync2(path10.join(this.#dir, "live", `${this.#id}.json`), { force: true });
2003
2154
  } catch {}
2004
2155
  }
2005
2156
  rename(name, cwd) {
@@ -2009,15 +2160,15 @@ class CodeMailbox2 {
2009
2160
  beat(cwd) {
2010
2161
  const peer = { id: this.#id, name: this.#name, cwd, pid: process.pid, at: Date.now() };
2011
2162
  try {
2012
- writeFileSync(path8.join(this.#dir, "live", `${this.#id}.json`), JSON.stringify(peer));
2163
+ writeFileSync2(path10.join(this.#dir, "live", `${this.#id}.json`), JSON.stringify(peer));
2013
2164
  } catch {}
2014
2165
  }
2015
2166
  peers() {
2016
- const dir = path8.join(this.#dir, "live");
2017
- if (!existsSync8(dir))
2167
+ const dir = path10.join(this.#dir, "live");
2168
+ if (!existsSync9(dir))
2018
2169
  return [];
2019
2170
  const now = Date.now();
2020
- 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);
2171
+ return readdirSync3(dir).filter((entry) => entry.endsWith(".json")).map((entry) => CodeMailbox2.#peer(path10.join(dir, entry))).filter((peer) => !!peer && peer.id !== this.#id && now - peer.at < CodeMailbox2.staleMs).sort((left, right) => right.at - left.at);
2021
2172
  }
2022
2173
  find(target) {
2023
2174
  const needle = target.trim().toLowerCase();
@@ -2035,8 +2186,8 @@ class CodeMailbox2 {
2035
2186
  throw new Error(`Too many messages: ${CodeMailbox2.sendsPerMinute} a minute is the ceiling.`);
2036
2187
  this.#sent.push(now);
2037
2188
  const mail = { at: now, from: this.#id, fromName: this.#name, text };
2038
- mkdirSync2(path8.join(this.#dir, "inbox"), { recursive: true });
2039
- appendFileSync(path8.join(this.#dir, "inbox", `${to}.jsonl`), `${JSON.stringify(mail)}
2189
+ mkdirSync3(path10.join(this.#dir, "inbox"), { recursive: true });
2190
+ appendFileSync(path10.join(this.#dir, "inbox", `${to}.jsonl`), `${JSON.stringify(mail)}
2040
2191
  `);
2041
2192
  }
2042
2193
  #drain() {
@@ -2049,7 +2200,7 @@ class CodeMailbox2 {
2049
2200
  }
2050
2201
  static #peer(file) {
2051
2202
  try {
2052
- const peer = JSON.parse(readFileSync4(file, "utf8"));
2203
+ const peer = JSON.parse(readFileSync5(file, "utf8"));
2053
2204
  return typeof peer.id === "string" ? { ...peer, at: peer.at || statSync4(file).mtimeMs } : undefined;
2054
2205
  } catch {
2055
2206
  return;
@@ -2057,7 +2208,7 @@ class CodeMailbox2 {
2057
2208
  }
2058
2209
  static #lines(file) {
2059
2210
  try {
2060
- return readFileSync4(file, "utf8").split(`
2211
+ return readFileSync5(file, "utf8").split(`
2061
2212
  `).filter((line) => !!line.trim());
2062
2213
  } catch {
2063
2214
  return [];
@@ -2074,15 +2225,15 @@ class CodeMailbox2 {
2074
2225
 
2075
2226
  // pkgs/@akanjs/devkit/codeAgent/agent/CodeSessionFork.ts
2076
2227
  import { randomBytes } from "crypto";
2077
- import { readFileSync as readFileSync5, writeFileSync as writeFileSync2 } from "fs";
2078
- import path9 from "path";
2228
+ import { readFileSync as readFileSync6, writeFileSync as writeFileSync3 } from "fs";
2229
+ import path11 from "path";
2079
2230
  import { codeAgentSessionName } from "akanjs/common";
2080
2231
  class CodeSessionFork2 {
2081
2232
  static fork(dir, id, name) {
2082
2233
  const source = CodeSessionIndex2.fileOf(dir, id);
2083
2234
  if (!source)
2084
2235
  throw new Error(`No stored session ${id} in ${dir}`);
2085
- const lines = readFileSync5(source, "utf8").split(`
2236
+ const lines = readFileSync6(source, "utf8").split(`
2086
2237
  `).filter((line) => !!line.trim());
2087
2238
  if (!lines.length)
2088
2239
  throw new Error(`Session ${id} has nothing in it to fork`);
@@ -2095,8 +2246,8 @@ class CodeSessionFork2 {
2095
2246
  first.id = forked;
2096
2247
  first.timestamp = at.toISOString();
2097
2248
  records.push(CodeSessionFork2.#named(records, name ?? CodeSessionFork2.#nameOf(records), at));
2098
- const file = path9.join(dir, `${at.toISOString().replace(/[:.]/g, "-")}_${forked}.jsonl`);
2099
- writeFileSync2(file, `${records.map((record) => JSON.stringify(record)).join(`
2249
+ const file = path11.join(dir, `${at.toISOString().replace(/[:.]/g, "-")}_${forked}.jsonl`);
2250
+ writeFileSync3(file, `${records.map((record) => JSON.stringify(record)).join(`
2100
2251
  `)}
2101
2252
  `);
2102
2253
  return { id: forked, file };
@@ -2131,6 +2282,7 @@ class CodeAgent2 {
2131
2282
  #gate;
2132
2283
  #mapper = new CodeAgentEventMapper2;
2133
2284
  #asks = new CodeAgentAsks2;
2285
+ #suspended = new CodeAgentSuspended(null);
2134
2286
  #listeners = new Set;
2135
2287
  #session;
2136
2288
  #disposePlugins;
@@ -2152,9 +2304,9 @@ class CodeAgent2 {
2152
2304
  const cwd = options.cwd ?? workspaceRoot;
2153
2305
  const agent = new CodeAgent2(options.profile);
2154
2306
  const settingsManager = AkanCodeServices2.settings();
2155
- const modelRuntime = await AkanCodeServices2.runtime(workspaceRoot);
2307
+ const modelRuntime = await AkanCodeServices2.runtime(workspaceRoot, CodeAgentProxy.fromEnv(options.profile));
2156
2308
  const model = await akanCodeModel2(modelRuntime, options.model);
2157
- const compaction = DEFAULT_COMPACTION_SETTINGS;
2309
+ const compaction = settingsManager.getCompactionSettings(model);
2158
2310
  const modelWarnings = akanCodeModelWarnings2(model, compaction.reserveTokens + compaction.keepRecentTokens);
2159
2311
  const akan = await AkanCodePlugins2.build({
2160
2312
  workspace: options.workspace,
@@ -2196,10 +2348,11 @@ class CodeAgent2 {
2196
2348
  agent.#disposePlugins = akan.dispose;
2197
2349
  agent.#mcp = akan.mcp;
2198
2350
  agent.#workspaceRoot = workspaceRoot;
2199
- if (options.profile.session.store === "file")
2351
+ if (options.profile.session.store !== "memory")
2200
2352
  agent.#sessionDir = akanCodePaths2.sessionsDir(workspaceRoot);
2201
2353
  await agent.#attach(session, options.mode ?? "print");
2202
- if (agent.#sessionDir)
2354
+ agent.#suspended = new CodeAgentSuspended(CodeAgentSuspended.fileOf(agent.#sessionDir, agent.sessionId));
2355
+ if (agent.#sessionDir && options.profile.session.store === "file")
2203
2356
  agent.#openMail(akanCodePaths2.mailDir(workspaceRoot), cwd);
2204
2357
  for (const message of modelWarnings)
2205
2358
  agent.#emit({ type: "notice", level: "warning", message });
@@ -2273,6 +2426,11 @@ ${mail.text}`).catch((error) => this.#emit({ type: "notice", level: "error", mes
2273
2426
  announce() {
2274
2427
  this.#emit({ type: "session", info: this.info });
2275
2428
  this.#restore();
2429
+ const { question, approvals } = this.#suspended;
2430
+ if (question)
2431
+ this.#emit({ type: "question", question });
2432
+ for (const request of approvals)
2433
+ this.#emit({ type: "approval", request });
2276
2434
  }
2277
2435
  #restore() {
2278
2436
  const session = this.#session;
@@ -2330,8 +2488,12 @@ ${mail.text}`).catch((error) => this.#emit({ type: "notice", level: "error", mes
2330
2488
  }
2331
2489
  if (this.#profile.interaction.question !== "suspend")
2332
2490
  return false;
2333
- this.#emit({ type: "question_resolved", questionId, answer, rendered });
2334
- await this.prompt(`The user answered: ${rendered}
2491
+ const suspended = this.#suspended.takeQuestion(questionId);
2492
+ if (!suspended)
2493
+ return false;
2494
+ const suspendedRendered = codeAgentRenderAnswer(suspended, answer);
2495
+ this.#emit({ type: "question_resolved", questionId, answer, rendered: suspendedRendered });
2496
+ await this.prompt(`The user answered: ${suspendedRendered}
2335
2497
  Continue the task.`);
2336
2498
  return true;
2337
2499
  }
@@ -2342,6 +2504,8 @@ Continue the task.`);
2342
2504
  }
2343
2505
  if (this.#profile.interaction.approval !== "suspend")
2344
2506
  return false;
2507
+ if (!this.#suspended.takeApproval(approvalId))
2508
+ return false;
2345
2509
  this.#emit({ type: "approval_resolved", approvalId, approved });
2346
2510
  if (approved)
2347
2511
  await this.prompt("The user approved the pending action. Retry it and continue.");
@@ -2507,28 +2671,30 @@ Continue the task.`);
2507
2671
  if (!this.#profile.ui.canPrompt)
2508
2672
  return true;
2509
2673
  const approvalId = this.#asks.nextId("a");
2510
- this.#emit({
2511
- type: "approval",
2512
- request: {
2513
- approvalId,
2514
- toolCallId,
2515
- name,
2516
- summary: codeAgentClip5(summary, codeAgentLabelChars2),
2517
- policy: this.#profile.approval
2518
- }
2519
- });
2674
+ const request = {
2675
+ approvalId,
2676
+ toolCallId,
2677
+ name,
2678
+ summary: codeAgentClip5(summary, codeAgentLabelChars2),
2679
+ policy: this.#profile.approval
2680
+ };
2681
+ this.#emit({ type: "approval", request });
2520
2682
  if (this.#profile.interaction.approval === "suspend") {
2683
+ this.#suspended.addApproval(request);
2521
2684
  this.#mapper.noteOutcome("awaiting");
2522
2685
  return false;
2523
2686
  }
2524
2687
  return await this.#asks.openApproval(approvalId);
2525
2688
  }
2526
2689
  async ask(spec) {
2527
- if (!this.#profile.ui.canPrompt)
2528
- return;
2529
2690
  const question = { questionId: this.#asks.nextId("q"), ...spec };
2691
+ if (!this.#profile.ui.canPrompt) {
2692
+ this.#emit({ type: "question_skipped", question, reason: "no-host" });
2693
+ return;
2694
+ }
2530
2695
  this.#emit({ type: "question", question });
2531
2696
  if (this.#profile.interaction.question === "suspend") {
2697
+ this.#suspended.setQuestion(question);
2532
2698
  this.#mapper.noteOutcome("awaiting");
2533
2699
  return;
2534
2700
  }
@@ -2,10 +2,10 @@
2
2
  import {
3
3
  runner,
4
4
  script
5
- } from "./index-ycy302an.js";
5
+ } from "./index-qdgzsnhg.js";
6
6
  import {
7
7
  ModuleExecutor
8
- } from "./index-bwxpk2cj.js";
8
+ } from "./index-crmeqnmf.js";
9
9
  import {
10
10
  sourceFile,
11
11
  moduleSourcePaths,
@@ -13,10 +13,10 @@ import {
13
13
  createPassedPrimitiveReport,
14
14
  bilingualLabelForField,
15
15
  bilingualDescriptionForField
16
- } from "./index-yw6g3bbv.js";
16
+ } from "./index-2446k7b4.js";
17
17
  import {
18
18
  PageScript
19
- } from "./index-mt2154s2.js";
19
+ } from "./index-22xtgmhn.js";
20
20
  import {
21
21
  pluralizeName
22
22
  } from "./index-nz8prx9g.js";
@@ -1,7 +1,7 @@
1
1
  // @bun
2
2
  import {
3
3
  AppInfo
4
- } from "./index-bwxpk2cj.js";
4
+ } from "./index-crmeqnmf.js";
5
5
 
6
6
  // pkgs/@akanjs/devkit/slicePlanner.ts
7
7
  class SlicePlanner {
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  GlobalConfig,
4
4
  CloudApi
5
- } from "./index-myj01w9r.js";
5
+ } from "./index-srmay5jw.js";
6
6
 
7
7
  // pkgs/@akanjs/cli/tunnel/TunnelShare.ts
8
8
  import { TunnelAgent } from "akanjs/server/tunnel";
@@ -9,7 +9,7 @@ import {
9
9
  LibExecutor,
10
10
  PkgExecutor,
11
11
  ModuleExecutor
12
- } from "./index-bwxpk2cj.js";
12
+ } from "./index-crmeqnmf.js";
13
13
  import {
14
14
  getDirname2
15
15
  } from "./index-6wwzs1bc.js";
@@ -2,22 +2,22 @@
2
2
  import {
3
3
  GlobalConfig,
4
4
  CloudApi
5
- } from "./index-myj01w9r.js";
5
+ } from "./index-srmay5jw.js";
6
6
  import {
7
7
  script
8
- } from "./index-ycy302an.js";
8
+ } from "./index-qdgzsnhg.js";
9
9
  import {
10
10
  PkgExecutor
11
- } from "./index-bwxpk2cj.js";
11
+ } from "./index-crmeqnmf.js";
12
12
  import {
13
13
  ApplicationScript
14
- } from "./index-h94faz96.js";
14
+ } from "./index-bftkz6cp.js";
15
15
  import {
16
16
  PackageScript
17
- } from "./index-sbfk9daf.js";
17
+ } from "./index-ab0c38ea.js";
18
18
  import {
19
19
  CloudRunner
20
- } from "./index-3hpxeys1.js";
20
+ } from "./index-bc88j1ry.js";
21
21
 
22
22
  // pkgs/@akanjs/cli/cloud/cloud.script.ts
23
23
  import { Logger } from "akanjs/common";
@@ -55,18 +55,43 @@ class CloudScript2 extends script("cloud", [CloudRunner, ApplicationScript, Pack
55
55
  await this.cloudRunner.uploadEnvByScp(workspace, path);
56
56
  return { workspaceId: null, files };
57
57
  }
58
- async deployAkan(workspace, { test = true, registryUrl } = {}) {
58
+ async deployAkan(workspace, {
59
+ test = true,
60
+ registryUrl,
61
+ platforms = []
62
+ } = {}) {
59
63
  const akanPkgs = await this.cloudRunner.getAkanPkgs(workspace);
60
64
  await this.packageScript.updateWorskpaceRootPackageJson(workspace);
61
65
  const pkgs = akanPkgs.map((pkgName) => PkgExecutor.from(workspace, pkgName));
62
- if (test)
63
- for (const pkg of pkgs)
64
- await this.applicationScript.test(pkg);
66
+ if (test) {
67
+ const platformRun = platforms.length ? await this.cloudRunner.startPlatformTests(workspace, platforms, akanPkgs) : null;
68
+ let localFailure = null;
69
+ try {
70
+ for (const pkg of pkgs)
71
+ await this.applicationScript.test(pkg);
72
+ } catch (error) {
73
+ localFailure = error;
74
+ }
75
+ if (platformRun)
76
+ await this.cloudRunner.settlePlatformTests(platformRun, {
77
+ interactive: !localFailure,
78
+ recordStreaks: !localFailure,
79
+ checkDrift: true
80
+ });
81
+ if (localFailure)
82
+ throw localFailure;
83
+ }
65
84
  for (const pkg of pkgs)
66
85
  await this.packageScript.buildPackage(pkg);
67
86
  await this.packageScript.verifyAkanPublishPackages(workspace);
68
87
  await this.cloudRunner.deployAkan(workspace, akanPkgs, { registryUrl });
69
88
  }
89
+ async testPlatforms(workspace, { platforms, pkgs }) {
90
+ if (!platforms.length)
91
+ throw new Error("No platform to test on \u2014 pass --platforms linux,windows");
92
+ const run = await this.cloudRunner.startPlatformTests(workspace, platforms, pkgs ?? await this.cloudRunner.getAkanPkgs(workspace));
93
+ await this.cloudRunner.settlePlatformTests(run, { interactive: false, recordStreaks: false, checkDrift: false });
94
+ }
70
95
  async update(workspace, tag = "latest", { registryUrl } = {}) {
71
96
  const spinner = workspace.spinning("Updating Akan.js packages and CLI...");
72
97
  await this.cloudRunner.update(workspace, tag, { registryUrl });
@@ -13,7 +13,8 @@ var configPath = `${basePath}/config.json`;
13
13
  var getDefaultHostConfig = (host = GlobalConfig.akanCloudHost) => ({ host });
14
14
  var defaultAkanGlobalConfig = {
15
15
  cloudHost: {},
16
- remoteEnvServers: {}
16
+ remoteEnvServers: {},
17
+ testTargets: {}
17
18
  };
18
19
 
19
20
  // pkgs/@akanjs/devkit/cloud/globalConfig.ts
@@ -26,7 +27,8 @@ class GlobalConfig {
26
27
  ...defaultAkanGlobalConfig,
27
28
  ...akanConfig,
28
29
  cloudHost: akanConfig.cloudHost ?? defaultAkanGlobalConfig.cloudHost,
29
- remoteEnvServers: akanConfig.remoteEnvServers ?? defaultAkanGlobalConfig.remoteEnvServers
30
+ remoteEnvServers: akanConfig.remoteEnvServers ?? defaultAkanGlobalConfig.remoteEnvServers,
31
+ testTargets: akanConfig.testTargets ?? defaultAkanGlobalConfig.testTargets
30
32
  };
31
33
  }
32
34
  static async#setAkanGlobalConfig(akanConfig) {
@@ -65,6 +67,17 @@ class GlobalConfig {
65
67
  remoteEnvServers
66
68
  });
67
69
  }
70
+ static async getTestTargets() {
71
+ const akanConfig = await GlobalConfig.#getAkanGlobalConfig();
72
+ return akanConfig.testTargets;
73
+ }
74
+ static async setTestTargets(testTargets) {
75
+ const akanConfig = await GlobalConfig.#getAkanGlobalConfig();
76
+ await GlobalConfig.#setAkanGlobalConfig({
77
+ ...akanConfig,
78
+ testTargets: { ...akanConfig.testTargets, ...testTargets }
79
+ });
80
+ }
68
81
  static needRefreshToken(accessToken) {
69
82
  return !!accessToken?.expiresAt?.isBefore(dayjs().add(1, "hour"));
70
83
  }