@tangle-network/agent-app 0.45.7 → 0.45.8

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.
@@ -3,18 +3,18 @@ import {
3
3
  ChatMessages,
4
4
  ModelPicker,
5
5
  ProviderLogo
6
- } from "../chunk-YRFB2KEA.js";
6
+ } from "../chunk-CKUZVDZ7.js";
7
+ import "../chunk-6MUJROBT.js";
8
+ import "../chunk-BATKJP3P.js";
7
9
  import "../chunk-FBVLEGEG.js";
8
10
  import "../chunk-GINKOZFD.js";
9
11
  import "../chunk-YTMKRL3L.js";
10
12
  import "../chunk-GEYACSFW.js";
11
- import "../chunk-6MUJROBT.js";
12
- import "../chunk-BATKJP3P.js";
13
13
  import "../chunk-QY4BRKRJ.js";
14
14
  import "../chunk-WBHPN5DY.js";
15
- import "../chunk-UXMIPX3Z.js";
16
- import "../chunk-ZVEEWGDK.js";
15
+ import "../chunk-WUZZVQKR.js";
17
16
  import "../chunk-KWXUBMXU.js";
17
+ import "../chunk-ZVEEWGDK.js";
18
18
  import "../chunk-5EPIPT4V.js";
19
19
  import "../chunk-3ZK5IJSW.js";
20
20
  import "../chunk-YJMCRXQQ.js";
@@ -1,3 +1,6 @@
1
+ import {
2
+ parseJsonObjectBody
3
+ } from "../chunk-J25RST7G.js";
1
4
  import {
2
5
  createSandboxFileIndexRoute
3
6
  } from "../chunk-QY4BRKRJ.js";
@@ -32,16 +35,12 @@ import {
32
35
  import {
33
36
  createInteractionAnswerRoute
34
37
  } from "../chunk-3BK3BC2L.js";
35
- import {
36
- parseJsonObjectBody
37
- } from "../chunk-J25RST7G.js";
38
38
  import {
39
39
  attachmentInputToPart,
40
40
  attachmentKindForMime,
41
41
  mentionInputToPart,
42
42
  toChatMessageParts
43
- } from "../chunk-UXMIPX3Z.js";
44
- import "../chunk-ZVEEWGDK.js";
43
+ } from "../chunk-WUZZVQKR.js";
45
44
  import {
46
45
  ChatTurnInputError,
47
46
  DISPATCH_MAX_MEDIA_PARTS,
@@ -63,6 +62,7 @@ import {
63
62
  promptPartsByteSize,
64
63
  validateSandboxMentionPath
65
64
  } from "../chunk-KWXUBMXU.js";
65
+ import "../chunk-ZVEEWGDK.js";
66
66
  import {
67
67
  asRecord,
68
68
  asString,
@@ -100,9 +100,9 @@ import {
100
100
  flattenHistory,
101
101
  readSandboxBinaryBytes,
102
102
  statSandboxFileSize
103
- } from "../chunk-4XNCMUVI.js";
104
- import "../chunk-LWSJK546.js";
103
+ } from "../chunk-REUAPWUS.js";
105
104
  import "../chunk-73F3CKVK.js";
105
+ import "../chunk-LWSJK546.js";
106
106
  import "../chunk-ITCINLSU.js";
107
107
  import "../chunk-IVEKCOM7.js";
108
108
  import "../chunk-YEFFHORB.js";
@@ -19,9 +19,9 @@ import {
19
19
  mentionInputToPart,
20
20
  mentionPartsFromMessageParts,
21
21
  toChatMessageParts
22
- } from "../chunk-UXMIPX3Z.js";
23
- import "../chunk-ZVEEWGDK.js";
22
+ } from "../chunk-WUZZVQKR.js";
24
23
  import "../chunk-KWXUBMXU.js";
24
+ import "../chunk-ZVEEWGDK.js";
25
25
  import {
26
26
  attachmentPartKey
27
27
  } from "../chunk-5EPIPT4V.js";
@@ -12,7 +12,7 @@ import {
12
12
  } from "./chunk-YTMKRL3L.js";
13
13
  import {
14
14
  attachmentPartsFromMessageParts
15
- } from "./chunk-UXMIPX3Z.js";
15
+ } from "./chunk-WUZZVQKR.js";
16
16
  import {
17
17
  formatBytes
18
18
  } from "./chunk-KWXUBMXU.js";
@@ -4309,4 +4309,4 @@ export {
4309
4309
  useThinkingSeconds,
4310
4310
  ChatMessages
4311
4311
  };
4312
- //# sourceMappingURL=chunk-YRFB2KEA.js.map
4312
+ //# sourceMappingURL=chunk-CKUZVDZ7.js.map
@@ -11,4 +11,4 @@ export {
11
11
  DesignCanvasLazy,
12
12
  DesignCanvasChromeLazy
13
13
  };
