@akanjs/cli 3.1.0-rc.0 → 3.1.0-rc.2
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-q7a4srt6.js → CodeAgent-q50k4s45.js} +2 -2
- package/{CodeTui-ak23dxc9.js → CodeTui-62g35ztk.js} +1 -1
- package/TunnelShare-f1egrktx.js +13 -0
- package/{agent.command-f3gsc1gd.js → agent.command-adfd5299.js} +5 -5
- package/akanCode.js +2 -2
- package/{application.command-3v2d53gd.js → application.command-hj3gv1rx.js} +52 -41
- package/{applicationBuildRunner-1yaqsrdq.js → applicationBuildRunner-by10r9gf.js} +16 -30
- package/buildBatch.proc.js +22 -13
- package/{cloud.command-kk2rwkvw.js → cloud.command-k2fhaape.js} +60 -63
- package/cloud.script-z8p5dz7e.js +23 -0
- package/{code.command-30sca09d.js → code.command-kt5zgcc2.js} +6 -6
- package/{context.command-k7eqacq6.js → context.command-8fgn42jw.js} +16 -13
- package/context.runner-hnh0rg7m.js +24 -0
- package/{guideline.command-dtczrqpf.js → guideline.command-3yxxr2mm.js} +2 -2
- package/guidelines/conventions/conventions.instruction.md +30 -15
- package/guidelines/cssRule/cssRule.instruction.md +12 -6
- package/guidelines/mcpRule/mcpRule.instruction.md +32 -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-kjvrq3nc.js → index-0909wckt.js} +361 -282
- package/{index-p9ystjrp.js → index-20cebtth.js} +92 -52
- package/{index-55mynnqs.js → index-2etqq75t.js} +455 -206
- package/{index-6jjtnhkw.js → index-31ce9vhg.js} +51 -9
- package/{index-y8q31011.js → index-3reaaa1h.js} +42 -153
- package/{index-ww9bhp67.js → index-4pf8g7ff.js} +1 -1
- package/{index-qt22xstj.js → index-58vvz603.js} +5 -3
- package/index-6726qr1m.js +668 -0
- package/index-8935h3n1.js +33 -0
- package/{index-nz15k0b6.js → index-8zdwpxef.js} +1 -1
- package/{index-c2yrsxdh.js → index-azh29dc8.js} +96 -320
- package/{index-c1x0be5j.js → index-bea2gwc6.js} +2 -2
- package/{index-v29746vb.js → index-e9prnmyt.js} +3 -3
- package/{index-tn4rpqp1.js → index-fjsv10hd.js} +73 -49
- package/index-g0vwzy9m.js +241 -0
- package/{index-c76k723e.js → index-h85cxfkg.js} +2 -2
- package/{index-rwq3ekqc.js → index-hnby7p9n.js} +7 -7
- package/{index-2etcv0sc.js → index-jwqtchha.js} +1 -1
- package/index-kc8z134d.js +248 -0
- package/index-nq045px5.js +1124 -0
- package/{index-fm46xrf1.js → index-nq2ja5e0.js} +3 -3
- package/{index-0bm04n5g.js → index-pyxn1b53.js} +10 -8
- package/{index-05g3jayg.js → index-rhbabmja.js} +1 -1
- package/{index-2mx692qq.js → index-rk9sdys3.js} +2 -2
- package/{index-7bymavqk.js → index-sby8fe1p.js} +1 -1
- package/{index-ctanya41.js → index-sqfdmb5b.js} +4 -4
- package/{index-2t4tqd1c.js → index-t7nws9mx.js} +3 -3
- package/{index-jyv387qw.js → index-tv8fjaba.js} +4 -4
- package/{index-gnyf1fqy.js → index-tz5evhdr.js} +2 -2
- package/{index-aprt7pkz.js → index-xpdgxsj5.js} +229 -1327
- package/{index-e0cvze1s.js → index-z507nzhg.js} +4 -4
- package/index.js +22 -22
- package/{library.command-gaga5bmq.js → library.command-8tw59xzj.js} +3 -3
- package/{localRegistry.command-9e84e32q.js → localRegistry.command-tf3dmznd.js} +12 -9
- package/{module.command-7vpf6db4.js → module.command-9vm8hffy.js} +5 -5
- package/{package.command-twmvvf69.js → package.command-erbxe2tz.js} +3 -3
- package/package.json +2 -2
- package/{page.command-5asq7fdf.js → page.command-jpavcj0p.js} +3 -3
- package/{pipeline.command-d0v38572.js → pipeline.command-b8rzvjvv.js} +220 -219
- package/{primitive.command-dyrs2fm8.js → primitive.command-sm32chzk.js} +6 -6
- package/{projectTypecheck-cvtkrzp2.js → projectTypecheck-jamtx95x.js} +1 -1
- package/{quality.command-6emsqpbg.js → quality.command-pkd17n6y.js} +2 -2
- package/{repair.command-8t6aegv5.js → repair.command-8y4mq6hs.js} +5 -5
- package/{scalar.command-bnggy1x7.js → scalar.command-q8khmyx5.js} +4 -4
- package/{subspace.command-f02j5tge.js → subspace.command-51n0ykbx.js} +421 -362
- package/templates/app/env/env.client.type.ts +2 -3
- package/templates/app/page/styles.css.template +8 -0
- package/{tunnel.command-9x8nfn75.js → tunnel.command-7820vtxq.js} +7 -4
- package/{workflow.command-jx0wag5r.js → workflow.command-n5sv4wqz.js} +10 -10
- package/{workspace.command-cmj6mqyk.js → workspace.command-zdy60jh8.js} +33 -30
- package/TunnelShare-21mm6dr5.js +0 -9
- package/cloud.script-r7eyfey4.js +0 -20
- package/context.runner-hqd1ppqe.js +0 -21
- package/index-6w0rbr9d.js +0 -68
- package/index-r2tpeb3n.js +0 -392
|
@@ -3,57 +3,47 @@ import {
|
|
|
3
3
|
App,
|
|
4
4
|
Workspace,
|
|
5
5
|
command
|
|
6
|
-
} from "./index-
|
|
6
|
+
} from "./index-31ce9vhg.js";
|
|
7
7
|
import"./index-52w0fvh8.js";
|
|
8
|
-
import"./index-
|
|
9
|
-
import"./index-
|
|
10
|
-
import"./index-r2tpeb3n.js";
|
|
8
|
+
import"./index-2etqq75t.js";
|
|
9
|
+
import"./index-6726qr1m.js";
|
|
11
10
|
import {
|
|
12
11
|
PlatformTestRun
|
|
13
|
-
} from "./index-
|
|
12
|
+
} from "./index-3reaaa1h.js";
|
|
13
|
+
import"./index-g0vwzy9m.js";
|
|
14
|
+
import"./index-0909wckt.js";
|
|
15
|
+
import"./index-nq045px5.js";
|
|
14
16
|
import"./index-k9rrten6.js";
|
|
15
|
-
import"./index-
|
|
16
|
-
import"./index-
|
|
17
|
+
import"./index-bea2gwc6.js";
|
|
18
|
+
import"./index-20cebtth.js";
|
|
17
19
|
import"./index-7md2g9vw.js";
|
|
18
20
|
import"./index-2ahj896a.js";
|
|
19
|
-
import"./index-
|
|
21
|
+
import"./index-tz5evhdr.js";
|
|
20
22
|
import {
|
|
21
23
|
CloudScript2
|
|
22
|
-
} from "./index-
|
|
23
|
-
import"./index-qt22xstj.js";
|
|
24
|
+
} from "./index-fjsv10hd.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-58vvz603.js";
|
|
36
|
+
import"./index-kc8z134d.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,8 +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, {
|
|
115
|
+
flag: "d",
|
|
116
|
+
desc: "a folder `akan pack-update` wrote, uploaded instead of packing; --platform, --target and --env must match it",
|
|
117
|
+
nullable: true
|
|
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) {
|
|
110
119
|
await this.cloudScript.pushUpdate(workspace, app, {
|
|
111
120
|
platform,
|
|
112
121
|
target,
|
|
@@ -116,15 +125,17 @@ class CloudCommand extends command("cloud", [CloudScript2], ({ public: target })
|
|
|
116
125
|
subspace,
|
|
117
126
|
host,
|
|
118
127
|
write,
|
|
119
|
-
allowLocalRelease
|
|
128
|
+
allowLocalRelease,
|
|
129
|
+
pack,
|
|
130
|
+
publicEnv
|
|
120
131
|
});
|
|
121
132
|
}),
|
|
122
133
|
registerBinary: target({
|
|
123
|
-
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"
|
|
124
135
|
}).with(App).option("platform", String, { enum: ["ios", "android"], desc: "the store build to register" }).option("distribution", String, {
|
|
125
136
|
enum: ["appStore", "testFlight", "playStore", "playTesting", "direct"],
|
|
126
137
|
desc: "where the binary ships"
|
|
127
|
-
}).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) {
|
|
128
139
|
await this.cloudScript.registerBinary(workspace, app, {
|
|
129
140
|
platform,
|
|
130
141
|
distribution,
|
|
@@ -133,51 +144,37 @@ class CloudCommand extends command("cloud", [CloudScript2], ({ public: target })
|
|
|
133
144
|
subspace,
|
|
134
145
|
host,
|
|
135
146
|
write,
|
|
136
|
-
allowLocalRelease
|
|
147
|
+
allowLocalRelease,
|
|
148
|
+
publicEnv
|
|
137
149
|
});
|
|
138
150
|
}),
|
|
139
151
|
uploadSecret: target({
|
|
140
|
-
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"
|
|
141
153
|
}).arg("name", String, { desc: "secret name, e.g. DISCORD_WEBHOOK" }).option("branch", String, {
|
|
142
154
|
desc: "only builds of this branch use it: debug, develop or main (default: every branch)",
|
|
143
155
|
nullable: true
|
|
144
156
|
}).option("file", String, {
|
|
145
157
|
desc: "read the value from this file instead of stdin or a hidden prompt",
|
|
146
158
|
nullable: true
|
|
147
|
-
}).option("subspace", String,
|
|
148
|
-
desc: "host of the cloud to target (default: cloud.host of the root akan.config.ts, else Akan Cloud)",
|
|
149
|
-
nullable: true
|
|
150
|
-
}).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) {
|
|
151
160
|
await this.cloudScript.uploadSecret(workspace, { name, branch, file, subspace, host });
|
|
152
161
|
}),
|
|
153
|
-
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, {
|
|
154
163
|
desc: "only the secrets builds of this branch use: debug, develop or main",
|
|
155
164
|
nullable: true
|
|
156
|
-
}).option("subspace", String,
|
|
157
|
-
desc: "host of the cloud to target (default: cloud.host of the root akan.config.ts, else Akan Cloud)",
|
|
158
|
-
nullable: true
|
|
159
|
-
}).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) {
|
|
160
166
|
await this.cloudScript.listSecrets(workspace, { branch, subspace, host });
|
|
161
167
|
}),
|
|
162
|
-
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, {
|
|
163
169
|
desc: "the branch override to remove: debug, develop or main (default: the every-branch value)",
|
|
164
170
|
nullable: true
|
|
165
|
-
}).option("subspace", String,
|
|
166
|
-
desc: "host of the cloud to target (default: cloud.host of the root akan.config.ts, else Akan Cloud)",
|
|
167
|
-
nullable: true
|
|
168
|
-
}).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) {
|
|
169
172
|
await this.cloudScript.removeSecret(workspace, { name, branch, subspace, host });
|
|
170
173
|
}),
|
|
171
|
-
downloadEnv: target({ desc: "Download environment variables from cloud or SCP server" }).option("host", String, {
|
|
172
|
-
desc: "host of the cloud to target (default: cloud.host of the root akan.config.ts, else Akan Cloud)",
|
|
173
|
-
nullable: true
|
|
174
|
-
}).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) {
|
|
175
175
|
await this.cloudScript.downloadEnv(workspace, undefined, { host });
|
|
176
176
|
}),
|
|
177
|
-
uploadEnv: target({ desc: "Upload environment variables to cloud or SCP server" }).option("host", String, {
|
|
178
|
-
desc: "host of the cloud to target (default: cloud.host of the root akan.config.ts, else Akan Cloud)",
|
|
179
|
-
nullable: true
|
|
180
|
-
}).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) {
|
|
181
178
|
await this.cloudScript.uploadEnv(workspace, { host });
|
|
182
179
|
})
|
|
183
180
|
})) {
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import {
|
|
3
|
+
CloudScript2
|
|
4
|
+
} from "./index-fjsv10hd.js";
|
|
5
|
+
import"./index-3reaaa1h.js";
|
|
6
|
+
import"./index-20cebtth.js";
|
|
7
|
+
import"./index-58vvz603.js";
|
|
8
|
+
import"./index-bea2gwc6.js";
|
|
9
|
+
import"./index-tz5evhdr.js";
|
|
10
|
+
import"./index-g0vwzy9m.js";
|
|
11
|
+
import"./index-6726qr1m.js";
|
|
12
|
+
import"./index-0909wckt.js";
|
|
13
|
+
import"./index-31ce9vhg.js";
|
|
14
|
+
import"./index-7md2g9vw.js";
|
|
15
|
+
import"./index-kc8z134d.js";
|
|
16
|
+
import"./index-k9rrten6.js";
|
|
17
|
+
import"./index-nq045px5.js";
|
|
18
|
+
import"./index-2etqq75t.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-31ce9vhg.js";
|
|
8
8
|
import"./index-52w0fvh8.js";
|
|
9
|
-
import"./index-
|
|
9
|
+
import"./index-2etqq75t.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-q50k4s45.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-q50k4s45.js"),
|
|
38
|
+
import("./CodeTui-62g35ztk.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-q50k4s45.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-31ce9vhg.js";
|
|
6
6
|
import"./index-52w0fvh8.js";
|
|
7
|
-
import"./index-
|
|
7
|
+
import"./index-2etqq75t.js";
|
|
8
8
|
import"./index-hj6w4ka1.js";
|
|
9
|
-
import"./index-
|
|
10
|
-
import"./index-
|
|
11
|
-
import"./index-
|
|
12
|
-
import"./index-
|
|
9
|
+
import"./index-rhbabmja.js";
|
|
10
|
+
import"./index-rk9sdys3.js";
|
|
11
|
+
import"./index-pyxn1b53.js";
|
|
12
|
+
import"./index-g0vwzy9m.js";
|
|
13
|
+
import"./index-0909wckt.js";
|
|
14
|
+
import"./index-nq045px5.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-nq2ja5e0.js";
|
|
17
|
+
import"./index-jwqtchha.js";
|
|
18
|
+
import"./index-z507nzhg.js";
|
|
19
|
+
import"./index-sqfdmb5b.js";
|
|
20
|
+
import"./index-h85cxfkg.js";
|
|
21
|
+
import"./index-hnby7p9n.js";
|
|
20
22
|
import {
|
|
21
23
|
ContextScript
|
|
22
|
-
} from "./index-
|
|
24
|
+
} from "./index-tv8fjaba.js";
|
|
25
|
+
import"./index-kc8z134d.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-pyxn1b53.js";
|
|
5
|
+
import"./index-hnby7p9n.js";
|
|
6
|
+
import"./index-h85cxfkg.js";
|
|
7
|
+
import"./index-sqfdmb5b.js";
|
|
8
|
+
import"./index-nq2ja5e0.js";
|
|
9
|
+
import"./index-z507nzhg.js";
|
|
10
|
+
import"./index-jwqtchha.js";
|
|
11
|
+
import"./index-g0vwzy9m.js";
|
|
12
|
+
import"./index-0909wckt.js";
|
|
13
|
+
import"./index-rk9sdys3.js";
|
|
14
|
+
import"./index-rhbabmja.js";
|
|
15
|
+
import"./index-zzvvc845.js";
|
|
16
|
+
import"./index-31ce9vhg.js";
|
|
17
|
+
import"./index-kc8z134d.js";
|
|
18
|
+
import"./index-nq045px5.js";
|
|
19
|
+
import"./index-2etqq75t.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
|
|
@@ -842,9 +854,11 @@ it.
|
|
|
842
854
|
- **The same page is a tool too, and an MCP Apps host renders it.** A `.prompt()` page answers `tools/call` with
|
|
843
855
|
that briefing plus its web URL, and a host that declares the `io.modelcontextprotocol/ui` extension (claude.ai,
|
|
844
856
|
ChatGPT, VS Code) shows the screen itself in the chat — the CSR bundle in a sandboxed iframe whose every call the
|
|
845
|
-
host relays under the agent's token.
|
|
846
|
-
|
|
847
|
-
|
|
857
|
+
host relays under the agent's token. It shows the page alone: every layout above it still runs (guards, providers,
|
|
858
|
+
`<Agent.Guide>`) and draws nothing, unless it draws no page, as a gate does. Nothing is written for the view. An
|
|
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).
|
|
848
862
|
|
|
849
863
|
Full contract — configuration, wire behaviour, resource URIs, OAuth metadata, protocol revisions, and
|
|
850
864
|
`McpProgress.report`: `get_guideline` with `mcpRule`, or `akan guideline show mcpRule`.
|
|
@@ -907,7 +921,7 @@ what every developer must know even when not building one.
|
|
|
907
921
|
|
|
908
922
|
### Scalar & Field Type Reference
|
|
909
923
|
|
|
910
|
-
- **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.
|
|
911
925
|
- **Use the JS globals directly (no import needed)**: `String`, `Boolean`, `Date`. They are monkey-patched to behave like scalars, so `field(String)` typechecks.
|
|
912
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.
|
|
913
927
|
- Runtime resolution of every scalar (globals included) goes through `PrimitiveRegistry` by `refName` (`pkgs/akanjs/base/primitiveRegistry.ts`).
|
|
@@ -995,7 +1009,8 @@ shape, so `cascade` never means "related" — it means one of exactly these:
|
|
|
995
1009
|
of the route's args returning it, and one that throws renders no head (warned about) so a layout's sign-in redirect
|
|
996
1010
|
still answers; there is no metadata object, and analytics is the app's own script, not a stage.
|
|
997
1011
|
Heads merge root first: a deeper `.head()` replaces the `<title>`, a `<meta>` with the same `name` / `property`,
|
|
998
|
-
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.
|
|
999
1014
|
- **A CSR bundle (a native app, `?csr=true`) never shows a root layout's own markup.** Pages render into the
|
|
1000
1015
|
frame, and what the root layout draws around `{children}` stays in a hidden container, so its wrappers cannot
|
|
1001
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,22 @@ 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.
|
|
398
|
+
- **The view is the page, not the app around it.** Each layout above it still runs — guards, providers,
|
|
399
|
+
`<Agent.Guide>` — but what it draws around `{children}` is hidden, with its frame chrome (`Layout.Navbar`,
|
|
400
|
+
`TopInset`, `BottomInset`, `BottomTab`), the `topInset` / `bottomInset` it reserves and the tools its controls
|
|
401
|
+
publish. A layout that draws no page, like a gate, is the screen then and is shown. The screen the view opened on
|
|
402
|
+
has no back button: there is nothing behind it.
|
|
382
403
|
- **The view has no network.** `connect-src` stays closed; the app's own origin is opened for what a page loads by
|
|
383
404
|
URL — fonts (served with `Access-Control-Allow-Origin: *`) and stored images — and every root-relative URL the
|
|
384
405
|
page writes is pointed at it, since a host may block the document's `<base>` (Claude does).
|