@wenathlan/argan 2.0.151 → 2.0.152

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wenathlan/argan",
3
- "version": "2.0.151",
3
+ "version": "2.0.152",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/wenathlan/devthink"
@@ -27,7 +27,7 @@
27
27
  "ecmascript": "^5.0.0",
28
28
  "firefox": ">=0.8.0",
29
29
  "iojs": "^1.0.0",
30
- "node": ">=26.12.1 <27",
30
+ "node": ">=26.13.0 <27",
31
31
  "npm": "^12.1.0",
32
32
  "pnpm": "^12.6.0",
33
33
  "teleport": ">=0.2.0",
@@ -38,7 +38,6 @@
38
38
  "files": [
39
39
  "README.md",
40
40
  "docs",
41
- "site",
42
41
  "tests"
43
42
  ],
44
43
  "homepage": "https://github.com/wenathlan/devthink/tree/main/argan",
@@ -61,23 +60,36 @@
61
60
  "restore:entry": "node -e \"const{readFileSync}=require('node:fs');const{execSync}=require('node:child_process');const script=/script[^>]*App\\.tsx/;const triad=/family=Inter[\\s\\S]*Geist\\+Mono/;const face=(h)=>script.test(h)&&triad.test(h);if(face(readFileSync('index.html','utf8'))){console.log('index.html already rides the source face');process.exit(0)}if(!face(execSync('git show HEAD:./index.html',{encoding:'utf8'}))){console.error('refusing: HEAD index.html is not the canonical source face yet (script App.tsx + the font triad) - land the source-face fix first; nothing was touched');process.exit(1)}execSync('git checkout -- index.html',{stdio:'inherit'});console.log('index.html restored from HEAD (the source face)')\""
62
61
  },
63
62
  "dependencies": {
63
+ "@fluentui/react-icons": "^2.0.345",
64
+ "@fontsource-variable/bricolage-grotesque": "^5.3.0",
65
+ "@fontsource-variable/jetbrains-mono": "^5.3.0",
66
+ "@fontsource-variable/outfit": "^5.3.0",
64
67
  "@hono/node-server": "^2.1.5",
68
+ "@libsql/client": "^0.18.0",
65
69
  "@prisma/adapter-libsql": "^7.10.1",
66
- "hono": "^4.13.13",
70
+ "@prisma/client": "^7.10.1",
71
+ "@wenathlan/saddle": "^2.1.6",
72
+ "@wenathlan/vault": "^2.0.151",
73
+ "hono": "^4.13.14",
67
74
  "ink": "^7.1.1",
75
+ "lucide-react": "^1.66.0",
76
+ "motion": "^12.43.0",
77
+ "react": "^19.3.1",
68
78
  "react-devtools-core": "^8.0.0",
79
+ "react-dom": "^19.3.1",
80
+ "wouter": "^3.13.0",
69
81
  "z-ai-web-dev-sdk": "^0.0.18"
70
82
  },