14
- //# sourceMappingURL=chunk-DMYCGXBP.js.map
14
+ //# sourceMappingURL=chunk-OO4DROKM.js.map
@@ -1,10 +1,10 @@
1
+ import {
2
+ assertHarnessModelCompatible
3
+ } from "./chunk-73F3CKVK.js";
1
4
  import {
2
5
  assertProfilePromptWithinBudget,
3
6
  fingerprintAgentProfile
4
7
  } from "./chunk-LWSJK546.js";
5
- import {
6
- assertHarnessModelCompatible
7
- } from "./chunk-73F3CKVK.js";
8
8
  import {
9
9
  buildAppToolMcpServer
10
10
  } from "./chunk-IVEKCOM7.js";
@@ -2224,4 +2224,4 @@ export {
2224
2224
  isTerminalPromptEvent,
2225
2225
  detectInteractiveQuestion
2226
2226
  };
2227
- //# sourceMappingURL=chunk-4XNCMUVI.js.map
2227
+ //# sourceMappingURL=chunk-REUAPWUS.js.map
@@ -1,9 +1,9 @@
1
- import {
2
- persistedPartToWorkProduct
3
- } from "./chunk-ZVEEWGDK.js";
4
1
  import {
5
2
  mentionKindForPath
6
3
  } from "./chunk-KWXUBMXU.js";
4
+ import {
5
+ persistedPartToWorkProduct
6
+ } from "./chunk-ZVEEWGDK.js";
7
7
  import {
8
8
  persistedPartToInteraction
9
9
  } from "./chunk-3ZK5IJSW.js";
@@ -155,4 +155,4 @@ export {
155
155
  buildAttachmentPromptBlock,
156
156
  historyContentWithAttachments
157
157
  };
