@squadrules/mcp 5.16.0 → 5.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/embed-docs/mem/adapter-migration.md +1 -1
  3. package/dist/embed-docs/mem/author-adapter.md +1 -1
  4. package/dist/embed-docs/mem/bulk-insert-adapters-via-cli.md +1 -1
  5. package/dist/embed-docs/mem/challenge-type-guide.md +8 -7
  6. package/dist/embed-docs/mem/critic-loop-guide.md +1 -1
  7. package/dist/embed-docs/mem/critic-loop.md +1 -1
  8. package/dist/embed-docs/mem/protocol-linking-guide.md +1 -1
  9. package/dist/embed-docs/mem/refine-search.md +1 -1
  10. package/dist/resources/embedded-mcp-resources.js +11 -11
  11. package/dist/resources/embedded-mcp-resources.js.map +1 -1
  12. package/dist/runtime-lock.json +2 -2
  13. package/dist/tools/activate-artifacts.d.ts +7 -0
  14. package/dist/tools/activate-artifacts.d.ts.map +1 -1
  15. package/dist/tools/activate-artifacts.js +97 -28
  16. package/dist/tools/activate-artifacts.js.map +1 -1
  17. package/dist/tools/activate_schema.d.ts +4 -12
  18. package/dist/tools/activate_schema.d.ts.map +1 -1
  19. package/dist/tools/activate_schema.js +9 -16
  20. package/dist/tools/activate_schema.js.map +1 -1
  21. package/dist/tools/artifact-local-cache-support.d.ts +62 -0
  22. package/dist/tools/artifact-local-cache-support.d.ts.map +1 -0
  23. package/dist/tools/artifact-local-cache-support.js +61 -0
  24. package/dist/tools/artifact-local-cache-support.js.map +1 -0
  25. package/dist/tools/artifact-local-cache.d.ts +55 -0
  26. package/dist/tools/artifact-local-cache.d.ts.map +1 -0
  27. package/dist/tools/artifact-local-cache.js +315 -0
  28. package/dist/tools/artifact-local-cache.js.map +1 -0
  29. package/dist/tools/artifact-materialize-command.d.ts +27 -21
  30. package/dist/tools/artifact-materialize-command.d.ts.map +1 -1
  31. package/dist/tools/artifact-materialize-command.js +72 -21
  32. package/dist/tools/artifact-materialize-command.js.map +1 -1
  33. package/dist/tools/artifact-relative-path.d.ts +16 -0
  34. package/dist/tools/artifact-relative-path.d.ts.map +1 -1
  35. package/dist/tools/artifact-relative-path.js +51 -0
  36. package/dist/tools/artifact-relative-path.js.map +1 -1
  37. package/dist/tools/export_schema.d.ts +5 -5
  38. package/dist/tools/shell-failure-diagnostics.d.ts.map +1 -1
  39. package/dist/tools/shell-failure-diagnostics.js +3 -2
  40. package/dist/tools/shell-failure-diagnostics.js.map +1 -1
  41. package/dist/tools/tool-registry.d.ts +7 -15
  42. package/dist/tools/tool-registry.d.ts.map +1 -1
  43. package/dist/ui/assets/{AccountPage-CVjbtp9b.js → AccountPage-DiHQo_GL.js} +1 -1
  44. package/dist/ui/assets/{index-BA7BPpk2.js → index-DplB4svU.js} +2 -2
  45. package/dist/ui/index.html +1 -1
  46. package/package.json +1 -1
