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

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 (134) hide show
  1. package/.build-stamp +1 -1
  2. package/{CodeAgent-zgccwajm.js → CodeAgent-0035exh3.js} +2 -2
  3. package/{CodeTui-993tx7gf.js → CodeTui-eweg1hep.js} +384 -28
  4. package/{agent.command-n664dtcv.js → agent.command-65zqfkg0.js} +6 -6
  5. package/akanCode.js +11 -9
  6. package/{application.command-t5542jte.js → application.command-2wcj5da3.js} +18 -11
  7. package/{applicationBuildRunner-x4gbfn7y.js → applicationBuildRunner-m0hhgwsx.js} +6 -5
  8. package/{applicationReleasePackager-z61ep017.js → applicationReleasePackager-vykfzgx3.js} +1 -1
  9. package/buildBatch.proc.js +2 -2
  10. package/{capacitorApp-shv3ajh5.js → capacitorApp-2daqhb5h.js} +2 -2
  11. package/{cloud.command-4x35k1z6.js → cloud.command-960bgbf4.js} +8 -8
  12. package/{cloud.script-3k8nbbpn.js → cloud.script-qhcnqt1n.js} +8 -8
  13. package/{code.command-mrfb7a1g.js → code.command-4feh3ef7.js} +7 -7
  14. package/{context.command-pqsm5jrk.js → context.command-kzehkx48.js} +14 -14
  15. package/context.runner-z0rrcz7b.js +22 -0
  16. package/{devTui-gy6mendg.js → devTui-ffjsarqa.js} +3 -3
  17. package/{devTuiView-y1548wy6.js → devTuiView-1q1mdgrv.js} +1 -1
  18. package/{guideline.command-rpc2emw8.js → guideline.command-3w2g20x4.js} +8 -13
  19. package/guidelines/conventions/conventions.instruction.md +37 -22
  20. package/guidelines/queryRule/queryRule.instruction.md +1 -1
  21. package/guidelines/ssrRule/ssrRule.instruction.md +4 -2
  22. package/guidelines/transportRule/transportRule.instruction.md +10 -8
  23. package/guidelines/workspaceRecipes/workspaceRecipes.instruction.md +4 -3
  24. package/incrementalBuilder.proc.js +1 -1
  25. package/{index-sxg87a8f.js → index-14zrtgfa.js} +164 -98
  26. package/{index-57p9p179.js → index-3hpxeys1.js} +6 -5
  27. package/{index-sn7dnzq4.js → index-4r42ext5.js} +1 -1
  28. package/{index-3mg4h788.js → index-6q589y9t.js} +2 -2
  29. package/index-9dp031by.js +12 -0
  30. package/{index-p4p9t45x.js → index-bwxpk2cj.js} +4 -18
  31. package/{index-g9zghs4h.js → index-cjw1sj1x.js} +12 -12
  32. package/{index-te0y1c0m.js → index-d9fjz06h.js} +12 -7
  33. package/{index-4n4821gp.js → index-dw943k93.js} +4 -4
  34. package/{index-4cvpzkq6.js → index-ef228gzf.js} +3 -3
  35. package/{index-3cymrzsb.js → index-erfc1x40.js} +17 -3
  36. package/{index-ns128c4q.js → index-h94faz96.js} +13 -20
  37. package/index-jd01kj5r.js +656 -0
  38. package/{index-5405kc0x.js → index-jwexzh42.js} +363 -247
  39. package/{index-wfwknnje.js → index-jwrpsrg3.js} +8 -6
  40. package/{index-kvzjda3v.js → index-m41ptvat.js} +5 -5
  41. package/{index-qh7brn20.js → index-mt2154s2.js} +6 -2
  42. package/{index-xjc7gg65.js → index-pn8mhpps.js} +23 -33
  43. package/{index-vpx68e4x.js → index-q9c3c0hy.js} +2 -2
  44. package/{index-v17gj504.js → index-rpgxs245.js} +2 -2
  45. package/{index-twq9p2sp.js → index-s5rhm04y.js} +0 -6
  46. package/{index-018dszb3.js → index-sbfk9daf.js} +10 -3
  47. package/{index-zg0v1zte.js → index-wcg582a8.js} +5 -5
  48. package/{index-6na0sd2b.js → index-ycy302an.js} +5 -2
  49. package/{index-qhtj9y6j.js → index-yw6g3bbv.js} +74 -21
  50. package/{index-2pm1j01n.js → index-zmj143x7.js} +4 -4
  51. package/{index-zn8qgeqx.js → index-zq0mr3hh.js} +1 -1
  52. package/index.js +21 -21
  53. package/{library.command-m8p2r1dh.js → library.command-fp0nhr62.js} +3 -3
  54. package/{localRegistry.command-tt00nwwg.js → localRegistry.command-8y0ecxb9.js} +7 -7
  55. package/{module.command-mfzvqt0n.js → module.command-kqkn48t2.js} +5 -5
  56. package/{package.command-8sy6jjwy.js → package.command-qverjh22.js} +4 -4
  57. package/package.json +8 -6
  58. package/{page.command-taenb02b.js → page.command-94bwhd0g.js} +3 -3
  59. package/{primitive.command-7kpncmkk.js → primitive.command-2ydvtah2.js} +6 -6
  60. package/{prompter-9mn3kp36.js → prompter-1f8d9pcc.js} +1 -1
  61. package/{quality.command-1ar94hrw.js → quality.command-fa0gth4p.js} +3 -4
  62. package/{repair.command-n08t6j8p.js → repair.command-4qng2hpm.js} +5 -5
  63. package/{routeSourceValidator-apyqw7wk.js → routeSourceValidator-7ycnfz0e.js} +0 -6
  64. package/{scalar.command-mq8qfp4t.js → scalar.command-pb2y95sh.js} +4 -4
  65. package/skills/akan-code/SKILL.md +122 -0
  66. package/skills/akan-module/SKILL.md +2 -2
  67. package/skills/akan-store/SKILL.md +6 -2
  68. package/{subspace.command-x9897gj4.js → subspace.command-vkxmwp74.js} +4 -4
  69. package/templates/__scalar/__model__/__model__.abstract.md.template +8 -0
  70. package/templates/appSample/lib/__scalar/workHistory/workHistory.abstract.ts +8 -39
  71. package/templates/appSample/lib/_noti/noti.abstract.ts +6 -29
  72. package/templates/appSample/lib/task/task.abstract.ts +12 -32
  73. package/templates/appSample/lib/task/task.signal.spec.ts +15 -18
  74. package/templates/appSample/lib/task/task.signal.test.ts +14 -0
  75. package/templates/appSample/lib/task/task.signal.ts +1 -1
  76. package/templates/appSample/srvkit/AuthGuard.ts +4 -1
  77. package/templates/appSample/srvkit/SessionInternalArg.ts +3 -1
  78. package/templates/crudPages/[__model__Id]/edit/page.tsx +2 -1
  79. package/templates/crudPages/[__model__Id]/page.tsx +2 -1
  80. package/templates/crudPages/new/page.tsx +2 -1
  81. package/templates/crudPages/page.tsx +2 -1
  82. package/templates/crudSinglePage/page.tsx +2 -1
  83. package/templates/module/__model__.signal.ts +12 -4
  84. package/templates/pkgRoot/tsconfig.json.template +2 -7
  85. package/templates/service/__model__.abstract.md.template +8 -0
  86. package/{tunnel.command-ht2es78c.js → tunnel.command-02cvp9nf.js} +2 -2
  87. package/{workflow.command-tvz4nm9n.js → workflow.command-132txnrh.js} +9 -9
  88. package/{workspace.command-ayqa1rgt.js → workspace.command-d5wkswek.js} +21 -21
  89. package/context.runner-bys6ykcp.js +0 -22
  90. package/guidelines/agentRule/agentRule.generate.json +0 -31
  91. package/guidelines/componentRule/componentRule.generate.json +0 -31
  92. package/guidelines/conventions/conventions.generate.json +0 -25
  93. package/guidelines/cssRule/cssRule.generate.json +0 -31
  94. package/guidelines/docPageRule/docPageRule.generate.json +0 -31
  95. package/guidelines/docPageRule/docPageRule.instruction.md +0 -25
  96. package/guidelines/docSyncRule/docSyncRule.generate.json +0 -31
  97. package/guidelines/docSyncRule/docSyncRule.instruction.md +0 -25
  98. package/guidelines/enumConstant/enumConstant.generate.json +0 -31
  99. package/guidelines/enumConstant/enumConstant.instruction.md +0 -28
  100. package/guidelines/fieldRule/fieldRule.generate.json +0 -31
  101. package/guidelines/framework/framework.generate.json +0 -32
  102. package/guidelines/mcpRule/mcpRule.generate.json +0 -35
  103. package/guidelines/modelConstant/modelConstant.generate.json +0 -32
  104. package/guidelines/modelDictionary/modelDictionary.generate.json +0 -32
  105. package/guidelines/modelDocument/modelDocument.generate.json +0 -31
  106. package/guidelines/modelService/modelService.generate.json +0 -31
  107. package/guidelines/modelSignal/modelSignal.generate.json +0 -31
  108. package/guidelines/modelStore/modelStore.generate.json +0 -31
  109. package/guidelines/modelTemplate/modelTemplate.generate.json +0 -31
  110. package/guidelines/modelUnit/modelUnit.generate.json +0 -31
  111. package/guidelines/modelUtil/modelUtil.generate.json +0 -31
  112. package/guidelines/modelView/modelView.generate.json +0 -31
  113. package/guidelines/modelZone/modelZone.generate.json +0 -31
  114. package/guidelines/moduleCodegen/moduleCodegen.generate.json +0 -31
  115. package/guidelines/moduleCodegen/moduleCodegen.instruction.md +0 -28
  116. package/guidelines/moduleOverview/moduleOverview.generate.json +0 -31
  117. package/guidelines/queryRule/queryRule.generate.json +0 -31
  118. package/guidelines/recipeRule/recipeRule.generate.json +0 -31
  119. package/guidelines/runtimeRule/runtimeRule.generate.json +0 -25
  120. package/guidelines/scalarConstant/scalarConstant.generate.json +0 -32
  121. package/guidelines/scalarDictionary/scalarDictionary.generate.json +0 -32
  122. package/guidelines/scalarModule/scalarModule.generate.json +0 -31
  123. package/guidelines/sharedUiUsage/sharedUiUsage.generate.json +0 -31
  124. package/guidelines/sharedUiUsage/sharedUiUsage.instruction.md +0 -25
  125. package/guidelines/ssrRule/ssrRule.generate.json +0 -31
  126. package/guidelines/transportRule/transportRule.generate.json +0 -31
  127. package/guidelines/utilUiUsage/utilUiUsage.generate.json +0 -31
  128. package/guidelines/utilUiUsage/utilUiUsage.instruction.md +0 -25
  129. package/guidelines/workspaceOnboarding/workspaceOnboarding.generate.json +0 -24
  130. package/guidelines/workspaceRecipes/workspaceRecipes.generate.json +0 -34
  131. package/index-jgrnpt6y.js +0 -121
  132. package/templates/__scalar/__model__/__model__.abstract.md +0 -28
  133. package/templates/module/__model__.abstract.md +0 -28
  134. package/templates/service/__model__.abstract.md +0 -28