158
- //# sourceMappingURL=chunk-UXMIPX3Z.js.map
158
+ //# sourceMappingURL=chunk-WUZZVQKR.js.map
@@ -0,0 +1,129 @@
1
+ // src/peer-floors/check.ts
2
+ import { existsSync, readFileSync } from "fs";
3
+ import { dirname, join } from "path";
4
+ function readInstalledManifest(name, fromDir, modulesDir) {
5
+ let dir = fromDir;
6
+ for (; ; ) {
7
+ const manifest = join(dir, modulesDir, name, "package.json");
8
+ if (existsSync(manifest)) {
9
+ return JSON.parse(readFileSync(manifest, "utf8"));
10
+ }
11
+ const parent = dirname(dir);
12
+ if (parent === dir) return null;
13
+ dir = parent;
14
+ }
15
+ }
16
+ function parseVersion(version) {
17
+ const [core] = version.split(/[-+]/);
18
+ const parts = (core ?? "").split(".").map((p) => Number.parseInt(p, 10));
19
+ return [parts[0] ?? 0, parts[1] ?? 0, parts[2] ?? 0];
20
+ }
21
+ function compare(a, b) {
22
+ const va = parseVersion(a);
23
+ const vb = parseVersion(b);
24
+ for (let i = 0; i < 3; i += 1) {
25
+ if (va[i] !== vb[i]) return va[i] < vb[i] ? -1 : 1;
26
+ }
27
+ return 0;
28
+ }
29
+ function satisfiesComparator(version, comparator) {
30
+ const trimmed = comparator.trim();
31
+ if (!trimmed || trimmed === "*" || trimmed === "x") return true;
32
+ const match = /^(>=|<=|>|<|=|\^|~)?\s*v?(.+)$/.exec(trimmed);
33
+ if (!match) return false;
34
+ const [, op = "=", target = ""] = match;
35
+ const cmp = compare(version, target);
36
+ switch (op) {
37
+ case ">=":
38
+ return cmp >= 0;
39
+ case "<=":
40
+ return cmp <= 0;
41
+ case ">":
42
+ return cmp > 0;
43
+ case "<":
44
+ return cmp < 0;
45
+ case "=":
46
+ return cmp === 0;
47
+ case "~": {
48
+ const [major, minor] = parseVersion(target);
49
+ const [vMajor, vMinor] = parseVersion(version);
50
+ return cmp >= 0 && vMajor === major && vMinor === minor;
51
+ }
52
+ case "^": {
53
+ const [major, minor] = parseVersion(target);
54
+ const [vMajor, vMinor] = parseVersion(version);
55
+ if (cmp < 0) return false;
56
+ if (major > 0) return vMajor === major;
57
+ if (minor > 0) return vMajor === 0 && vMinor === minor;
58
+ return vMajor === 0 && vMinor === 0;
59
+ }
60
+ default:
61
+ return false;
62
+ }
63
+ }
64
+ function satisfiesRange(version, range) {
65
+ return range.split("||").some(
66
+ (alternative) => alternative.trim().split(/\s+/).filter(Boolean).every((c) => satisfiesComparator(version, c))
67
+ );
68
+ }
69
+ function checkPeerFloors(options) {
70
+ const {
71
+ appDir,
72
+ shell = "@tangle-network/agent-app",
73
+ scope = "@tangle-network/",
74
+ modulesDir = "node_modules"
75
+ } = options;
76
+ const shellManifest = options.shellManifest ?? readInstalledManifest(shell, appDir, modulesDir);
77
+ if (!shellManifest) throw new Error(`${shell} is not installed under ${appDir}`);
78
+ const appManifest = JSON.parse(readFileSync(join(appDir, "package.json"), "utf8"));
79
+ const declared = {
80
+ ...appManifest.dependencies,
81
+ ...appManifest.devDependencies,
82
+ ...appManifest.optionalDependencies
83
+ };
84
+ const floors = Object.entries(shellManifest.peerDependencies ?? {}).filter(([name]) => name.startsWith(scope));
85
+ const rows = floors.map(([name, range]) => {
86
+ const installed = readInstalledManifest(name, appDir, modulesDir)?.version ?? null;
87
+ if (installed === null) {
88
+ return { name, range, installed, verdict: declared[name] ? "absent-but-declared" : "absent-unused" };
89
+ }
90
+ return {
91
+ name,
92
+ range,
93
+ installed,
94
+ verdict: satisfiesRange(installed, range) ? "satisfied" : "below-floor"
95
+ };
96
+ });
97
+ const violations = rows.filter((row) => row.verdict === "below-floor" || row.verdict === "absent-but-declared");
98
+ return {
99
+ shellVersion: shellManifest.version ?? "unknown",
100
+ rows,
101
+ violations,
102
+ ok: violations.length === 0
103
+ };
104
+ }
105
+ function describePeerFloorViolation(row, shellVersion, shell = "@tangle-network/agent-app") {
106
+ if (row.verdict === "below-floor") {
107
+ return `PEER FLOOR VIOLATED: ${shell}@${shellVersion} requires ${row.name}@${row.range}, but ${row.installed} is installed. A peer floor encodes a wire contract \u2014 bump the dependency, do not widen the floor. A caret on a 0.x version is minor-locked (^0.36.0 can never resolve to 0.38.0), so reinstalling alone will not fix this: change the pin, in EVERY place it appears including pnpm.overrides.`;
108
+ }
109
+ return `${row.name} is a declared dependency of this app, but no installed version could be read, so its peer floor ${row.range} went UNCHECKED. Failing loudly rather than reporting a pass this guard did not earn.`;
110
+ }
111
+ function formatPeerFloorReport(report, shell = "@tangle-network/agent-app") {
112
+ const width = Math.max(...report.rows.map((r) => r.name.length), 4);
113
+ const lines = [
114
+ `${shell}@${report.shellVersion} \u2014 peer floors`,
115
+ "",
116
+ ...report.rows.map((row) => ` ${row.verdict === "satisfied" ? "ok " : row.verdict.startsWith("absent") ? "-- " : "FAIL"} ${row.name.padEnd(width)} installed ${(row.installed ?? "(none)").padEnd(10)} floor ${row.range}`),
117
+ "",
118
+ report.ok ? `all ${report.rows.length} floors satisfied` : report.violations.map((row) => describePeerFloorViolation(row, report.shellVersion, shell)).join("\n\n")
119
+ ];
120
+ return lines.join("\n");
121
+ }
122
+
123
+ export {
124
+ satisfiesRange,
125
+ checkPeerFloors,
126
+ describePeerFloorViolation,
127
+ formatPeerFloorReport
128
+ };
129
+ //# sourceMappingURL=chunk-ZSJRDHCN.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/peer-floors/check.ts"],"sourcesContent":["import { existsSync, readFileSync } from 'node:fs'\nimport { dirname, join } from 'node:path'\n\n/**\n * Audit a consumer's installed tree against the peer floors this package\n * declares.\n *\n * A peer floor is not documentation — it encodes a WIRE CONTRACT, and breaking\n * one is invisible to every other gate. `pnpm` only WARNS on an unmet peer when\n * the package is also a direct dependency, and says nothing at all for an unmet\n * OPTIONAL peer, which is how most of the substrate is declared here. So a\n * product can sit below a floor with a clean install, a clean typecheck, a green\n * suite and a successful deploy, and fail only on a live wire call:\n *\n * `@tangle-network/sandbox` 0.15.0 → 0.15.1 changed the sidecar spawn body\n * from `{ command }` to `{ executable, args }`. Below the floor, every\n * `box.exec()` on a live sandbox returns 400 `Unrecognized key: \"command\"`.\n *\n * `@tangle-network/agent-interface` 0.38.0 changed MCP config values from\n * plain strings to tagged public/secret-ref objects. Below the floor, this\n * package fails at MODULE LOAD with \"does not provide an export named\n * defineAgentProfilePublicConfig\" — while `tsc` reports zero errors, because\n * the types resolve and only the runtime export is missing.\n *\n * That second shape is why this exists as its own gate: typecheck cannot see it,\n * and a suite only sees it as dozens of unrelated-looking import failures.\n */\n\n/** Installed, and inside the declared range. */\nexport type PeerFloorVerdict =\n | 'satisfied'\n /** Installed and BELOW the floor — the silent case this module exists for. */\n | 'below-floor'\n /** Not installed and never asked for. A legitimate answer for an optional peer. */\n | 'absent-unused'\n /** Declared by the app, yet no version could be read, so the floor went\n * UNCHECKED. Reported as a failure rather than a pass this did not earn. */\n | 'absent-but-declared'\n\nexport interface PeerFloorRow {\n readonly name: string\n readonly range: string\n readonly installed: string | null\n readonly verdict: PeerFloorVerdict\n}\n\nexport interface PeerFloorReport {\n readonly shellVersion: string\n readonly rows: readonly PeerFloorRow[]\n readonly violations: readonly PeerFloorRow[]\n readonly ok: boolean\n}\n\nexport interface CheckPeerFloorsOptions {\n /** Directory of the app under audit — the one whose `package.json` and\n * installed tree are read. */\n appDir: string\n /** Package whose peer floors are the contract. Defaults to this shell. */\n shell?: string\n /** Only audit peers under this scope. Third-party peers (react, drizzle) are\n * the app's own business, not part of the Tangle wire contract. Pass `''` to\n * audit every peer. */\n scope?: string\n /** Floors to audit against, when the shell is not resolvable from `appDir` —\n * the package auditing ITSELF, which has no copy of itself in its own\n * `node_modules`. Without this a package cannot check that the contract it\n * publishes is one its own dev install satisfies. */\n shellManifest?: { version?: string; peerDependencies?: Record<string, string> }\n /** Directory name to walk for installed packages. Overridable so a test can\n * point at a committed fixture tree — `node_modules` is gitignored\n * everywhere, so a fixture using that name could not be committed, and a\n * calibration proof that is not committed is a proof that stops running. */\n modulesDir?: string\n}\n\n/**\n * Read a package's manifest off disk, walking `modulesDir` up from `fromDir`.\n *\n * Deliberately NOT `require.resolve('<name>/package.json')`: most of these\n * packages omit `./package.json` from their `exports` map, so that throws\n * ERR_PACKAGE_PATH_NOT_EXPORTED — and a try/catch around it reports an INSTALLED\n * package as absent, turning the whole audit into a silent no-op. Walking the\n * tree is exports-map-independent and mirrors Node's own resolution order, so\n * the version reported is the version that would actually load.\n *\n * Returns null only when no directory for the package exists anywhere up the\n * tree, which is the genuine not-installed case.\n */\nfunction readInstalledManifest(\n name: string,\n fromDir: string,\n modulesDir: string,\n): { version?: string; peerDependencies?: Record<string, string> } | null {\n let dir = fromDir\n for (;;) {\n const manifest = join(dir, modulesDir, name, 'package.json')\n if (existsSync(manifest)) {\n return JSON.parse(readFileSync(manifest, 'utf8')) as {\n version?: string\n peerDependencies?: Record<string, string>\n }\n }\n const parent = dirname(dir)\n if (parent === dir) return null\n dir = parent\n }\n}\n\n/**\n * Minimal range satisfaction for the ranges peer floors actually use:\n * `>=x <y`, `^x.y.z`, `~x.y.z`, `x.y.z`, and `*`/`x`.\n *\n * Hand-rolled rather than taking a `semver` dependency, because this package\n * ships zero runtime dependencies and a checker that forces one on every\n * consumer is a worse trade than 40 lines of comparison. Prerelease versions\n * compare by their release part — a floor is about the wire contract, and a\n * prerelease of a satisfying version speaks it.\n */\nfunction parseVersion(version: string): [number, number, number] {\n const [core] = version.split(/[-+]/)\n const parts = (core ?? '').split('.').map((p) => Number.parseInt(p, 10))\n return [parts[0] ?? 0, parts[1] ?? 0, parts[2] ?? 0]\n}\n\nfunction compare(a: string, b: string): number {\n const va = parseVersion(a)\n const vb = parseVersion(b)\n for (let i = 0; i < 3; i += 1) {\n if (va[i]! !== vb[i]!) return va[i]! < vb[i]! ? -1 : 1\n }\n return 0\n}\n\nfunction satisfiesComparator(version: string, comparator: string): boolean {\n const trimmed = comparator.trim()\n if (!trimmed || trimmed === '*' || trimmed === 'x') return true\n const match = /^(>=|<=|>|<|=|\\^|~)?\\s*v?(.+)$/.exec(trimmed)\n if (!match) return false\n const [, op = '=', target = ''] = match\n const cmp = compare(version, target)\n switch (op) {\n case '>=': return cmp >= 0\n case '<=': return cmp <= 0\n case '>': return cmp > 0\n case '<': return cmp < 0\n case '=': return cmp === 0\n case '~': {\n // ~1.2.3 allows patch bumps; ~1.2 allows minor.\n const [major, minor] = parseVersion(target)\n const [vMajor, vMinor] = parseVersion(version)\n return cmp >= 0 && vMajor === major && vMinor === minor\n }\n case '^': {\n // A caret on a 0.x version is MINOR-locked: ^0.36.0 can never resolve to\n // 0.38.0. That is the single most common reason a floor cannot be met by\n // reinstalling, so it is modelled exactly rather than approximated.\n const [major, minor] = parseVersion(target)\n const [vMajor, vMinor] = parseVersion(version)\n if (cmp < 0) return false\n if (major > 0) return vMajor === major\n if (minor > 0) return vMajor === 0 && vMinor === minor\n return vMajor === 0 && vMinor === 0\n }\n default: return false\n }\n}\n\nexport function satisfiesRange(version: string, range: string): boolean {\n // `||` is alternation; whitespace inside an alternative is conjunction.\n return range.split('||').some((alternative) =>\n alternative.trim().split(/\\s+/).filter(Boolean).every((c) => satisfiesComparator(version, c)),\n )\n}\n\n/** Audit one app directory against the shell's declared peer floors. */\nexport function checkPeerFloors(options: CheckPeerFloorsOptions): PeerFloorReport {\n const {\n appDir,\n shell = '@tangle-network/agent-app',\n scope = '@tangle-network/',\n modulesDir = 'node_modules',\n } = options\n\n const shellManifest = options.shellManifest ?? readInstalledManifest(shell, appDir, modulesDir)\n if (!shellManifest) throw new Error(`${shell} is not installed under ${appDir}`)\n\n const appManifest = JSON.parse(readFileSync(join(appDir, 'package.json'), 'utf8')) as {\n dependencies?: Record<string, string>\n devDependencies?: Record<string, string>\n optionalDependencies?: Record<string, string>\n }\n const declared = {\n ...appManifest.dependencies,\n ...appManifest.devDependencies,\n ...appManifest.optionalDependencies,\n }\n\n const floors = Object.entries(shellManifest.peerDependencies ?? {})\n .filter(([name]) => name.startsWith(scope))\n\n const rows = floors.map(([name, range]): PeerFloorRow => {\n const installed = readInstalledManifest(name, appDir, modulesDir)?.version ?? null\n if (installed === null) {\n return { name, range, installed, verdict: declared[name] ? 'absent-but-declared' : 'absent-unused' }\n }\n return {\n name,\n range,\n installed,\n verdict: satisfiesRange(installed, range) ? 'satisfied' : 'below-floor',\n }\n })\n\n const violations = rows.filter((row) => row.verdict === 'below-floor' || row.verdict === 'absent-but-declared')\n return {\n shellVersion: shellManifest.version ?? 'unknown',\n rows,\n violations,\n ok: violations.length === 0,\n }\n}\n\n/** The failure message for one violating row. Split out so a caller can raise\n * it from a test and a CLI can print it identically. */\nexport function describePeerFloorViolation(row: PeerFloorRow, shellVersion: string, shell = '@tangle-network/agent-app'): string {\n if (row.verdict === 'below-floor') {\n return `PEER FLOOR VIOLATED: ${shell}@${shellVersion} requires ${row.name}@${row.range}, `\n + `but ${row.installed} is installed. A peer floor encodes a wire contract — bump the `\n + `dependency, do not widen the floor. A caret on a 0.x version is minor-locked `\n + `(^0.36.0 can never resolve to 0.38.0), so reinstalling alone will not fix this: `\n + `change the pin, in EVERY place it appears including pnpm.overrides.`\n }\n return `${row.name} is a declared dependency of this app, but no installed version could be `\n + `read, so its peer floor ${row.range} went UNCHECKED. Failing loudly rather than `\n + `reporting a pass this guard did not earn.`\n}\n\nexport function formatPeerFloorReport(report: PeerFloorReport, shell = '@tangle-network/agent-app'): string {\n const width = Math.max(...report.rows.map((r) => r.name.length), 4)\n const lines = [\n `${shell}@${report.shellVersion} — peer floors`,\n '',\n ...report.rows.map((row) =>\n ` ${row.verdict === 'satisfied' ? 'ok ' : row.verdict.startsWith('absent') ? '-- ' : 'FAIL'} `\n + `${row.name.padEnd(width)} installed ${(row.installed ?? '(none)').padEnd(10)} floor ${row.range}`),\n '',\n report.ok\n ? `all ${report.rows.length} floors satisfied`\n : report.violations.map((row) => describePeerFloorViolation(row, report.shellVersion, shell)).join('\\n\\n'),\n ]\n return lines.join('\\n')\n}\n"],"mappings":"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","names":[]}
@@ -43,6 +43,10 @@ import {
43
43
  selectTickStep
44
44
  } from "../chunk-KPRBFNGT.js";