@@ -0,0 +1,315 @@
1
+ /**
2
+ * STDIO local artifact cache (ADR 0040).
3
+ *
4
+ * The stdio transport has no HTTP listener, so the running server writes the
5
+ * verified artifact bytes it already holds (`AdapterArtifactMetadata.text`) to a
6
+ * private per-process namespace under `os.tmpdir()` and returns a `file://` URL.
7
+ * That gives linked-artifact materialization one transport-neutral URL contract
8
+ * shared with the HTTP capability URL — no CLI, no second backend, and no
9
+ * artifact bytes (raw or base64) through MCP context.
10
+ *
11
+ * Each server process owns exactly one `0700` namespace, publishes with digest
12
+ * verification and atomic rename, leases each returned URL for
13
+ * `SQUADRULES_EXPORT_DOWNLOAD_TTL_SEC` after its last issuance, admits within
14
+ * per-instance entry/byte quotas (failing the whole batch rather than evicting a
15
+ * live lease), and scavenges only namespaces whose owner PID is dead. Helpers,
16
+ * quotas, and error types live in `artifact-local-cache-support.ts`.
17
+ */
18
+ import { randomBytes } from 'node:crypto';
19
+ import { constants as fsConstants } from 'node:fs';
20
+ import fsp from 'node:fs/promises';
21
+ import path from 'node:path';
22
+ import { pathToFileURL } from 'node:url';
23
+ import { SQUADRULES_EXPORT_DOWNLOAD_TTL_SEC } from '../config/export-download-settings.js';
24
+ import { sha256Hex } from './skill-export/sha256.js';
25
+ import { ArtifactCacheDigestError, ArtifactCacheError, ArtifactCacheQuotaError, DEFAULT_MAX_BYTES, DEFAULT_MAX_ENTRIES, DEFAULT_ORPHAN_GRACE_SEC, LEASE_SUFFIX, MAINTENANCE_INTERVAL_MS, NAMESPACE_PREFIX, SHA256_RE, UUID_RE, defaultRootDir, envInt, extensionFor, ownerUid, processMayBeAlive } from './artifact-local-cache-support.js';
26
+ export { ArtifactCacheDigestError, ArtifactCacheError, ArtifactCacheQuotaError };
27
+ /**
28
+ * Read-only open flags that refuse to follow a trailing symlink where the
29
+ * platform exposes `O_NOFOLLOW` (POSIX): a symlink then fails the open with
30
+ * `ELOOP` instead of resolving to its target. On a platform without the flag the
31
+ * bitwise OR degrades to a plain read-only open.
32
+ */
33
+ const READ_NOFOLLOW = fsConstants.O_RDONLY | fsConstants.O_NOFOLLOW;
34
+ export class ArtifactLocalCache {
35
+ rootDir;
36
+ ttlSec;
37
+ maxEntries;
38
+ maxBytes;
39
+ orphanGraceSec;
40
+ now;
41
+ namespace = null;
42
+ lock = Promise.resolve();
43
+ maintenance = null;
44
+ constructor(options = {}) {
45
+ this.rootDir = options.rootDir ?? defaultRootDir();
46
+ this.ttlSec = options.ttlSec ?? envInt('SQUADRULES_ARTIFACT_CACHE_TTL_SEC', SQUADRULES_EXPORT_DOWNLOAD_TTL_SEC);
47
+ this.maxEntries = options.maxEntries ?? envInt('SQUADRULES_ARTIFACT_CACHE_MAX_ENTRIES', DEFAULT_MAX_ENTRIES);
48
+ this.maxBytes = options.maxBytes ?? envInt('SQUADRULES_ARTIFACT_CACHE_MAX_BYTES', DEFAULT_MAX_BYTES);
49
+ this.orphanGraceSec =
50
+ options.orphanGraceSec ?? envInt('SQUADRULES_ARTIFACT_CACHE_ORPHAN_GRACE_SEC', DEFAULT_ORPHAN_GRACE_SEC);
51
+ this.now = options.now ?? (() => Date.now());
52
+ }
53
+ /**
54
+ * Verify and publish a whole activation batch, or fail it entirely. Digest
55
+ * verification and quota preflight run before any write, so a bad artifact or
56
+ * an over-quota batch never leaves a partially usable cache behind.
57
+ */
58
+ async publishBatch(entries) {
59
+ return this.withLock(async () => {
60
+ const ns = await this.ensureNamespace();
61
+ const nowSec = Math.floor(this.now() / 1000);
62
+ const prepared = entries.map((entry) => this.prepare(entry));
63
+ await this.pruneExpiredIn(ns, nowSec);
64
+ this.preflightQuota(await this.listLeases(ns), prepared, nowSec);
65
+ const out = new Map();
66
+ for (const item of prepared) {
67
+ out.set(item.uuid, await this.publishOne(ns, item, nowSec));
68
+ }
69
+ return out;
70
+ });
71
+ }
72
+ /** Remove entries whose lease has expired. Returns the number pruned. */
73
+ async pruneExpired() {
74
+ return this.withLock(async () => {
75
+ if (!this.namespace)
76
+ return 0;
77
+ return this.pruneExpiredIn(this.namespace, Math.floor(this.now() / 1000));
78
+ });
79
+ }
80
+ /**
81
+ * Scavenge namespaces whose owner PID is dead, whose newest lease has expired,
82
+ * and whose grace period has passed. Never touches a live process's namespace,
83
+ * including this one; ambiguous liveness is treated as live.
84
+ */
85
+ async scavengeOrphans() {
86
+ return this.withLock(async () => {
87
+ await this.ensureRoot();
88
+ const nowSec = Math.floor(this.now() / 1000);
89
+ let removed = 0;
90
+ for (const entry of await fsp.readdir(this.rootDir, { withFileTypes: true })) {
91
+ if (!entry.name.startsWith(NAMESPACE_PREFIX) || !entry.isDirectory())
92
+ continue;
93
+ const full = path.join(this.rootDir, entry.name);
94
+ if (full === this.namespace)
95
+ continue;
96
+ const pid = Number.parseInt(entry.name.slice(NAMESPACE_PREFIX.length).split('-')[0] ?? '', 10);
97
+ if (!Number.isFinite(pid) || pid === process.pid || processMayBeAlive(pid))
98
+ continue;
99
+ const newest = await this.newestLeaseExpiry(full);
100
+ const mtimeSec = Math.floor((await fsp.lstat(full)).mtimeMs / 1000);
101
+ if (nowSec < Math.max(newest, mtimeSec) + this.orphanGraceSec)
102
+ continue;
103
+ await fsp.rm(full, { recursive: true, force: true });
104
+ removed += 1;
105
+ }
106
+ return removed;
107
+ });
108
+ }
109
+ startPeriodicMaintenance(intervalMs = MAINTENANCE_INTERVAL_MS) {
110
+ if (this.maintenance)
111
+ return;
112
+ const timer = setInterval(() => {
113
+ void this.runMaintenance();
114
+ }, intervalMs);
115
+ if (typeof timer.unref === 'function')
116
+ timer.unref();
117
+ this.maintenance = timer;
118
+ }
119
+ stopPeriodicMaintenance() {
120
+ if (this.maintenance) {
121
+ clearInterval(this.maintenance);
122
+ this.maintenance = null;
123
+ }
124
+ }
125
+ async runMaintenance() {
126
+ try {
127
+ await this.pruneExpired();
128
+ await this.scavengeOrphans();
129
+ }
130
+ catch {
131
+ // Best-effort maintenance; a failure here must not crash the server.
132
+ }
133
+ }
134
+ prepare(entry) {
135
+ if (!UUID_RE.test(entry.artifactUuid)) {
136
+ throw new ArtifactCacheError('artifact identity is not a UUID; refusing to cache it');
137
+ }
138
+ if (!SHA256_RE.test(entry.sha256)) {
139
+ throw new ArtifactCacheError(`artifact ${entry.artifactUuid} has no valid SHA-256; refusing to cache it`);
140
+ }
141
+ const sha256 = entry.sha256.toLowerCase();
142
+ const buf = Buffer.from(entry.text, 'utf8');
143
+ if (sha256Hex(buf) !== sha256) {
144
+ throw new ArtifactCacheDigestError(`artifact ${entry.artifactUuid} bytes do not match their stored SHA-256; re-activate to refresh the source`);
145
+ }
146
+ const ext = extensionFor(entry.relativePath, entry.contentType);
147
+ return { uuid: entry.artifactUuid, name: `${entry.artifactUuid}-${sha256}.${ext}`, buf, bytes: buf.length };
148
+ }
149
+ preflightQuota(leases, prepared, nowSec) {
150
+ const live = new Map();
151
+ for (const lease of leases) {
152
+ if (lease.expiresSec > nowSec)
153
+ live.set(lease.name, lease);
154
+ }
155
+ let entries = live.size;
156
+ let bytes = 0;
157
+ for (const lease of live.values())
158
+ bytes += lease.bytes;
159
+ const counted = new Set();
160
+ for (const item of prepared) {
161
+ if (live.has(item.name) || counted.has(item.name))
162
+ continue;
163
+ counted.add(item.name);
164
+ entries += 1;
165
+ bytes += item.bytes;
166
+ }
167
+ if (entries > this.maxEntries || bytes > this.maxBytes) {
168
+ throw new ArtifactCacheQuotaError(`linked-artifact batch does not fit the local cache quota (${entries} entries / ${bytes} bytes); ` +
169
+ 'no cached artifact is evicted while its lease is live — re-activate after cached entries expire');
170
+ }
171
+ }
172
+ async publishOne(ns, item, nowSec) {
173
+ const finalPath = path.join(ns, item.name);
174
+ const prior = await this.readLease(`${finalPath}${LEASE_SUFFIX}`);
175
+ if (!(await this.matchesDigest(finalPath, sha256Hex(item.buf)))) {
176
+ await this.writeFileAtomic(finalPath, item.buf, 0o600);
177
+ }
178
+ const lease = {
179
+ v: 1,
180
+ name: item.name,
181
+ bytes: item.bytes,
182
+ createdSec: prior?.createdSec ?? nowSec,
183
+ lastIssuedSec: nowSec,
184
+ expiresSec: nowSec + this.ttlSec
185
+ };
186
+ await this.writeFileAtomic(`${finalPath}${LEASE_SUFFIX}`, Buffer.from(JSON.stringify(lease), 'utf8'), 0o600);
187
+ return { url: pathToFileURL(finalPath).href, path: finalPath, bytes: item.bytes };
188
+ }
189
+ /**
190
+ * True only when `finalPath` is an existing regular file whose bytes match the
191
+ * digest. The path is resolved exactly once: it is opened read-only with
192
+ * `O_NOFOLLOW` (so a symlink fails the open with `ELOOP` instead of being
193
+ * followed), and both the type check and the read run through that single
194
+ * descriptor. Operating on the opened fd instead of re-resolving the path after
195
+ * a stat removes the check-then-read race on `finalPath`.
196
+ */
197
+ async matchesDigest(finalPath, sha256) {
198
+ const handle = await fsp.open(finalPath, READ_NOFOLLOW).catch((err) => {
199
+ if (err.code === 'ELOOP') {
200
+ throw new ArtifactCacheError('a cache entry is a symlink; refusing to reuse or overwrite it');
201
+ }
202
+ return null;
203
+ });
204
+ if (handle === null)
205
+ return false;
206
+ try {
207
+ const stat = await handle.stat();
208
+ if (!stat.isFile())
209
+ return false;
210
+ return sha256Hex(await handle.readFile()) === sha256;
211
+ }
212
+ finally {
213
+ await handle.close();
214
+ }
215
+ }
216
+ async ensureNamespace() {
217
+ if (this.namespace)
218
+ return this.namespace;
219
+ await this.ensureRoot();
220
+ const token = randomBytes(8).toString('hex');
221
+ const ns = await fsp.mkdtemp(path.join(this.rootDir, `${NAMESPACE_PREFIX}${process.pid}-${token}-`));
222
+ await fsp.chmod(ns, 0o700);
223
+ this.namespace = ns;
224
+ return ns;
225
+ }
226
+ async ensureRoot() {
227
+ await fsp.mkdir(this.rootDir, { recursive: true, mode: 0o700 });
228
+ const stat = await fsp.lstat(this.rootDir);
229
+ if (stat.isSymbolicLink())
230
+ throw new ArtifactCacheError('the artifact cache root is a symlink; refusing to use it');
231
+ if (!stat.isDirectory())
232
+ throw new ArtifactCacheError('the artifact cache root is not a directory');
233
+ const uid = ownerUid();
234
+ if (uid !== undefined && stat.uid !== uid) {
235
+ throw new ArtifactCacheError('the artifact cache root is owned by another user; refusing to use it');
236
+ }
237
+ if (stat.mode & 0o077)
238
+ await fsp.chmod(this.rootDir, 0o700);
239
+ }
240
+ async writeFileAtomic(target, data, mode) {
241
+ const tmp = `${target}.tmp-${randomBytes(6).toString('hex')}`;
242
+ const handle = await fsp.open(tmp, 'w', mode);
243
+ try {
244
+ await handle.writeFile(data);
245
+ await handle.chmod(mode);
246
+ await handle.sync();
247
+ }
248
+ finally {
249
+ await handle.close();
250
+ }
251
+ await fsp.rename(tmp, target);
252
+ }
253
+ async readLease(leasePath) {
254
+ try {
255
+ const parsed = JSON.parse(await fsp.readFile(leasePath, 'utf8'));
256
+ return parsed && typeof parsed === 'object' && parsed.v === 1 ? parsed : null;
257
+ }
258
+ catch {
259
+ return null;
260
+ }
261
+ }
262
+ async listLeases(ns) {
263
+ const leases = [];
264
+ let names;
265
+ try {
266
+ names = await fsp.readdir(ns);
267
+ }
268
+ catch {
269
+ return leases;
270
+ }
271
+ for (const name of names) {
272
+ if (!name.endsWith(LEASE_SUFFIX))
273
+ continue;
274
+ const lease = await this.readLease(path.join(ns, name));
275
+ if (lease)
276
+ leases.push(lease);
277
+ }
278
+ return leases;
279
+ }
280
+ async pruneExpiredIn(ns, nowSec) {
281
+ let removed = 0;
282
+ for (const lease of await this.listLeases(ns)) {
283
+ if (lease.expiresSec > nowSec)
284
+ continue;
285
+ const dataPath = path.join(ns, lease.name);
286
+ await fsp.rm(dataPath, { force: true });
287
+ await fsp.rm(`${dataPath}${LEASE_SUFFIX}`, { force: true });
288
+ removed += 1;
289
+ }
290
+ return removed;
291
+ }
292
+ async newestLeaseExpiry(ns) {
293
+ let newest = 0;
294
+ for (const lease of await this.listLeases(ns)) {
295
+ if (lease.expiresSec > newest)
296
+ newest = lease.expiresSec;
297
+ }
298
+ return newest;
299
+ }
300
+ async withLock(fn) {
301
+ const run = this.lock.then(fn, fn);
302
+ this.lock = run.then(() => undefined, () => undefined);
303
+ return run;
304
+ }
305
+ }
306
+ let singleton;
307
+ /** The process-wide stdio cache; created on first use with periodic maintenance. */
308
+ export function getArtifactLocalCache() {
309
+ if (!singleton) {
310
+ singleton = new ArtifactLocalCache();
311
+ singleton.startPeriodicMaintenance();
312
+ }
313
+ return singleton;
314
+ }
315
+ //# sourceMappingURL=artifact-local-cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"artifact-local-cache.js","sourceRoot":"","sources":["../../src/tools/artifact-local-cache.ts"],"names":[],"mappings":"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"}
@@ -1,41 +1,47 @@
1
1
  /**
2
- * Build the materialize instruction for one adapter-linked artifact.
2
+ * Build the materialize instruction for one adapter-linked artifact (ADR 0040).
3
3
  *
4
4
  * Byte-exactness is framework work, not agent work: the instruction carries an
5
- * exact shell line (`cmd`) that writes, verifies, and marks the file executable,
6
- * so the agent never re-types artifact bytes through an editor or a heredoc
7
- * (SquadRules/mcp#231). The byte source depends on the transport: HTTP serves the
8
- * stored bytes itself, stdio has no listener and goes through the `export` tool.
5
+ * exact shell line (`cmd`) that downloads the artifact from a transport-neutral
6
+ * URL, verifies its digest, marks it `0700`, and publishes it atomically, so the
7
+ * agent never re-types artifact bytes through an editor or a heredoc
8
+ * (SquadRules/mcp#231). The URL is a `file://` cache path on stdio and a
9
+ * short-lived capability URL on HTTP; this builder does not branch on transport
10
+ * because `curl` fetches both. The destination tree is caller-owned and trusted:
11
+ * a POSIX shell alone cannot close time-of-check/time-of-use races against a
12
+ * hostile concurrent writer, so `cmd` rejects symlinked roots/ancestors and
13
+ * re-checks containment after resolution, but does not claim race-free isolation.
9
14
  */
