@akanjs/cli 3.1.0-rc.1 → 3.1.0-rc.3

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 (74) hide show
  1. package/.build-stamp +1 -1
  2. package/{CodeAgent-kyprmy06.js → CodeAgent-ctk4fh2b.js} +2 -2
  3. package/{CodeTui-21mtze3j.js → CodeTui-mrxtrdzw.js} +1 -1
  4. package/TunnelShare-rj74jd6x.js +13 -0
  5. package/{agent.command-f3gsc1gd.js → agent.command-ncre6kwz.js} +5 -5
  6. package/akanCode.js +2 -2
  7. package/{application.command-5s780vnz.js → application.command-54mawreg.js} +52 -41
  8. package/{applicationBuildRunner-1yaqsrdq.js → applicationBuildRunner-8573zr2w.js} +16 -30
  9. package/buildBatch.proc.js +22 -13
  10. package/{cloud.command-yj6xb2a7.js → cloud.command-nyemv0m3.js} +57 -65
  11. package/cloud.script-ht6yb203.js +23 -0
  12. package/{code.command-3wkn4ja5.js → code.command-spsrzg63.js} +6 -6
  13. package/{context.command-9jjn3gcw.js → context.command-768zv7z4.js} +16 -13
  14. package/context.runner-tf1b53qq.js +24 -0
  15. package/{guideline.command-dtczrqpf.js → guideline.command-4ycwc51q.js} +2 -2
  16. package/guidelines/conventions/conventions.instruction.md +28 -15
  17. package/guidelines/cssRule/cssRule.instruction.md +12 -6
  18. package/guidelines/mcpRule/mcpRule.instruction.md +27 -11
  19. package/guidelines/runtimeRule/runtimeRule.instruction.md +24 -15
  20. package/guidelines/transportRule/transportRule.instruction.md +28 -5
  21. package/incrementalBuilder.proc.js +9 -6
  22. package/{index-2etcv0sc.js → index-00seamy5.js} +1 -1
  23. package/{index-jx4bzvwg.js → index-1a7nhq56.js} +92 -52
  24. package/{index-e0cvze1s.js → index-1nyxvz8j.js} +4 -4
  25. package/index-2z3kykvd.js +248 -0
  26. package/{index-rtct7d43.js → index-3675mvjw.js} +1 -1
  27. package/{index-56d2g8ms.js → index-3ddt3qjg.js} +1 -1
  28. package/{index-6jjtnhkw.js → index-3x7yeecy.js} +51 -9
  29. package/{index-ww9bhp67.js → index-4pf8g7ff.js} +1 -1
  30. package/index-8935h3n1.js +33 -0
  31. package/{index-v29746vb.js → index-8eqkxwsx.js} +3 -3
  32. package/{index-c2yrsxdh.js → index-91rt5bye.js} +96 -320
  33. package/{index-55mynnqs.js → index-bv210r6t.js} +459 -210
  34. package/{index-c76k723e.js → index-c4h5b5nq.js} +2 -2
  35. package/{index-qt22xstj.js → index-c9zjb3tw.js} +5 -3
  36. package/{index-c1x0be5j.js → index-dmsvd2rv.js} +2 -2
  37. package/index-ec080x99.js +1124 -0
  38. package/{index-ctanya41.js → index-fjqvd5mx.js} +4 -4
  39. package/{index-aprt7pkz.js → index-fvn6f5wx.js} +229 -1327
  40. package/{index-rc5rwyps.js → index-jj7yapwq.js} +71 -60
  41. package/index-kmamh5bv.js +241 -0
  42. package/{index-fm46xrf1.js → index-q5abh0jq.js} +3 -3
  43. package/{index-1w2qaee2.js → index-qf8g88j9.js} +361 -291
  44. package/{index-gnyf1fqy.js → index-qvghfv6v.js} +2 -2
  45. package/{index-ae5pwhgs.js → index-r5d6rq19.js} +10 -8
  46. package/{index-2mx692qq.js → index-vhfjzda3.js} +2 -2
  47. package/{index-8r4d7cmt.js → index-w9b71b6y.js} +4 -4
  48. package/{index-8ggztp8k.js → index-wanhh011.js} +42 -177
  49. package/{index-05g3jayg.js → index-wdze51wz.js} +1 -1
  50. package/index-wjqbc7sf.js +668 -0
  51. package/{index-rwq3ekqc.js → index-xf40a295.js} +7 -7
  52. package/{index-krq7btbt.js → index-xm5tmpv0.js} +3 -3
  53. package/index.js +22 -22
  54. package/{library.command-gaga5bmq.js → library.command-88ahgych.js} +3 -3
  55. package/{localRegistry.command-vsreyy42.js → localRegistry.command-ykea1m7b.js} +12 -9
  56. package/{module.command-7vpf6db4.js → module.command-zky4b7m9.js} +5 -5
  57. package/{package.command-twmvvf69.js → package.command-vh8pcedh.js} +3 -3
  58. package/package.json +2 -2
  59. package/{page.command-5asq7fdf.js → page.command-fyqeqxc3.js} +3 -3
  60. package/{pipeline.command-d0v38572.js → pipeline.command-r5t30py6.js} +220 -219
  61. package/{primitive.command-dyrs2fm8.js → primitive.command-a0516zfk.js} +6 -6
  62. package/{projectTypecheck-cvtkrzp2.js → projectTypecheck-7djd4z50.js} +1 -1
  63. package/{quality.command-6emsqpbg.js → quality.command-k7jcnfn0.js} +2 -2
  64. package/{repair.command-8t6aegv5.js → repair.command-85zg2an3.js} +5 -5
  65. package/{scalar.command-bnggy1x7.js → scalar.command-g5vmqwca.js} +4 -4
  66. package/{subspace.command-md2teygq.js → subspace.command-mp4evgsj.js} +421 -362
  67. package/{tunnel.command-jx3tdm2d.js → tunnel.command-kbnr99sj.js} +7 -4
  68. package/{workflow.command-jx0wag5r.js → workflow.command-9y9p1n8y.js} +10 -10
  69. package/{workspace.command-yxd7rr7g.js → workspace.command-jmec2kjg.js} +33 -30
  70. package/TunnelShare-q4jq08qg.js +0 -9
  71. package/cloud.script-h6pvcpa2.js +0 -20
  72. package/context.runner-atcrzz5b.js +0 -21
  73. package/index-6w0rbr9d.js +0 -68
  74. package/index-pgj2rt78.js +0 -404