package/.build-stamp CHANGED
@@ -1 +1 @@
1
- 6491b2d0e0e0215fa142863a77651ee2089f845be399582cd40b8149669b2a6f
1
+ d79f8789b2f3ccd418de907777c842f30b9db11bb3c64eda43e42036d960faf4
@@ -1,8 +1,8 @@
1
1
  // @bun
2
2
  import {
3
3
  CodeAgent2
4
- } from "./index-5405kc0x.js";
5
- import"./index-jgrnpt6y.js";
4
+ } from "./index-jwexzh42.js";
5
+ import"./index-jd01kj5r.js";
6
6
  import"./index-7md2g9vw.js";
7
7
  export {
8
8
  CodeAgent2 as CodeAgent
@@ -1,16 +1,23 @@
1
1
  // @bun
2
2
  import {
3
- SubagentPool2
4
- } from "./index-jgrnpt6y.js";
3
+ SubagentPool2,
4
+ McpServerConfig,
5
+ McpTokenStore,
6
+ McpSignIn
7
+ } from "./index-jd01kj5r.js";
5
8
  import {
9
+ CodeTuiLines2,
10
+ CodeTuiAgents2,
6
11
  CodeTuiClipboard2,
7
12
  CodeTuiCommands2,
8
- CodeTuiLines2,
9
13
  CodeTuiEditor2,
10
14
  CodeTuiFiles2,
11
15
  CodeTuiMarkdown2,
12
16
  CodeTuiParts2
13
- } from "./index-sxg87a8f.js";
17
+ } from "./index-14zrtgfa.js";
18
+ import {
19
+ openBrowser
20
+ } from "./index-9dp031by.js";
14
21
 