10
15
  export declare const SQUADRULES_LOCAL_ARTIFACT_DIR_ENV = "SQUADRULES_LOCAL_ARTIFACT_DIR";
11
16
  export interface ArtifactMaterializeInput {
12
- transport: 'http' | 'stdio';
13
- /** Artifact URI accepted by the `export` tool: `squadrules://artifact/{slug|uuid}`. */
14
- artifactUri: string;
15
- /** Capability download URL served by the HTTP transport. */
16
- downloadUrl: string;
17
+ /** Transport-neutral source URL `cmd` curls: a `file://` cache path (stdio) or an `http(s)://` capability URL (HTTP). */
18
+ url: string;
17
19
  /** Skill-root-relative artifact path; the payload lands here under the artifact dir. */
18
20
  relativePath: string;
19
- /** SHA-256 hex of the stored artifact bytes. */
21
+ /** SHA-256 hex of the stored artifact bytes; `cmd` verifies the download against it. */
20
22
  sha256: string;
21
23
  }
22
24
  export interface MaterializeInstruction {
23
- /** MCP tool that returns the bytes (required on stdio, a read option on HTTP). */
24
- tool: 'export';
25
- arguments: {
26
- uri: string;
27
- format: 'source';
28
- /** Set on stdio: raw text cannot be re-written byte-exactly by an agent. */
29
- delivery?: 'inline_base64';
30
- };
25
+ /** Always `url`: the bytes are fetched from `url` by `cmd` on every transport. */
26
+ method: 'url';
27
+ /** Source URL `cmd` downloads (a `file://` cache path on stdio, a capability URL on HTTP). */
28
+ url: string;
31
29
  /** Absolute path where the bytes land (uses $SQUADRULES_LOCAL_ARTIFACT_DIR). */
32
30
  out: string;
33
31
  /** SHA-256 digest `cmd` verifies; check it against the same value. */
34
32
  sha256: string;
35
- /** File permissions the agent must set after verification. */
33
+ /** File permissions `cmd` sets on the verified bytes before publishing. */
36
34
  chmod: '700';
37
- /** Exact POSIX shell line that writes the file, verifies the digest, and sets permissions. */
35
+ /** Exact POSIX shell line that downloads, verifies, chmods, and atomically publishes. Run it verbatim. */
38
36
  cmd: string;
39
37
  }