45
45
  import "../chunk-TZO3SOUL.js";
46
+ import {
47
+ DesignCanvasChromeLazy,
48
+ DesignCanvasLazy
49
+ } from "../chunk-OO4DROKM.js";
46
50
  import "../chunk-ZN5J47UX.js";
47
51
  import {
48
52
  DEFAULT_INSERT_TEMPLATES,
@@ -88,10 +92,6 @@ import {
88
92
  bleedAwareExportBounds,
89
93
  scaleForPreset
90
94
  } from "../chunk-U4BXAZCN.js";
91
- import {
92
- DesignCanvasChromeLazy,
93
- DesignCanvasLazy
94
- } from "../chunk-DMYCGXBP.js";
95
95
  import "../chunk-J25RST7G.js";
96
96
 
97
97
  // src/design-canvas-react/components/CanvasInsertPanel.tsx
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  DesignCanvasChromeLazy,
3
3
  DesignCanvasLazy
4
- } from "../chunk-DMYCGXBP.js";
4
+ } from "../chunk-OO4DROKM.js";
5
5
  export {
6
6
  DesignCanvasChromeLazy,
7
7
  DesignCanvasLazy
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Audit a consumer's installed tree against the peer floors this package
3
+ * declares.
4
+ *
5
+ * A peer floor is not documentation — it encodes a WIRE CONTRACT, and breaking
6
+ * one is invisible to every other gate. `pnpm` only WARNS on an unmet peer when
7
+ * the package is also a direct dependency, and says nothing at all for an unmet
8
+ * OPTIONAL peer, which is how most of the substrate is declared here. So a
9
+ * product can sit below a floor with a clean install, a clean typecheck, a green
10
+ * suite and a successful deploy, and fail only on a live wire call:
11
+ *
12
+ * `@tangle-network/sandbox` 0.15.0 → 0.15.1 changed the sidecar spawn body
13
+ * from `{ command }` to `{ executable, args }`. Below the floor, every
14
+ * `box.exec()` on a live sandbox returns 400 `Unrecognized key: "command"`.
15
+ *
16
+ * `@tangle-network/agent-interface` 0.38.0 changed MCP config values from
17
+ * plain strings to tagged public/secret-ref objects. Below the floor, this
18
+ * package fails at MODULE LOAD with "does not provide an export named
19
+ * defineAgentProfilePublicConfig" — while `tsc` reports zero errors, because
20
+ * the types resolve and only the runtime export is missing.
21
+ *
22
+ * That second shape is why this exists as its own gate: typecheck cannot see it,
23
+ * and a suite only sees it as dozens of unrelated-looking import failures.
24
+ */
25
+ /** Installed, and inside the declared range. */
26
+ type PeerFloorVerdict = 'satisfied'
27
+ /** Installed and BELOW the floor — the silent case this module exists for. */
28
+ | 'below-floor'
29
+ /** Not installed and never asked for. A legitimate answer for an optional peer. */
30
+ | 'absent-unused'
31
+ /** Declared by the app, yet no version could be read, so the floor went
32
+ * UNCHECKED. Reported as a failure rather than a pass this did not earn. */
33
+ | 'absent-but-declared';
34
+ interface PeerFloorRow {
35
+ readonly name: string;
36
+ readonly range: string;
37
+ readonly installed: string | null;
38
+ readonly verdict: PeerFloorVerdict;
39
+ }
40
+ interface PeerFloorReport {
41
+ readonly shellVersion: string;
42
+ readonly rows: readonly PeerFloorRow[];
43
+ readonly violations: readonly PeerFloorRow[];
44
+ readonly ok: boolean;
45
+ }
46
+ interface CheckPeerFloorsOptions {
47
+ /** Directory of the app under audit — the one whose `package.json` and
48
+ * installed tree are read. */
49
+ appDir: string;
50
+ /** Package whose peer floors are the contract. Defaults to this shell. */
51
+ shell?: string;
52
+ /** Only audit peers under this scope. Third-party peers (react, drizzle) are
53
+ * the app's own business, not part of the Tangle wire contract. Pass `''` to
54
+ * audit every peer. */
55
+ scope?: string;
56
+ /** Floors to audit against, when the shell is not resolvable from `appDir` —
57
+ * the package auditing ITSELF, which has no copy of itself in its own
58
+ * `node_modules`. Without this a package cannot check that the contract it
59
+ * publishes is one its own dev install satisfies. */
60
+ shellManifest?: {
61
+ version?: string;
62
+ peerDependencies?: Record<string, string>;
63
+ };
64
+ /** Directory name to walk for installed packages. Overridable so a test can
65
+ * point at a committed fixture tree — `node_modules` is gitignored
66
+ * everywhere, so a fixture using that name could not be committed, and a
67
+ * calibration proof that is not committed is a proof that stops running. */
68
+ modulesDir?: string;
69
+ }
70
+ declare function satisfiesRange(version: string, range: string): boolean;
71
+ /** Audit one app directory against the shell's declared peer floors. */
72
+ declare function checkPeerFloors(options: CheckPeerFloorsOptions): PeerFloorReport;
73
+ /** The failure message for one violating row. Split out so a caller can raise
74
+ * it from a test and a CLI can print it identically. */
75
+ declare function describePeerFloorViolation(row: PeerFloorRow, shellVersion: string, shell?: string): string;
76
+ declare function formatPeerFloorReport(report: PeerFloorReport, shell?: string): string;
77
+
78
+ export { type CheckPeerFloorsOptions, type PeerFloorReport, type PeerFloorRow, type PeerFloorVerdict, checkPeerFloors, describePeerFloorViolation, formatPeerFloorReport, satisfiesRange };
@@ -0,0 +1,13 @@
1
+ import {
2
+ checkPeerFloors,
3
+ describePeerFloorViolation,
4
+ formatPeerFloorReport,
5
+ satisfiesRange
6
+ } from "../chunk-ZSJRDHCN.js";
7
+ export {
8
+ checkPeerFloors,
9
+ describePeerFloorViolation,
10
+ formatPeerFloorReport,
11
+ satisfiesRange
12
+ };
13
+ //# sourceMappingURL=check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ checkPeerFloors,
4
+ formatPeerFloorReport
5
+ } from "../chunk-ZSJRDHCN.js";
6
+
7
+ // src/peer-floors/cli.ts
8
+ var appDir = process.argv[2] ?? process.cwd();
9
+ try {
10
+ const report = checkPeerFloors({ appDir });
11
+ process.stdout.write(`${formatPeerFloorReport(report)}
12
+ `);
13
+ process.exit(report.ok ? 0 : 1);
14
+ } catch (err) {
15
+ process.stderr.write(`agent-app-peer-check failed: ${err instanceof Error ? err.message : String(err)}
16
+ `);
17
+ process.exit(1);
18
+ }
19
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/peer-floors/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * `agent-app-peer-check` — fail a consumer's CI when its installed tree sits\n * below a peer floor this package declares.\n *\n * Runs in the CONSUMER's repo, over the consumer's own `node_modules`, because\n * the floors only mean anything against a real install. Add it next to\n * typecheck:\n *\n * \"scripts\": { \"peer-check\": \"agent-app-peer-check\" }\n *\n * Exits 1 on any violation, 0 otherwise. Takes no configuration — the floors\n * come from the installed shell manifest, so the check cannot go stale when the\n * shell adds an engine.\n */\nimport { checkPeerFloors, formatPeerFloorReport } from './check'\n\nconst appDir = process.argv[2] ?? process.cwd()\n\ntry {\n const report = checkPeerFloors({ appDir })\n process.stdout.write(`${formatPeerFloorReport(report)}\\n`)\n process.exit(report.ok ? 0 : 1)\n} catch (err) {\n process.stderr.write(`agent-app-peer-check failed: ${err instanceof Error ? err.message : String(err)}\\n`)\n process.exit(1)\n}\n"],"mappings":";;;;;;;AAiBA,IAAM,SAAS,QAAQ,KAAK,CAAC,KAAK,QAAQ,IAAI;AAE9C,IAAI;AACF,QAAM,SAAS,gBAAgB,EAAE,OAAO,CAAC;AACzC,UAAQ,OAAO,MAAM,GAAG,sBAAsB,MAAM,CAAC;AAAA,CAAI;AACzD,UAAQ,KAAK,OAAO,KAAK,IAAI,CAAC;AAChC,SAAS,KAAK;AACZ,UAAQ,OAAO,MAAM,gCAAgC,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,CAAI;AACzG,UAAQ,KAAK,CAAC;AAChB;","names":[]}
@@ -1,9 +1,9 @@
1
- import {
2
- createWorkspaceKeyManager
3
- } from "../chunk-GXE6KHTS.js";
4
1
  import {
5
2
  createFieldCrypto
6
3
  } from "../chunk-TA5Q4I2K.js";