@@ -3,57 +3,47 @@ import {
3
3
  App,
4
4
  Workspace,
5
5
  command
6
- } from "./index-6jjtnhkw.js";
6
+ } from "./index-3x7yeecy.js";
7
7
  import"./index-52w0fvh8.js";
8
- import"./index-55mynnqs.js";
9
- import"./index-1w2qaee2.js";
10
- import"./index-pgj2rt78.js";
8
+ import"./index-bv210r6t.js";
9
+ import"./index-wjqbc7sf.js";
11
10
  import {
12
11
  PlatformTestRun
13
- } from "./index-8ggztp8k.js";
12
+ } from "./index-wanhh011.js";
13
+ import"./index-kmamh5bv.js";
14
+ import"./index-qf8g88j9.js";
15
+ import"./index-ec080x99.js";
14
16
  import"./index-k9rrten6.js";
15
- import"./index-c1x0be5j.js";
16
- import"./index-jx4bzvwg.js";
17
+ import"./index-dmsvd2rv.js";
18
+ import"./index-1a7nhq56.js";
17
19
  import"./index-7md2g9vw.js";
18
20
  import"./index-2ahj896a.js";
19
- import"./index-gnyf1fqy.js";
21
+ import"./index-qvghfv6v.js";
20
22
  import {
21
23
  CloudScript2
22
- } from "./index-rc5rwyps.js";
23
- import"./index-qt22xstj.js";
24
+ } from "./index-jj7yapwq.js";
24
25
  import {
25
- getMobileTargetChoices
26
- } from "./index-q958tqqg.js";
26
+ writeOption,
27
+ oneNativeTargetOption,
28
+ nativeEnvs,
29
+ releaseEnvOption,
30
+ allowLocalOption,
31
+ publicEnvOption,
32
+ hostOption,
33
+ subspaceOption
34
+ } from "./index-8935h3n1.js";
35
+ import"./index-c9zjb3tw.js";
36
+ import"./index-2z3kykvd.js";
27
37
 
28
38
  // pkgs/@akanjs/cli/cloud/cloud.command.ts
29
39
  var localRegistryUrl = () => process.env.AKAN_NPM_REGISTRY ?? "http://127.0.0.1:4873";
30
- var hostOption = {
31
- desc: "host of the cloud to target (default: cloud.host of the root akan.config.ts, else Akan Cloud)",
32
- nullable: true
33
- };
34
- var targetOption = {
35
- desc: "native target name (a key of native.targets)",
36
- ask: "Select native target",
37
- enum: async ({ app }) => await getMobileTargetChoices(app)
38
- };
39
- var envOption = {
40
- enum: ["debug", "develop", "main", "local"],
41
- desc: "backend environment",
42
- default: "main"
43
- };
44
40
  var resolveRegistryUrl = (registry) => registry === "local" ? localRegistryUrl() : undefined;
45
41
 