38
+ /**
39
+ * Wrap a value in single quotes for safe interpolation into a POSIX shell
40
+ * command. Every embedded `'` becomes the four-character sequence `'\''`, which
41
+ * closes the quoted string, adds an escaped quote, and reopens it. Single quotes
42
+ * suppress `$`, backtick, glob, and word-splitting expansion, so any URL — even
43
+ * one carrying adversarial characters — reaches `curl` as a literal argument.
44
+ */
45
+ export declare function shellSingleQuote(value: string): string;
40
46
  export declare function buildArtifactMaterializeInstruction(input: ArtifactMaterializeInput): MaterializeInstruction;
41
47
  //# sourceMappingURL=artifact-materialize-command.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"artifact-materialize-command.d.ts","sourceRoot":"","sources":["../../src/tools/artifact-materialize-command.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,eAAO,MAAM,iCAAiC,kCAAkC,CAAC;AAEjF,MAAM,WAAW,wBAAwB;IACvC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC;IAC5B,uFAAuF;IACvF,WAAW,EAAE,MAAM,CAAC;IACpB,4DAA4D;IAC5D,WAAW,EAAE,MAAM,CAAC;IACpB,wFAAwF;IACxF,YAAY,EAAE,MAAM,CAAC;IACrB,gDAAgD;IAChD,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,sBAAsB;IACrC,kFAAkF;IAClF,IAAI,EAAE,QAAQ,CAAC;IACf,SAAS,EAAE;QACT,GAAG,EAAE,MAAM,CAAC;QACZ,MAAM,EAAE,QAAQ,CAAC;QACjB,4EAA4E;QAC5E,QAAQ,CAAC,EAAE,eAAe,CAAC;KAC5B,CAAC;IACF,gFAAgF;IAChF,GAAG,EAAE,MAAM,CAAC;IACZ,sEAAsE;IACtE,MAAM,EAAE,MAAM,CAAC;IACf,8DAA8D;IAC9D,KAAK,EAAE,KAAK,CAAC;IACb,8FAA8F;IAC9F,GAAG,EAAE,MAAM,CAAC;CACb;AAED,wBAAgB,mCAAmC,CAAC,KAAK,EAAE,wBAAwB,GAAG,sBAAsB,CAmB3G"}