4
+ import {
5
+ createWorkspaceKeyManager
6
+ } from "../chunk-GXE6KHTS.js";
7
7
 
8
8
  // src/preset-cloudflare/workflow-instance.ts
9
9
  async function ensureCloudflareWorkflowInstance(binding, input) {
@@ -85,9 +85,9 @@ import {
85
85
  workspaceSandboxRecoveryMessage,
86
86
  workspaceSandboxRecoveryRecommendedActions,
87
87
  writeProfileFilesToBox
88
- } from "../chunk-4XNCMUVI.js";
89
- import "../chunk-LWSJK546.js";
88
+ } from "../chunk-REUAPWUS.js";
90
89
  import "../chunk-73F3CKVK.js";
90
+ import "../chunk-LWSJK546.js";
91
91
  import "../chunk-ITCINLSU.js";
92
92
  import "../chunk-IVEKCOM7.js";
93
93
  import "../chunk-YEFFHORB.js";
@@ -78,7 +78,14 @@ import {
78
78
  useSmoothText,
79
79
  useThinkingSeconds,
80
80
  waterfallLayout
81
- } from "../chunk-YRFB2KEA.js";
81
+ } from "../chunk-CKUZVDZ7.js";
82
+ import {
83
+ useComposerAttachments
84
+ } from "../chunk-6MUJROBT.js";
85
+ import {
86
+ tabTerminalConnectionId,
87
+ useSandboxTerminalConnection
88
+ } from "../chunk-BATKJP3P.js";
82
89
  import "../chunk-FBVLEGEG.js";
