@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.
- package/.build-stamp +1 -1
- package/{CodeAgent-kyprmy06.js → CodeAgent-ctk4fh2b.js} +2 -2
- package/{CodeTui-21mtze3j.js → CodeTui-mrxtrdzw.js} +1 -1
- package/TunnelShare-rj74jd6x.js +13 -0
- package/{agent.command-f3gsc1gd.js → agent.command-ncre6kwz.js} +5 -5
- package/akanCode.js +2 -2
- package/{application.command-5s780vnz.js → application.command-54mawreg.js} +52 -41
- package/{applicationBuildRunner-1yaqsrdq.js → applicationBuildRunner-8573zr2w.js} +16 -30
- package/buildBatch.proc.js +22 -13
- package/{cloud.command-yj6xb2a7.js → cloud.command-nyemv0m3.js} +57 -65
- package/cloud.script-ht6yb203.js +23 -0
- package/{code.command-3wkn4ja5.js → code.command-spsrzg63.js} +6 -6
- package/{context.command-9jjn3gcw.js → context.command-768zv7z4.js} +16 -13
- package/context.runner-tf1b53qq.js +24 -0
- package/{guideline.command-dtczrqpf.js → guideline.command-4ycwc51q.js} +2 -2
- package/guidelines/conventions/conventions.instruction.md +28 -15
- package/guidelines/cssRule/cssRule.instruction.md +12 -6
- package/guidelines/mcpRule/mcpRule.instruction.md +27 -11
- package/guidelines/runtimeRule/runtimeRule.instruction.md +24 -15
- package/guidelines/transportRule/transportRule.instruction.md +28 -5
- package/incrementalBuilder.proc.js +9 -6
- package/{index-2etcv0sc.js → index-00seamy5.js} +1 -1
- package/{index-jx4bzvwg.js → index-1a7nhq56.js} +92 -52
- package/{index-e0cvze1s.js → index-1nyxvz8j.js} +4 -4
- package/index-2z3kykvd.js +248 -0
- package/{index-rtct7d43.js → index-3675mvjw.js} +1 -1
- package/{index-56d2g8ms.js → index-3ddt3qjg.js} +1 -1
- package/{index-6jjtnhkw.js → index-3x7yeecy.js} +51 -9
- package/{index-ww9bhp67.js → index-4pf8g7ff.js} +1 -1
- package/index-8935h3n1.js +33 -0
- package/{index-v29746vb.js → index-8eqkxwsx.js} +3 -3
- package/{index-c2yrsxdh.js → index-91rt5bye.js} +96 -320
- package/{index-55mynnqs.js → index-bv210r6t.js} +459 -210
- package/{index-c76k723e.js → index-c4h5b5nq.js} +2 -2
- package/{index-qt22xstj.js → index-c9zjb3tw.js} +5 -3
- package/{index-c1x0be5j.js → index-dmsvd2rv.js} +2 -2
- package/index-ec080x99.js +1124 -0
- package/{index-ctanya41.js → index-fjqvd5mx.js} +4 -4
- package/{index-aprt7pkz.js → index-fvn6f5wx.js} +229 -1327
- package/{index-rc5rwyps.js → index-jj7yapwq.js} +71 -60
- package/index-kmamh5bv.js +241 -0
- package/{index-fm46xrf1.js → index-q5abh0jq.js} +3 -3
- package/{index-1w2qaee2.js → index-qf8g88j9.js} +361 -291
- package/{index-gnyf1fqy.js → index-qvghfv6v.js} +2 -2
- package/{index-ae5pwhgs.js → index-r5d6rq19.js} +10 -8
- package/{index-2mx692qq.js → index-vhfjzda3.js} +2 -2
- package/{index-8r4d7cmt.js → index-w9b71b6y.js} +4 -4
- package/{index-8ggztp8k.js → index-wanhh011.js} +42 -177
- package/{index-05g3jayg.js → index-wdze51wz.js} +1 -1
- package/index-wjqbc7sf.js +668 -0
- package/{index-rwq3ekqc.js → index-xf40a295.js} +7 -7
- package/{index-krq7btbt.js → index-xm5tmpv0.js} +3 -3
- package/index.js +22 -22
- package/{library.command-gaga5bmq.js → library.command-88ahgych.js} +3 -3
- package/{localRegistry.command-vsreyy42.js → localRegistry.command-ykea1m7b.js} +12 -9
- package/{module.command-7vpf6db4.js → module.command-zky4b7m9.js} +5 -5
- package/{package.command-twmvvf69.js → package.command-vh8pcedh.js} +3 -3
- package/package.json +2 -2
- package/{page.command-5asq7fdf.js → page.command-fyqeqxc3.js} +3 -3
- package/{pipeline.command-d0v38572.js → pipeline.command-r5t30py6.js} +220 -219
- package/{primitive.command-dyrs2fm8.js → primitive.command-a0516zfk.js} +6 -6
- package/{projectTypecheck-cvtkrzp2.js → projectTypecheck-7djd4z50.js} +1 -1
- package/{quality.command-6emsqpbg.js → quality.command-k7jcnfn0.js} +2 -2
- package/{repair.command-8t6aegv5.js → repair.command-85zg2an3.js} +5 -5
- package/{scalar.command-bnggy1x7.js → scalar.command-g5vmqwca.js} +4 -4
- package/{subspace.command-md2teygq.js → subspace.command-mp4evgsj.js} +421 -362
- package/{tunnel.command-jx3tdm2d.js → tunnel.command-kbnr99sj.js} +7 -4
- package/{workflow.command-jx0wag5r.js → workflow.command-9y9p1n8y.js} +10 -10
- package/{workspace.command-yxd7rr7g.js → workspace.command-jmec2kjg.js} +33 -30
- package/TunnelShare-q4jq08qg.js +0 -9
- package/cloud.script-h6pvcpa2.js +0 -20
- package/context.runner-atcrzz5b.js +0 -21
- package/index-6w0rbr9d.js +0 -68
- package/index-pgj2rt78.js +0 -404
|
@@ -3,57 +3,47 @@ import {
|
|
|
3
3
|
App,
|
|
4
4
|
Workspace,
|
|
5
5
|
command
|
|
6
|
-
} from "./index-
|
|
6
|
+
} from "./index-3x7yeecy.js";
|
|
7
7
|
import"./index-52w0fvh8.js";
|
|
8
|
-
import"./index-
|
|
9
|
-
import"./index-
|
|
10
|
-
import"./index-pgj2rt78.js";
|
|
8
|
+
import"./index-bv210r6t.js";
|
|
9
|
+
import"./index-wjqbc7sf.js";
|
|
11
10
|
import {
|
|
12
11
|
PlatformTestRun
|
|
13
|
-
} from "./index-
|
|
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-
|
|
16
|
-
import"./index-
|
|
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-
|
|
21
|
+
import"./index-qvghfv6v.js";
|
|
20
22
|
import {
|
|
21
23
|
CloudScript2
|
|
22
|
-
} from "./index-
|
|
23
|
-
import"./index-qt22xstj.js";
|
|
24
|
+
} from "./index-jj7yapwq.js";
|
|
24
25
|
import {
|
|
25
|
-
|
|
26
|
-
|
|
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
|
|
109
|
-
}).with(App).option("platform", 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
|
|
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,
|
|
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
|
|
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,
|
|
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
|
|
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,
|
|
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
|
|
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,
|
|
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-
|
|
7
|
+
} from "./index-3x7yeecy.js";
|
|
8
8
|
import"./index-52w0fvh8.js";
|
|
9
|
-
import"./index-
|
|
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-
|
|
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-
|
|
38
|
-
import("./CodeTui-
|
|
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-
|
|
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-
|
|
5
|
+
} from "./index-3x7yeecy.js";
|
|
6
6
|
import"./index-52w0fvh8.js";
|
|
7
|
-
import"./index-
|
|
7
|
+
import"./index-bv210r6t.js";
|
|
8
8
|
import"./index-hj6w4ka1.js";
|
|
9
|
-
import"./index-
|
|
10
|
-
import"./index-
|
|
11
|
-
import"./index-
|
|
12
|
-
import"./index-
|
|
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-
|
|
15
|
-
import"./index-
|
|
16
|
-
import"./index-
|
|
17
|
-
import"./index-
|
|
18
|
-
import"./index-
|
|
19
|
-
import"./index-
|
|
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-
|
|
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
|
+
};
|
|
@@ -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
|
|
72
|
-
`bun:*` modules (a temp dir, a socket, sqlite), which module code leaves to
|
|
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
|
|
393
|
-
|
|
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
|
|
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
|
|
759
|
-
another server, and a socket it opened would reconnect forever with nobody
|
|
760
|
-
visitor's session either: a call to another origin sends only the `jwt` its
|
|
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
|
|
764
|
-
server runs a mutation once per key and
|
|
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`
|
|
848
|
-
act is still refused there. `option.setMcp({ apps: false })` keeps pages
|
|
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
|
|
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
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
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
|
|
235
|
-
`initialize` settles on `2025-11-25`, because claude.ai renders a view only for a server it reached
|
|
236
|
-
`initialize`.
|
|
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
|
|
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
|
|
376
|
-
|
|
377
|
-
neither those tools nor the `ui://` resources, a
|
|
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.<
|
|
381
|
-
|
|
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
|