1
+ {"version":3,"file":"artifact-materialize-command.d.ts","sourceRoot":"","sources":["../../src/tools/artifact-materialize-command.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH,eAAO,MAAM,iCAAiC,kCAAkC,CAAC;AAKjF,MAAM,WAAW,wBAAwB;IACvC,yHAAyH;IACzH,GAAG,EAAE,MAAM,CAAC;IACZ,wFAAwF;IACxF,YAAY,EAAE,MAAM,CAAC;IACrB,wFAAwF;IACxF,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,sBAAsB;IACrC,kFAAkF;IAClF,MAAM,EAAE,KAAK,CAAC;IACd,8FAA8F;IAC9F,GAAG,EAAE,MAAM,CAAC;IACZ,gFAAgF;IAChF,GAAG,EAAE,MAAM,CAAC;IACZ,sEAAsE;IACtE,MAAM,EAAE,MAAM,CAAC;IACf,2EAA2E;IAC3E,KAAK,EAAE,KAAK,CAAC;IACb,0GAA0G;IAC1G,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED,wBAAgB,mCAAmC,CAAC,KAAK,EAAE,wBAAwB,GAAG,sBAAsB,CA0D3G"}
@@ -1,29 +1,80 @@
1
1
  /**
2
- * Build the materialize instruction for one adapter-linked artifact.
2
+ * Build the materialize instruction for one adapter-linked artifact (ADR 0040).
3
3
  *
4
4
  * Byte-exactness is framework work, not agent work: the instruction carries an
5
- * exact shell line (`cmd`) that writes, verifies, and marks the file executable,
6
- * so the agent never re-types artifact bytes through an editor or a heredoc
7
- * (SquadRules/mcp#231). The byte source depends on the transport: HTTP serves the
8
- * stored bytes itself, stdio has no listener and goes through the `export` tool.
5
+ * exact shell line (`cmd`) that downloads the artifact from a transport-neutral
6
+ * URL, verifies its digest, marks it `0700`, and publishes it atomically, so the
7
+ * agent never re-types artifact bytes through an editor or a heredoc
8
+ * (SquadRules/mcp#231). The URL is a `file://` cache path on stdio and a
9
+ * short-lived capability URL on HTTP; this builder does not branch on transport
10
+ * because `curl` fetches both. The destination tree is caller-owned and trusted:
11
+ * a POSIX shell alone cannot close time-of-check/time-of-use races against a
12
+ * hostile concurrent writer, so `cmd` rejects symlinked roots/ancestors and
13
+ * re-checks containment after resolution, but does not claim race-free isolation.
9
14
  */
15
+ import { normalizeMaterializeRelativePath } from './artifact-relative-path.js';
10
16
  export const SQUADRULES_LOCAL_ARTIFACT_DIR_ENV = 'SQUADRULES_LOCAL_ARTIFACT_DIR';
17
+ const SHA256_RE = /^[a-f0-9]{64}$/i;
18
+ const URL_SCHEME_RE = /^(?:https?|file):\/\//i;
19
+ /**
20
+ * Wrap a value in single quotes for safe interpolation into a POSIX shell
21
+ * command. Every embedded `'` becomes the four-character sequence `'\''`, which
22
+ * closes the quoted string, adds an escaped quote, and reopens it. Single quotes
23
+ * suppress `$`, backtick, glob, and word-splitting expansion, so any URL — even
24
+ * one carrying adversarial characters — reaches `curl` as a literal argument.
25
+ */
26
+ export function shellSingleQuote(value) {
27
+ return `'${value.replace(/'/g, "'\\''")}'`;
28
+ }
11
29
  export function buildArtifactMaterializeInstruction(input) {
12
- const outPath = `$${SQUADRULES_LOCAL_ARTIFACT_DIR_ENV}/${input.relativePath}`;
13
- const outRef = `"${outPath}"`;
14
- const bytes = input.transport === 'http'
15
- ? `curl -fsS -o ${outRef} ${JSON.stringify(input.downloadUrl)}`
16
- : `: "\${B64:?B64 must hold the export response content field}" && printf '%s' "$B64" | base64 -d > ${outRef}`;
17
- const verify = `printf '%s %s\\n' '${input.sha256}' ${outRef} | sha256sum -c`;
18
- return {
19
- tool: 'export',
20
- arguments: input.transport === 'http'
21
- ? { uri: input.artifactUri, format: 'source' }
22
- : { uri: input.artifactUri, format: 'source', delivery: 'inline_base64' },
23
- out: outPath,
24
- sha256: input.sha256,
25
- chmod: '700',
26
- cmd: `mkdir -p "$(dirname ${outRef})" && ${bytes} && ${verify} && chmod 700 ${outRef}`
27
- };
30
+ const relativePath = normalizeMaterializeRelativePath(input.relativePath);
31
+ if (relativePath === null) {
32
+ throw new Error(`refusing to build a materialize command for an unsafe artifact relative_path: ${JSON.stringify(input.relativePath)}`);
33
+ }
34
+ if (!SHA256_RE.test(input.sha256)) {
35
+ throw new Error(`refusing to build a materialize command without a valid SHA-256 for ${relativePath}`);
36
+ }
37
+ if (!URL_SCHEME_RE.test(input.url)) {
38
+ throw new Error(`refusing to build a materialize command for a URL scheme that is not http(s) or file: ${JSON.stringify(input.url)}`);
39
+ }
40
+ const envName = SQUADRULES_LOCAL_ARTIFACT_DIR_ENV;
41
+ const sha256 = input.sha256.toLowerCase();
42
+ const out = `$${envName}/${relativePath}`;
43
+ // Reject a symlinked root, every existing destination ancestor, and the final
44
+ // destination before anything is created or written.
45
+ const segments = relativePath.split('/');
46
+ const symlinkGuards = ['[ ! -L "$dir" ]'];
47
+ for (let i = 1; i <= segments.length; i += 1) {
48
+ symlinkGuards.push(`[ ! -L "$dir/${segments.slice(0, i).join('/')}" ]`);
49
+ }
50
+ const cmd = [
51
+ // Fail closed unless the artifact dir is set, non-empty, and absolute.
52
+ `dir="\${${envName}:?${envName} must be set to an absolute artifact directory}"`,
53
+ `case "$dir" in /*) ;; *) printf '%s\\n' '${envName} must be an absolute path' >&2; exit 1 ;; esac`,
54
+ ...symlinkGuards,
55
+ `out="$dir/${relativePath}"`,
56
+ `parent="$(dirname "$out")"`,
57
+ `mkdir -p "$parent"`,
58
+ // The resolved parent must stay inside the resolved root, not merely lack `../`.
59
+ `root_phys="$(cd "$dir" && pwd -P)"`,
60
+ `parent_phys="$(cd "$parent" && pwd -P)"`,
61
+ `case "$parent_phys" in "$root_phys" | "$root_phys"/*) ;; *) printf '%s\\n' 'resolved destination escapes the artifact root' >&2; exit 1 ;; esac`,
62
+ // Download into a fresh private temp file in the destination directory so the
63
+ // final rename is atomic on one filesystem.
64
+ `staging="$(mktemp "$parent/.squadrules-materialize.XXXXXX")"`,
65
+ `trap 'rm -f "$staging"' EXIT INT TERM HUP`,
66
+ `curl -fsS -o "$staging" ${shellSingleQuote(input.url)}`,
67
+ // Portable digest chain with no platform assumption baked in.
68
+ `{ if command -v sha256sum >/dev/null 2>&1; then digest="$(sha256sum "$staging" | cut -d' ' -f1)"; ` +
69
+ `elif command -v shasum >/dev/null 2>&1; then digest="$(shasum -a 256 "$staging" | cut -d' ' -f1)"; ` +
70
+ `elif command -v openssl >/dev/null 2>&1; then digest="$(openssl dgst -sha256 "$staging" | sed 's/^.*= //')"; ` +
71
+ `else printf '%s\\n' 'no sha256 tool (need sha256sum, shasum, or openssl) on PATH' >&2; exit 1; fi; }`,
72
+ `[ "$digest" = '${sha256}' ]`,
73
+ // Only a verified file is chmod'd and published; a prior destination survives any earlier failure.
74
+ `chmod 700 "$staging"`,
75
+ `mv -f "$staging" "$out"`,
76
+ `trap - EXIT INT TERM HUP`
77
+ ].join(' && ');
78
+ return { method: 'url', url: input.url, out, sha256, chmod: '700', cmd };
28
79
  }
29
80
  //# sourceMappingURL=artifact-materialize-command.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"artifact-materialize-command.js","sourceRoot":"","sources":["../../src/tools/artifact-materialize-command.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,CAAC,MAAM,iCAAiC,GAAG,+BAA+B,CAAC;AAiCjF,MAAM,UAAU,mCAAmC,CAAC,KAA+B;IACjF,MAAM,OAAO,GAAG,IAAI,iCAAiC,IAAI,KAAK,CAAC,YAAY,EAAE,CAAC;IAC9E,MAAM,MAAM,GAAG,IAAI,OAAO,GAAG,CAAC;IAC9B,MAAM,KAAK,GACT,KAAK,CAAC,SAAS,KAAK,MAAM;QACxB,CAAC,CAAC,gBAAgB,MAAM,IAAI,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE;QAC/D,CAAC,CAAC,oGAAoG,MAAM,EAAE,CAAC;IACnH,MAAM,MAAM,GAAG,uBAAuB,KAAK,CAAC,MAAM,KAAK,MAAM,iBAAiB,CAAC;IAC/E,OAAO;QACL,IAAI,EAAE,QAAQ;QACd,SAAS,EACP,KAAK,CAAC,SAAS,KAAK,MAAM;YACxB,CAAC,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE;YAC9C,CAAC,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,eAAe,EAAE;QAC7E,GAAG,EAAE,OAAO;QACZ,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,KAAK,EAAE,KAAK;QACZ,GAAG,EAAE,uBAAuB,MAAM,SAAS,KAAK,OAAO,MAAM,iBAAiB,MAAM,EAAE;KACvF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"artifact-materialize-command.js","sourceRoot":"","sources":["../../src/tools/artifact-materialize-command.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,gCAAgC,EAAE,MAAM,6BAA6B,CAAC;AAE/E,MAAM,CAAC,MAAM,iCAAiC,GAAG,+BAA+B,CAAC;AAEjF,MAAM,SAAS,GAAG,iBAAiB,CAAC;AACpC,MAAM,aAAa,GAAG,wBAAwB,CAAC;AA0B/C;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAa;IAC5C,OAAO,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC;AAC7C,CAAC;AAED,MAAM,UAAU,mCAAmC,CAAC,KAA+B;IACjF,MAAM,YAAY,GAAG,gCAAgC,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;IAC1E,IAAI,YAAY,KAAK,IAAI,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CACb,iFAAiF,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,YAAY,CAAC,EAAE,CACtH,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;QAClC,MAAM,IAAI,KAAK,CAAC,uEAAuE,YAAY,EAAE,CAAC,CAAC;IACzG,CAAC;IACD,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QACnC,MAAM,IAAI,KAAK,CACb,yFAAyF,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CACrH,CAAC;IACJ,CAAC;IAED,MAAM,OAAO,GAAG,iCAAiC,CAAC;IAClD,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;IAC1C,MAAM,GAAG,GAAG,IAAI,OAAO,IAAI,YAAY,EAAE,CAAC;IAE1C,8EAA8E;IAC9E,qDAAqD;IACrD,MAAM,QAAQ,GAAG,YAAY,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACzC,MAAM,aAAa,GAAa,CAAC,iBAAiB,CAAC,CAAC;IACpD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,QAAQ,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QAC7C,aAAa,CAAC,IAAI,CAAC,gBAAgB,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAC1E,CAAC;IAED,MAAM,GAAG,GAAG;QACV,uEAAuE;QACvE,WAAW,OAAO,KAAK,OAAO,kDAAkD;QAChF,4CAA4C,OAAO,gDAAgD;QACnG,GAAG,aAAa;QAChB,aAAa,YAAY,GAAG;QAC5B,4BAA4B;QAC5B,oBAAoB;QACpB,iFAAiF;QACjF,oCAAoC;QACpC,yCAAyC;QACzC,iJAAiJ;QACjJ,8EAA8E;QAC9E,4CAA4C;QAC5C,8DAA8D;QAC9D,2CAA2C;QAC3C,2BAA2B,gBAAgB,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE;QACxD,8DAA8D;QAC9D,oGAAoG;YAClG,qGAAqG;YACrG,+GAA+G;YAC/G,sGAAsG;QACxG,kBAAkB,MAAM,KAAK;QAC7B,mGAAmG;QACnG,sBAAsB;QACtB,yBAAyB;QACzB,0BAA0B;KAC3B,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAEf,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC;AAC3E,CAAC"}
@@ -4,4 +4,20 @@
4
4
  */
5
5
  /** Normalize and validate a skill-root-relative path. Returns null if invalid. */
6
6
  export declare function normalizeArtifactRelativePath(raw: string): string | null;
7
+ /**
8
+ * Canonicalize and validate a skill-root-relative path destined for the
9
+ * materialize command. Stricter than {@link normalizeArtifactRelativePath}, which
10
+ * is shared with the ZIP export layout: this also rejects shell metacharacters and
11
+ * ambiguous interior `.` segments, because the result is embedded in a shell
12
+ * command and resolved against an absolute filesystem root. Returns null if
13
+ * invalid; the caller must fail closed rather than substitute a default.
14
+ */
15
+ export declare function normalizeMaterializeRelativePath(raw: string): string | null;
16
+ /**
17
+ * Reduce an arbitrary artifact name to a conservative, shell-safe single filename
18
+ * segment for a synthesized materialize path. Disallowed characters become `_`;
19
+ * an empty, `.`, or `..` result is ambiguous and returns null so the caller fails
20
+ * the load instead of inventing an unsafe destination.
21
+ */
22
+ export declare function sanitizeArtifactFileName(name: string): string | null;
7
23
  //# sourceMappingURL=artifact-relative-path.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"artifact-relative-path.d.ts","sourceRoot":"","sources":["../../src/tools/artifact-relative-path.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,kFAAkF;AAClF,wBAAgB,6BAA6B,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAoBxE"}
1
+ {"version":3,"file":"artifact-relative-path.d.ts","sourceRoot":"","sources":["../../src/tools/artifact-relative-path.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,kFAAkF;AAClF,wBAAgB,6BAA6B,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAoBxE;AAcD;;;;;;;GAOG;AACH,wBAAgB,gCAAgC,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAmB3E;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAMpE"}
@@ -26,4 +26,55 @@ export function normalizeArtifactRelativePath(raw) {
26
26
  }
27
27
  return s;
28
28
  }
29
+ /**
30
+ * Shell metacharacters that must never appear in a materialize destination path
31
+ * (ADR 0040): double quote, single quote, backtick, dollar sign, backslash, and
32
+ * control / DEL bytes (including newline). Spaces and ordinary filename
33
+ * characters stay allowed; {@link normalizeArtifactRelativePath} already rejects
34
+ * `..`, absolute paths, empty segments, and over-long paths.
35
+ */
36
+ const MATERIALIZE_FORBIDDEN_RE = /["'`$\\\u0000-\u001f\u007f]/;
37
+ /** Characters allowed in a synthesized artifact filename segment. */
38
+ const FILENAME_DISALLOWED_RE = /[^A-Za-z0-9._-]/g;
39
+ /**
40
+ * Canonicalize and validate a skill-root-relative path destined for the
41
+ * materialize command. Stricter than {@link normalizeArtifactRelativePath}, which
42
+ * is shared with the ZIP export layout: this also rejects shell metacharacters and
43
+ * ambiguous interior `.` segments, because the result is embedded in a shell
44
+ * command and resolved against an absolute filesystem root. Returns null if
45
+ * invalid; the caller must fail closed rather than substitute a default.
46
+ */
47
+ export function normalizeMaterializeRelativePath(raw) {
48
+ if (MATERIALIZE_FORBIDDEN_RE.test(raw)) {
49
+ return null;
50
+ }
51
+ const normalized = normalizeArtifactRelativePath(raw);
52
+ if (normalized === null) {
53
+ return null;
54
+ }
55
+ for (const segment of normalized.split('/')) {
56
+ if (segment === '.') {
57
+ return null;
58
+ }
59
+ }
60
+ // Defense in depth: the base canonicalizer maps `\` to `/`, so re-check the
61
+ // normalized result for metacharacters that must never reach the shell.
62
+ if (MATERIALIZE_FORBIDDEN_RE.test(normalized)) {
63
+ return null;
64
+ }
65
+ return normalized;
66
+ }
67
+ /**
68
+ * Reduce an arbitrary artifact name to a conservative, shell-safe single filename
69
+ * segment for a synthesized materialize path. Disallowed characters become `_`;
70
+ * an empty, `.`, or `..` result is ambiguous and returns null so the caller fails
71
+ * the load instead of inventing an unsafe destination.
72
+ */
73
+ export function sanitizeArtifactFileName(name) {
74
+ const candidate = name.trim().replace(FILENAME_DISALLOWED_RE, '_');
75
+ if (candidate.length === 0 || candidate === '.' || candidate === '..') {
76
+ return null;
77
+ }
78
+ return candidate;
79
+ }
29
80
  //# sourceMappingURL=artifact-relative-path.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"artifact-relative-path.js","sourceRoot":"","sources":["../../src/tools/artifact-relative-path.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,kFAAkF;AAClF,MAAM,UAAU,6BAA6B,CAAC,GAAW;IACvD,IAAI,CAAC,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IACvC,OAAO,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QAC1B,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACjB,CAAC;IACD,IAAI,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACtB,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC9B,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;QAC3B,IAAI,GAAG,KAAK,IAAI;YAAE,OAAO,IAAI,CAAC;QAC9B,IAAI,GAAG,KAAK,EAAE;YAAE,OAAO,IAAI,CAAC;IAC9B,CAAC;IACD,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QAC1B,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,CAAC,CAAC,MAAM,GAAG,IAAI,EAAE,CAAC;QACpB,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC"}
1
+ {"version":3,"file":"artifact-relative-path.js","sourceRoot":"","sources":["../../src/tools/artifact-relative-path.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,kFAAkF;AAClF,MAAM,UAAU,6BAA6B,CAAC,GAAW;IACvD,IAAI,CAAC,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IACvC,OAAO,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QAC1B,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACjB,CAAC;IACD,IAAI,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACtB,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC9B,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;QAC3B,IAAI,GAAG,KAAK,IAAI;YAAE,OAAO,IAAI,CAAC;QAC9B,IAAI,GAAG,KAAK,EAAE;YAAE,OAAO,IAAI,CAAC;IAC9B,CAAC;IACD,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QAC1B,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,CAAC,CAAC,MAAM,GAAG,IAAI,EAAE,CAAC;QACpB,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC;AAED;;;;;;GAMG;AACH,MAAM,wBAAwB,GAAG,6BAA6B,CAAC;AAE/D,qEAAqE;AACrE,MAAM,sBAAsB,GAAG,kBAAkB,CAAC;AAElD;;;;;;;GAOG;AACH,MAAM,UAAU,gCAAgC,CAAC,GAAW;IAC1D,IAAI,wBAAwB,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QACvC,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,UAAU,GAAG,6BAA6B,CAAC,GAAG,CAAC,CAAC;IACtD,IAAI,UAAU,KAAK,IAAI,EAAE,CAAC;QACxB,OAAO,IAAI,CAAC;IACd,CAAC;IACD,KAAK,MAAM,OAAO,IAAI,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QAC5C,IAAI,OAAO,KAAK,GAAG,EAAE,CAAC;YACpB,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IACD,4EAA4E;IAC5E,wEAAwE;IACxE,IAAI,wBAAwB,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;QAC9C,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,UAAU,CAAC;AACpB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,wBAAwB,CAAC,IAAY;IACnD,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,sBAAsB,EAAE,GAAG,CAAC,CAAC;IACnE,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,IAAI,SAAS,KAAK,GAAG,IAAI,SAAS,KAAK,IAAI,EAAE,CAAC;QACtE,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC"}