83
90
  import "../chunk-GINKOZFD.js";
84
91
  import {
@@ -96,13 +103,6 @@ import {
96
103
  import {
97
104
  parseReviewQueueItem
98
105
  } from "../chunk-GEYACSFW.js";
99
- import {
100
- useComposerAttachments
101
- } from "../chunk-6MUJROBT.js";
102
- import {
103
- tabTerminalConnectionId,
104
- useSandboxTerminalConnection
105
- } from "../chunk-BATKJP3P.js";
106
106
  import "../chunk-QY4BRKRJ.js";
107
107
  import {
108
108
  ATTACHMENT_ACCEPT
@@ -114,8 +114,7 @@ import {
114
114
  isChatAttachmentPart,
115
115
  mentionInputToPart,
116
116
  mentionPartsFromMessageParts
117
- } from "../chunk-UXMIPX3Z.js";
118
- import "../chunk-ZVEEWGDK.js";
117
+ } from "../chunk-WUZZVQKR.js";
119
118
  import {
120
119
  DISPATCH_MAX_MEDIA_PARTS,
121
120
  DISPATCH_MAX_PARTS,
@@ -128,6 +127,7 @@ import {
128
127
  mediaTypeForMentionPath,
129
128
  mentionKindForPath
130
129
  } from "../chunk-KWXUBMXU.js";
130
+ import "../chunk-ZVEEWGDK.js";
131
131
  import {
132
132
  attachmentPartKey
133
133
  } from "../chunk-5EPIPT4V.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tangle-network/agent-app",
3
- "version": "0.45.7",
3
+ "version": "0.45.8",
4
4
  "packageManager": "pnpm@11.17.0",
5
5
  "description": "Build agent applications with typed chat, tools, sandboxes, integrations, billing, and evaluation.",
6
6
  "keywords": [
@@ -33,7 +33,8 @@
33
33
  ],
34
34
  "bin": {
35
35
  "agent-app-theme-check": "./dist/theme-contract/cli.js",
36
- "agent-app-preflight": "./dist/preflight/cli.js"
36
+ "agent-app-preflight": "./dist/preflight/cli.js",
37
+ "agent-app-peer-check": "./dist/peer-floors/cli.js"
37
38
  },
38
39
  "exports": {
39
40
  "./package.json": "./package.json",
@@ -418,7 +419,12 @@
418
419
  "import": "./dist/theme-contract/index.js",
419
420
  "default": "./dist/theme-contract/index.js"
420
421
  },
421
- "./styles": "./dist/theme/tokens.css"
422
+ "./styles": "./dist/theme/tokens.css",
423
+ "./peer-floors": {
424
+ "types": "./dist/peer-floors/check.d.ts",
425
+ "import": "./dist/peer-floors/check.js",
426
+ "default": "./dist/peer-floors/check.js"
427
+ }
422
428
  },
423
429
  "scripts": {
424
430
  "build": "tsup",