71
83
  "devDependencies": {
72
- "@biomejs/biome": "^2.6.3",
73
- "@capacitor/android": "^8.5.3",
74
- "@capacitor/cli": "^8.5.3",
75
- "@capacitor/core": "^8.5.3",
76
- "@capacitor/ios": "^8.5.3",
77
- "@fluentui/react-icons": "^2.0.344",
84
+ "@biomejs/biome": "^2.6.4",
85
+ "@capacitor/android": "^8.6.0",
86
+ "@capacitor/cli": "^8.6.0",
87
+ "@capacitor/core": "^8.6.0",
88
+ "@capacitor/ios": "^8.6.0",
89
+ "@fluentui/react-icons": "^2.0.345",
78
90
  "@hookform/resolvers": "^5.9.2",
79
91
  "@libsql/client": "^0.18.0",
80
- "@opencode-ai/sdk": "^1.19.4",
92
+ "@opencode-ai/sdk": "^1.19.5",
81
93
  "@prisma/client": "^7.10.1",
82
94
  "@radix-ui/react-accordion": "^1.3.1",
83
95
  "@radix-ui/react-alert-dialog": "^1.2.1",
@@ -110,41 +122,49 @@
110
122
  "@tailwindcss/vite": "^4.3.3",
111
123
  "@tsconfig/node26": "^26.0.1",
112
124
  "@types/better-sqlite3": "^9.6.0",
113
- "@types/chrome": "^0.3.6",
125
+ "@types/chrome": "^0.3.7",
114
126
  "@types/express": "^5.0.6",
115
- "@types/node": "^26.6.5",
127
+ "@types/google.maps": "^3.66.9",
128
+ "@types/node": "^26.6.6",
116
129
  "@types/react": "^19.3.0",
117
130
  "@types/react-dom": "^19.3.0",
118
131
  "@vitejs/plugin-react": "^6.1.2",
119
132
  "add": "^2.0.9",
120
- "autoprefixer": "^10.6.1",
121
- "axios": "^1.20.0",
133
+ "autoprefixer": "^10.6.2",
134
+ "axios": "^1.21.0",
122
135
  "better-sqlite3": "^13.0.3",
123
136
  "bun-types": "^1.4.4",
137
+ "cheerio": "^1.2.0",
124
138
  "class-variance-authority": "^0.7.1",
125
139
  "clsx": "^2.1.1",
126
140
  "cmdk": "^1.1.1",
127
141
  "drizzle-kit": "^0.31.11",
128
142
  "drizzle-orm": "^0.45.4",
129
143
  "embla-carousel-react": "^8.6.0",
144
+ "emittery": "^2.2.0",
130
145
  "esbuild": "^0.28.2",
131
146
  "express": "^5.3.0",
132
147
  "fast-check": "^4.10.2",
133
148
  "framer-motion": "^13.5.1",
149
+ "hono": "^4.13.14",
134
150
  "input-otp": "^1.5.0",
135
- "lucide-react": "^1.61.0",
151
+ "jsdom": "26.1.0",
152
+ "lucide-react": "^1.66.0",
136
153
  "mysql2": "^3.24.6",
137
154
  "nanoid": "^6.0.2",
138
155
  "next-themes": "^0.4.6",
139
- "pnpm": "^12.15.0",
140
- "postcss": "^8.5.31",
156
+ "p-limit": "^7.3.3",
157
+ "p-retry": "^8.0.1",
158
+ "playwright": "^1.64.1",
159
+ "pnpm": "^12.16.1",
160
+ "postcss": "^8.5.32",
141
161
  "prettier": "^3.9.10",
142
162
  "prisma": "^7.10.1",
143
163
  "react": "^19.3.1",
144
164
  "react-day-picker": "^10.0.2",
145
165
  "react-dom": "^19.3.1",
146
166
  "react-hook-form": "^7.91.0",
147
- "react-resizable-panels": "^4.15.0",
167
+ "react-resizable-panels": "^4.15.3",
148
168
  "recharts": "^3.10.1",
149
169
  "sonner": "^2.0.8",
150
170
  "streamdown": "^2.7.1",
@@ -157,6 +177,7 @@
157
177
  "typescript": "^7.0.2",
158
178
  "vaul": "^1.1.2",
159
179
  "vite": "^8.3.5",
180
+ "vite-plugin-manus-runtime": "^0.0.59",
160
181
  "vitest": "^5.0.5",
161
182
  "wouter": "^3.13.0",
162
183
  "yaml": "^2.9.1",
@@ -174,8 +195,11 @@
174
195
  "proxy-addr": "2.0.8",
175
196
  "body-parser": "^2.4.0",
176
197
  "fast-uri": "^3.1.9",
177
- "follow-redirects": "^1.16.1",
198
+ "follow-redirects": "^1.16.2",
199
+ "minimatch": "^11.0.3",
200
+ "glob": "^14.0.3",
178
201
  "zod": "^4.6.7",
179
- "undici": "^7.30.1"
202
+ "undici": "^7.30.1",
203
+ "shell-quote": "^1.11.0"
180
204
  }