46
42
  class CloudCommand extends command("cloud", [CloudScript2], ({ public: target }) => ({
47
- login: target({ desc: "Login to Akan Cloud services" }).option("host", String, {
48
- desc: "host of the cloud (default: cloud.host of the root akan.config.ts, else Akan Cloud)",
49
- nullable: true
50
- }).with(Workspace).exec(async function(host, workspace) {
43
+ login: target({ desc: "Login to Akan Cloud services" }).option("host", String, hostOption).with(Workspace).exec(async function(host, workspace) {
51
44
  await this.cloudScript.login(workspace, host);
52
45
  }),
53
- logout: target({ desc: "Logout from Akan Cloud services" }).option("host", String, {
54
- desc: "host of the cloud (default: cloud.host of the root akan.config.ts, else Akan Cloud)",
55
- nullable: true
56
- }).with(Workspace).exec(async function(host, workspace) {
46
+ logout: target({ desc: "Logout from Akan Cloud services" }).option("host", String, hostOption).with(Workspace).exec(async function(host, workspace) {
57
47
  await this.cloudScript.logout(workspace, host);
58
48
  }),
59
49
  deployAkan: target({ devOnly: true, desc: "Deploy Akan.js framework to cloud (internal use)" }).option("test", Boolean, { desc: "test the deployment", default: true }).option("registry", String, {
@@ -105,12 +95,27 @@ class CloudCommand extends command("cloud", [CloudScript2], ({ public: target })
105
95
  await this.cloudScript.update(workspace, tag, { registryUrl: resolveRegistryUrl(registry) });
106
96
  }),
107
97
  pushUpdate: target({
108
- desc: "Pack an over-the-air update of a phone's web bundle and upload it to the akasys project, which signs and publishes it"
109
- }).with(App).option("platform", String, { enum: ["ios", "android"], desc: "the app it updates" }).option("target", String, targetOption).option("env", String, envOption).option("channel", String, { desc: "the channel (default: the target's updates.channel)", nullable: true }).option("notes", String, { desc: "release notes shown in the project", nullable: true }).option("subspace", String, { desc: "the subspace whose project gets it", nullable: true }).option("host", String, hostOption).option("write", Boolean, { desc: "write code generation", default: true }).option("allowLocalRelease", Boolean, { flag: "l", desc: "allow packing with --env local", default: false }).option("pack", String, {
98
+ desc: "Pack an over-the-air update of a phone's web bundle, or take the folder `akan pack-update` wrote, and upload it to the Akan Cloud project, which signs and publishes it. Exits 2 when the pack needs a new store build or the project rejects it, 1 on any other failure"
99
+ }).with(App).option("platform", String, {
100
+ enum: ["ios", "android"],
101
+ desc: "the app it updates (with --pack, default: the pack's)",
102
+ nullable: true
103
+ }).option("target", String, {
104
+ desc: "native target name, a key of native.targets (default: the only one; with --pack, the pack's)",
105
+ nullable: true
106
+ }).option("env", String, {
107
+ enum: nativeEnvs,
108
+ desc: "backend environment (default: main; with --pack, the pack's)",
109
+ nullable: true
110
+ }).option("channel", String, { desc: "the channel (default: the target's updates.channel)", nullable: true }).option("notes", String, { desc: "release notes shown in the project", nullable: true }).option("subspace", String, subspaceOption("gets it")).option("host", String, hostOption).option("write", Boolean, writeOption).option("allowLocalRelease", Boolean, {
111
+ flag: "l",
112
+ desc: "allow packing, or uploading a pack made, with --env local",
113
+ default: false
114
+ }).option("pack", String, {
110
115
  flag: "d",
111
- desc: "a folder `akan pack-update` wrote, uploaded instead of packing",
116
+ desc: "a folder `akan pack-update` wrote, uploaded instead of packing; --platform, --target and --env must match it",
112
117
  nullable: true
113
- }).with(Workspace).exec(async function(app, platform, target, env, channel, notes, subspace, host, write, allowLocalRelease, pack, workspace) {
118
+ }).option("publicEnv", String, publicEnvOption("the update")).with(Workspace).exec(async function(app, platform, target, env, channel, notes, subspace, host, write, allowLocalRelease, pack, publicEnv, workspace) {
114
119
  await this.cloudScript.pushUpdate(workspace, app, {
115
120
  platform,
116
121
  target,
@@ -121,15 +126,16 @@ class CloudCommand extends command("cloud", [CloudScript2], ({ public: target })
121
126
  host,
122
127
  write,
123
128
  allowLocalRelease,
124
- pack
129
+ pack,
130
+ publicEnv
125
131
  });
126
132
  }),
127
133
  registerBinary: target({
128
- desc: "Register the store build of a phone app with the akasys project, with a pack of the same commit as its embedded bundle"
134
+ desc: "Register the store build of a phone app with the Akan Cloud project, with a pack of the same commit as its embedded bundle. Exits 2 when the store build differs natively from this commit's pack, 1 on any other failure"
129
135
  }).with(App).option("platform", String, { enum: ["ios", "android"], desc: "the store build to register" }).option("distribution", String, {
130
136
  enum: ["appStore", "testFlight", "playStore", "playTesting", "direct"],
131
137
  desc: "where the binary ships"
132
- }).option("target", String, targetOption).option("env", String, envOption).option("subspace", String, { desc: "the subspace whose project gets it", nullable: true }).option("host", String, hostOption).option("write", Boolean, { desc: "write code generation", default: true }).option("allowLocalRelease", Boolean, { flag: "l", desc: "allow packing with --env local", default: false }).with(Workspace).exec(async function(app, platform, distribution, target, env, subspace, host, write, allowLocalRelease, workspace) {
138
+ }).option("target", String, oneNativeTargetOption).option("env", String, releaseEnvOption).option("subspace", String, subspaceOption("gets it")).option("host", String, hostOption).option("write", Boolean, writeOption).option("allowLocalRelease", Boolean, allowLocalOption("packing")).option("publicEnv", String, publicEnvOption("the pack (default: what the store build recorded)")).with(Workspace).exec(async function(app, platform, distribution, target, env, subspace, host, write, allowLocalRelease, publicEnv, workspace) {
133
139
  await this.cloudScript.registerBinary(workspace, app, {
134
140
  platform,
135
141
  distribution,
@@ -138,51 +144,37 @@ class CloudCommand extends command("cloud", [CloudScript2], ({ public: target })
138
144
  subspace,
139
145
  host,
140
146
  write,
141
- allowLocalRelease
147
+ allowLocalRelease,
148
+ publicEnv
142
149
  });
143
150
  }),
144
151
  uploadSecret: target({
145
- desc: "Upload a named pipeline secret to the akasys project; write-only, it can never be read back"
152
+ desc: "Upload a named pipeline secret to the Akan Cloud project; write-only, it can never be read back"
146
153
  }).arg("name", String, { desc: "secret name, e.g. DISCORD_WEBHOOK" }).option("branch", String, {
147
154
  desc: "only builds of this branch use it: debug, develop or main (default: every branch)",
148
155
  nullable: true
149
156
  }).option("file", String, {
150
157
  desc: "read the value from this file instead of stdin or a hidden prompt",
151
158
  nullable: true
152
- }).option("subspace", String, { desc: "the subspace whose project gets it", nullable: true }).option("host", String, {
153
- desc: "host of the cloud to target (default: cloud.host of the root akan.config.ts, else Akan Cloud)",
154
- nullable: true
155
- }).with(Workspace).exec(async function(name, branch, file, subspace, host, workspace) {
159
+ }).option("subspace", String, subspaceOption("gets it")).option("host", String, hostOption).with(Workspace).exec(async function(name, branch, file, subspace, host, workspace) {
156
160
  await this.cloudScript.uploadSecret(workspace, { name, branch, file, subspace, host });
157
161
  }),
158
- listSecrets: target({ desc: "List the pipeline secrets of the akasys project: names and scopes, never values" }).option("branch", String, {
162
+ listSecrets: target({ desc: "List the pipeline secrets of the Akan Cloud project: names and scopes, never values" }).option("branch", String, {
159
163
  desc: "only the secrets builds of this branch use: debug, develop or main",
160
164
  nullable: true
161
- }).option("subspace", String, { desc: "the subspace whose project to list", nullable: true }).option("host", String, {
162
- desc: "host of the cloud to target (default: cloud.host of the root akan.config.ts, else Akan Cloud)",
163
- nullable: true
164
- }).with(Workspace).exec(async function(branch, subspace, host, workspace) {
165
+ }).option("subspace", String, subspaceOption("to list")).option("host", String, hostOption).with(Workspace).exec(async function(branch, subspace, host, workspace) {
165
166
  await this.cloudScript.listSecrets(workspace, { branch, subspace, host });
166
167
  }),
167
- removeSecret: target({ desc: "Remove a named pipeline secret from the akasys project" }).arg("name", String, { desc: "secret name" }).option("branch", String, {
168
+ removeSecret: target({ desc: "Remove a named pipeline secret from the Akan Cloud project" }).arg("name", String, { desc: "secret name" }).option("branch", String, {
168
169
  desc: "the branch override to remove: debug, develop or main (default: the every-branch value)",
169
170
  nullable: true
170
- }).option("subspace", String, { desc: "the subspace whose project holds it", nullable: true }).option("host", String, {
171
- desc: "host of the cloud to target (default: cloud.host of the root akan.config.ts, else Akan Cloud)",
172
- nullable: true
173
- }).with(Workspace).exec(async function(name, branch, subspace, host, workspace) {
171
+ }).option("subspace", String, subspaceOption("holds it")).option("host", String, hostOption).with(Workspace).exec(async function(name, branch, subspace, host, workspace) {
174
172
  await this.cloudScript.removeSecret(workspace, { name, branch, subspace, host });
175
173
  }),
176
- downloadEnv: target({ desc: "Download environment variables from cloud or SCP server" }).option("host", String, {
177
- desc: "host of the cloud to target (default: cloud.host of the root akan.config.ts, else Akan Cloud)",
178
- nullable: true
179
- }).with(Workspace).exec(async function(host, workspace) {
174
+ downloadEnv: target({ desc: "Download environment variables from cloud or SCP server" }).option("host", String, hostOption).with(Workspace).exec(async function(host, workspace) {
180
175
  await this.cloudScript.downloadEnv(workspace, undefined, { host });
181
176
  }),
182
- uploadEnv: target({ desc: "Upload environment variables to cloud or SCP server" }).option("host", String, {
183
- desc: "host of the cloud to target (default: cloud.host of the root akan.config.ts, else Akan Cloud)",
184
- nullable: true
185
- }).with(Workspace).exec(async function(host, workspace) {
177
+ uploadEnv: target({ desc: "Upload environment variables to cloud or SCP server" }).option("host", String, hostOption).with(Workspace).exec(async function(host, workspace) {
186
178
  await this.cloudScript.uploadEnv(workspace, { host });
187
179
  })
188
180
  })) {
@@ -0,0 +1,23 @@
1
+ // @bun
2
+ import {
3
+ CloudScript2
4
+ } from "./index-jj7yapwq.js";
5
+ import"./index-wanhh011.js";
6
+ import"./index-1a7nhq56.js";
7
+ import"./index-c9zjb3tw.js";
8
+ import"./index-dmsvd2rv.js";
9
+ import"./index-qvghfv6v.js";
10
+ import"./index-kmamh5bv.js";
11
+ import"./index-wjqbc7sf.js";
12
+ import"./index-qf8g88j9.js";
13
+ import"./index-3x7yeecy.js";
14
+ import"./index-7md2g9vw.js";
15
+ import"./index-2z3kykvd.js";
16
+ import"./index-k9rrten6.js";
17
+ import"./index-ec080x99.js";
18
+ import"./index-bv210r6t.js";
19
+ import"./index-2ahj896a.js";
20
+ import"./index-52w0fvh8.js";
21
+ export {
22
+ CloudScript2 as CloudScript
23
+ };
@@ -4,9 +4,9 @@ import {
4
4
  runner,
5
5
  script,
6
6
  command
7
- } from "./index-6jjtnhkw.js";
7
+ } from "./index-3x7yeecy.js";
8
8
  import"./index-52w0fvh8.js";
9
- import"./index-55mynnqs.js";
9
+ import"./index-bv210r6t.js";
10
10
  import {
11
11
  akanCodeDefaultModel2,
12
12
  CodeAgentStreamPrinter2
@@ -19,7 +19,7 @@ class CodeRunner extends runner("code") {
19
19
  async serve(options, listen) {
20
20
  await import("./consoleToStderr-h5bryj94.js");
21
21
  const [{ CodeAgent }, { CodeAgentRpcHost }, { CodeAgentRpcListener }] = await Promise.all([
22
- import("./CodeAgent-kyprmy06.js"),
22
+ import("./CodeAgent-ctk4fh2b.js"),
23
23
  import("./CodeAgentRpcHost-p7h6n2hp.js"),
24
24
  import("./CodeAgentRpcListener-7p7z5dd7.js")
25
25
  ]);
@@ -34,8 +34,8 @@ class CodeRunner extends runner("code") {
34
34
  }
35
35
  async tui(options, seed) {
36
36
  const [{ CodeAgent }, { CodeTui }] = await Promise.all([
37
- import("./CodeAgent-kyprmy06.js"),
38
- import("./CodeTui-21mtze3j.js")
37
+ import("./CodeAgent-ctk4fh2b.js"),
38
+ import("./CodeTui-mrxtrdzw.js")
39
39
  ]);
40
40
  const agentOptions = await CodeRunner.#agentOptions(options, false);
41
41
  let resume = options.resume;
@@ -60,7 +60,7 @@ class CodeRunner extends runner("code") {
60
60
  }
61
61
  }
62
62
  async run(prompt, options) {
63
- const { CodeAgent } = await import("./CodeAgent-kyprmy06.js");
63
+ const { CodeAgent } = await import("./CodeAgent-ctk4fh2b.js");
64
64
  const agent = await CodeAgent.create(await CodeRunner.#agentOptions(options, false));
65
65
  const printer = new CodeAgentStreamPrinter2({ json: options.json, thinking: options.thinking });
66
66
  agent.on((event) => printer.print(event));
@@ -2,24 +2,27 @@
2
2
  import {
3
3
  Workspace,
4
4
  command
5
- } from "./index-6jjtnhkw.js";
5
+ } from "./index-3x7yeecy.js";
6
6
  import"./index-52w0fvh8.js";
7
- import"./index-55mynnqs.js";
7
+ import"./index-bv210r6t.js";
8
8
  import"./index-hj6w4ka1.js";
9
- import"./index-05g3jayg.js";
10
- import"./index-2mx692qq.js";
11
- import"./index-ae5pwhgs.js";
12
- import"./index-1w2qaee2.js";
9
+ import"./index-wdze51wz.js";
10
+ import"./index-vhfjzda3.js";
11
+ import"./index-r5d6rq19.js";
12
+ import"./index-kmamh5bv.js";
13
+ import"./index-qf8g88j9.js";
14
+ import"./index-ec080x99.js";
13
15
  import"./index-zzvvc845.js";
14
- import"./index-fm46xrf1.js";
15
- import"./index-2etcv0sc.js";
16
- import"./index-e0cvze1s.js";
17
- import"./index-ctanya41.js";
18
- import"./index-c76k723e.js";
19
- import"./index-rwq3ekqc.js";
16
+ import"./index-q5abh0jq.js";
17
+ import"./index-00seamy5.js";
18
+ import"./index-1nyxvz8j.js";
19
+ import"./index-fjqvd5mx.js";
20
+ import"./index-c4h5b5nq.js";
21
+ import"./index-xf40a295.js";
20
22
  import {
21
23
  ContextScript
22
- } from "./index-8r4d7cmt.js";
24
+ } from "./index-w9b71b6y.js";
25
+ import"./index-2z3kykvd.js";
23
26
 
24
27
  // pkgs/@akanjs/cli/context/context.command.ts
25
28
  class ContextCommand extends command("context", [ContextScript], ({ public: target }) => ({
@@ -0,0 +1,24 @@
1
+ // @bun
2
+ import {
3
+ ContextRunner2
4
+ } from "./index-r5d6rq19.js";
5
+ import"./index-xf40a295.js";
6
+ import"./index-c4h5b5nq.js";
7
+ import"./index-fjqvd5mx.js";
8
+ import"./index-q5abh0jq.js";
9
+ import"./index-1nyxvz8j.js";
10
+ import"./index-00seamy5.js";
11
+ import"./index-kmamh5bv.js";
12
+ import"./index-qf8g88j9.js";
13
+ import"./index-vhfjzda3.js";
14
+ import"./index-wdze51wz.js";
15
+ import"./index-zzvvc845.js";
16
+ import"./index-3x7yeecy.js";
17
+ import"./index-2z3kykvd.js";
18
+ import"./index-ec080x99.js";
19
+ import"./index-bv210r6t.js";
20
+ import"./index-hj6w4ka1.js";
21
+ import"./index-52w0fvh8.js";
22
+ export {
23
+ ContextRunner2 as ContextRunner
24
+ };
@@ -2,9 +2,9 @@
2
2
  import {
3
3
  script,
4
4
  command
5
- } from "./index-6jjtnhkw.js";
5
+ } from "./index-3x7yeecy.js";
6
6
  import"./index-52w0fvh8.js";
7
- import"./index-55mynnqs.js";
7
+ import"./index-bv210r6t.js";
8
8
  import {
9
9
  Prompter2
10
10
  } from "./index-zzvvc845.js";
@@ -68,8 +68,9 @@ back.
68
68
  `*.{constant,dictionary,document,service,signal,store}.ts` / `*.{Template,Unit,Util,View,Zone}.tsx`
69
69
  (`no-import-external-library.grit`). Re-export the symbol through a lib first. One-line re-export shims in a lib's
70
70
  `common/`, `webkit/`, or `ui/` exist for exactly this reason — they are load-bearing, not cruft. A module's
71
- `*.signal.test.ts` / `*.service.test.ts` is held to the same rule but may import the runtime's `node:*` and
72
- `bun:*` modules (a temp dir, a socket, sqlite), which module code leaves to `srvkit/`.
71
+ `*.signal.test.ts` / `*.service.test.ts` is held to the same rule (`no-import-external-library-in-test.grit`) but
72
+ may import the runtime's `node:*` and `bun:*` modules (a temp dir, a socket, sqlite), which module code leaves to
73
+ `srvkit/`.
73
74
  - **`#private` is banned in exactly four file suffixes:** `*.constant.ts`, `*.document.ts`, `*.service.ts`, and
74
75
  `*.store.ts` (`no-js-private-class-method.grit`). The rule is scoped by file path, not by class shape, so
75
76
  `#private` remains the house style everywhere under `srvkit/`, including `adapt()` adapter classes.
@@ -389,8 +390,11 @@ Full contract: `get_guideline` with `runtimeRule`, or `akan guideline show runti
389
390
  `dist/native/<app>/<target>/build/<platform>`, a desktop app only for the OS that builds it — `--arch` picks
390
391
  a Windows or Linux app's CPU, and a macOS app is Apple silicon only. `--installer true` adds a Windows setup, a
391
392
  macOS dmg or a Linux AppImage; `--sign` signs with the identity `AKAN_NATIVE_MACOS_*` / `AKAN_NATIVE_WINDOWS_*`
392
- names and `--notarize` uploads the signed macOS app to Apple — the env alone does neither. With `updates: { url, publicKey }` an installed app takes the signed
393
- releases `akan publish-update` makes; `akan update-keygen` makes the key and prints its `publicKey`.
393
+ names and `--notarize` uploads the signed macOS app to Apple — the env alone does neither. With
394
+ `updates: { url, publicKeys }` an installed app takes the signed releases `akan publish-update` makes: 1 to 3 keys,
395
+ the online signing key first and offline spares after it (a key may revoke only those listed before it), of which a
396
+ desktop app trusts the first, or `publicKey` for one. `akan update-keygen` makes the key and prints it for
397
+ `publicKeys`.
394
398
  - **A desktop app that carries its server (`desktop: { server: true }` in `native`, or in one target) gets nothing
395
399
  from `docker`** — and `server: { omit: [...] }` leaves out packages only the image needs. That server is API-only, runs in database mode `single`, and listens on a loopback port any
396
400
  program on the computer can call, so guard its endpoints as a network server's. An executable the app spawns
@@ -532,7 +536,8 @@ workflow changes.
532
536
  - Keep execution contracts and triggers in `.signal.ts` classes built with `internal(...)`, `slice(...)`, and `endpoint(...)`.
533
537
  - Use `Internal` for internal triggers such as init, interval, cron, or queue jobs. A `process` job's
534
538
  `backoff: { type: "exponential", delay, maxDelay }` caps the wait between attempts, and the internal's
535
- `onFailed(job, error)` runs once a job has failed its last attempt — the dead letter, on either queue.
539
+ `onFailed(job, error)` runs once a job has failed for good — its last attempt, or bullmq's stall limit — the dead
540
+ letter, on either queue.
536
541
  - Use `Slice` for typed data views that feed client stores and zones; keep each slice focused on one purpose.
537
542
  - Use `Endpoint` for query and mutation contracts exposed to callers.
538
543
  - Connect external APIs or infrastructure through adapters, usually under `srvkit/`, and inject them into services instead of importing vendor clients directly into domain logic.
@@ -755,13 +760,16 @@ Conventions that hold for both shapes:
755
760
  - Best-effort code returns a sentinel (`null`, `undefined`, `[0, 0]`, `{}`). There are no Result/Either wrappers.
756
761
  - `try/catch` is rare and always converts an exception into a decision, never swallows one. Guards catch → `logger.warn` → `return false`; adapters catch → `logger.error` → `return null`; UI uses `try/finally` to reset a spinner. A bodyless `catch {}` is acceptable only with a one-line reason.
757
762
  - Store actions do not `try/catch` — let the framework toast the `Err`. Client-side validation failure is `msg.error("<key>")` plus an early return, never a throw.
758
- - **A server-side `fetch.clone({ origin })` opens no websocket unless `connect: true`**: it makes one-off calls to
759
- another server, and a socket it opened would reconnect forever with nobody to close it. It never carries the
760
- visitor's session either: a call to another origin sends only the `jwt` its caller gave the clone.
763
+ - **A server-side `fetch.clone({ origin })` opens no websocket unless `connect: true`**, and neither does a clone of
764
+ such a clone: it makes one-off calls to another server, and a socket it opened would reconnect forever with nobody
765
+ to close it. It never carries the visitor's session either: a call to another origin sends only the `jwt` its
766
+ caller gave the clone.
761
767
  - **Retry a call with `retry`, never with a loop of your own.** `fetch.clone({ origin, retry: {} })` (or a call's
762
768
  own `{ retry }`) tries again on an unreachable server, a 502/503/504 and a 429 after its Retry-After, backing off
763
- with jitter; a mutation retries under one `Idempotency-Key` it mints, or the `idempotencyKey` you name, and the
764
- server runs a mutation once per key and caller, answering a repeat with the first result. A 4xx is never retried.
769
+ with jitter until the call's one deadline runs out; a mutation retries under one `Idempotency-Key` it mints, or the
770
+ `idempotencyKey` you name, and the server runs a mutation once per key, caller and arguments, answering a repeat
771
+ with the first response as it was sent; a signed-out call, one whose handler returns a `Response`, and a call
772
+ through MCP run every time. A 4xx is never retried.
765
773
  - `String(err)` and `${err}` read `Err: <key> {…data}`, the data as one line of JSON with secret-named keys masked,
766
774
  so a ``logger.warn(`…: ${String(error)}`)`` keeps the exit code or status the `Err` carried.
767
775
  - **A failure another process reported travels as itself.** A server-to-server `fetch.<endpoint>(..., { origin })` restores the remote `Err` — the same class, key and `data` — so a hop that rethrows it answers its own caller with that error and the dictionary translates it. Never wrap the catch in a `new Error`, and never re-key it as a `new Err` of your own: both discard what the endpoint chose to say, and a bare `Error` is generalized to `Internal Server Error` on the way out.
@@ -831,6 +839,10 @@ it.
831
839
  - **A `field.visual` field is stripped from every MCP result** and from the readable schema so the two agree.
832
840
  - **A structured result ships twice by default** — as `structuredContent` and as the same JSON in the text block.
833
841
  `option.setMcp({ legacyTextBlock: false })` leaves a pointer there instead.
842
+ - **A picture is an `ImageResult` return** (`akanjs/base`): `query(ImageResult, { guards })` returns `{ data,
843
+ mimeType, caption? }` — padded base64 with no `data:` prefix, and `image/png` / `jpeg` / `webp` / `gif`. Over MCP it
844
+ answers the caption as a text block and the picture as an image block, with no `structuredContent`; over HTTP it
845
+ is that JSON object. Like `Binary` it is never a model field.
834
846
  - **A prompt is a screen: `page().prompt(name, description)`.** There is no `prompt()` on `endpoint()`.
835
847
  `prompts/get` runs the page's body in the RSC worker under the caller's token — nothing is rendered — and answers
836
848
  the description, one `resource` per `fetch.*` the page made (masked by the endpoint's return model, addressed by
@@ -844,9 +856,9 @@ it.
844
856
  ChatGPT, VS Code) shows the screen itself in the chat — the CSR bundle in a sandboxed iframe whose every call the
845
857
  host relays under the agent's token. It shows the page alone: every layout above it still runs (guards, providers,
846
858
  `<Agent.Guide>`) and draws nothing, unless it draws no page, as a gate does. Nothing is written for the view. An
847
- endpoint kept off the shelf only by `mcp: false` stays callable by that view and is listed to no model; a `Person`
848
- act is still refused there. `option.setMcp({ apps: false })` keeps pages prompts only, and a page named like an
849
- endpoint stays one (boot warns).
859
+ endpoint kept off the shelf only by `mcp: false`, and the generated `light<Model>` read, stay callable by that view
860
+ and are listed to no model; a `Person` act is still refused there. `option.setMcp({ apps: false })` keeps pages
861
+ prompts only, as a read-only deployment does, and a page named like an endpoint stays one (boot warns).
850
862
 
851
863
  Full contract — configuration, wire behaviour, resource URIs, OAuth metadata, protocol revisions, and
852
864
  `McpProgress.report`: `get_guideline` with `mcpRule`, or `akan guideline show mcpRule`.
@@ -909,7 +921,7 @@ what every developer must know even when not building one.
909
921
 
910
922
  ### Scalar & Field Type Reference
911
923
 
912
- - **Import from `akanjs/base`** (real classes/helpers, not globals): `Int`, `Float`, `ID`, `Any`, `Binary`, `Upload`, `enumOf`, and the `dayjs` factory. There is **no `JSON` scalar** — use `Any` for open/flexible payloads.
924
+ - **Import from `akanjs/base`** (real classes/helpers, not globals): `Int`, `Float`, `ID`, `Any`, `Binary`, `Upload`, `ImageResult`, `enumOf`, and the `dayjs` factory. There is **no `JSON` scalar** — use `Any` for open/flexible payloads.
913
925
  - **Use the JS globals directly (no import needed)**: `String`, `Boolean`, `Date`. They are monkey-patched to behave like scalars, so `field(String)` typechecks.
914
926
  - **`Number` is not a valid field/body type.** `NumberConstructor` is intentionally not augmented, so `field(Number)` / `.body("x", Number)` fails to typecheck. Use `Int` or `Float` instead.
915
927
  - Runtime resolution of every scalar (globals included) goes through `PrimitiveRegistry` by `refName` (`pkgs/akanjs/base/primitiveRegistry.ts`).
@@ -997,7 +1009,8 @@ shape, so `cascade` never means "related" — it means one of exactly these:
997
1009
  of the route's args returning it, and one that throws renders no head (warned about) so a layout's sign-in redirect
998
1010
  still answers; there is no metadata object, and analytics is the app's own script, not a stage.
999
1011
  Heads merge root first: a deeper `.head()` replaces the `<title>`, a `<meta>` with the same `name` / `property`,
1000
- and a canonical / manifest / icon link, and keeps the rest — so a page states only what it changes.
1012
+ and a canonical / manifest / icon link, and keeps the rest — so a page states only what it changes. A canonical
1013
+ link and `og:url` each name one URL, so a page carries them only from its own `.head()`, never from a layout's.
1001
1014
  - **A CSR bundle (a native app, `?csr=true`) never shows a root layout's own markup.** Pages render into the
1002
1015
  frame, and what the root layout draws around `{children}` stays in a hidden container, so its wrappers cannot
1003
1016
  stack a second screen beside the frame. Its components still mount and their effects run (`<Auth.User />` works).
@@ -64,19 +64,25 @@ Screen code is invariant — a plain `<Button variant="primary">` never changes.
64
64
 
65
65
  ## Frame Variables (the page's chrome and the device's insets)
66
66
 
67
- The frame writes these on `#frameRoot` and `<html>`, so any class can read them, web and native alike:
67
+ The frame writes these on `#frameRoot` and `<html>`, so any class can read them. The insets and the content height
68
+ are there on every surface; the three keyboard variables are written only on the server-rendered web:
68
69
 
69
70
  - `--akan-top-safe-area` / `--akan-bottom-safe-area` — the notch and the home indicator. On the web they are
70
71
  `env(safe-area-inset-*)` where the route chain declares `safeArea` (`.config({ safeArea: true })` on the root
71
- layout) and `0px` where it does not; in a native app they are the shell's inset. Use the variable alone: never
72
- write `env(safe-area-inset-*)` beside it, and never subtract one from the other. The frame paints the bottom strip
73
- only under bottom chrome (a `BottomInset` or `BottomTab`) or a route's own `bottomSafeAreaColor`; elsewhere a page's
74
- `fixed bottom-0` bar paints its own safe-area padding.
72
+ layout) and `0px` where it does not, and `env()` measures nothing unless the viewport meta carries
73
+ `viewport-fit=cover` — the root layout's `.viewport({ fitCover: true })`, which a native app has by default; in a
74
+ native app they are the shell's inset. Use the variable alone: never write `env(safe-area-inset-*)` beside it, and
75
+ never subtract one from the other. The frame paints the bottom strip only under bottom chrome (a `BottomInset` or
76
+ `BottomTab`) or a route's own `bottomSafeAreaColor`; elsewhere a page's `fixed bottom-0` bar paints its own
77
+ safe-area padding.
75
78
  - `--akan-top-inset` / `--akan-bottom-inset` — the height of the page's top bar and bottom tab slot, per breakpoint
76
79
  when the page declares a responsive inset. A slot whose inset is 0 at a width clips its chrome there and hides it
77
80
  from the keyboard and screen readers, so a phone-only bar needs no `md:hidden`.
78
81
  - `--akan-keyboard-inset`, `--akan-viewport-height`, `--akan-viewport-offset-top` — the on-screen keyboard over the
79
- page's bottom, the visible height, and how far iOS panned the page to show a field (the top slots follow it).
82
+ page's bottom, the visible height, and how far iOS panned the page to show a field (the top slots follow it). Only
83
+ an SSR page in a browser writes them; a CSR bundle and a native app never do, so read them with a fallback
84
+ (`var(--akan-keyboard-inset, 0px)`), or take the keyboard from the store's `keyboardHeight`, which a native app's
85
+ keyboard plugin fills.
80
86
  - `--akan-content-height` — the room between the insets. iOS pans under the keyboard instead of shrinking the page,
81
87
  so a column sized by it leaves the panned-to area blank: keep a keyboard-heavy screen's input bar in flow at the end
82
88
  of its column, or in the keyboard slot.
@@ -155,6 +155,17 @@ export default page()
155
155
  clients read the structured half. A scalar return is unaffected: it has no structured half to point at, so it
156
156
  ships as the value itself either way. `resources/read` is unaffected too: `ReadResourceResult` has no
157
157
  `structuredContent`, so a resource's text is its only channel and always carries the serialized value.
158
+ - **A picture is an `ImageResult` return, and the one result a model sees rather than reads.**
159
+ `query(ImageResult, { guards: [...] })` (or `[ImageResult]`) returns `{ data, mimeType, caption? }`: `data` is
160
+ padded standard base64 with no `data:` prefix, `mimeType` one of `image/png`, `image/jpeg`, `image/webp`,
161
+ `image/gif` — the types the Anthropic and OpenAI models take. `tools/call` answers the caption as a text block and
162
+ the picture as an image block, one pair per picture, and publishes no `outputSchema` and no `structuredContent`:
163
+ either would repeat the base64, a few hundred KB, as text the model pays for and cannot see. A value that breaks
164
+ the shape is not sent — the dispatcher logs what an `ImageResult` needs and answers the generic failure. Put in
165
+ the caption what the picture cannot say on its own (the region or scale it spans). Over HTTP the endpoint is the
166
+ JSON object, so the app's own client and tests read it as usual; everywhere else an agent reads it — a page
167
+ prompt's resource, the in-page agent — its agent face carries `mimeType` and `caption` only. Nothing caps the
168
+ size, and Anthropic refuses an image over 5 MB, so keep a picture well under that. It is never a model field.
158
169
  - **A request schema asks for a relation's id, and a response schema names a nested model.** `serialize` sends a
159
170
  relation field as its id and the server never converts an object back, so publishing the related model's shape
160
171
  asked an agent for what the document layer cannot take. On the response side every entry inlines the transitive
@@ -231,9 +242,10 @@ export default page()
231
242
  wire-identical over the POST-only surface this implements — a client whose proposal is not listed is told to
232
243
  disconnect. An unknown proposal is answered at whichever end of that list it is closer to, and an unimplemented
233
244
  method answers `404` to a modern client but `200` to a legacy one, whose era spends `404` on "your session is
234
- gone". **While MCP Apps renders views only the legacy pair is spoken**: `server/discover` answers `-32601` and
235
- `initialize` settles on `2025-11-25`, because claude.ai renders a view only for a server it reached through
236
- `initialize`. `modern: true` / `AKAN_MCP_MODERN=true` offers `2026-07-28` anyway; `false` withholds it everywhere.
245
+ gone". **While a `.prompt()` page may show as a view only the legacy pair is spoken**: `server/discover` answers
246
+ `-32601` and `initialize` settles on `2025-11-25`, because claude.ai renders a view only for a server it reached
247
+ through `initialize`. An app that renders no view, or whose RSC worker lists no `.prompt()` page, speaks all three.
248
+ `modern: true` / `AKAN_MCP_MODERN=true` offers `2026-07-28` anyway; `false` withholds it everywhere.
237
249
  - **A modern-era request mirrors `MCP-Protocol-Version` and `Mcp-Method` into headers** (plus `Mcp-Name` when the
238
250
  body names one), and one that leaves a mirror out is refused just like one that contradicts the body: a gateway
239
251
  rule keyed on a header never fires for the request that omitted it. Legacy requests are not checked. Capabilities
@@ -362,7 +374,8 @@ rule: a page taking no arguments is the most useful prompt, since MCP has no com
362
374
  when the id is already in hand.
363
375
 
364
376
  ## MCP Apps — The Page, Rendered In The Chat
365
- **A `.prompt()` page is also a tool**, of the same name and arguments, marked `readOnlyHint`. Its result is the
377
+ **A `.prompt()` page is also a tool**, of the same name and arguments, marked `readOnlyHint: false`, since running
378
+ the page makes its own `fetch.*` calls, mutations included. Its result is the
366
379
  prompt's briefing plus `Open this screen in a browser: <url>` — what a client without the
367
380
  `io.modelcontextprotocol/ui` extension (Claude Code, Codex) reads. A host that declares the extension (claude.ai,
368
381
  Claude Desktop, ChatGPT, VS Code, Goose) is also given `_meta.ui.resourceUri` (`ui://<app>/app`, or
@@ -371,14 +384,17 @@ in a sandboxed iframe started on the page the tool ran. Its first queries are an
371
384
  the result's `_meta`, the one part no host shows the model — so the first paint costs no round trip; every later
372
385
  call is relayed by the host as `tools/call` under the host's token. Nothing is declared for any of it.
373
386
 
374
- - **What a view may call** is every published tool and every endpoint kept off the shelf by `mcp: false` alone,
375
- listed with `visibility: ["app"]` — which a host offers to the view and never to the model. Visibility is a host's
376
- UX, not authorization: the guards decide, as everywhere. A client that did not declare the extension is listed
377
- neither those tools nor the `ui://` resources, a call to one answers `Unknown tool`, and a page tool's result
378
- carries none of the view's data for it.
387
+ - **What a view may call** is every published tool, and every endpoint kept off the shelf by `mcp: false` alone or
388
+ the generated `light<Model>` read, listed with `visibility: ["app"]` — which a host offers to the view and never to
389
+ the model; a `Person` guard still refuses one. Visibility is a host's UX, not authorization: the guards decide, as
390
+ everywhere. A client that did not declare the extension is listed neither those tools nor the `ui://` resources, a
391
+ call to one answers `Unknown tool`, and a page tool's result carries none of the view's data for it.
379
392
  - **The capability is read per request.** A legacy client declares it once at `initialize` and is issued an
380
- `Mcp-Session-Id` (`ui.<uuid>`) that stores nothing, since its id is the capability; with `modern: true` a modern
381
- request carries it in `_meta`. A client that declares nothing is issued no session, exactly as before.
393
+ `Mcp-Session-Id` (`ui.<nonce>.<signature>`) that stores nothing: the app signs it, and an id the app did not sign is
394
+ served as a client without views. With `modern: true` a modern request carries the capability in `_meta`. A client
395
+ that declares nothing is issued no session, exactly as before.
396
+ - **A read-only deployment has no MCP Apps.** With `readOnly` / `AKAN_MCP_READONLY` there are no page tools, app-only
397
+ tools, views or UI sessions, since running a page makes its own `fetch.*` calls, mutations included.
382
398
  - **The view is the page, not the app around it.** Each layout above it still runs — guards, providers,
383
399
  `<Agent.Guide>` — but what it draws around `{children}` is hidden, with its frame chrome (`Layout.Navbar`,
384
400
  `TopInset`, `BottomInset`, `BottomTab`), the `topInset` / `bottomInset` it reserves and the tools its controls