@akanjs/cli 3.0.0-beta.17 → 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 (149) hide show
  1. package/.build-stamp +1 -1
  2. package/{CodeAgent-gjqnc2mg.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-nd9hqvrw.js → CodeTui-za4jsm41.js} +205 -34
  6. package/{TunnelShare-r5tc2qk5.js → TunnelShare-2j6s511d.js} +2 -2
  7. package/{agent.command-n664dtcv.js → agent.command-e0wpbbyg.js} +6 -6
  8. package/akanCode.js +7 -5
  9. package/{application.command-t5542jte.js → application.command-8wyxqc8q.js} +28 -15
  10. package/{applicationBuildRunner-x4gbfn7y.js → applicationBuildRunner-n9gzaxd0.js} +35 -10
  11. package/{applicationReleasePackager-z61ep017.js → applicationReleasePackager-vpggfqgq.js} +1 -1
  12. package/buildBatch.proc.js +3 -3
  13. package/{capacitorApp-shv3ajh5.js → capacitorApp-q3z0qht0.js} +2 -2
  14. package/{cloud.command-dk5tj39k.js → cloud.command-4zwa5dsx.js} +34 -12
  15. package/cloud.script-fwx3vb34.js +20 -0
  16. package/{code.command-88sebgnn.js → code.command-468c9d7s.js} +41 -19
  17. package/commandManifest.json +1 -1
  18. package/{context.command-pqsm5jrk.js → context.command-dsnw0jby.js} +14 -14
  19. package/context.runner-rs4rj15d.js +22 -0
  20. package/{dependencyScanner-shs82ynp.js → dependencyScanner-0z2h2tks.js} +1 -1
  21. package/{devTui-gy6mendg.js → devTui-ffjsarqa.js} +3 -3
  22. package/{devTuiView-y1548wy6.js → devTuiView-1q1mdgrv.js} +1 -1
  23. package/{guideline.command-rpc2emw8.js → guideline.command-vhw13pqr.js} +8 -13
  24. package/guidelines/agentRule/agentRule.instruction.md +27 -10
  25. package/guidelines/conventions/conventions.instruction.md +53 -26
  26. package/guidelines/queryRule/queryRule.instruction.md +17 -7
  27. package/guidelines/runtimeRule/runtimeRule.instruction.md +74 -0
  28. package/guidelines/ssrRule/ssrRule.instruction.md +4 -2
  29. package/guidelines/transportRule/transportRule.instruction.md +10 -8
  30. package/guidelines/workspaceRecipes/workspaceRecipes.instruction.md +4 -3
  31. package/incrementalBuilder.proc.js +3 -2
  32. package/{index-4n4821gp.js → index-10dkrrww.js} +4 -4
  33. package/{index-bzakk0c2.js → index-14zrtgfa.js} +5 -3
  34. package/{index-v17gj504.js → index-18zybgkc.js} +2 -2
  35. package/{index-qh7brn20.js → index-22xtgmhn.js} +6 -2
  36. package/{index-qhtj9y6j.js → index-2446k7b4.js} +74 -21
  37. package/{index-g9zghs4h.js → index-3jrp517k.js} +12 -12
  38. package/{index-vpx68e4x.js → index-4m929vvn.js} +2 -2
  39. package/{index-4cvpzkq6.js → index-53176s7j.js} +3 -3
  40. package/{index-jwrpsrg3.js → index-667w0yah.js} +1 -1
  41. package/{index-3mg4h788.js → index-7ep8qtvp.js} +2 -2
  42. package/{index-w8kmx1b6.js → index-89hy31kf.js} +30 -7
  43. package/index-9d6nvkz2.js +656 -0
  44. package/index-9dp031by.js +12 -0
  45. package/{index-zn8qgeqx.js → index-a1w6934z.js} +3 -3
  46. package/{index-p0tew3fq.js → index-ab0c38ea.js} +10 -5
  47. package/index-bc88j1ry.js +1166 -0
  48. package/{index-ns128c4q.js → index-bftkz6cp.js} +280 -73
  49. package/{index-kcxmv48c.js → index-bhtmj233.js} +4 -1
  50. package/{index-kvzjda3v.js → index-bwf965h6.js} +5 -5
  51. package/{index-p4p9t45x.js → index-crmeqnmf.js} +56 -44
  52. package/{index-8k16atqy.js → index-d2242ksy.js} +23 -6
  53. package/{index-2sq06vv0.js → index-e4v6vhxq.js} +417 -105
  54. package/{index-xjc7gg65.js → index-esk82rvk.js} +23 -33
  55. package/{index-sn7dnzq4.js → index-kwaq3n9n.js} +1 -1
  56. package/{index-gm76f0qb.js → index-n3cv0tm4.js} +1 -1
  57. package/{index-6na0sd2b.js → index-qdgzsnhg.js} +5 -2
  58. package/{index-twq9p2sp.js → index-s5rhm04y.js} +0 -6
  59. package/{index-n8kt2wh6.js → index-sq2dzkzm.js} +35 -10
  60. package/{index-myj01w9r.js → index-srmay5jw.js} +15 -2
  61. package/{index-2pm1j01n.js → index-txr7dj2g.js} +4 -4
  62. package/{index-3cymrzsb.js → index-vqx8bdxz.js} +17 -3
  63. package/{index-te0y1c0m.js → index-zqgj2rt2.js} +12 -7
  64. package/index.js +21 -21
  65. package/{library.command-m8p2r1dh.js → library.command-cqr175dy.js} +3 -3
  66. package/{localRegistry.command-yppdqrxv.js → localRegistry.command-49z55qqz.js} +9 -9
  67. package/{module.command-mfzvqt0n.js → module.command-9p8mm3b0.js} +5 -5
  68. package/{package.command-cgp2p2v5.js → package.command-wxyz909t.js} +5 -5
  69. package/package.json +2 -2
  70. package/{page.command-taenb02b.js → page.command-gsrsfqqs.js} +3 -3
  71. package/{primitive.command-7kpncmkk.js → primitive.command-ns1mptje.js} +6 -6
  72. package/{prompter-9mn3kp36.js → prompter-1f8d9pcc.js} +1 -1
  73. package/{quality.command-1ar94hrw.js → quality.command-e76k2q9k.js} +18 -17
  74. package/{repair.command-n08t6j8p.js → repair.command-pkrsm3cw.js} +5 -5
  75. package/{routeSourceValidator-apyqw7wk.js → routeSourceValidator-7ycnfz0e.js} +0 -6
  76. package/{scalar.command-mq8qfp4t.js → scalar.command-0cpt3fc8.js} +4 -4
  77. package/skills/akan-code/SKILL.md +122 -0
  78. package/skills/akan-module/SKILL.md +2 -2
  79. package/skills/akan-store/SKILL.md +6 -2
  80. package/{subspace.command-jqv5n79w.js → subspace.command-fktpwp0g.js} +20 -10
  81. package/templates/__scalar/__model__/__model__.abstract.md.template +8 -0
  82. package/templates/appSample/lib/__scalar/workHistory/workHistory.abstract.ts +8 -39
  83. package/templates/appSample/lib/_noti/noti.abstract.ts +6 -29
  84. package/templates/appSample/lib/task/task.abstract.ts +12 -32
  85. package/templates/appSample/lib/task/task.signal.spec.ts +15 -18
  86. package/templates/appSample/lib/task/task.signal.test.ts +15 -1
  87. package/templates/appSample/lib/task/task.signal.ts +1 -1
  88. package/templates/appSample/srvkit/AuthGuard.ts +4 -1
  89. package/templates/appSample/srvkit/SessionInternalArg.ts +3 -1
  90. package/templates/crudPages/[__model__Id]/edit/page.tsx +2 -1
  91. package/templates/crudPages/[__model__Id]/page.tsx +2 -1
  92. package/templates/crudPages/new/page.tsx +2 -1
  93. package/templates/crudPages/page.tsx +2 -1
  94. package/templates/crudSinglePage/page.tsx +2 -1
  95. package/templates/localDev/docker-compose.yaml.template +3 -14
  96. package/templates/module/__model__.signal.ts +12 -4
  97. package/templates/pkgRoot/tsconfig.json.template +2 -7
  98. package/templates/service/__model__.abstract.md.template +8 -0
  99. package/{tunnel.command-ht2es78c.js → tunnel.command-d5jy9gk8.js} +4 -4
  100. package/{workflow.command-tvz4nm9n.js → workflow.command-6tkcysmx.js} +9 -9
  101. package/{workspace.command-txv1yv5e.js → workspace.command-gv84eh1p.js} +25 -24
  102. package/cloud.script-ch3xrw3s.js +0 -20
  103. package/context.runner-bys6ykcp.js +0 -22
  104. package/guidelines/agentRule/agentRule.generate.json +0 -31
  105. package/guidelines/componentRule/componentRule.generate.json +0 -31
  106. package/guidelines/conventions/conventions.generate.json +0 -25
  107. package/guidelines/cssRule/cssRule.generate.json +0 -31
  108. package/guidelines/docPageRule/docPageRule.generate.json +0 -31
  109. package/guidelines/docPageRule/docPageRule.instruction.md +0 -25
  110. package/guidelines/docSyncRule/docSyncRule.generate.json +0 -31
  111. package/guidelines/docSyncRule/docSyncRule.instruction.md +0 -25
  112. package/guidelines/enumConstant/enumConstant.generate.json +0 -31
  113. package/guidelines/enumConstant/enumConstant.instruction.md +0 -28
  114. package/guidelines/fieldRule/fieldRule.generate.json +0 -31
  115. package/guidelines/framework/framework.generate.json +0 -32
  116. package/guidelines/mcpRule/mcpRule.generate.json +0 -35
  117. package/guidelines/modelConstant/modelConstant.generate.json +0 -32
  118. package/guidelines/modelDictionary/modelDictionary.generate.json +0 -32
  119. package/guidelines/modelDocument/modelDocument.generate.json +0 -31
  120. package/guidelines/modelService/modelService.generate.json +0 -31
  121. package/guidelines/modelSignal/modelSignal.generate.json +0 -31
  122. package/guidelines/modelStore/modelStore.generate.json +0 -31
  123. package/guidelines/modelTemplate/modelTemplate.generate.json +0 -31
  124. package/guidelines/modelUnit/modelUnit.generate.json +0 -31
  125. package/guidelines/modelUtil/modelUtil.generate.json +0 -31
  126. package/guidelines/modelView/modelView.generate.json +0 -31
  127. package/guidelines/modelZone/modelZone.generate.json +0 -31
  128. package/guidelines/moduleCodegen/moduleCodegen.generate.json +0 -31
  129. package/guidelines/moduleCodegen/moduleCodegen.instruction.md +0 -28
  130. package/guidelines/moduleOverview/moduleOverview.generate.json +0 -31
  131. package/guidelines/queryRule/queryRule.generate.json +0 -31
  132. package/guidelines/recipeRule/recipeRule.generate.json +0 -31
  133. package/guidelines/runtimeRule/runtimeRule.generate.json +0 -25
  134. package/guidelines/scalarConstant/scalarConstant.generate.json +0 -32
  135. package/guidelines/scalarDictionary/scalarDictionary.generate.json +0 -32
  136. package/guidelines/scalarModule/scalarModule.generate.json +0 -31
  137. package/guidelines/sharedUiUsage/sharedUiUsage.generate.json +0 -31
  138. package/guidelines/sharedUiUsage/sharedUiUsage.instruction.md +0 -25
  139. package/guidelines/ssrRule/ssrRule.generate.json +0 -31
  140. package/guidelines/transportRule/transportRule.generate.json +0 -31
  141. package/guidelines/utilUiUsage/utilUiUsage.generate.json +0 -31
  142. package/guidelines/utilUiUsage/utilUiUsage.instruction.md +0 -25
  143. package/guidelines/workspaceOnboarding/workspaceOnboarding.generate.json +0 -24
  144. package/guidelines/workspaceRecipes/workspaceRecipes.generate.json +0 -34
  145. package/index-57p9p179.js +0 -461
  146. package/index-qt8dqgnf.js +0 -250
  147. package/templates/__scalar/__model__/__model__.abstract.md +0 -28
  148. package/templates/module/__model__.abstract.md +0 -28
  149. package/templates/service/__model__.abstract.md +0 -28