15
22
  // pkgs/@akanjs/cli/code/CodeTui.tsx
16
23
  import {
@@ -22,10 +29,46 @@ import { render } from "ink";
22
29
  // pkgs/@akanjs/cli/ui/CodeTuiApp.tsx
23
30
  import { Box, Text, useCursor, useInput } from "ink";
24
31
  import { useEffect, useRef, useState } from "react";
32
+
33
+ // pkgs/@akanjs/cli/code/CodeTuiMouse.ts
34
+ class CodeTuiMouse {
35
+ static on = "\x1B[?1000h\x1B[?1006h";
36
+ static off = "\x1B[?1006l\x1B[?1000l";
37
+ static step = 3;
38
+ #pending = 0;
39
+ read(input) {
40
+ if (this.#pending) {
41
+ const button = (input.codePointAt(0) ?? 32) - 32;
42
+ const rest = input.slice(this.#pending);
43
+ this.#pending = 0;
44
+ return { rows: CodeTuiMouse.rowsOf(button), rest };
45
+ }
46
+ const sgr = /^\[<(\d+);\d+;\d+[Mm]$/.exec(input);
47
+ if (sgr)
48
+ return { rows: CodeTuiMouse.rowsOf(Number(sgr[1])), rest: "" };
49
+ if (input !== "[M")
50
+ return;
51
+ this.#pending = 3;
52
+ return { rows: 0, rest: "" };
53
+ }
54
+ static rowsOf(button) {
55
+ if (!(button & 64))
56
+ return 0;
57
+ const direction = button & 3;
58
+ if (direction === 0)
59
+ return -CodeTuiMouse.step;
60
+ if (direction === 1)
61
+ return CodeTuiMouse.step;
62
+ return 0;
63
+ }
64
+ }
65
+
66
+ // pkgs/@akanjs/cli/ui/CodeTuiApp.tsx
25
67
  import { jsxDEV } from "react/jsx-dev-runtime";
26
68
  var promptMarkWidth = 2;
27
69
  var pasteOpen = "[200~";
28
70
  var pasteClose = "[201~";
71
+ var continuation = /^[^\r\n]*\\(?:\r\n|[\r\n])$/;
29
72
  var Styled = ({ span }) => /* @__PURE__ */ jsxDEV(Text, {
30
73
  bold: span.bold,
31
74
  color: span.color,
@@ -113,6 +156,7 @@ var Menu = ({ options, selected, marker, checked }) => /* @__PURE__ */ jsxDEV(Bo
113
156
  var CodeTuiApp = ({ actions }) => {
114
157
  const [snapshot, setSnapshot] = useState(actions.snapshot);
115
158
  const pasting = useRef(null);
159
+ const mouse = useRef(new CodeTuiMouse);
116
160
  const { setCursorPosition } = useCursor();
117
161
  useEffect(() => {
118
162
  const unsubscribe = actions.subscribe(() => setSnapshot(actions.snapshot()));
@@ -136,6 +180,14 @@ var CodeTuiApp = ({ actions }) => {
136
180
  ` : key.tab ? "\t" : input);
137
181
  return;
138
182
  }
183
+ const wheel = mouse.current.read(input);
184
+ if (wheel) {
185
+ if (wheel.rows)
186
+ actions.scroll(wheel.rows);
187
+ if (wheel.rest)
188
+ actions.type(wheel.rest);
189
+ return;
190
+ }
139
191
  if (key.ctrl && input === "c")
140
192
  return actions.interrupt();
141
193
  if (key.pageUp)
@@ -185,6 +237,10 @@ var CodeTuiApp = ({ actions }) => {
185
237
  return actions.newline();
186
238
  if (key.ctrl && input === "j")
187
239
  return actions.newline();
240
+ if (continuation.test(input)) {
241
+ actions.type(input.replace(/[\r\n]+$/, ""));
242
+ return actions.newline();
243
+ }
188
244
  if (key.return)
189
245
  return actions.submit();
190
246
  if (key.backspace || key.delete)
@@ -267,6 +323,12 @@ var CodeTuiApp = ({ actions }) => {
267
323
  }, undefined, false, undefined, this) : null
268
324
  ]
269
325
  }, undefined, true, undefined, this),
326
+ snapshot.subagents.length ? /* @__PURE__ */ jsxDEV(Box, {
327
+ flexDirection: "column",
328
+ children: snapshot.subagents.map((line) => /* @__PURE__ */ jsxDEV(Line, {
329
+ line
330
+ }, line.key, false, undefined, this))
331
+ }, undefined, false, undefined, this) : null,
270
332
  /* @__PURE__ */ jsxDEV(Rule, {
271
333
  spans: snapshot.bottomRule
272
334
  }, undefined, false, undefined, this),
@@ -283,6 +345,171 @@ var CodeTuiApp = ({ actions }) => {
283
345
  }, undefined, true, undefined, this);
284
346
  };
285
347
 
348
+ // pkgs/@akanjs/cli/code/CodeTuiMcp.ts
349
+ class CodeTuiMcp {
350
+ static namePattern = /^[a-zA-Z0-9_-]+$/;
351
+ static usage = [
352
+ "/mcp add <name> <command> [args\u2026] declare a server this session starts",
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",
357
+ "/mcp remove <name> undeclare it",
358
+ "/mcp reload reopen this session so the file takes effect"
359
+ ];
360
+ static #where(view) {
361
+ return view.files.map(({ scope, file }) => `${scope.padEnd(11)}${file}`);
362
+ }
363
+ static list(view) {
364
+ const lines = view.problem ? [view.problem, ""] : [];
365
+ const rows = CodeTuiMcp.#rows(view);
366
+ if (!rows.length)
367
+ return [
368
+ ...lines,
369
+ "No MCP server is declared.",
370
+ "",
371
+ "Declare one here, or paste an editor's `mcpServers` block into either file:",
372
+ ...CodeTuiMcp.#where(view),
373
+ "",
374
+ ...CodeTuiMcp.usage
375
+ ].join(`
376
+ `);
377
+ const width = (at) => Math.max(...rows.map((row) => (row[at] ?? "").length)) + 2;
378
+ const [name, scope, transport, target] = [width(0), width(1), width(2), width(3)];
379
+ return [
380
+ ...lines,
381
+ `${rows.length} server${rows.length === 1 ? "" : "s"}`,
382
+ "",
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),
386
+ "",
387
+ ...CodeTuiMcp.usage
388
+ ].join(`
389
+ `);
390
+ }
391
+ static #rows(view) {
392
+ const byName = new Map;
393
+ for (const entry of view.declared)
394
+ byName.set(entry.ref.name, { ref: entry.ref, disabled: entry.disabled, scope: entry.scope });
395
+ for (const live of view.status)
396
+ byName.set(live.name, { ...byName.get(live.name), live });
397
+ return [...byName].sort(([a], [b]) => a.localeCompare(b)).map(([name, entry]) => {
398
+ const transport = entry.live?.transport ?? entry.ref?.transport ?? "";
399
+ const target = entry.live?.target ?? CodeTuiMcp.targetOf(entry.ref);
400
+ return [name, entry.scope ?? "", transport, target, CodeTuiMcp.#stateOf(entry)];
401
+ });
402
+ }
403
+ static #stateOf(entry) {
404
+ if (entry.disabled)
405
+ return "disabled in the file";
406
+ if (!entry.live)
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}`;
410
+ if (entry.live.error)
411
+ return `unreachable \u2014 ${entry.live.error}`;
412
+ const tools = `${entry.live.tools.length} tool${entry.live.tools.length === 1 ? "" : "s"}`;
413
+ if (!entry.ref)
414
+ return `${tools} \xB7 removed from the file`;
415
+ return entry.live.auth === "authorized" ? `${tools} \xB7 signed in` : tools;
416
+ }
417
+ static targetOf(ref) {
418
+ if (!ref)
419
+ return "";
420
+ return ref.url ?? [ref.command, ...ref.args ?? []].filter(Boolean).join(" ");
421
+ }
422
+ static tools(status) {
423
+ if (status.error)
424
+ return `${status.name} is unreachable \u2014 ${status.error}`;
425
+ if (!status.tools.length)
426
+ return `${status.name} connected and published no tools.`;
427
+ return [`${status.name} \xB7 ${status.target}`, "", status.tools.join(`
428
+ `)].join(`
429
+ `);
430
+ }
431
+ }
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
+
286
513
  // pkgs/@akanjs/cli/code/CodeTui.tsx
287
514
  import { jsxDEV as jsxDEV2 } from "react/jsx-dev-runtime";
288
515
 
@@ -296,6 +523,7 @@ class CodeTui {
296
523
  static maxInputRows = 8;
297
524
  static title = "Akan \u2014 write one line, deploy every stack";
298
525
  static imageMark = /\[image #(\d+)] ?/g;
526
+ static freeTextKey = "__free_text__";
299
527
  static pasteOn = "\x1B[?2004h";
300
528
  static pasteOff = "\x1B[?2004l";
301
529
  #agent;
@@ -309,6 +537,7 @@ class CodeTui {
309
537
  #historyAt = -1;
310
538
  #anchor = null;
311
539
  #selected = 0;
540
+ #typing = false;
312
541
  #menuAt = 0;
313
542
  #checked = [];
314
543
  #overlay = null;
@@ -360,11 +589,13 @@ class CodeTui {
360
589
  });
361
590
  }
362
591
  async run(seed) {
363
- this.#stdout.write(CodeTui.pasteOn);
592
+ this.#stdout.write(`${CodeTui.pasteOn}${CodeTuiMouse.on}`);
364
593
  if (this.#opening)
365
594
  this.#say(this.#opening);
366
595
  this.#unsubscribe = this.#agent.on((event) => {
367
596
  this.#transcript.apply(event);
597
+ if (event.type === "question")
598
+ this.#openQuestion(event.question);
368
599
  this.#scheduleFrame();
369
600
  });
370
601
  this.#agent.announce();
@@ -433,10 +664,10 @@ class CodeTui {
433
664
  for (const listener of this.#listeners)
434
665
  listener();
435
666
  }
436
- static layout(frameRows, askRows) {
437
- const room = Math.max(1, frameRows - CodeTui.minBodyRows - CodeTui.chromeRows);
667
+ static layout(frameRows, askRows, railRows = 0) {
668
+ const room = Math.max(1, frameRows - CodeTui.minBodyRows - CodeTui.chromeRows - railRows);
438
669
  const ask = Math.max(1, Math.min(askRows, room));
439
- return { ask, bodyHeight: Math.max(CodeTui.minBodyRows, frameRows - ask - CodeTui.chromeRows) };
670
+ return { ask, bodyHeight: Math.max(CodeTui.minBodyRows, frameRows - ask - CodeTui.chromeRows - railRows) };
440
671
  }
441
672
  static frameRowsOf(terminalRows) {
442
673
  return Math.max(CodeTui.minBodyRows + CodeTui.chromeRows + 1, terminalRows - 1);
@@ -448,9 +679,10 @@ class CodeTui {
448
679
  const frameRows = CodeTui.frameRowsOf(Math.max(10, this.#stdout.rows || 24));
449
680
  const question = this.#transcript.question;
450
681
  const approval = this.#transcript.approval;
451
- const mode = CodeTui.#modeOf(question, approval);
452
- const ask = mode === "input" ? this.#inputBlock(columns, frameRows) : this.#askBlock(question, frameRows);
453
- const { bodyHeight } = CodeTui.layout(frameRows, ask.rows);
682
+ const mode = this.#typing ? "input" : CodeTui.#modeOf(question, approval);
683
+ const subagents = this.#railRows(columns);
684
+ const ask = mode === "input" ? this.#inputBlock(columns, frameRows - subagents.length) : this.#askBlock(question, frameRows - subagents.length);
685
+ const { bodyHeight } = CodeTui.layout(frameRows, ask.rows, subagents.length);
454
686
  const width = columns - 2;
455
687
  const lines = this.#lines(width);
456
688
  const end = this.#anchor === null ? lines.length : Math.min(lines.length, Math.max(bodyHeight, this.#anchor));
@@ -466,15 +698,16 @@ class CodeTui {
466
698
  following: this.#anchor === null,
467
699
  overlay: this.#overlayBlock(width, bodyHeight),
468
700
  status: this.#status(),
701
+ subagents,
469
702
  mode,
470
- placeholder: this.#transcript.streaming ? "type to steer, esc to interrupt" : "ask for something, / for commands",
703
+ placeholder: this.#placeholder(),
471
704
  offered: this.#offered,
472
705
  prompt: CodeTui.#promptOf(question, approval),
473
706
  selected: ask.selected,
474
707
  checked: this.#checked,
475
708
  multiSelect: !!question?.multiSelect,
476
709
  notice: this.#notice,
477
- 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),
478
711
  columns,
479
712
  frameRows,
480
713
  bodyHeight,
@@ -489,6 +722,14 @@ class CodeTui {
489
722
  ...CodeTuiParts2.lines(this.#transcript.parts, width, { thinking: this.#thinking })
490
723
  ];
491
724
  }
725
+ #railRows(columns) {
726
+ const agents = this.#transcript.subagents;
727
+ if (!agents.length)
728
+ return [];
729
+ const rows = CodeTuiAgents2.rows(agents, this.#transcript.info?.name ?? "main", columns);
730
+ const room = CodeTui.frameRowsOf(Math.max(10, this.#stdout.rows || 24)) - CodeTui.minBodyRows - CodeTui.chromeRows - 2 * CodeTui.promptRuleRows - 1;
731
+ return rows.length <= room ? rows : [];
732
+ }
492
733
  #banner() {
493
734
  const cwd = this.#transcript.info?.cwd;
494
735
  return [
@@ -676,24 +917,36 @@ class CodeTui {
676
917
  return "input";
677
918
  }
678
919
  static #optionsOf(question) {
679
- return (question?.options ?? []).map((option) => ({
920
+ const options = (question?.options ?? []).map((option) => ({
680
921
  key: option.key,
681
- label: option.label,
922
+ label: option.recommended ? `${option.label} (recommended)` : option.label,
682
923
  ...option.detail ? { detail: option.detail } : {}
683
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" }];
684
928
  }
685
929
  static #promptOf(question, approval) {
686
930
  if (approval)
687
931
  return `approve? ${approval.summary} [y/n]`;
688
932
  return question ? `? ${question.prompt}` : "";
689
933
  }
690
- static #hintOf(mode, multiSelect) {
934
+ #hint(mode, multiSelect) {
935
+ if (this.#typing)
936
+ return "enter answer \xB7 esc back to the choices";
691
937
  if (mode === "confirm")
692
938
  return "y yes \xB7 n no \xB7 esc no";
693
939
  if (mode === "select")
694
940
  return `\u2191\u2193 choose${multiSelect ? " \xB7 space toggle" : ""} \xB7 enter answer \xB7 esc skip \xB7 pgup/pgdn scroll`;
695
941
  return "enter send \xB7 shift+enter newline \xB7 \u2191\u2193 move \xB7 esc interrupt \xB7 pgup/pgdn scroll \xB7 ^c quit \xB7 /help";
696
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
+ }
697
950
  #type = (text) => {
698
951
  const pasted = this.#agent.canSeeImages ? CodeTuiClipboard2.imagePathsIn(text) : undefined;
699
952
  if (pasted?.images.length) {
@@ -799,14 +1052,14 @@ class CodeTui {
799
1052
  picker.at = Math.max(0, Math.min(picker.entries.length - 1, picker.at + delta));
800
1053
  return this.#renderNow();
801
1054
  }
802
- const count = this.#transcript.question?.options?.length ?? 0;
1055
+ const count = CodeTui.#optionsOf(this.#transcript.question).length;
803
1056
  if (!count)
804
1057
  return;
805
1058
  this.#selected = (this.#selected + delta + count) % count;
806
1059
  this.#renderNow();
807
1060
  };
808
1061
  #toggle = () => {
809
- const option = this.#transcript.question?.options?.[this.#selected];
1062
+ const option = CodeTui.#optionsOf(this.#transcript.question)[this.#selected];
810
1063
  if (!option)
811
1064
  return;
812
1065
  this.#checked = this.#checked.includes(option.key) ? this.#checked.filter((key) => key !== option.key) : [...this.#checked, option.key];
@@ -823,6 +1076,11 @@ class CodeTui {
823
1076
  #cancel = () => {
824
1077
  if (this.#overlay || this.#picker)
825
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
+ }
826
1084
  const approval = this.#transcript.approval;
827
1085
  if (approval)
828
1086
  return void this.#agent.approve(approval.approvalId, false);
@@ -848,7 +1106,7 @@ class CodeTui {
848
1106
  if (this.#exiting)
849
1107
  return;
850
1108
  this.#exiting = true;
851
- this.#stdout.write(CodeTui.pasteOff);
1109
+ this.#stdout.write(`${CodeTuiMouse.off}${CodeTui.pasteOff}`);
852
1110
  this.#instance.clear();
853
1111
  this.#instance.unmount();
854
1112
  }
@@ -945,11 +1203,28 @@ class CodeTui {
945
1203
  this.#fail(error);
946
1204
  }
947
1205
  }
1206
+ #openQuestion(question) {
1207
+ this.#typing = false;
1208
+ this.#checked = [];
1209
+ this.#selected = Math.max(0, (question.options ?? []).findIndex((option) => option.recommended));
1210
+ }
948
1211
  #answerCurrent(questionId) {
949
- const options = this.#transcript.question?.options ?? [];
950
- 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 ?? ""];
951
1226
  this.#editor.clear();
952
- this.#answer(questionId, answer);
1227
+ this.#answer(questionId, { keys });
953
1228
  }
954
1229
  async#answer(questionId, answer) {
955
1230
  this.#selected = 0;
@@ -995,6 +1270,8 @@ ${tools.join(" \xB7 ")}`);
995
1270
  return this.#fork(argument);
996
1271
  case "agents":
997
1272
  return this.#open("agents", this.#agentList());
1273
+ case "mcp":
1274
+ return this.#mcp(argument);
998
1275
  case "name":
999
1276
  if (!argument)
1000
1277
  return this.#open("name", "Usage: /name <what this session is about>");
@@ -1021,6 +1298,77 @@ ${CodeTuiCommands2.help()}`);
1021
1298
  ].join(`
1022
1299
  `);
1023
1300
  }
1301
+ #mcp(argument) {
1302
+ const words = argument.split(" ").filter(Boolean);
1303
+ const local = words.includes("--local");
1304
+ const [verb, name, ...rest] = words.filter((word) => word !== "--local");
1305
+ const root = this.#agent.workspaceRoot;
1306
+ if (!verb)
1307
+ return this.#open("mcp", CodeTuiMcp.list(this.#mcpView()));
1308
+ if (verb === "reload")
1309
+ return this.#reload("reconnected the MCP servers");
1310
+ if (verb === "login" || verb === "logout")
1311
+ return this.#mcpAuth(verb, name);
1312
+ if (verb !== "add" && verb !== "remove") {
1313
+ const status = this.#agent.mcpServers().find((entry) => entry.name === verb);
1314
+ if (status)
1315
+ return this.#open(`mcp \xB7 ${verb}`, CodeTuiMcp.tools(status));
1316
+ return this.#open("mcp", [`There is no /mcp ${verb}.`, "", ...CodeTuiMcp.usage].join(`
1317
+ `));
1318
+ }
1319
+ if (!name)
1320
+ return this.#open("mcp", [`Usage:`, "", ...CodeTuiMcp.usage].join(`
1321
+ `));
1322
+ if (!CodeTuiMcp.namePattern.test(name))
1323
+ return this.#open("mcp", `"${name}" cannot name a server: letters, digits, dash and underscore only.`);
1324
+ try {
1325
+ if (verb === "remove") {
1326
+ const scope = McpServerConfig.remove(root, name);
1327
+ if (!scope)
1328
+ return this.#open("mcp", `No server named "${name}" is declared.`);
1329
+ return this.#reload(`removed ${name} from the ${scope} file`);
1330
+ }
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}`);
1335
+ } catch (error) {
1336
+ this.#fail(error);
1337
+ }
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
+ }
1355
+ #mcpView() {
1356
+ const root = this.#agent.workspaceRoot;
1357
+ const problem = McpServerConfig.problem(root);
1358
+ return {
1359
+ status: this.#agent.mcpServers(),
1360
+ declared: McpServerConfig.declared(root),
1361
+ files: McpServerConfig.files(root),
1362
+ ...problem ? { problem } : {}
1363
+ };
1364
+ }
1365
+ #reload(notice) {
1366
+ const id = this.#transcript.info?.sessionId;
1367
+ if (!id || !this.#agent.sessions().some((entry) => entry.id === id))
1368
+ return this.#open("mcp", "This session is not on disk yet, so there is nothing to reopen. Say something first, or start a new `akan code`.");
1369
+ this.#switchTo = { id, notice };
1370
+ this.#quit();
1371
+ }
1024
1372
  static #peerList(peers) {
1025
1373
  if (!peers.length)
1026
1374
  return "No other akan code session is running in this workspace.";
@@ -1061,12 +1409,20 @@ ${levels.join(" \xB7 ")}`);
1061
1409
  }
1062
1410
  }
1063
1411
  #setModel(argument) {
1064
- const [provider, ...rest] = argument.split("/");
1065
- if (!provider || !rest.length)
1066
- return this.#open("model", `Usage: /model <provider>/<id>
1067
-
1068
- e.g. /model deepseek/deepseek-v4-pro`);
1069
- 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
+ `));
1070
1426
  }
1071
1427
  #open(title, text) {
1072
1428
  this.#overlay = { title, text };
@@ -2,17 +2,17 @@
2
2
  import {
3
3
  Workspace,
4
4
  command
5
- } from "./index-6na0sd2b.js";
5
+ } from "./index-ycy302an.js";
6
6
  import"./index-q0y2jq9j.js";
7
- import"./index-p4p9t45x.js";
7
+ import"./index-bwxpk2cj.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-yw6g3bbv.js";
11
+ import"./index-rpgxs245.js";
12
+ import"./index-s5rhm04y.js";
13
13
  import {
14
14
  AgentScript
15
- } from "./index-kvzjda3v.js";
15
+ } from "./index-m41ptvat.js";
16
16
 
17
17
  // pkgs/@akanjs/cli/agent/agent.command.ts
18
18
  class AgentCommand extends command("agent", [AgentScript], ({ public: target }) => ({