181
205
  }
@@ -37,9 +37,11 @@ describe("design contract", () => {
37
37
  }
38
38
  });
39
39
 
40
- it("carries the argan jade #34d8a8 as the one signal (mark story #14b98c)", () => {
41
- // the jade token stands literal and the primary rides it — both stay pinned
42
- expect(CSS).toMatch(/--arg-jade: #34d8a8/);
40
+ it("carries the white sun as the one signal with the jade story in the mark (#14b98c)", () => {
41
+ // the white sun answers the single-theme law: the jade rides the signal
42
+ // alias and the story survives in the drawn brand mark
43
+ expect(CSS).toMatch(/--color-signal: #ffffff/);
44
+ expect(CSS).toMatch(/--arg-jade: var\(--color-signal\)/);
43
45
  expect(CSS).toMatch(/--sol-primary: var\(--arg-jade\)/);
44
46
  expect(MARK).toMatch(/#14b98c/);
45
47
  });
@@ -50,14 +52,14 @@ describe("design contract", () => {
50
52
  });
51
53
 
52
54
  it("never ships an all-properties transition", () => {
53
- expect(/transition:\s*all/.test(CSS), "transition: all is a reprovação").toBe(false);
55
+ expect(/transition:\s*all/.test(CSS), "transition: all is a rejection").toBe(false);
54
56
  });
55
57
 
56
58
  it("never enters an element from zero scale (the windows dtPopIntro bounce excepted)", () => {
57
59
  const sansPopIntro = CSS.replace(/@keyframes dtPopIntro \{[\s\S]*?\n\}/g, "");
58
60
  expect(
59
61
  /scale\(0\)/.test(sansPopIntro),
60
- "scale(0) entries are a reprovação (the dtPopIntro bounce of the windows recipe excepted)",
62
+ "scale(0) entries are a rejection (the dtPopIntro bounce of the windows recipe excepted)",
61
63
  ).toBe(false);
62
64
  });
63
65
 
@@ -120,7 +122,7 @@ describe("design contract", () => {
120
122
  });
121
123
 
122
124
  it("carries the flow contract sources (the entry gate behind the home anchor, the shared state module)", () => {
123
- const GATE = read("../Sol/widgets/HomeEntrygate.tsx");
125
+ const GATE = read("../Sol/wingets/HomeEntrygate.tsx");
124
126
  const STATE = read("../onboardingstate.ts");
125
127
  const HOME = read("../Sol/home/home.tsx");
126
128
  const ONBOARDING = read("../Sol/onboarding/onboarding.tsx");
@@ -0,0 +1,114 @@
1
+ // # mimetypes.test — honest unit tests for the gateway media type catalog, runnable
2
+ // with the vitest runner:
3
+ // pnpm test
4
+ // The suite pins the owner law of wave 2-a: three thousand mimetypes on the internal
5
+ // api surface (3217 rows, every family the gateway answers for), the canonical pins of
6
+ // the extension lookup (.ts answers video/mp2t, .tsx answers application/typescript),
7
+ // the one-row-per-extension collision law and the catalog accessor that serves the
8
+ // catalog offline.
9
+ import assert from "node:assert/strict";
10
+ import { describe, it } from "vitest";
11
+ import { listMimetypes } from "../catalog.ts";
12
+ import {
13
+ extensionsForType,
14
+ findMimeType,
15
+ MIMETYPES,
16
+ MIMETYPE_COUNT,
17
+ mimeFamilyOf,
18
+ mimeTypeForExtension,
19
+ mimetypesByFamily,
20
+ } from "../mimetypes.ts";
21
+
22
+ /** The families the law names (the type tree the catalog must cover). */
23
+ const LAW_FAMILIES: readonly string[] = [
24
+ "text", "image", "audio", "video", "application", "font", "model", "chemical",
25
+ "message", "multipart",
26
+ ];
27
+
28
+ describe("mimetype catalog scale (the three-thousand law)", () => {
29
+ it("answers 3217 media types — past the three thousand line", () => {
30
+ assert.equal(MIMETYPE_COUNT, 3217);
31
+ assert.ok(MIMETYPE_COUNT >= 3000, "the catalog must clear three thousand");
32
+ });
33
+
34
+ it("carries one row per media type", () => {
35
+ const seen = new Set<string>();
36
+ for (const row of MIMETYPES) {
37
+ assert.ok(!seen.has(row.type), `the type ${row.type} rides twice`);
38
+ seen.add(row.type);
39
+ }
40
+ assert.equal(seen.size, MIMETYPE_COUNT);
41
+ });
42
+
43
+ it("covers every family of the owner law", () => {
44
+ const families = new Set(MIMETYPES.map((row) => row.family as string));
45
+ for (const family of LAW_FAMILIES) {
46
+ assert.ok(families.has(family), `the catalog must cover ${family}`);
47
+ }
48
+ assert.equal(families.size, 10);
49
+ });
50
+
51
+ it("answers the family of every row from the type tree before the slash", () => {
52
+ for (const row of MIMETYPES) {
53
+ assert.equal(row.family, row.type.split("/")[0]);
54
+ }
55
+ });
56
+ });
57
+
58
+ describe("mimetype canonical pins (the extension lookup law)", () => {
59
+ it("answers .ts with video/mp2t and .tsx with application/typescript", () => {
60
+ assert.equal(mimeTypeForExtension("ts")?.type, "video/mp2t");
61
+ assert.equal(mimeTypeForExtension(".tsx")?.type, "application/typescript");
62
+ assert.equal(mimeTypeForExtension("TS")?.type, "video/mp2t");
63
+ assert.equal(mimeTypeForExtension(".TSX")?.type, "application/typescript");
64
+ });
65
+
66
+ it("answers the everyday extensions of the web family", () => {
67
+ assert.equal(mimeTypeForExtension("html")?.type, "text/html");
68
+ assert.equal(mimeTypeForExtension(".css")?.type, "text/css");
69
+ assert.equal(mimeTypeForExtension("js")?.type, "application/javascript");
70
+ assert.equal(mimeTypeForExtension("json")?.type, "application/json");
71
+ assert.equal(mimeTypeForExtension("svg")?.type, "image/svg+xml");
72
+ assert.equal(mimeTypeForExtension("md")?.type, "text/markdown");
73
+ assert.equal(mimeTypeForExtension("wasm")?.type, "application/wasm");
74
+ });
75
+
76
+ it("resolves types case-insensitively and answers unknowns with undefined", () => {
77
+ assert.equal(findMimeType("VIDEO/MP2T")?.family, "video");
78
+ assert.equal(findMimeType(" application/typescript ")?.extensions.includes("tsx"), true);
79
+ assert.equal(mimeFamilyOf("font/woff2"), "font");
80
+ assert.equal(findMimeType("video/mp3t"), undefined);
81
+ assert.equal(mimeTypeForExtension("nope"), undefined);
82
+ assert.equal(mimeTypeForExtension(""), undefined);
83
+ });
84
+
85
+ it("lists the extensions of one type and the rows of one family", () => {
86
+ assert.deepEqual(extensionsForType("video/mp2t"), ["ts"]);
87
+ assert.deepEqual(extensionsForType("font/woff"), ["woff"]);
88
+ assert.equal(extensionsForType("video/mp3t").length, 0);
89
+ assert.equal(mimetypesByFamily("font").length, 6);
90
+ assert.ok(mimetypesByFamily("text").every((row) => row.family === "text"));
91
+ });
92
+
93
+ it("keeps every extension on exactly one row (the collision law)", () => {
94
+ const claimed = new Map<string, string>();
95
+ for (const row of MIMETYPES) {
96
+ for (const extension of row.extensions) {
97
+ const owner = claimed.get(extension);
98
+ assert.ok(owner === undefined, `.${extension} rides both ${owner} and ${row.type}`);
99
+ claimed.set(extension, row.type);
100
+ }
101
+ }
102
+ assert.ok(claimed.size > 1500, "the catalog maps a dense extension set");
103
+ assert.equal(claimed.get("ts"), "video/mp2t");
104
+ assert.equal(claimed.get("tsx"), "application/typescript");
105
+ });
106
+ });
107
+
108
+ describe("mimetype catalog on the catalog surface", () => {
109
+ it("serves the catalog through the typed accessor offline (the registry seed)", async () => {
110
+ const rows = await listMimetypes();
111
+ assert.equal(rows.length, MIMETYPE_COUNT);
112
+ assert.ok(rows.some((row) => row.type === "video/mp2t"));
113
+ });
114
+ });
@@ -0,0 +1,106 @@
1
+ // # protocols.test — honest unit tests for the gateway protocol mesh, runnable with
2
+ // the vitest runner:
3
+ // pnpm test
4
+ // The suite pins the owner law of wave 2-a: more than one hundred protocols on the
5
+ // internal api surface (144 tls-capable wires over the hundred line, 231 rows above
6
+ // the two hundred line), the canonical schemes of the mesh, the family grouping, the
7
+ // tone derivation and the catalog accessor that serves the mesh offline.
8
+ import assert from "node:assert/strict";
9
+ import { describe, it } from "vitest";
10
+ import { listProtocols } from "../catalog.ts";
11
+ import {
12
+ findProtocol,
13
+ PROTOCOLS,
14
+ PROTOCOL_COUNT,
15
+ protocolGroups,
16
+ protocolsByGroup,
17
+ protocolSchemes,
18
+ protocolTone,
19
+ tlsCapableProtocols,
20
+ } from "../protocols.ts";
21
+
22
+ /** The schemes the owner law names (the transfer and application wires of the mesh). */
23
+ const LAW_SCHEMES: readonly string[] = [
24
+ "https", "wss", "webtransport", "webcodecs", "webrtc", "webdav", "webdavs", "sftp",
25
+ "ftps", "smtp", "smtps", "imap", "imaps", "pop3", "pop3s", "dns", "doh", "dot",
26
+ "quic", "h3", "h2", "h2c", "spdy", "socks5", "socks5h", "tor", "i2p", "ipfs",
27
+ "hypercore", "gemini", "gopher", "ldap", "ldaps", "rdp", "vnc", "ssh", "telnet",
28
+ "mqtt", "mqtts", "amqp", "amqps", "stomp", "nats", "grpc", "grpcs", "capnproto",
29
+ "msgpack-rpc", "thrift", "xmlrpc", "jsonrpc", "soap", "graphql-ws", "sse", "longpoll",
30
+ "echo", "discard", "chargen", "daytime", "ntp", "snmp", "syslog", "tftp",
31
+ ];
32
+
33
+ describe("protocol mesh scale (the hundred law)", () => {
34
+ it("answers 231 protocols — more than one hundred, above the two hundred line", () => {
35
+ assert.equal(PROTOCOL_COUNT, 231);
36
+ assert.ok(PROTOCOL_COUNT > 100, "the mesh must clear one hundred");
37
+ assert.ok(PROTOCOL_COUNT >= 200, "the mesh must clear the two hundred line");
38
+ });
39
+
40
+ it("carries 144 tls-capable wires — the https-grade count clears one hundred", () => {
41
+ const capable = tlsCapableProtocols();
42
+ assert.equal(capable.length, 144);
43
+ assert.ok(capable.length > 100, "the tls-capable count must clear one hundred");
44
+ });
45
+
46
+ it("registers every scheme of the owner law", () => {
47
+ const schemes = new Set(protocolSchemes());
48
+ for (const scheme of LAW_SCHEMES) {
49
+ assert.ok(schemes.has(scheme), `the mesh must register ${scheme}`);
50
+ }
51
+ });
52
+
53
+ it("answers one row per scheme with a name, port, spec, family and state", () => {
54
+ const seen = new Set<string>();
55
+ for (const row of PROTOCOLS) {
56
+ assert.ok(!seen.has(row.scheme), `the scheme ${row.scheme} rides twice`);
57
+ seen.add(row.scheme);
58
+ assert.ok(row.name.length > 0, `${row.scheme} needs a name`);
59
+ assert.ok(row.port.length > 0, `${row.scheme} needs a port answer`);
60
+ assert.ok(row.spec.length > 0, `${row.scheme} needs a spec`);
61
+ assert.ok(row.state.length > 0, `${row.scheme} needs a state`);
62
+ }
63
+ assert.equal(seen.size, PROTOCOL_COUNT);
64
+ });
65
+ });
66
+
67
+ describe("protocol mesh grouping and lookups", () => {
68
+ it("groups the mesh into the fifteen family keywords", () => {
69
+ const groups = protocolGroups();
70
+ assert.equal(groups.length, 15);
71
+ for (const group of groups) {
72
+ assert.ok(protocolsByGroup(group).length > 0, `the ${group} family carries rows`);
73
+ }
74
+ });
75
+
76
+ it("answers the dns family with the argan home transports", () => {
77
+ const dns = protocolsByGroup("dns");
78
+ assert.equal(dns.length, 12);
79
+ assert.ok(dns.every((row) => row.group === "dns"));
80
+ const doh = dns.find((row) => row.scheme === "doh");
81
+ assert.equal(doh?.spec, "RFC 8484");
82
+ assert.equal(doh?.state, "preferred");
83
+ });
84
+
85
+ it("resolves schemes case-insensitively and answers unknowns with undefined", () => {
86
+ assert.equal(findProtocol("WSS")?.name, "WebSocket Secure");
87
+ assert.equal(findProtocol(" https ")?.port, "443");
88
+ assert.equal(findProtocol("gopher")?.security, "cleartext");
89
+ assert.equal(findProtocol("telstar"), undefined);
90
+ });
91
+
92
+ it("derives the pane tone from the security posture", () => {
93
+ assert.equal(protocolTone(findProtocol("wss")!), "success");
94
+ assert.equal(protocolTone(findProtocol("imap")!), "info");
95
+ assert.equal(protocolTone(findProtocol("telnet")!), "default");
96
+ assert.equal(protocolTone(findProtocol("http")!), "warning");
97
+ });
98
+ });
99
+
100
+ describe("protocol mesh on the catalog surface", () => {
101
+ it("serves the mesh through the typed accessor offline (the registry seed)", async () => {
102
+ const rows = await listProtocols();
103
+ assert.equal(rows.length, PROTOCOL_COUNT);
104
+ assert.ok(rows.some((row) => row.scheme === "webtransport"));
105
+ });
106
+ });
@@ -0,0 +1,84 @@
1
+ // # sandboxmodality.test — the workload lane declaration of argan (wave
2
+ // WL1): the mirrored rows answer the engine catalog byte for byte (the
3
+ // lockstep pin — every lane, role, demand and honest today the engine
4
+ // FAMILYLANES table carries for argan, compared through the library
5
+ // bridge so the vendor can never drift in silence), every row names the
6
+ // app slug, and the seat law answers the deploy's opt-in (absent or blank
7
+ // answers the declared local default, "join" opts the lanes onto the
8
+ // platform's join resolver — the nuclear modality law, and a named
9
+ // modality id pins the seat for the platform's join to validate at
10
+ // dispatch — this module never judges engine vocabulary). runnable with
11
+ // vitest:
12
+ // pnpm vitest run tests/sandboxmodality.test.ts
13
+ import assert from "node:assert/strict";
14
+ import { describe, it } from "vitest";
15
+ import { lanesof } from "@wenathlan/saddle/workloadlaw";
16
+ import {
17
+ APPSLUG,
18
+ SANDBOXLANEENV,
19
+ WORKLOADLANES,
20
+ laneof,
21
+ lanesandbox,
22
+ lanesandboxfromenv,
23
+ } from "../sandboxmodality.ts";
24
+
25
+ describe("the workload lane mirror (the engine catalog lockstep)", () => {
26
+ it("answers the engine catalog rows for argan — the byte pin", () => {
27
+ const engine = lanesof("argan");
28
+ assert.equal(engine.length, WORKLOADLANES.length, "the mirror carries every argan lane");
29
+ for (let index = 0; index < engine.length; index += 1) {
30
+ const row = engine[index];
31
+ const mirror = WORKLOADLANES[index];
32
+ assert.equal(mirror.app, row.app);
33
+ assert.equal(mirror.lane, row.lane, `lane ${index} id drifts from the engine`);
34
+ assert.equal(mirror.role, row.role, `lane ${row.lane} role drifts from the engine`);
35
+ assert.deepEqual(mirror.demand, row.demand, `lane ${row.lane} demand drifts from the engine`);
36
+ assert.equal(mirror.today, row.today, `lane ${row.lane} today drifts from the engine`);
37
+ }
38
+ });
39
+
40
+ it("carries the app slug on every row and answers the lane lookup", () => {
41
+ for (const row of WORKLOADLANES) {
42
+ assert.equal(row.app, APPSLUG);
43
+ }
44
+ const first = laneof("dnssec-validate");
45
+ assert.ok(first !== undefined);
46
+ assert.equal(first.today, "app-lane");
47
+ assert.equal(laneof("no-such-lane"), undefined);
48
+ });
49
+ });
50
+
51
+ describe("the sandbox lane seat (the deploy decides)", () => {
52
+ it("answers the declared local default when the deploy carries no choice", () => {
53
+ const absent = lanesandbox(undefined);
54
+ assert.deepEqual(absent, { ok: true, seat: "local", sandboxed: false });
55
+ const blank = lanesandbox(" ");
56
+ assert.deepEqual(blank, { ok: true, seat: "local", sandboxed: false });
57
+ const explicit = lanesandbox("local");
58
+ assert.deepEqual(explicit, { ok: true, seat: "local", sandboxed: false });
59
+ });
60
+
61
+ it("opts the lanes onto the platform join when the deploy chooses join", () => {
62
+ const joined = lanesandbox("join");
63
+ assert.deepEqual(joined, { ok: true, seat: "join", sandboxed: true, pinned: false });
64
+ const padded = lanesandbox(" join ");
65
+ assert.deepEqual(padded, { ok: true, seat: "join", sandboxed: true, pinned: false });
66
+ });
67
+
68
+ it("pins the named modality for the platform join to validate", () => {
69
+ const pinned = lanesandbox("runner-node");
70
+ assert.deepEqual(pinned, { ok: true, seat: "runner-node", sandboxed: true, pinned: true });
71
+ // the module never judges engine vocabulary: the platform's join
72
+ // validates the pinned id at dispatch, the mirror only names it
73
+ const unusual = lanesandbox("microvm-firecracker");
74
+ assert.deepEqual(unusual, { ok: true, seat: "microvm-firecracker", sandboxed: true, pinned: true });
75
+ });
76
+
77
+ it("reads the seat off the environment lookup the deploy pins", () => {
78
+ assert.equal(SANDBOXLANEENV, "ARGAN_SANDBOX_LANE");
79
+ const unset = lanesandboxfromenv(() => undefined);
80
+ assert.deepEqual(unset, { ok: true, seat: "local", sandboxed: false });
81
+ const set = lanesandboxfromenv((key) => (key === SANDBOXLANEENV ? "join" : undefined));
82
+ assert.deepEqual(set, { ok: true, seat: "join", sandboxed: true, pinned: false });
83
+ });
84
+ });
package/tests/.gitkeep DELETED
File without changes