package/.build-stamp CHANGED
@@ -1 +1 @@
1
- 8adda265985140249a01af8a9966dd10b8dd38c2c3dd887ea8919e4aeff4a70e
1
+ 54a8d9f8d1b98d302928a879423c5be74f2316a5c28baad5f32fed8da1db0ca1
@@ -1,8 +1,8 @@
1
1
  // @bun
2
2
  import {
3
3
  CodeAgent2
4
- } from "./index-2sq06vv0.js";
5
- import"./index-qt8dqgnf.js";
4
+ } from "./index-e4v6vhxq.js";
5
+ import"./index-9d6nvkz2.js";
6
6
  import"./index-7md2g9vw.js";
7
7
  export {
8
8
  CodeAgent2 as CodeAgent
@@ -1,7 +1,7 @@
1
1
  // @bun
2
2
  import {
3
3
  CodeAgentRpcHost2
4
- } from "./index-8k16atqy.js";
4
+ } from "./index-d2242ksy.js";
5
5
  export {
6
6
  CodeAgentRpcHost2 as CodeAgentRpcHost
7
7
  };
@@ -0,0 +1,97 @@
1
+ // @bun
2
+ // pkgs/@akanjs/devkit/codeAgent/agent/CodeAgentRpcListener.ts
3
+ import { existsSync, rmSync } from "fs";
4
+
5
+ class CodeAgentRpcListener {
6
+ #host;
7
+ #address;
8
+ #listener = null;
9
+ #client = null;
10
+ constructor(host, address) {
11
+ this.#host = host;
12
+ this.#address = address;
13
+ }
14
+ static parse(spec) {
15
+ if (spec.startsWith("unix:"))
16
+ return { unix: spec.slice("unix:".length) };
17
+ const rest = spec.startsWith("tcp:") ? spec.slice("tcp:".length) : spec;
18
+ const separator = rest.lastIndexOf(":");
19
+ const hostname = separator >= 0 ? rest.slice(0, separator) : "127.0.0.1";
20
+ const port = Number(separator >= 0 ? rest.slice(separator + 1) : rest);
21
+ if (!Number.isInteger(port) || port < 0 || port > 65535)
22
+ throw new Error(`--rpc-listen takes unix:<path> or tcp:[host:]<port>, not "${spec}"`);
23
+ return { hostname: hostname || "127.0.0.1", port };
24
+ }
25
+ get port() {
26
+ return this.#listener && "port" in this.#listener ? this.#listener.port : null;
27
+ }
28
+ listen() {
29
+ if ("unix" in this.#address && existsSync(this.#address.unix))
30
+ rmSync(this.#address.unix);
31
+ const socket = {
32
+ open: (client) => this.#open(client),
33
+ data: (client, data) => this.#data(client, data),
34
+ drain: (client) => this.#drain(client),
35
+ close: (client) => this.#close(client),
36
+ error: (client) => this.#close(client)
37
+ };
38
+ this.#listener = "unix" in this.#address ? Bun.listen({ unix: this.#address.unix, socket }) : Bun.listen({ hostname: this.#address.hostname, port: this.#address.port, socket });
39
+ this.#host.start();
40
+ return this;
41
+ }
42
+ async serve() {
43
+ if (!this.#listener)
44
+ this.listen();
45
+ await this.#host.shutdown;
46
+ this.stop();
47
+ }
48
+ stop() {
49
+ this.#client?.end();
50
+ this.#client = null;
51
+ this.#host.attach(null);
52
+ this.#listener?.stop(true);
53
+ this.#listener = null;
54
+ if ("unix" in this.#address && existsSync(this.#address.unix))
55
+ rmSync(this.#address.unix);
56
+ }
57
+ #open(client) {
58
+ client.data = { pending: null, decoder: new TextDecoder };
59
+ const previous = this.#client;
60
+ this.#client = client;
61
+ previous?.end();
62
+ this.#host.attach((line) => this.#write(client, line));
63
+ }
64
+ #data(client, data) {
65
+ if (client !== this.#client)
66
+ return;
67
+ this.#host.feed(client.data.decoder.decode(data, { stream: true }));
68
+ }
69
+ #write(client, line) {
70
+ if (client !== this.#client)
71
+ return;
72
+ const bytes = Buffer.from(line);
73
+ if (client.data.pending) {
74
+ client.data.pending = Buffer.concat([client.data.pending, bytes]);
75
+ return;
76
+ }
77
+ const written = client.write(bytes);
78
+ if (written < bytes.length)
79
+ client.data.pending = bytes.subarray(Math.max(0, written));
80
+ }
81
+ #drain(client) {
82
+ const pending = client.data.pending;
83
+ if (!pending)
84
+ return;
85
+ const written = client.write(pending);
86
+ client.data.pending = written < pending.length ? pending.subarray(Math.max(0, written)) : null;
87
+ }
88
+ #close(client) {
89
+ if (client !== this.#client)
90
+ return;
91
+ this.#client = null;
92
+ this.#host.attach(null);
93
+ }
94
+ }
95
+ export {
96
+ CodeAgentRpcListener
97
+ };
@@ -1,8 +1,10 @@
1
1
  // @bun
2
2
  import {
3
3
  SubagentPool2,
4
- McpServerConfig
5
- } from "./index-qt8dqgnf.js";
4
+ McpServerConfig,
5
+ McpTokenStore,
6
+ McpSignIn
7
+ } from "./index-9d6nvkz2.js";
6
8
  import {
7
9
  CodeTuiLines2,
8
10
  CodeTuiAgents2,
@@ -12,7 +14,10 @@ import {
12
14
  CodeTuiFiles2,
13
15
  CodeTuiMarkdown2,
14
16
  CodeTuiParts2
15
- } from "./index-bzakk0c2.js";
17
+ } from "./index-14zrtgfa.js";
18
+ import {
19
+ openBrowser
20
+ } from "./index-9dp031by.js";
16
21
 
17
22
  // pkgs/@akanjs/cli/code/CodeTui.tsx
18
23
  import {
@@ -63,6 +68,7 @@ import { jsxDEV } from "react/jsx-dev-runtime";
63
68
  var promptMarkWidth = 2;
64
69
  var pasteOpen = "[200~";
65
70
  var pasteClose = "[201~";
71
+ var continuation = /^[^\r\n]*\\(?:\r\n|[\r\n])$/;
66
72
  var Styled = ({ span }) => /* @__PURE__ */ jsxDEV(Text, {
67
73
  bold: span.bold,
68
74
  color: span.color,
@@ -231,6 +237,10 @@ var CodeTuiApp = ({ actions }) => {
231
237
  return actions.newline();
232
238
  if (key.ctrl && input === "j")
233
239
  return actions.newline();
240
+ if (continuation.test(input)) {
241
+ actions.type(input.replace(/[\r\n]+$/, ""));
242
+ return actions.newline();
243
+ }
234
244
  if (key.return)
235
245
  return actions.submit();
236
246
  if (key.backspace || key.delete)
@@ -341,9 +351,15 @@ class CodeTuiMcp {
341
351
  static usage = [
342
352
  "/mcp add <name> <command> [args\u2026] declare a server this session starts",
343
353
  "/mcp add <name> <https://\u2026> declare one it reaches over http",
354
+ "/mcp add --local <name> \u2026 declare it for this repo only, not every repo",
355
+ "/mcp login <name> sign in through the browser (OAuth)",
356
+ "/mcp logout <name> forget the token, leaving the server declared",
344
357
  "/mcp remove <name> undeclare it",
345
358
  "/mcp reload reopen this session so the file takes effect"
346
359
  ];
360
+ static #where(view) {
361
+ return view.files.map(({ scope, file }) => `${scope.padEnd(11)}${file}`);
362
+ }
347
363
  static list(view) {
348
364
  const lines = view.problem ? [view.problem, ""] : [];
349
365
  const rows = CodeTuiMcp.#rows(view);
@@ -352,18 +368,21 @@ class CodeTuiMcp {
352
368
  ...lines,
353
369
  "No MCP server is declared.",
354
370
  "",
355
- `Declare one here, or paste an editor's \`mcpServers\` block into ${view.file}.`,
371
+ "Declare one here, or paste an editor's `mcpServers` block into either file:",
372
+ ...CodeTuiMcp.#where(view),
356
373
  "",
357
374
  ...CodeTuiMcp.usage
358
375
  ].join(`
359
376
  `);
360
377
  const width = (at) => Math.max(...rows.map((row) => (row[at] ?? "").length)) + 2;
361
- const [name, transport, target] = [width(0), width(1), width(2)];
378
+ const [name, scope, transport, target] = [width(0), width(1), width(2), width(3)];
362
379
  return [
363
380
  ...lines,
364
- `${rows.length} server${rows.length === 1 ? "" : "s"} \xB7 ${view.file}`,
381
+ `${rows.length} server${rows.length === 1 ? "" : "s"}`,
365
382
  "",
366
- ...rows.map(([a, b, c, d]) => `${(a ?? "").padEnd(name)}${(b ?? "").padEnd(transport)}${(c ?? "").padEnd(target)}${d ?? ""}`),
383
+ ...rows.map(([a, b, c, d, e]) => `${(a ?? "").padEnd(name)}${(b ?? "").padEnd(scope)}${(c ?? "").padEnd(transport)}${(d ?? "").padEnd(target)}${e ?? ""}`),
384
+ "",
385
+ ...CodeTuiMcp.#where(view),
367
386
  "",
368
387
  ...CodeTuiMcp.usage
369
388
  ].join(`
@@ -372,13 +391,13 @@ class CodeTuiMcp {
372
391
  static #rows(view) {
373
392
  const byName = new Map;
374
393
  for (const entry of view.declared)
375
- byName.set(entry.ref.name, { ref: entry.ref, disabled: entry.disabled });
394
+ byName.set(entry.ref.name, { ref: entry.ref, disabled: entry.disabled, scope: entry.scope });
376
395
  for (const live of view.status)
377
396
  byName.set(live.name, { ...byName.get(live.name), live });
378
397
  return [...byName].sort(([a], [b]) => a.localeCompare(b)).map(([name, entry]) => {
379
398
  const transport = entry.live?.transport ?? entry.ref?.transport ?? "";
380
399
  const target = entry.live?.target ?? CodeTuiMcp.targetOf(entry.ref);
381
- return [name, transport, target, CodeTuiMcp.#stateOf(entry)];
400
+ return [name, entry.scope ?? "", transport, target, CodeTuiMcp.#stateOf(entry)];
382
401
  });
383
402
  }
384
403
  static #stateOf(entry) {
@@ -386,11 +405,14 @@ class CodeTuiMcp {
386
405
  return "disabled in the file";
387
406
  if (!entry.live)
388
407
  return "declared \xB7 /mcp reload to connect";
408
+ if (entry.live.auth === "required")
409
+ return `sign-in needed \xB7 /mcp login ${entry.live.name}`;
389
410
  if (entry.live.error)
390
411
  return `unreachable \u2014 ${entry.live.error}`;
412
+ const tools = `${entry.live.tools.length} tool${entry.live.tools.length === 1 ? "" : "s"}`;
391
413
  if (!entry.ref)
392
- return `${entry.live.tools.length} tools \xB7 removed from the file`;
393
- return `${entry.live.tools.length} tool${entry.live.tools.length === 1 ? "" : "s"}`;
414
+ return `${tools} \xB7 removed from the file`;
415
+ return entry.live.auth === "authorized" ? `${tools} \xB7 signed in` : tools;
394
416
  }
395
417
  static targetOf(ref) {
396
418
  if (!ref)
@@ -408,6 +430,86 @@ class CodeTuiMcp {
408
430
  }
409
431
  }
410
432
 
433
+ // pkgs/@akanjs/cli/code/CodeTuiModels.ts
434
+ class CodeTuiModels {
435
+ static envKeyOf(provider) {
436
+ return `${provider.toUpperCase().replace(/-/g, "_")}_API_KEY`;
437
+ }
438
+ static usage = [
439
+ "/model <provider>/<id> switch to it, e.g. /model deepseek/deepseek-v4-pro",
440
+ "/model providers every provider, and which ones have a key",
441
+ "/model <provider> what one provider offers"
442
+ ];
443
+ static list(catalogue) {
444
+ const ready = catalogue.filter((provider) => provider.authorized);
445
+ const locked = catalogue.length - ready.length;
446
+ if (!ready.length)
447
+ return [
448
+ "No provider has a key, so there is no model to switch to.",
449
+ "",
450
+ `Set <PROVIDER>_API_KEY in the workspace \`.env\` or your environment \u2014 ${CodeTuiModels.envKeyOf("deepseek")}, ${CodeTuiModels.envKeyOf("anthropic")}.`,
451
+ "",
452
+ ...CodeTuiModels.usage
453
+ ].join(`
454
+ `);
455
+ const rows = ready.flatMap((provider) => provider.models.map((model) => [
456
+ `${model.current ? "\u276F " : " "}${provider.id}/${model.id}`,
457
+ model.name,
458
+ CodeTuiModels.#window(model.contextWindow)
459
+ ]));
460
+ return [
461
+ `${rows.length} model${rows.length === 1 ? "" : "s"} ready \xB7 ${ready.map((provider) => provider.id).join(", ")}`,
462
+ "",
463
+ ...CodeTuiModels.#table(rows),
464
+ "",
465
+ `${locked} more provider${locked === 1 ? "" : "s"} need a key \u2014 /model providers`,
466
+ "",
467
+ ...CodeTuiModels.usage
468
+ ].join(`
469
+ `);
470
+ }
471
+ static providers(catalogue) {
472
+ const rows = catalogue.map((provider) => [
473
+ provider.id,
474
+ provider.authorized ? "ready" : "no key",
475
+ `${provider.models.length} model${provider.models.length === 1 ? "" : "s"}`,
476
+ provider.name
477
+ ]);
478
+ return [
479
+ `${catalogue.length} providers`,
480
+ "",
481
+ ...CodeTuiModels.#table(rows),
482
+ "",
483
+ "A provider is reached by setting <PROVIDER>_API_KEY \u2014 in the workspace `.env` or your environment,",
484
+ "both of which are read at startup. /model <provider> lists what one offers.",
485
+ "",
486
+ ...CodeTuiModels.usage
487
+ ].join(`
488
+ `);
489
+ }
490
+ static ofProvider(catalogue, id) {
491
+ const provider = catalogue.find((entry) => entry.id === id);
492
+ if (!provider)
493
+ return;
494
+ const rows = provider.models.map((model) => [
495
+ `${model.current ? "\u276F " : " "}${provider.id}/${model.id}`,
496
+ model.name,
497
+ CodeTuiModels.#window(model.contextWindow)
498
+ ]);
499
+ const head = provider.authorized ? `${provider.name} \xB7 ${rows.length} models \xB7 ready` : `${provider.name} \xB7 ${rows.length} models \xB7 set ${CodeTuiModels.envKeyOf(provider.id)} to use it`;
500
+ return [head, "", ...CodeTuiModels.#table(rows)].join(`
501
+ `);
502
+ }
503
+ static #window(tokens) {
504
+ return tokens ? `${Math.round(tokens / 1000)}k ctx` : "";
505
+ }
506
+ static #table(rows) {
507
+ const width = (at) => Math.max(0, ...rows.map((row) => (row[at] ?? "").length)) + 2;
508
+ const columns = [width(0), width(1)];
509
+ return rows.map((row) => `${(row[0] ?? "").padEnd(columns[0] ?? 0)}${(row[1] ?? "").padEnd(columns[1] ?? 0)}${row[2] ?? ""}`.trimEnd());
510
+ }
511
+ }
512
+
411
513
  // pkgs/@akanjs/cli/code/CodeTui.tsx
412
514
  import { jsxDEV as jsxDEV2 } from "react/jsx-dev-runtime";
413
515
 
@@ -421,6 +523,7 @@ class CodeTui {
421
523
  static maxInputRows = 8;
422
524
  static title = "Akan \u2014 write one line, deploy every stack";
423
525
  static imageMark = /\[image #(\d+)] ?/g;
526
+ static freeTextKey = "__free_text__";
424
527
  static pasteOn = "\x1B[?2004h";
425
528
  static pasteOff = "\x1B[?2004l";
426
529
  #agent;
@@ -434,6 +537,7 @@ class CodeTui {
434
537
  #historyAt = -1;
435
538
  #anchor = null;
436
539
  #selected = 0;
540
+ #typing = false;
437
541
  #menuAt = 0;
438
542
  #checked = [];
439
543
  #overlay = null;
@@ -490,6 +594,8 @@ class CodeTui {
490
594
  this.#say(this.#opening);
491
595
  this.#unsubscribe = this.#agent.on((event) => {
492
596
  this.#transcript.apply(event);
597
+ if (event.type === "question")
598
+ this.#openQuestion(event.question);
493
599
  this.#scheduleFrame();
494
600
  });
495
601
  this.#agent.announce();
@@ -573,7 +679,7 @@ class CodeTui {
573
679
  const frameRows = CodeTui.frameRowsOf(Math.max(10, this.#stdout.rows || 24));
574
680
  const question = this.#transcript.question;
575
681
  const approval = this.#transcript.approval;
576
- const mode = CodeTui.#modeOf(question, approval);
682
+ const mode = this.#typing ? "input" : CodeTui.#modeOf(question, approval);
577
683
  const subagents = this.#railRows(columns);
578
684
  const ask = mode === "input" ? this.#inputBlock(columns, frameRows - subagents.length) : this.#askBlock(question, frameRows - subagents.length);
579
685
  const { bodyHeight } = CodeTui.layout(frameRows, ask.rows, subagents.length);
@@ -594,14 +700,14 @@ class CodeTui {
594
700
  status: this.#status(),
595
701
  subagents,
596
702
  mode,
597
- placeholder: this.#transcript.streaming ? "type to steer, esc to interrupt" : "ask for something, / for commands",
703
+ placeholder: this.#placeholder(),
598
704
  offered: this.#offered,
599
705
  prompt: CodeTui.#promptOf(question, approval),
600
706
  selected: ask.selected,
601
707
  checked: this.#checked,
602
708
  multiSelect: !!question?.multiSelect,
603
709
  notice: this.#notice,
604
- hint: this.#overlay ? "esc close \xB7 \u2191\u2193 scroll" : CodeTui.#hintOf(mode, !!question?.multiSelect),
710
+ hint: this.#overlay ? "esc close \xB7 \u2191\u2193 scroll" : this.#hint(mode, !!question?.multiSelect),
605
711
  columns,
606
712
  frameRows,
607
713
  bodyHeight,
@@ -811,24 +917,36 @@ class CodeTui {
811
917
  return "input";
812
918
  }
813
919
  static #optionsOf(question) {
814
- return (question?.options ?? []).map((option) => ({
920
+ const options = (question?.options ?? []).map((option) => ({
815
921
  key: option.key,
816
- label: option.label,
922
+ label: option.recommended ? `${option.label} (recommended)` : option.label,
817
923
  ...option.detail ? { detail: option.detail } : {}
818
924
  }));
925
+ if (!options.length || !question?.freeText)
926
+ return options;
927
+ return [...options, { key: CodeTui.freeTextKey, label: "Something else\u2026", detail: "answer in your own words" }];
819
928
  }
820
929
  static #promptOf(question, approval) {
821
930
  if (approval)
822
931
  return `approve? ${approval.summary} [y/n]`;
823
932
  return question ? `? ${question.prompt}` : "";
824
933
  }
825
- static #hintOf(mode, multiSelect) {
934
+ #hint(mode, multiSelect) {
935
+ if (this.#typing)
936
+ return "enter answer \xB7 esc back to the choices";
826
937
  if (mode === "confirm")
827
938
  return "y yes \xB7 n no \xB7 esc no";
828
939
  if (mode === "select")
829
940
  return `\u2191\u2193 choose${multiSelect ? " \xB7 space toggle" : ""} \xB7 enter answer \xB7 esc skip \xB7 pgup/pgdn scroll`;
830
941
  return "enter send \xB7 shift+enter newline \xB7 \u2191\u2193 move \xB7 esc interrupt \xB7 pgup/pgdn scroll \xB7 ^c quit \xB7 /help";
831
942
  }
943
+ #placeholder() {
944
+ if (this.#typing)
945
+ return "your answer";
946
+ if (this.#transcript.question)
947
+ return "type an answer, or esc to skip";
948
+ return this.#transcript.streaming ? "type to steer, esc to interrupt" : "ask for something, / for commands";
949
+ }
832
950
  #type = (text) => {
833
951
  const pasted = this.#agent.canSeeImages ? CodeTuiClipboard2.imagePathsIn(text) : undefined;
834
952
  if (pasted?.images.length) {
@@ -934,14 +1052,14 @@ class CodeTui {
934
1052
  picker.at = Math.max(0, Math.min(picker.entries.length - 1, picker.at + delta));
935
1053
  return this.#renderNow();
936
1054
  }
937
- const count = this.#transcript.question?.options?.length ?? 0;
1055
+ const count = CodeTui.#optionsOf(this.#transcript.question).length;
938
1056
  if (!count)
939
1057
  return;
940
1058
  this.#selected = (this.#selected + delta + count) % count;
941
1059
  this.#renderNow();
942
1060
  };
943
1061
  #toggle = () => {
944
- const option = this.#transcript.question?.options?.[this.#selected];
1062
+ const option = CodeTui.#optionsOf(this.#transcript.question)[this.#selected];
945
1063
  if (!option)
946
1064
  return;
947
1065
  this.#checked = this.#checked.includes(option.key) ? this.#checked.filter((key) => key !== option.key) : [...this.#checked, option.key];
@@ -958,6 +1076,11 @@ class CodeTui {
958
1076
  #cancel = () => {
959
1077
  if (this.#overlay || this.#picker)
960
1078
  return this.#dismiss();
1079
+ if (this.#typing && this.#transcript.question?.options?.length) {
1080
+ this.#typing = false;
1081
+ this.#editor.clear();
1082
+ return this.#renderNow();
1083
+ }
961
1084
  const approval = this.#transcript.approval;
962
1085
  if (approval)
963
1086
  return void this.#agent.approve(approval.approvalId, false);
@@ -1080,11 +1203,28 @@ class CodeTui {
1080
1203
  this.#fail(error);
1081
1204
  }
1082
1205
  }
1206
+ #openQuestion(question) {
1207
+ this.#typing = false;
1208
+ this.#checked = [];
1209
+ this.#selected = Math.max(0, (question.options ?? []).findIndex((option) => option.recommended));
1210
+ }
1083
1211
  #answerCurrent(questionId) {
1084
- const options = this.#transcript.question?.options ?? [];
1085
- const answer = options.length ? { keys: this.#transcript.question?.multiSelect ? this.#checked : [options[this.#selected]?.key ?? ""] } : { text: this.#editor.text.trim() };
1212
+ const question = this.#transcript.question;
1213
+ const shown = CodeTui.#optionsOf(question);
1214
+ if (this.#typing || !shown.length) {
1215
+ const text = this.#editor.text.trim();
1216
+ this.#editor.clear();
1217
+ this.#typing = false;
1218
+ return void this.#answer(questionId, { text });
1219
+ }
1220
+ if (shown[this.#selected]?.key === CodeTui.freeTextKey) {
1221
+ this.#typing = true;
1222
+ this.#editor.clear();
1223
+ return this.#renderNow();
1224
+ }
1225
+ const keys = question?.multiSelect ? this.#checked.filter((key) => key !== CodeTui.freeTextKey) : [shown[this.#selected]?.key ?? ""];
1086
1226
  this.#editor.clear();
1087
- this.#answer(questionId, answer);
1227
+ this.#answer(questionId, { keys });
1088
1228
  }
1089
1229
  async#answer(questionId, answer) {
1090
1230
  this.#selected = 0;
@@ -1159,12 +1299,16 @@ ${CodeTuiCommands2.help()}`);
1159
1299
  `);
1160
1300
  }
1161
1301
  #mcp(argument) {
1162
- const [verb, name, ...rest] = argument.split(" ").filter(Boolean);
1302
+ const words = argument.split(" ").filter(Boolean);
1303
+ const local = words.includes("--local");
1304
+ const [verb, name, ...rest] = words.filter((word) => word !== "--local");
1163
1305
  const root = this.#agent.workspaceRoot;
1164
1306
  if (!verb)
1165
1307
  return this.#open("mcp", CodeTuiMcp.list(this.#mcpView()));
1166
1308
  if (verb === "reload")
1167
1309
  return this.#reload("reconnected the MCP servers");
1310
+ if (verb === "login" || verb === "logout")
1311
+ return this.#mcpAuth(verb, name);
1168
1312
  if (verb !== "add" && verb !== "remove") {
1169
1313
  const status = this.#agent.mcpServers().find((entry) => entry.name === verb);
1170
1314
  if (status)
@@ -1179,23 +1323,42 @@ ${CodeTuiCommands2.help()}`);
1179
1323
  return this.#open("mcp", `"${name}" cannot name a server: letters, digits, dash and underscore only.`);
1180
1324
  try {
1181
1325
  if (verb === "remove") {
1182
- if (!McpServerConfig.remove(root, name))
1326
+ const scope = McpServerConfig.remove(root, name);
1327
+ if (!scope)
1183
1328
  return this.#open("mcp", `No server named "${name}" is declared.`);
1184
- return this.#reload(`removed ${name}`);
1329
+ return this.#reload(`removed ${name} from the ${scope} file`);
1185
1330
  }
1186
- const ref = McpServerConfig.add(root, name, rest);
1187
- return this.#reload(`added ${name} \xB7 ${McpServerConfig.targetOf(ref)}`);
1331
+ const scope = local ? "workspace" : "global";
1332
+ const ref = McpServerConfig.add(root, name, rest, scope);
1333
+ const where = scope === "global" ? "every repo" : "this repo";
1334
+ return this.#reload(`added ${name} \xB7 ${McpServerConfig.targetOf(ref)} \xB7 ${where}`);
1188
1335
  } catch (error) {
1189
1336
  this.#fail(error);
1190
1337
  }
1191
1338
  }
1339
+ #mcpAuth(verb, name) {
1340
+ const root = this.#agent.workspaceRoot;
1341
+ if (!name)
1342
+ return this.#open("mcp", [`Usage: /mcp ${verb} <name>`, "", ...CodeTuiMcp.usage].join(`
1343
+ `));
1344
+ if (verb === "logout") {
1345
+ if (!McpTokenStore.clear(name))
1346
+ return this.#open("mcp", `"${name}" is not signed in.`);
1347
+ return this.#reload(`signed out of ${name}`);
1348
+ }
1349
+ const ref = McpServerConfig.read(root).find((entry) => entry.name === name);
1350
+ if (!ref)
1351
+ return this.#open("mcp", `No server named "${name}" is declared.`);
1352
+ this.#say(`signing in to ${name} \u2014 finish in the browser`);
1353
+ McpSignIn.run(ref, { open: (url) => void openBrowser(url), onNotice: (message) => this.#say(message) }).then(() => this.#reload(`signed in to ${name}`)).catch((error) => this.#fail(error));
1354
+ }
1192
1355
  #mcpView() {
1193
1356
  const root = this.#agent.workspaceRoot;
1194
1357
  const problem = McpServerConfig.problem(root);
1195
1358
  return {
1196
1359
  status: this.#agent.mcpServers(),
1197
1360
  declared: McpServerConfig.declared(root),
1198
- file: McpServerConfig.file(root),
1361
+ files: McpServerConfig.files(root),
1199
1362
  ...problem ? { problem } : {}
1200
1363
  };
1201
1364
  }
@@ -1246,12 +1409,20 @@ ${levels.join(" \xB7 ")}`);
1246
1409
  }
1247
1410
  }
1248
1411
  #setModel(argument) {
1249
- const [provider, ...rest] = argument.split("/");
1250
- if (!provider || !rest.length)
1251
- return this.#open("model", `Usage: /model <provider>/<id>
1252
-
1253
- e.g. /model deepseek/deepseek-v4-pro`);
1254
- this.#agent.setModel({ provider, id: rest.join("/") }).catch((error) => this.#fail(error));
1412
+ const wanted = argument.trim();
1413
+ const [provider, ...rest] = wanted.split("/");
1414
+ if (provider && rest.length)
1415
+ return void this.#agent.setModel({ provider, id: rest.join("/") }).catch((error) => this.#fail(error));
1416
+ const catalogue = this.#agent.catalogue();
1417
+ if (wanted === "providers")
1418
+ return this.#open("model \xB7 providers", CodeTuiModels.providers(catalogue));
1419
+ if (!provider)
1420
+ return this.#open("model", CodeTuiModels.list(catalogue));
1421
+ const listing = CodeTuiModels.ofProvider(catalogue, provider);
1422
+ if (listing)
1423
+ return this.#open(`model \xB7 ${provider}`, listing);
1424
+ return this.#open("model", [`There is no provider called "${provider}".`, "", ...CodeTuiModels.usage].join(`
1425
+ `));
1255
1426
  }
1256
1427
  #open(title, text) {
1257
1428
  this.#overlay = { title, text };
@@ -1,8 +1,8 @@
1
1
  // @bun
2
2
  import {
3
3
  TunnelShare2
4
- } from "./index-gm76f0qb.js";
5
- import"./index-myj01w9r.js";
4
+ } from "./index-n3cv0tm4.js";
5
+ import"./index-srmay5jw.js";
6
6
  import"./index-q0y2jq9j.js";
7
7
  export {
8
8
  TunnelShare2 as TunnelShare
@@ -2,17 +2,17 @@
2
2
  import {
3
3
  Workspace,
4
4
  command
5
- } from "./index-6na0sd2b.js";
5
+ } from "./index-qdgzsnhg.js";
6
6
  import"./index-q0y2jq9j.js";
7
- import"./index-p4p9t45x.js";
7
+ import"./index-crmeqnmf.js";
8
8
  import"./index-6wwzs1bc.js";
9
9
  import"./index-by5gpp8x.js";
10
- import"./index-qhtj9y6j.js";
11
- import"./index-v17gj504.js";
12
- import"./index-twq9p2sp.js";
10
+ import"./index-2446k7b4.js";
11
+ import"./index-18zybgkc.js";
12
+ import"./index-s5rhm04y.js";
13
13
  import {
14
14
  AgentScript
15
- } from "./index-kvzjda3v.js";
15
+ } from "./index-bwf965h6.js";
16
16
 
17
17
  // pkgs/@akanjs/cli/agent/agent.command.ts
18
18
  class AgentCommand extends command("agent", [AgentScript], ({ public: target }) => ({
package/akanCode.js CHANGED
@@ -11,6 +11,7 @@ import {
11
11
  VerifyFeedback2,
12
12
  AkanToolPack2,
13
13
  MailToolPack2,
14
+ McpUnauthorized2,
14
15
  McpClient2,
15
16
  McpToolPack2,
16
17
  SessionToolPack2,
@@ -27,22 +28,22 @@ import {
27
28
  CodeMailbox2,
28
29
  CodeSessionFork2,
29
30
  CodeAgent2
30
- } from "./index-2sq06vv0.js";
31
+ } from "./index-e4v6vhxq.js";
31
32
  import {
32
33
  akanCodeDefaultModel2,
33
34
  akanCodeModel2,
34
35
  akanCodeModelSupportsImages2,
35
36
  akanCodeModelWarnings2,
36
37
  CodeAgentStreamPrinter2
37
- } from "./index-jwrpsrg3.js";
38
+ } from "./index-667w0yah.js";
38
39
  import {
39
40
  SubagentPool2,
40
41
  akanCodePaths2
41
- } from "./index-qt8dqgnf.js";
42
+ } from "./index-9d6nvkz2.js";
42
43
  import"./index-7md2g9vw.js";
43
44
  import {
44
45
  CodeAgentRpcHost2
45
- } from "./index-8k16atqy.js";
46
+ } from "./index-d2242ksy.js";
46
47
  import {
47
48
  CodeTuiLines2,
48
49
  CodeTuiAgents2,
@@ -52,7 +53,7 @@ import {
52
53
  CodeTuiFiles2,
53
54
  CodeTuiMarkdown2,
54
55
  CodeTuiParts2
55
- } from "./index-bzakk0c2.js";
56
+ } from "./index-14zrtgfa.js";
56
57
  export {
57
58
  AkanCli2 as AkanCli,
58
59
  AkanCodePlugins2 as AkanCodePlugins,
@@ -83,6 +84,7 @@ export {
83
84
  MailToolPack2 as MailToolPack,
84
85
  McpClient2 as McpClient,
85
86
  McpToolPack2 as McpToolPack,
87
+ McpUnauthorized2 as McpUnauthorized,
86
88
  PreviewChrome2 as PreviewChrome,
87
89
  PreviewFeedback2 as PreviewFeedback,
88
90
  PreviewView2 as PreviewView,