@tangle-network/agent-app 0.45.6 → 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.
- package/dist/assistant/index.js +5 -5
- package/dist/chat-routes/index.js +8 -8
- package/dist/chat-store/index.js +2 -2
- package/dist/{chunk-6KMAM7BL.js → chunk-3BK3BC2L.js} +92 -1
- package/dist/chunk-3BK3BC2L.js.map +1 -0
- package/dist/{chunk-YRFB2KEA.js → chunk-CKUZVDZ7.js} +2 -2
- package/dist/{chunk-DMYCGXBP.js → chunk-OO4DROKM.js} +1 -1
- package/dist/{chunk-4XNCMUVI.js → chunk-REUAPWUS.js} +4 -4
- package/dist/{chunk-UXMIPX3Z.js → chunk-WUZZVQKR.js} +4 -4
- package/dist/chunk-ZSJRDHCN.js +129 -0
- package/dist/chunk-ZSJRDHCN.js.map +1 -0
- package/dist/design-canvas-react/index.js +4 -4
- package/dist/design-canvas-react/lazy.js +1 -1
- package/dist/interactions/index.d.ts +50 -1
- package/dist/interactions/index.js +7 -1
- package/dist/peer-floors/check.d.ts +78 -0
- package/dist/peer-floors/check.js +13 -0
- package/dist/peer-floors/check.js.map +1 -0
- package/dist/peer-floors/cli.d.ts +1 -0
- package/dist/peer-floors/cli.js +19 -0
- package/dist/peer-floors/cli.js.map +1 -0
- package/dist/preset-cloudflare/index.js +3 -3
- package/dist/sandbox/index.js +2 -2
- package/dist/web-react/index.js +10 -10
- package/package.json +9 -3
- package/dist/chunk-6KMAM7BL.js.map +0 -1
- /package/dist/{chunk-YRFB2KEA.js.map → chunk-CKUZVDZ7.js.map} +0 -0
- /package/dist/{chunk-DMYCGXBP.js.map → chunk-OO4DROKM.js.map} +0 -0
- /package/dist/{chunk-4XNCMUVI.js.map → chunk-REUAPWUS.js.map} +0 -0
- /package/dist/{chunk-UXMIPX3Z.js.map → chunk-WUZZVQKR.js.map} +0 -0
package/dist/assistant/index.js
CHANGED
|
@@ -3,18 +3,18 @@ import {
|
|
|
3
3
|
ChatMessages,
|
|
4
4
|
ModelPicker,
|
|
5
5
|
ProviderLogo
|
|
6
|
-
} from "../chunk-
|
|
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-
|
|
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";
|
|
@@ -31,17 +34,13 @@ import {
|
|
|
31
34
|
} from "../chunk-SDEADFHZ.js";
|
|
32
35
|
import {
|
|
33
36
|
createInteractionAnswerRoute
|
|
34
|
-
} from "../chunk-
|
|
35
|
-
import {
|
|
36
|
-
parseJsonObjectBody
|
|
37
|
-
} from "../chunk-J25RST7G.js";
|
|
37
|
+
} from "../chunk-3BK3BC2L.js";
|
|
38
38
|
import {
|
|
39
39
|
attachmentInputToPart,
|
|
40
40
|
attachmentKindForMime,
|
|
41
41
|
mentionInputToPart,
|
|
42
42
|
toChatMessageParts
|
|
43
|
-
} from "../chunk-
|
|
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-
|
|
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";
|
package/dist/chat-store/index.js
CHANGED
|
@@ -19,9 +19,9 @@ import {
|
|
|
19
19
|
mentionInputToPart,
|
|
20
20
|
mentionPartsFromMessageParts,
|
|
21
21
|
toChatMessageParts
|
|
22
|
-
} from "../chunk-
|
|
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";
|
|
@@ -75,6 +75,94 @@ async function respondToSessionInteraction(connection, response) {
|
|
|
75
75
|
if (!result.succeeded) return result;
|
|
76
76
|
return { succeeded: true, value: void 0 };
|
|
77
77
|
}
|
|
78
|
+
function isTerminalSidecarState(state) {
|
|
79
|
+
if (state.activeExecutionId) return false;
|
|
80
|
+
if (state.reconnectable === true) return false;
|
|
81
|
+
if (state.outstandingInteractions && state.outstandingInteractions.length > 0) return false;
|
|
82
|
+
return TERMINAL_SESSION_STATES.includes(state.state ?? "") || state.reconnectable === false;
|
|
83
|
+
}
|
|
84
|
+
var TERMINAL_SESSION_STATES = ["completed", "failed", "aborted", "expired", "idle", "terminal"];
|
|
85
|
+
async function sessionFetch(connection, init = { method: "GET" }) {
|
|
86
|
+
const doFetch = connection.fetchImpl ?? fetch;
|
|
87
|
+
const base = `${connection.runtimeUrl.replace(/\/$/, "")}/agents/sessions/${encodeURIComponent(connection.sessionId)}`;
|
|
88
|
+
const url = init.method === "POST" ? `${base}/abort` : base;
|
|
89
|
+
let response;
|
|
90
|
+
try {
|
|
91
|
+
response = await doFetch(url, {
|
|
92
|
+
method: init.method,
|
|
93
|
+
headers: {
|
|
94
|
+
...connection.authToken ? { authorization: `Bearer ${connection.authToken}` } : {},
|
|
95
|
+
...init.method === "POST" ? { "content-type": "application/json" } : {}
|
|
96
|
+
},
|
|
97
|
+
...init.method === "POST" ? { body: "{}" } : {},
|
|
98
|
+
signal: AbortSignal.timeout(connection.timeoutMs ?? DEFAULT_TIMEOUT_MS)
|
|
99
|
+
});
|
|
100
|
+
} catch (err) {
|
|
101
|
+
return {
|
|
102
|
+
succeeded: false,
|
|
103
|
+
error: { code: "SIDECAR_UNREACHABLE", message: sanitizeUpstreamMessage(err), status: 502 }
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
let parsed = {};
|
|
107
|
+
try {
|
|
108
|
+
parsed = await response.json();
|
|
109
|
+
} catch {
|
|
110
|
+
parsed = {};
|
|
111
|
+
}
|
|
112
|
+
if (!response.ok) {
|
|
113
|
+
const upstreamError = parsed.error && typeof parsed.error === "object" ? parsed.error : {};
|
|
114
|
+
return {
|
|
115
|
+
succeeded: false,
|
|
116
|
+
error: {
|
|
117
|
+
code: typeof upstreamError.code === "string" && upstreamError.code ? upstreamError.code : "SIDECAR_SESSION_FAILED",
|
|
118
|
+
message: sanitizeUpstreamMessage(
|
|
119
|
+
typeof upstreamError.message === "string" && upstreamError.message ? upstreamError.message : `sidecar session ${init.method} failed (${response.status})`
|
|
120
|
+
),
|
|
121
|
+
status: response.status
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
return { succeeded: true, value: parsed };
|
|
126
|
+
}
|
|
127
|
+
function sessionStateFromPayload(payload) {
|
|
128
|
+
const data = payload.data && typeof payload.data === "object" ? payload.data : payload;
|
|
129
|
+
const session = data.session && typeof data.session === "object" ? data.session : data;
|
|
130
|
+
const activeExecution = data.activeExecution && typeof data.activeExecution === "object" ? data.activeExecution : session.activeExecution && typeof session.activeExecution === "object" ? session.activeExecution : null;
|
|
131
|
+
const interactions = session.outstandingInteractions ?? session.interactions;
|
|
132
|
+
return {
|
|
133
|
+
...typeof session.state === "string" ? { state: session.state } : {},
|
|
134
|
+
...typeof session.activeExecutionId === "string" ? { activeExecutionId: session.activeExecutionId } : session.activeExecutionId === null ? { activeExecutionId: null } : {},
|
|
135
|
+
...typeof session.reconnectable === "boolean" ? { reconnectable: session.reconnectable } : {},
|
|
136
|
+
...typeof session.registryAuthority === "string" ? { registryAuthority: session.registryAuthority } : session.registryAuthority === null ? { registryAuthority: null } : {},
|
|
137
|
+
...typeof session.terminalReason === "string" ? { terminalReason: session.terminalReason } : session.terminalReason === null ? { terminalReason: null } : {},
|
|
138
|
+
...typeof session.lastEventAt === "string" || typeof session.lastEventAt === "number" || session.lastEventAt === null ? { lastEventAt: session.lastEventAt } : {},
|
|
139
|
+
...Array.isArray(interactions) ? { outstandingInteractions: interactions } : {},
|
|
140
|
+
...activeExecution && typeof activeExecution.id === "string" && typeof session.activeExecutionId !== "string" ? { activeExecutionId: activeExecution.id } : {},
|
|
141
|
+
...activeExecution && typeof activeExecution.status === "string" ? { activeExecutionStatus: activeExecution.status } : activeExecution === null && session.activeExecution === null ? { activeExecutionStatus: null } : {}
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
async function getSessionState(connection) {
|
|
145
|
+
const result = await sessionFetch(connection);
|
|
146
|
+
if (!result.succeeded) return result;
|
|
147
|
+
return { succeeded: true, value: sessionStateFromPayload(result.value) };
|
|
148
|
+
}
|
|
149
|
+
async function abortSession(connection) {
|
|
150
|
+
const result = await sessionFetch(connection, { method: "POST" });
|
|
151
|
+
if (!result.succeeded) {
|
|
152
|
+
if (result.error.status === 404) return { succeeded: true, value: { cancelled: false, reason: "not-found" } };
|
|
153
|
+
return result;
|
|
154
|
+
}
|
|
155
|
+
const data = result.value.data && typeof result.value.data === "object" ? result.value.data : result.value;
|
|
156
|
+
const reason = typeof data.reason === "string" && data.reason.trim() ? data.reason.trim() : typeof data.noopReason === "string" && data.noopReason.trim() ? data.noopReason.trim() : void 0;
|
|
157
|
+
return {
|
|
158
|
+
succeeded: true,
|
|
159
|
+
value: {
|
|
160
|
+
cancelled: data.cancelled === true,
|
|
161
|
+
...reason ? { reason } : {},
|
|
162
|
+
...data.session && typeof data.session === "object" ? { session: sessionStateFromPayload(result.value) } : {}
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
}
|
|
78
166
|
|
|
79
167
|
// src/interactions/route.ts
|
|
80
168
|
function validateInteractionAnswerBody(body) {
|
|
@@ -300,8 +388,11 @@ function createInteractionAnswerRoute(options) {
|
|
|
300
388
|
export {
|
|
301
389
|
listSessionInteractions,
|
|
302
390
|
respondToSessionInteraction,
|
|
391
|
+
isTerminalSidecarState,
|
|
392
|
+
getSessionState,
|
|
393
|
+
abortSession,
|
|
303
394
|
validateInteractionAnswerBody,
|
|
304
395
|
mapInteractionRespondFailure,
|
|
305
396
|
createInteractionAnswerRoute
|
|
306
397
|
};
|
|
307
|
-
//# sourceMappingURL=chunk-
|
|
398
|
+
//# sourceMappingURL=chunk-3BK3BC2L.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/interactions/sidecar.ts","../src/interactions/route.ts"],"sourcesContent":["/**\n * Server-side client for the sandbox sidecar's generic interaction routes\n * (`GET/POST {runtimeUrl}/agents/sessions/{sessionId}/interactions`). The\n * pinned sandbox SDK exposes only the question-specific `session().answer()`\n * convenience; these raw calls are backend-agnostic (question/permission/plan,\n * any harness) and carry explicit outcomes (accepted/declined).\n *\n * Server-only: the sidecar bearer must never reach browser code. The caller\n * supplies the connection as a structural value (runtime URL + bearer +\n * session id) — no sandbox-SDK import, so any box-resolution strategy works.\n */\n\nimport type { InteractionData, InteractionOutcome, InteractionRequestWire } from './contract'\n\n/** Describe error details including code, message, and upstream HTTP status for sidecar interactions */\nexport interface SidecarInteractionsError {\n code: string\n message: string\n /** Upstream HTTP status; 0 when the sidecar was unreachable. */\n status: number\n}\n\n/** Represent the outcome of sidecar interactions with success or error details */\nexport type SidecarInteractionsResult<T> =\n | { succeeded: true; value: T }\n | { succeeded: false; error: SidecarInteractionsError }\n\n/** Where and how to reach one session's interaction registry. */\nexport interface SidecarInteractionsConnection {\n runtimeUrl: string\n authToken?: string\n /** The sidecar agent-session id (the chat thread's session). */\n sessionId: string\n /** Request deadline. A pending interaction means the box is up and the\n * sidecar responsive; a short default keeps a wedged runtime from stalling\n * the answering request. */\n timeoutMs?: number\n /** Injection seam for tests; defaults to global fetch. */\n fetchImpl?: typeof fetch\n}\n\nconst DEFAULT_TIMEOUT_MS = 5_000\n\n/** Strips bearer tokens / key material before an upstream message is logged\n * or surfaced. */\nfunction sanitizeUpstreamMessage(input: unknown): string {\n const message = input instanceof Error ? input.message : String(input)\n return message\n .replace(/Bearer\\s+[^\\s]+/gi, 'Bearer [redacted]')\n .replace(/\\b(?:sk|pk|tc)[_-][A-Za-z0-9_-]{8,}\\b/g, '[redacted-key]')\n}\n\nasync function interactionsFetch(\n connection: SidecarInteractionsConnection,\n init: { method: 'GET' } | { method: 'POST'; body: Record<string, unknown> },\n): Promise<SidecarInteractionsResult<Record<string, unknown>>> {\n const doFetch = connection.fetchImpl ?? fetch\n const url = `${connection.runtimeUrl.replace(/\\/$/, '')}/agents/sessions/${encodeURIComponent(connection.sessionId)}/interactions`\n let response: Response\n try {\n response = await doFetch(url, {\n method: init.method,\n headers: {\n ...(connection.authToken ? { Authorization: `Bearer ${connection.authToken}` } : {}),\n ...(init.method === 'POST' ? { 'Content-Type': 'application/json' } : {}),\n },\n ...(init.method === 'POST' ? { body: JSON.stringify(init.body) } : {}),\n signal: AbortSignal.timeout(connection.timeoutMs ?? DEFAULT_TIMEOUT_MS),\n })\n } catch (err) {\n return {\n succeeded: false,\n error: { code: 'UPSTREAM_UNREACHABLE', message: sanitizeUpstreamMessage(err), status: 0 },\n }\n }\n const raw = await response.text().catch(() => '')\n let parsed: Record<string, unknown> = {}\n try {\n parsed = raw ? (JSON.parse(raw) as Record<string, unknown>) : {}\n } catch {\n // Non-JSON error bodies (proxy 502 pages) fall through to the status check.\n }\n if (!response.ok) {\n const upstreamError = (parsed.error ?? {}) as { code?: unknown; message?: unknown }\n return {\n succeeded: false,\n error: {\n code: typeof upstreamError.code === 'string' && upstreamError.code ? upstreamError.code : 'UPSTREAM_ERROR',\n message: sanitizeUpstreamMessage(\n typeof upstreamError.message === 'string' && upstreamError.message\n ? upstreamError.message\n : `sidecar interactions ${init.method} failed (${response.status})`,\n ),\n status: response.status,\n },\n }\n }\n return { succeeded: true, value: parsed }\n}\n\n/** Outstanding (unanswered) interactions for the session — the sidecar's\n * registry is authoritative, so this is the reconnect/reload source of truth. */\nexport async function listSessionInteractions(\n connection: SidecarInteractionsConnection,\n): Promise<SidecarInteractionsResult<InteractionRequestWire[]>> {\n const result = await interactionsFetch(connection, { method: 'GET' })\n if (!result.succeeded) return result\n const data = result.value.data as { interactions?: unknown } | undefined\n if (!Array.isArray(data?.interactions)) {\n return {\n succeeded: false,\n error: { code: 'MALFORMED_RESPONSE', message: 'sidecar list returned no interactions array', status: 200 },\n }\n }\n return { succeeded: true, value: data.interactions as InteractionRequestWire[] }\n}\n\n/** Resolves one interaction. `data` is required by the sidecar only for\n * `accepted` outcomes and is validated fail-closed against the answerSpec\n * (400 INVALID_INTERACTION_ANSWER on mismatch). */\nexport async function respondToSessionInteraction(\n connection: SidecarInteractionsConnection,\n response: { id: string; outcome: InteractionOutcome; data?: InteractionData },\n): Promise<SidecarInteractionsResult<void>> {\n const result = await interactionsFetch(connection, {\n method: 'POST',\n body: {\n id: response.id,\n outcome: response.outcome,\n ...(response.data ? { data: response.data } : {}),\n },\n })\n if (!result.succeeded) return result\n return { succeeded: true, value: undefined }\n}\n\n/**\n * A sandbox session's lifecycle as the sidecar reports it.\n *\n * Every field is optional because the sidecar's payload has grown over time and\n * an older box answers with a subset. A reader that assumes a field is present\n * mis-reads an old box as terminal; the shapes below are read defensively for\n * that reason, not out of caution about types.\n */\nexport interface SidecarSessionState {\n state?: string\n activeExecutionId?: string | null\n activeExecutionStatus?: string | null\n reconnectable?: boolean\n registryAuthority?: string | null\n terminalReason?: string | null\n lastEventAt?: string | number | null\n outstandingInteractions?: unknown[]\n}\n\nexport interface SidecarAbortResult {\n cancelled: boolean\n reason?: string\n session?: SidecarSessionState\n}\n\n/**\n * Whether a session has finished and will not produce more events.\n *\n * The three early returns are the ones that matter: a session with a live\n * execution, one the platform says is reconnectable, or one holding an\n * unanswered interaction is NOT terminal however its `state` string reads. An\n * app that treats such a session as finished abandons a turn mid-flight, or\n * leaves an agent blocked on an answer nobody will send.\n */\nexport function isTerminalSidecarState(state: {\n state?: string\n activeExecutionId?: string | null\n reconnectable?: boolean\n outstandingInteractions?: unknown[]\n}): boolean {\n if (state.activeExecutionId) return false\n if (state.reconnectable === true) return false\n if (state.outstandingInteractions && state.outstandingInteractions.length > 0) return false\n return TERMINAL_SESSION_STATES.includes(state.state ?? '') || state.reconnectable === false\n}\n\nconst TERMINAL_SESSION_STATES = ['completed', 'failed', 'aborted', 'expired', 'idle', 'terminal']\n\nasync function sessionFetch(\n connection: SidecarInteractionsConnection,\n init: { method: 'GET' | 'POST' } = { method: 'GET' },\n): Promise<SidecarInteractionsResult<Record<string, unknown>>> {\n const doFetch = connection.fetchImpl ?? fetch\n const base = `${connection.runtimeUrl.replace(/\\/$/, '')}/agents/sessions/${encodeURIComponent(connection.sessionId)}`\n const url = init.method === 'POST' ? `${base}/abort` : base\n let response: Response\n try {\n response = await doFetch(url, {\n method: init.method,\n headers: {\n ...(connection.authToken ? { authorization: `Bearer ${connection.authToken}` } : {}),\n ...(init.method === 'POST' ? { 'content-type': 'application/json' } : {}),\n },\n ...(init.method === 'POST' ? { body: '{}' } : {}),\n signal: AbortSignal.timeout(connection.timeoutMs ?? DEFAULT_TIMEOUT_MS),\n })\n } catch (err) {\n return {\n succeeded: false,\n error: { code: 'SIDECAR_UNREACHABLE', message: sanitizeUpstreamMessage(err), status: 502 },\n }\n }\n let parsed: Record<string, unknown> = {}\n try {\n parsed = (await response.json()) as Record<string, unknown>\n } catch {\n parsed = {}\n }\n if (!response.ok) {\n const upstreamError = (parsed.error && typeof parsed.error === 'object'\n ? parsed.error\n : {}) as Record<string, unknown>\n return {\n succeeded: false,\n error: {\n code: typeof upstreamError.code === 'string' && upstreamError.code\n ? upstreamError.code\n : 'SIDECAR_SESSION_FAILED',\n message: sanitizeUpstreamMessage(\n typeof upstreamError.message === 'string' && upstreamError.message\n ? upstreamError.message\n : `sidecar session ${init.method} failed (${response.status})`,\n ),\n status: response.status,\n },\n }\n }\n return { succeeded: true, value: parsed }\n}\n\n/** Read the session payload defensively: newer boxes nest under `data`, and\n * the execution id appears either on the session or on `activeExecution`. */\nfunction sessionStateFromPayload(payload: Record<string, unknown>): SidecarSessionState {\n const data = (payload.data && typeof payload.data === 'object' ? payload.data : payload) as Record<string, unknown>\n const session = data.session && typeof data.session === 'object'\n ? data.session as Record<string, unknown>\n : data\n const activeExecution = data.activeExecution && typeof data.activeExecution === 'object'\n ? data.activeExecution as Record<string, unknown>\n : session.activeExecution && typeof session.activeExecution === 'object'\n ? session.activeExecution as Record<string, unknown>\n : null\n const interactions = session.outstandingInteractions ?? session.interactions\n return {\n ...(typeof session.state === 'string' ? { state: session.state } : {}),\n ...(typeof session.activeExecutionId === 'string'\n ? { activeExecutionId: session.activeExecutionId }\n : session.activeExecutionId === null ? { activeExecutionId: null } : {}),\n ...(typeof session.reconnectable === 'boolean' ? { reconnectable: session.reconnectable } : {}),\n ...(typeof session.registryAuthority === 'string'\n ? { registryAuthority: session.registryAuthority }\n : session.registryAuthority === null ? { registryAuthority: null } : {}),\n ...(typeof session.terminalReason === 'string'\n ? { terminalReason: session.terminalReason }\n : session.terminalReason === null ? { terminalReason: null } : {}),\n ...(typeof session.lastEventAt === 'string' || typeof session.lastEventAt === 'number' || session.lastEventAt === null\n ? { lastEventAt: session.lastEventAt }\n : {}),\n ...(Array.isArray(interactions) ? { outstandingInteractions: interactions } : {}),\n ...(activeExecution && typeof activeExecution.id === 'string' && typeof session.activeExecutionId !== 'string'\n ? { activeExecutionId: activeExecution.id }\n : {}),\n ...(activeExecution && typeof activeExecution.status === 'string'\n ? { activeExecutionStatus: activeExecution.status }\n : activeExecution === null && session.activeExecution === null ? { activeExecutionStatus: null } : {}),\n }\n}\n\n/** The session's current lifecycle, for reconnect and resume decisions. */\nexport async function getSessionState(\n connection: SidecarInteractionsConnection,\n): Promise<SidecarInteractionsResult<SidecarSessionState>> {\n const result = await sessionFetch(connection)\n if (!result.succeeded) return result\n return { succeeded: true, value: sessionStateFromPayload(result.value) }\n}\n\n/**\n * Cancel a running session.\n *\n * A 404 is reported as a SUCCESSFUL no-op rather than an error: the caller's\n * intent is \"this session must not be running\", and a session the sidecar has\n * never heard of already satisfies that. Surfacing it as a failure makes every\n * cancel-after-completion look like an outage.\n */\nexport async function abortSession(\n connection: SidecarInteractionsConnection,\n): Promise<SidecarInteractionsResult<SidecarAbortResult>> {\n const result = await sessionFetch(connection, { method: 'POST' })\n if (!result.succeeded) {\n if (result.error.status === 404) return { succeeded: true, value: { cancelled: false, reason: 'not-found' } }\n return result\n }\n const data = (result.value.data && typeof result.value.data === 'object'\n ? result.value.data\n : result.value) as Record<string, unknown>\n const reason = typeof data.reason === 'string' && data.reason.trim()\n ? data.reason.trim()\n : typeof data.noopReason === 'string' && data.noopReason.trim()\n ? data.noopReason.trim()\n : undefined\n return {\n succeeded: true,\n value: {\n cancelled: data.cancelled === true,\n ...(reason ? { reason } : {}),\n ...(data.session && typeof data.session === 'object' ? { session: sessionStateFromPayload(result.value) } : {}),\n },\n }\n}\n","/**\n * Framework-neutral interaction-answer endpoints, lifted out of the per-app\n * route files (gtm `api.chat.interactions`, legal `api.chat.interactions`,\n * tax `api.sessions.$id.interactions` — three byte-similar forks):\n *\n * list(request) — GET: outstanding asks for a live turn (reload restore)\n * answer(request) — POST `{ id, outcome, data? }`: resolve one ask\n *\n * The product supplies ONE seam, `resolveConnection`: authenticate the caller,\n * authorize the thread/session, and resolve the sidecar connection. Everything\n * behind the seam is mechanism the forks kept re-fixing:\n *\n * - body validation (safe field keys, typed values),\n * - sidecar error → client contract mapping (every \"the ask is gone\" shape\n * becomes 410 so the card flips to its expired state),\n * - duplicate resolution: after answering, every other outstanding ask with\n * the same content signature (a re-emitted duplicate) gets the same answer,\n * - unblock verification: re-list and fail loud (503 INTERACTION_STILL_PENDING)\n * when the sidecar accepted the POST but the ask is still open,\n * - best-effort list: sidecar failures return `{ interactions: [],\n * unavailable }` so a reload restore never breaks the live stream.\n *\n * Handlers return web-standard `Response`s (Workers, Node 18+, Deno) — no\n * router import anywhere.\n */\n\nimport {\n interactionFromWireRequest,\n isSafeInteractionFieldKey,\n questionInteractionContentSignature,\n type InteractionData,\n type InteractionRequestWire,\n} from './contract'\nimport {\n listSessionInteractions,\n respondToSessionInteraction,\n type SidecarInteractionsConnection,\n type SidecarInteractionsError,\n} from './sidecar'\n\n// A client resolves an ask by answering (`accepted`) or refusing (`declined`).\n// Withdrawal (`cancelled`) is an agent/broker outcome delivered via the\n// `interaction.cancel` event, never a client POST, so it is not accepted here.\n/** Define possible outcomes for an interaction client as accepted or declined */\nexport type InteractionClientOutcome = 'accepted' | 'declined'\n\n/** Validate interaction answer body and return success with data or failure with error message */\nexport type InteractionAnswerBodyValidation =\n | { ok: true; id: string; outcome: InteractionClientOutcome; data?: InteractionData }\n | { ok: false; error: string }\n\n/** Validates the client POST body: `{ id, outcome, data? }` with\n * identifier-safe field keys and primitive/string-array values only. */\nexport function validateInteractionAnswerBody(body: Record<string, unknown>): InteractionAnswerBodyValidation {\n const id = typeof body.id === 'string' && body.id ? body.id : null\n if (!id) return { ok: false, error: 'Missing interaction id' }\n const outcome = body.outcome\n if (outcome !== 'accepted' && outcome !== 'declined') {\n return { ok: false, error: 'Invalid outcome: expected accepted or declined' }\n }\n if (body.data === undefined) return { ok: true, id, outcome }\n if (!body.data || typeof body.data !== 'object' || Array.isArray(body.data)) {\n return { ok: false, error: 'Invalid data: expected an object of field values' }\n }\n const data: InteractionData = {}\n for (const [key, value] of Object.entries(body.data)) {\n if (!isSafeInteractionFieldKey(key)) {\n return { ok: false, error: 'Invalid data: field names must contain only letters, numbers, underscores, or hyphens' }\n }\n const validValue =\n typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean' ||\n (Array.isArray(value) && value.every((item) => typeof item === 'string'))\n if (!validValue) {\n return { ok: false, error: 'Invalid data: field values must be strings, numbers, booleans, or string arrays' }\n }\n data[key] = value as InteractionData[string]\n }\n return { ok: true, id, outcome, data }\n}\n\n/** Provide logging methods for warnings and errors in interaction routes */\nexport type InteractionRouteLogger = Pick<Console, 'warn' | 'error'>\n\n/** Sidecar error → the client-actionable contract. Every \"the ask is gone\"\n * shape maps to 410 so the card flips to its expired state — a raw 404/409\n * must never surface. */\nexport function mapInteractionRespondFailure(\n error: SidecarInteractionsError,\n logger: InteractionRouteLogger = console,\n): Response {\n if (error.code === 'INVALID_INTERACTION_ANSWER') {\n return Response.json(\n { code: 'INVALID_INTERACTION_ANSWER', error: 'This question needs an answer from the card above — pick one of the listed options.' },\n { status: 400 },\n )\n }\n if (error.status === 404) {\n return Response.json(\n { code: 'INTERACTION_EXPIRED', error: 'This question is no longer waiting for an answer.' },\n { status: 410 },\n )\n }\n if (error.status === 501 || error.code === 'NOT_IMPLEMENTED') {\n return Response.json(\n { code: 'INTERACTIONS_UNSUPPORTED', error: 'This agent backend cannot accept answers this way.' },\n { status: 501 },\n )\n }\n logger.error('[interactions] respond failed:', error)\n return Response.json(\n { code: 'INTERACTION_UPSTREAM_FAILED', error: 'Could not reach the agent. Try again.' },\n { status: 503 },\n )\n}\n\n/** The product seam's verdict for one request. `response` short-circuits with\n * a product-authored Response (401/404/429…); `unavailable` means the caller\n * is fine but the sandbox runtime is not reachable — the factory shapes that\n * per intent (empty list for `list`, 503 for `answer`). */\nexport type InteractionConnectionResolution =\n | { ok: true; connection: SidecarInteractionsConnection }\n | { ok: false; response: Response }\n | { ok: false; unavailable: string }\n\n/** Define arguments required to resolve interaction connections based on request and intent */\nexport interface ResolveInteractionConnectionArgs {\n request: Request\n intent: 'list' | 'answer'\n /** The parsed, validated POST body (answer intent only) so the resolver can\n * read product routing fields (workspaceId/threadId) without re-parsing. */\n body?: Record<string, unknown>\n}\n\n/** Describe the arguments provided before processing an interaction answer including request, body, and connection details */\nexport interface BeforeInteractionAnswerArgs {\n request: Request\n /** Original parsed body, including product routing fields. */\n body: Record<string, unknown>\n /** Shared validation result; products never need to parse the answer again. */\n answer: Extract<InteractionAnswerBodyValidation, { ok: true }>\n connection: SidecarInteractionsConnection\n /** The route's single authoritative pre-answer sidecar snapshot. */\n outstanding: InteractionRequestWire[]\n answeredRequest?: InteractionRequestWire\n /** Content-identical questions that the shared route will also answer. */\n duplicateRequests: InteractionRequestWire[]\n}\n\n/** Define arguments for durable interaction routes including a stable caller-created attempt key */\nexport interface DurableInteractionRouteArgs extends BeforeInteractionAnswerArgs {\n /** Caller-created opaque identifier, stable across an ambiguous retry. */\n attemptKey: string\n}\n\n/** Crash-recoverable persistence lifecycle for the answer route. The product\n * binds this structural port to its OWN durable store — agent-app ships no\n * implementation (the `/durable-chat` module that used to provide one was\n * removed in 0.44.0 after nine repos produced zero imports of it). Existing\n * `beforeAnswer` behavior remains independent and unchanged. */\nexport interface DurableInteractionRoutePersistence<TPrepared = unknown> {\n guarantee: 'reconciled' | 'best-effort'\n prepare(args: DurableInteractionRouteArgs): TPrepared | Promise<TPrepared>\n /** Resolve an ambiguous retry (for example, the sidecar says the ask is\n * already gone). Only `settled:true` permits the route to report success. */\n reconcile(args: DurableInteractionRouteArgs & { prepared: TPrepared }):\n | { settled: boolean }\n | Promise<{ settled: boolean }>\n /** Record the authority acknowledgement before terminal projection. */\n acknowledge(args: DurableInteractionRouteArgs & {\n prepared: TPrepared\n duplicateIds: string[]\n }): void | Promise<void>\n /** Idempotently materialize terminal status and accepted values. */\n finalize(args: DurableInteractionRouteArgs & {\n prepared: TPrepared\n duplicateIds: string[]\n }): void | Promise<void>\n fail?(args: DurableInteractionRouteArgs & { prepared: TPrepared; error: unknown }): void | Promise<void>\n}\n\n/** Define options to authenticate, authorize, and manage persistence for interaction answer routes */\nexport interface InteractionAnswerRouteOptions {\n /** Authenticate + authorize the caller and resolve the sidecar connection.\n * This is the only product-supplied step: session auth, workspace/thread\n * access, rate limiting, and box resolution all live here. */\n resolveConnection: (args: ResolveInteractionConnectionArgs) => Promise<InteractionConnectionResolution>\n /** Product persistence seam that runs before the answer can unblock and\n * finalize the agent turn. A throw aborts the request before any answer POST. */\n beforeAnswer?: (args: BeforeInteractionAnswerArgs) => void | Promise<void>\n /** Additive crash-recoverable settlement. When configured, POST requires an\n * `attemptKey`; accepted values are finalized only after sidecar ack. */\n durable?: DurableInteractionRoutePersistence\n logger?: InteractionRouteLogger\n}\n\n/** Define routes to list outstanding interactions and resolve answers for live turns */\nexport interface InteractionAnswerRoute {\n /** GET — outstanding interactions for a live turn. Failures return an empty\n * list with an explicit `unavailable` code: the caller is a best-effort\n * reload restore, and the live/replayed stream must stay untouched when the\n * sidecar cannot answer. */\n list: (request: Request) => Promise<Response>\n /** POST `{ id, outcome, data?, ...productFields }` — resolve one ask, answer\n * content-identical duplicates the same way, then re-list to prove the run\n * actually unblocked. */\n answer: (request: Request) => Promise<Response>\n}\n\n/** Create an interaction answer route that handles listing and resolving interaction requests */\nexport function createInteractionAnswerRoute(options: InteractionAnswerRouteOptions): InteractionAnswerRoute {\n const logger = options.logger ?? console\n\n async function list(request: Request): Promise<Response> {\n const resolution = await options.resolveConnection({ request, intent: 'list' })\n if (!resolution.ok) {\n if ('response' in resolution) return resolution.response\n return Response.json({ interactions: [], unavailable: resolution.unavailable })\n }\n const result = await listSessionInteractions(resolution.connection)\n if (!result.succeeded) {\n logger.warn('[interactions] list failed:', result.error)\n return Response.json({ interactions: [], unavailable: result.error.code })\n }\n return Response.json({ interactions: result.value })\n }\n\n async function answer(request: Request): Promise<Response> {\n const body = await request.json().catch(() => null) as Record<string, unknown> | null\n if (!body || typeof body !== 'object' || Array.isArray(body)) {\n return Response.json({ error: 'Invalid JSON body' }, { status: 400 })\n }\n const validation = validateInteractionAnswerBody(body)\n if (!validation.ok) return Response.json({ error: validation.error }, { status: 400 })\n const attemptKey = typeof body.attemptKey === 'string' ? body.attemptKey.trim() : ''\n if (options.durable && !attemptKey) {\n return Response.json({ error: 'Missing attemptKey for durable interaction answer' }, { status: 400 })\n }\n\n const resolution = await options.resolveConnection({ request, intent: 'answer', body })\n if (!resolution.ok) {\n if ('response' in resolution) return resolution.response\n return mapInteractionRespondFailure(\n { code: resolution.unavailable, message: 'sandbox runtime unavailable', status: 0 },\n logger,\n )\n }\n const connection = resolution.connection\n const answerPayload = {\n outcome: validation.outcome,\n ...(validation.data ? { data: validation.data } : {}),\n }\n\n // Snapshot the answered ask's content signature BEFORE resolving it, so any\n // content-identical duplicates still outstanding afterwards (the agent may\n // have re-emitted the same question N times) can be answered the same way.\n const before = await listSessionInteractions(connection)\n if (!before.succeeded && (options.beforeAnswer || options.durable)) {\n return mapInteractionRespondFailure(before.error, logger)\n }\n const answeredRequest = before.succeeded ? before.value.find((item) => item.id === validation.id) : undefined\n if (options.beforeAnswer && !options.durable && !answeredRequest) {\n return mapInteractionRespondFailure(\n { code: 'NOT_FOUND', message: 'interaction not found', status: 404 },\n logger,\n )\n }\n const answeredSignature = answeredRequest\n ? questionInteractionContentSignature(interactionFromWireRequest(answeredRequest))\n : null\n const duplicateRequests = before.succeeded && answeredSignature\n ? before.value.filter((item) => item.id !== validation.id && (\n questionInteractionContentSignature(interactionFromWireRequest(item)) === answeredSignature\n ))\n : []\n\n const lifecycleArgs: BeforeInteractionAnswerArgs = {\n request,\n body,\n answer: validation,\n connection,\n outstanding: before.succeeded ? before.value : [],\n ...(answeredRequest ? { answeredRequest } : {}),\n duplicateRequests,\n }\n\n if (options.beforeAnswer && answeredRequest) {\n try {\n await options.beforeAnswer(lifecycleArgs)\n } catch (error) {\n logger.error('[interactions] beforeAnswer failed:', error)\n return Response.json(\n { code: 'INTERACTION_BEFORE_ANSWER_FAILED', error: 'Could not save the answer. Try again.' },\n { status: 503 },\n )\n }\n }\n\n let prepared: unknown\n const durableArgs = options.durable\n ? { ...lifecycleArgs, attemptKey }\n : null\n if (options.durable && durableArgs) {\n try {\n prepared = await options.durable.prepare(durableArgs)\n } catch (error) {\n logger.error('[interactions] durable prepare failed:', error)\n return Response.json(\n { code: 'INTERACTION_PREPARE_FAILED', error: 'Could not prepare the answer. Try again.' },\n { status: 503 },\n )\n }\n if (!answeredRequest) {\n let reconciled: { settled: boolean }\n try {\n reconciled = await options.durable.reconcile({ ...durableArgs, prepared })\n } catch (error) {\n logger.error('[interactions] durable reconcile failed:', error)\n reconciled = { settled: false }\n }\n if (reconciled.settled) return Response.json({ ok: true, idempotent: true })\n return Response.json(\n { code: 'INTERACTION_RECONCILIATION_PENDING', error: 'The answer status is still being checked. Retry with the same attempt.' },\n { status: 503 },\n )\n }\n }\n\n const result = await respondToSessionInteraction(connection, { id: validation.id, ...answerPayload })\n if (!result.succeeded) {\n if (options.durable && durableArgs) {\n let reconciled: { settled: boolean }\n try {\n reconciled = await options.durable.reconcile({ ...durableArgs, prepared })\n } catch {\n reconciled = { settled: false }\n }\n if (reconciled.settled) return Response.json({ ok: true, idempotent: true })\n if (result.error.status === 404) {\n return Response.json(\n { code: 'INTERACTION_RECONCILIATION_PENDING', error: 'The answer status is still being checked. Retry with the same attempt.' },\n { status: 503 },\n )\n }\n try {\n await options.durable.fail?.({ ...durableArgs, prepared, error: result.error })\n } catch {\n // The upstream failure remains authoritative; a persistence cleanup\n // failure must not replace its client-facing mapping.\n }\n }\n return mapInteractionRespondFailure(result.error, logger)\n }\n\n let remaining = await listSessionInteractions(connection)\n const acknowledgedDuplicateIds: string[] = []\n if (remaining.succeeded && answeredSignature) {\n const remainingDuplicates = remaining.value.filter((item) => {\n if (item.id === validation.id) return false\n return questionInteractionContentSignature(interactionFromWireRequest(item)) === answeredSignature\n })\n for (const duplicate of remainingDuplicates) {\n const duplicateResult = await respondToSessionInteraction(connection, { id: duplicate.id, ...answerPayload })\n if (!duplicateResult.succeeded) break\n acknowledgedDuplicateIds.push(duplicate.id)\n }\n if (remainingDuplicates.length > 0) remaining = await listSessionInteractions(connection)\n }\n\n // Prove the run actually unblocked: neither the answered id nor any\n // content-duplicate may still be outstanding. If one is, the sidecar\n // accepted the POST but did not release the run — report it rather than\n // tell the user it was answered.\n if (remaining.succeeded && remaining.value.some((item) => item.id === validation.id || (\n answeredSignature && questionInteractionContentSignature(interactionFromWireRequest(item)) === answeredSignature\n ))) {\n logger.error('[interactions] respond returned ok but interaction is still pending:', {\n sessionId: connection.sessionId,\n interactionId: validation.id,\n })\n return Response.json(\n { code: 'INTERACTION_STILL_PENDING', error: 'The agent did not accept the answer. Try answering again.' },\n { status: 503 },\n )\n }\n\n if (options.durable && durableArgs) {\n try {\n await options.durable.acknowledge({\n ...durableArgs,\n prepared,\n duplicateIds: acknowledgedDuplicateIds,\n })\n await options.durable.finalize({\n ...durableArgs,\n prepared,\n duplicateIds: acknowledgedDuplicateIds,\n })\n } catch (error) {\n logger.error('[interactions] durable finalize failed:', error)\n return Response.json(\n { code: 'INTERACTION_FINALIZE_FAILED', error: 'The answer was accepted but is still being saved. Retry to reconcile it.' },\n { status: 503 },\n )\n }\n }\n\n return Response.json({ ok: true })\n }\n\n return { list, answer }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
} from "./chunk-YTMKRL3L.js";
|
|
13
13
|
import {
|
|
14
14
|
attachmentPartsFromMessageParts
|
|
15
|
-
} from "./chunk-
|
|
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-
|
|
4312
|
+
//# sourceMappingURL=chunk-CKUZVDZ7.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-
|
|
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-
|
|
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
|
|
@@ -54,6 +54,55 @@ declare function respondToSessionInteraction(connection: SidecarInteractionsConn
|
|
|
54
54
|
outcome: InteractionOutcome;
|
|
55
55
|
data?: InteractionData;
|
|
56
56
|
}): Promise<SidecarInteractionsResult<void>>;
|
|
57
|
+
/**
|
|
58
|
+
* A sandbox session's lifecycle as the sidecar reports it.
|
|
59
|
+
*
|
|
60
|
+
* Every field is optional because the sidecar's payload has grown over time and
|
|
61
|
+
* an older box answers with a subset. A reader that assumes a field is present
|
|
62
|
+
* mis-reads an old box as terminal; the shapes below are read defensively for
|
|
63
|
+
* that reason, not out of caution about types.
|
|
64
|
+
*/
|
|
65
|
+
interface SidecarSessionState {
|
|
66
|
+
state?: string;
|
|
67
|
+
activeExecutionId?: string | null;
|
|
68
|
+
activeExecutionStatus?: string | null;
|
|
69
|
+
reconnectable?: boolean;
|
|
70
|
+
registryAuthority?: string | null;
|
|
71
|
+
terminalReason?: string | null;
|
|
72
|
+
lastEventAt?: string | number | null;
|
|
73
|
+
outstandingInteractions?: unknown[];
|
|
74
|
+
}
|
|
75
|
+
interface SidecarAbortResult {
|
|
76
|
+
cancelled: boolean;
|
|
77
|
+
reason?: string;
|
|
78
|
+
session?: SidecarSessionState;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Whether a session has finished and will not produce more events.
|
|
82
|
+
*
|
|
83
|
+
* The three early returns are the ones that matter: a session with a live
|
|
84
|
+
* execution, one the platform says is reconnectable, or one holding an
|
|
85
|
+
* unanswered interaction is NOT terminal however its `state` string reads. An
|
|
86
|
+
* app that treats such a session as finished abandons a turn mid-flight, or
|
|
87
|
+
* leaves an agent blocked on an answer nobody will send.
|
|
88
|
+
*/
|
|
89
|
+
declare function isTerminalSidecarState(state: {
|
|
90
|
+
state?: string;
|
|
91
|
+
activeExecutionId?: string | null;
|
|
92
|
+
reconnectable?: boolean;
|
|
93
|
+
outstandingInteractions?: unknown[];
|
|
94
|
+
}): boolean;
|
|
95
|
+
/** The session's current lifecycle, for reconnect and resume decisions. */
|
|
96
|
+
declare function getSessionState(connection: SidecarInteractionsConnection): Promise<SidecarInteractionsResult<SidecarSessionState>>;
|
|
97
|
+
/**
|
|
98
|
+
* Cancel a running session.
|
|
99
|
+
*
|
|
100
|
+
* A 404 is reported as a SUCCESSFUL no-op rather than an error: the caller's
|
|
101
|
+
* intent is "this session must not be running", and a session the sidecar has
|
|
102
|
+
* never heard of already satisfies that. Surfacing it as a failure makes every
|
|
103
|
+
* cancel-after-completion look like an outage.
|
|
104
|
+
*/
|
|
105
|
+
declare function abortSession(connection: SidecarInteractionsConnection): Promise<SidecarInteractionsResult<SidecarAbortResult>>;
|
|
57
106
|
|
|
58
107
|
/**
|
|
59
108
|
* Framework-neutral interaction-answer endpoints, lifted out of the per-app
|
|
@@ -206,4 +255,4 @@ interface InteractionAnswerRoute {
|
|
|
206
255
|
/** Create an interaction answer route that handles listing and resolving interaction requests */
|
|
207
256
|
declare function createInteractionAnswerRoute(options: InteractionAnswerRouteOptions): InteractionAnswerRoute;
|
|
208
257
|
|
|
209
|
-
export { type BeforeInteractionAnswerArgs, type DurableInteractionRouteArgs, type DurableInteractionRoutePersistence, type InteractionAnswerBodyValidation, type InteractionAnswerRoute, type InteractionAnswerRouteOptions, type InteractionClientOutcome, type InteractionConnectionResolution, InteractionRequestWire, type InteractionRouteLogger, type ResolveInteractionConnectionArgs, type SidecarInteractionsConnection, type SidecarInteractionsError, type SidecarInteractionsResult, createInteractionAnswerRoute, listSessionInteractions, mapInteractionRespondFailure, respondToSessionInteraction, validateInteractionAnswerBody };
|
|
258
|
+
export { type BeforeInteractionAnswerArgs, type DurableInteractionRouteArgs, type DurableInteractionRoutePersistence, type InteractionAnswerBodyValidation, type InteractionAnswerRoute, type InteractionAnswerRouteOptions, type InteractionClientOutcome, type InteractionConnectionResolution, InteractionRequestWire, type InteractionRouteLogger, type ResolveInteractionConnectionArgs, type SidecarAbortResult, type SidecarInteractionsConnection, type SidecarInteractionsError, type SidecarInteractionsResult, type SidecarSessionState, abortSession, createInteractionAnswerRoute, getSessionState, isTerminalSidecarState, listSessionInteractions, mapInteractionRespondFailure, respondToSessionInteraction, validateInteractionAnswerBody };
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
|
+
abortSession,
|
|
2
3
|
createInteractionAnswerRoute,
|
|
4
|
+
getSessionState,
|
|
5
|
+
isTerminalSidecarState,
|
|
3
6
|
listSessionInteractions,
|
|
4
7
|
mapInteractionRespondFailure,
|
|
5
8
|
respondToSessionInteraction,
|
|
6
9
|
validateInteractionAnswerBody
|
|
7
|
-
} from "../chunk-
|
|
10
|
+
} from "../chunk-3BK3BC2L.js";
|
|
8
11
|
import {
|
|
9
12
|
INTERACTION_CANCEL_EVENT,
|
|
10
13
|
INTERACTION_EVENT,
|
|
@@ -34,6 +37,7 @@ export {
|
|
|
34
37
|
INTERACTION_CANCEL_EVENT,
|
|
35
38
|
INTERACTION_EVENT,
|
|
36
39
|
INTERACTION_RESOLVED_EVENT,
|
|
40
|
+
abortSession,
|
|
37
41
|
canTransitionInteractionStatus,
|
|
38
42
|
cancelStatusFor,
|
|
39
43
|
composerAnswerData,
|
|
@@ -41,12 +45,14 @@ export {
|
|
|
41
45
|
createInteractionAnswerRoute,
|
|
42
46
|
dedupeQuestionInteractionsByContent,
|
|
43
47
|
fieldAcceptsFreeText,
|
|
48
|
+
getSessionState,
|
|
44
49
|
interactionFromWireRequest,
|
|
45
50
|
interactionPartKey,
|
|
46
51
|
interactionToPersistedPart,
|
|
47
52
|
isRenderableInteractionKind,
|
|
48
53
|
isSafeInteractionFieldKey,
|
|
49
54
|
isTerminalInteractionStatus,
|
|
55
|
+
isTerminalSidecarState,
|
|
50
56
|
listSessionInteractions,
|
|
51
57
|
mapInteractionRespondFailure,
|
|
52
58
|
noticePart,
|
|
@@ -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) {
|
package/dist/sandbox/index.js
CHANGED
|
@@ -85,9 +85,9 @@ import {
|
|
|
85
85
|
workspaceSandboxRecoveryMessage,
|
|
86
86
|
workspaceSandboxRecoveryRecommendedActions,
|
|
87
87
|
writeProfileFilesToBox
|
|
88
|
-
} from "../chunk-
|
|
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";
|
package/dist/web-react/index.js
CHANGED
|
@@ -78,7 +78,14 @@ import {
|
|
|
78
78
|
useSmoothText,
|
|
79
79
|
useThinkingSeconds,
|
|
80
80
|
waterfallLayout
|
|
81
|
-
} from "../chunk-
|
|
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-
|
|
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.
|
|
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",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/interactions/sidecar.ts","../src/interactions/route.ts"],"sourcesContent":["/**\n * Server-side client for the sandbox sidecar's generic interaction routes\n * (`GET/POST {runtimeUrl}/agents/sessions/{sessionId}/interactions`). The\n * pinned sandbox SDK exposes only the question-specific `session().answer()`\n * convenience; these raw calls are backend-agnostic (question/permission/plan,\n * any harness) and carry explicit outcomes (accepted/declined).\n *\n * Server-only: the sidecar bearer must never reach browser code. The caller\n * supplies the connection as a structural value (runtime URL + bearer +\n * session id) — no sandbox-SDK import, so any box-resolution strategy works.\n */\n\nimport type { InteractionData, InteractionOutcome, InteractionRequestWire } from './contract'\n\n/** Describe error details including code, message, and upstream HTTP status for sidecar interactions */\nexport interface SidecarInteractionsError {\n code: string\n message: string\n /** Upstream HTTP status; 0 when the sidecar was unreachable. */\n status: number\n}\n\n/** Represent the outcome of sidecar interactions with success or error details */\nexport type SidecarInteractionsResult<T> =\n | { succeeded: true; value: T }\n | { succeeded: false; error: SidecarInteractionsError }\n\n/** Where and how to reach one session's interaction registry. */\nexport interface SidecarInteractionsConnection {\n runtimeUrl: string\n authToken?: string\n /** The sidecar agent-session id (the chat thread's session). */\n sessionId: string\n /** Request deadline. A pending interaction means the box is up and the\n * sidecar responsive; a short default keeps a wedged runtime from stalling\n * the answering request. */\n timeoutMs?: number\n /** Injection seam for tests; defaults to global fetch. */\n fetchImpl?: typeof fetch\n}\n\nconst DEFAULT_TIMEOUT_MS = 5_000\n\n/** Strips bearer tokens / key material before an upstream message is logged\n * or surfaced. */\nfunction sanitizeUpstreamMessage(input: unknown): string {\n const message = input instanceof Error ? input.message : String(input)\n return message\n .replace(/Bearer\\s+[^\\s]+/gi, 'Bearer [redacted]')\n .replace(/\\b(?:sk|pk|tc)[_-][A-Za-z0-9_-]{8,}\\b/g, '[redacted-key]')\n}\n\nasync function interactionsFetch(\n connection: SidecarInteractionsConnection,\n init: { method: 'GET' } | { method: 'POST'; body: Record<string, unknown> },\n): Promise<SidecarInteractionsResult<Record<string, unknown>>> {\n const doFetch = connection.fetchImpl ?? fetch\n const url = `${connection.runtimeUrl.replace(/\\/$/, '')}/agents/sessions/${encodeURIComponent(connection.sessionId)}/interactions`\n let response: Response\n try {\n response = await doFetch(url, {\n method: init.method,\n headers: {\n ...(connection.authToken ? { Authorization: `Bearer ${connection.authToken}` } : {}),\n ...(init.method === 'POST' ? { 'Content-Type': 'application/json' } : {}),\n },\n ...(init.method === 'POST' ? { body: JSON.stringify(init.body) } : {}),\n signal: AbortSignal.timeout(connection.timeoutMs ?? DEFAULT_TIMEOUT_MS),\n })\n } catch (err) {\n return {\n succeeded: false,\n error: { code: 'UPSTREAM_UNREACHABLE', message: sanitizeUpstreamMessage(err), status: 0 },\n }\n }\n const raw = await response.text().catch(() => '')\n let parsed: Record<string, unknown> = {}\n try {\n parsed = raw ? (JSON.parse(raw) as Record<string, unknown>) : {}\n } catch {\n // Non-JSON error bodies (proxy 502 pages) fall through to the status check.\n }\n if (!response.ok) {\n const upstreamError = (parsed.error ?? {}) as { code?: unknown; message?: unknown }\n return {\n succeeded: false,\n error: {\n code: typeof upstreamError.code === 'string' && upstreamError.code ? upstreamError.code : 'UPSTREAM_ERROR',\n message: sanitizeUpstreamMessage(\n typeof upstreamError.message === 'string' && upstreamError.message\n ? upstreamError.message\n : `sidecar interactions ${init.method} failed (${response.status})`,\n ),\n status: response.status,\n },\n }\n }\n return { succeeded: true, value: parsed }\n}\n\n/** Outstanding (unanswered) interactions for the session — the sidecar's\n * registry is authoritative, so this is the reconnect/reload source of truth. */\nexport async function listSessionInteractions(\n connection: SidecarInteractionsConnection,\n): Promise<SidecarInteractionsResult<InteractionRequestWire[]>> {\n const result = await interactionsFetch(connection, { method: 'GET' })\n if (!result.succeeded) return result\n const data = result.value.data as { interactions?: unknown } | undefined\n if (!Array.isArray(data?.interactions)) {\n return {\n succeeded: false,\n error: { code: 'MALFORMED_RESPONSE', message: 'sidecar list returned no interactions array', status: 200 },\n }\n }\n return { succeeded: true, value: data.interactions as InteractionRequestWire[] }\n}\n\n/** Resolves one interaction. `data` is required by the sidecar only for\n * `accepted` outcomes and is validated fail-closed against the answerSpec\n * (400 INVALID_INTERACTION_ANSWER on mismatch). */\nexport async function respondToSessionInteraction(\n connection: SidecarInteractionsConnection,\n response: { id: string; outcome: InteractionOutcome; data?: InteractionData },\n): Promise<SidecarInteractionsResult<void>> {\n const result = await interactionsFetch(connection, {\n method: 'POST',\n body: {\n id: response.id,\n outcome: response.outcome,\n ...(response.data ? { data: response.data } : {}),\n },\n })\n if (!result.succeeded) return result\n return { succeeded: true, value: undefined }\n}\n","/**\n * Framework-neutral interaction-answer endpoints, lifted out of the per-app\n * route files (gtm `api.chat.interactions`, legal `api.chat.interactions`,\n * tax `api.sessions.$id.interactions` — three byte-similar forks):\n *\n * list(request) — GET: outstanding asks for a live turn (reload restore)\n * answer(request) — POST `{ id, outcome, data? }`: resolve one ask\n *\n * The product supplies ONE seam, `resolveConnection`: authenticate the caller,\n * authorize the thread/session, and resolve the sidecar connection. Everything\n * behind the seam is mechanism the forks kept re-fixing:\n *\n * - body validation (safe field keys, typed values),\n * - sidecar error → client contract mapping (every \"the ask is gone\" shape\n * becomes 410 so the card flips to its expired state),\n * - duplicate resolution: after answering, every other outstanding ask with\n * the same content signature (a re-emitted duplicate) gets the same answer,\n * - unblock verification: re-list and fail loud (503 INTERACTION_STILL_PENDING)\n * when the sidecar accepted the POST but the ask is still open,\n * - best-effort list: sidecar failures return `{ interactions: [],\n * unavailable }` so a reload restore never breaks the live stream.\n *\n * Handlers return web-standard `Response`s (Workers, Node 18+, Deno) — no\n * router import anywhere.\n */\n\nimport {\n interactionFromWireRequest,\n isSafeInteractionFieldKey,\n questionInteractionContentSignature,\n type InteractionData,\n type InteractionRequestWire,\n} from './contract'\nimport {\n listSessionInteractions,\n respondToSessionInteraction,\n type SidecarInteractionsConnection,\n type SidecarInteractionsError,\n} from './sidecar'\n\n// A client resolves an ask by answering (`accepted`) or refusing (`declined`).\n// Withdrawal (`cancelled`) is an agent/broker outcome delivered via the\n// `interaction.cancel` event, never a client POST, so it is not accepted here.\n/** Define possible outcomes for an interaction client as accepted or declined */\nexport type InteractionClientOutcome = 'accepted' | 'declined'\n\n/** Validate interaction answer body and return success with data or failure with error message */\nexport type InteractionAnswerBodyValidation =\n | { ok: true; id: string; outcome: InteractionClientOutcome; data?: InteractionData }\n | { ok: false; error: string }\n\n/** Validates the client POST body: `{ id, outcome, data? }` with\n * identifier-safe field keys and primitive/string-array values only. */\nexport function validateInteractionAnswerBody(body: Record<string, unknown>): InteractionAnswerBodyValidation {\n const id = typeof body.id === 'string' && body.id ? body.id : null\n if (!id) return { ok: false, error: 'Missing interaction id' }\n const outcome = body.outcome\n if (outcome !== 'accepted' && outcome !== 'declined') {\n return { ok: false, error: 'Invalid outcome: expected accepted or declined' }\n }\n if (body.data === undefined) return { ok: true, id, outcome }\n if (!body.data || typeof body.data !== 'object' || Array.isArray(body.data)) {\n return { ok: false, error: 'Invalid data: expected an object of field values' }\n }\n const data: InteractionData = {}\n for (const [key, value] of Object.entries(body.data)) {\n if (!isSafeInteractionFieldKey(key)) {\n return { ok: false, error: 'Invalid data: field names must contain only letters, numbers, underscores, or hyphens' }\n }\n const validValue =\n typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean' ||\n (Array.isArray(value) && value.every((item) => typeof item === 'string'))\n if (!validValue) {\n return { ok: false, error: 'Invalid data: field values must be strings, numbers, booleans, or string arrays' }\n }\n data[key] = value as InteractionData[string]\n }\n return { ok: true, id, outcome, data }\n}\n\n/** Provide logging methods for warnings and errors in interaction routes */\nexport type InteractionRouteLogger = Pick<Console, 'warn' | 'error'>\n\n/** Sidecar error → the client-actionable contract. Every \"the ask is gone\"\n * shape maps to 410 so the card flips to its expired state — a raw 404/409\n * must never surface. */\nexport function mapInteractionRespondFailure(\n error: SidecarInteractionsError,\n logger: InteractionRouteLogger = console,\n): Response {\n if (error.code === 'INVALID_INTERACTION_ANSWER') {\n return Response.json(\n { code: 'INVALID_INTERACTION_ANSWER', error: 'This question needs an answer from the card above — pick one of the listed options.' },\n { status: 400 },\n )\n }\n if (error.status === 404) {\n return Response.json(\n { code: 'INTERACTION_EXPIRED', error: 'This question is no longer waiting for an answer.' },\n { status: 410 },\n )\n }\n if (error.status === 501 || error.code === 'NOT_IMPLEMENTED') {\n return Response.json(\n { code: 'INTERACTIONS_UNSUPPORTED', error: 'This agent backend cannot accept answers this way.' },\n { status: 501 },\n )\n }\n logger.error('[interactions] respond failed:', error)\n return Response.json(\n { code: 'INTERACTION_UPSTREAM_FAILED', error: 'Could not reach the agent. Try again.' },\n { status: 503 },\n )\n}\n\n/** The product seam's verdict for one request. `response` short-circuits with\n * a product-authored Response (401/404/429…); `unavailable` means the caller\n * is fine but the sandbox runtime is not reachable — the factory shapes that\n * per intent (empty list for `list`, 503 for `answer`). */\nexport type InteractionConnectionResolution =\n | { ok: true; connection: SidecarInteractionsConnection }\n | { ok: false; response: Response }\n | { ok: false; unavailable: string }\n\n/** Define arguments required to resolve interaction connections based on request and intent */\nexport interface ResolveInteractionConnectionArgs {\n request: Request\n intent: 'list' | 'answer'\n /** The parsed, validated POST body (answer intent only) so the resolver can\n * read product routing fields (workspaceId/threadId) without re-parsing. */\n body?: Record<string, unknown>\n}\n\n/** Describe the arguments provided before processing an interaction answer including request, body, and connection details */\nexport interface BeforeInteractionAnswerArgs {\n request: Request\n /** Original parsed body, including product routing fields. */\n body: Record<string, unknown>\n /** Shared validation result; products never need to parse the answer again. */\n answer: Extract<InteractionAnswerBodyValidation, { ok: true }>\n connection: SidecarInteractionsConnection\n /** The route's single authoritative pre-answer sidecar snapshot. */\n outstanding: InteractionRequestWire[]\n answeredRequest?: InteractionRequestWire\n /** Content-identical questions that the shared route will also answer. */\n duplicateRequests: InteractionRequestWire[]\n}\n\n/** Define arguments for durable interaction routes including a stable caller-created attempt key */\nexport interface DurableInteractionRouteArgs extends BeforeInteractionAnswerArgs {\n /** Caller-created opaque identifier, stable across an ambiguous retry. */\n attemptKey: string\n}\n\n/** Crash-recoverable persistence lifecycle for the answer route. The product\n * binds this structural port to its OWN durable store — agent-app ships no\n * implementation (the `/durable-chat` module that used to provide one was\n * removed in 0.44.0 after nine repos produced zero imports of it). Existing\n * `beforeAnswer` behavior remains independent and unchanged. */\nexport interface DurableInteractionRoutePersistence<TPrepared = unknown> {\n guarantee: 'reconciled' | 'best-effort'\n prepare(args: DurableInteractionRouteArgs): TPrepared | Promise<TPrepared>\n /** Resolve an ambiguous retry (for example, the sidecar says the ask is\n * already gone). Only `settled:true` permits the route to report success. */\n reconcile(args: DurableInteractionRouteArgs & { prepared: TPrepared }):\n | { settled: boolean }\n | Promise<{ settled: boolean }>\n /** Record the authority acknowledgement before terminal projection. */\n acknowledge(args: DurableInteractionRouteArgs & {\n prepared: TPrepared\n duplicateIds: string[]\n }): void | Promise<void>\n /** Idempotently materialize terminal status and accepted values. */\n finalize(args: DurableInteractionRouteArgs & {\n prepared: TPrepared\n duplicateIds: string[]\n }): void | Promise<void>\n fail?(args: DurableInteractionRouteArgs & { prepared: TPrepared; error: unknown }): void | Promise<void>\n}\n\n/** Define options to authenticate, authorize, and manage persistence for interaction answer routes */\nexport interface InteractionAnswerRouteOptions {\n /** Authenticate + authorize the caller and resolve the sidecar connection.\n * This is the only product-supplied step: session auth, workspace/thread\n * access, rate limiting, and box resolution all live here. */\n resolveConnection: (args: ResolveInteractionConnectionArgs) => Promise<InteractionConnectionResolution>\n /** Product persistence seam that runs before the answer can unblock and\n * finalize the agent turn. A throw aborts the request before any answer POST. */\n beforeAnswer?: (args: BeforeInteractionAnswerArgs) => void | Promise<void>\n /** Additive crash-recoverable settlement. When configured, POST requires an\n * `attemptKey`; accepted values are finalized only after sidecar ack. */\n durable?: DurableInteractionRoutePersistence\n logger?: InteractionRouteLogger\n}\n\n/** Define routes to list outstanding interactions and resolve answers for live turns */\nexport interface InteractionAnswerRoute {\n /** GET — outstanding interactions for a live turn. Failures return an empty\n * list with an explicit `unavailable` code: the caller is a best-effort\n * reload restore, and the live/replayed stream must stay untouched when the\n * sidecar cannot answer. */\n list: (request: Request) => Promise<Response>\n /** POST `{ id, outcome, data?, ...productFields }` — resolve one ask, answer\n * content-identical duplicates the same way, then re-list to prove the run\n * actually unblocked. */\n answer: (request: Request) => Promise<Response>\n}\n\n/** Create an interaction answer route that handles listing and resolving interaction requests */\nexport function createInteractionAnswerRoute(options: InteractionAnswerRouteOptions): InteractionAnswerRoute {\n const logger = options.logger ?? console\n\n async function list(request: Request): Promise<Response> {\n const resolution = await options.resolveConnection({ request, intent: 'list' })\n if (!resolution.ok) {\n if ('response' in resolution) return resolution.response\n return Response.json({ interactions: [], unavailable: resolution.unavailable })\n }\n const result = await listSessionInteractions(resolution.connection)\n if (!result.succeeded) {\n logger.warn('[interactions] list failed:', result.error)\n return Response.json({ interactions: [], unavailable: result.error.code })\n }\n return Response.json({ interactions: result.value })\n }\n\n async function answer(request: Request): Promise<Response> {\n const body = await request.json().catch(() => null) as Record<string, unknown> | null\n if (!body || typeof body !== 'object' || Array.isArray(body)) {\n return Response.json({ error: 'Invalid JSON body' }, { status: 400 })\n }\n const validation = validateInteractionAnswerBody(body)\n if (!validation.ok) return Response.json({ error: validation.error }, { status: 400 })\n const attemptKey = typeof body.attemptKey === 'string' ? body.attemptKey.trim() : ''\n if (options.durable && !attemptKey) {\n return Response.json({ error: 'Missing attemptKey for durable interaction answer' }, { status: 400 })\n }\n\n const resolution = await options.resolveConnection({ request, intent: 'answer', body })\n if (!resolution.ok) {\n if ('response' in resolution) return resolution.response\n return mapInteractionRespondFailure(\n { code: resolution.unavailable, message: 'sandbox runtime unavailable', status: 0 },\n logger,\n )\n }\n const connection = resolution.connection\n const answerPayload = {\n outcome: validation.outcome,\n ...(validation.data ? { data: validation.data } : {}),\n }\n\n // Snapshot the answered ask's content signature BEFORE resolving it, so any\n // content-identical duplicates still outstanding afterwards (the agent may\n // have re-emitted the same question N times) can be answered the same way.\n const before = await listSessionInteractions(connection)\n if (!before.succeeded && (options.beforeAnswer || options.durable)) {\n return mapInteractionRespondFailure(before.error, logger)\n }\n const answeredRequest = before.succeeded ? before.value.find((item) => item.id === validation.id) : undefined\n if (options.beforeAnswer && !options.durable && !answeredRequest) {\n return mapInteractionRespondFailure(\n { code: 'NOT_FOUND', message: 'interaction not found', status: 404 },\n logger,\n )\n }\n const answeredSignature = answeredRequest\n ? questionInteractionContentSignature(interactionFromWireRequest(answeredRequest))\n : null\n const duplicateRequests = before.succeeded && answeredSignature\n ? before.value.filter((item) => item.id !== validation.id && (\n questionInteractionContentSignature(interactionFromWireRequest(item)) === answeredSignature\n ))\n : []\n\n const lifecycleArgs: BeforeInteractionAnswerArgs = {\n request,\n body,\n answer: validation,\n connection,\n outstanding: before.succeeded ? before.value : [],\n ...(answeredRequest ? { answeredRequest } : {}),\n duplicateRequests,\n }\n\n if (options.beforeAnswer && answeredRequest) {\n try {\n await options.beforeAnswer(lifecycleArgs)\n } catch (error) {\n logger.error('[interactions] beforeAnswer failed:', error)\n return Response.json(\n { code: 'INTERACTION_BEFORE_ANSWER_FAILED', error: 'Could not save the answer. Try again.' },\n { status: 503 },\n )\n }\n }\n\n let prepared: unknown\n const durableArgs = options.durable\n ? { ...lifecycleArgs, attemptKey }\n : null\n if (options.durable && durableArgs) {\n try {\n prepared = await options.durable.prepare(durableArgs)\n } catch (error) {\n logger.error('[interactions] durable prepare failed:', error)\n return Response.json(\n { code: 'INTERACTION_PREPARE_FAILED', error: 'Could not prepare the answer. Try again.' },\n { status: 503 },\n )\n }\n if (!answeredRequest) {\n let reconciled: { settled: boolean }\n try {\n reconciled = await options.durable.reconcile({ ...durableArgs, prepared })\n } catch (error) {\n logger.error('[interactions] durable reconcile failed:', error)\n reconciled = { settled: false }\n }\n if (reconciled.settled) return Response.json({ ok: true, idempotent: true })\n return Response.json(\n { code: 'INTERACTION_RECONCILIATION_PENDING', error: 'The answer status is still being checked. Retry with the same attempt.' },\n { status: 503 },\n )\n }\n }\n\n const result = await respondToSessionInteraction(connection, { id: validation.id, ...answerPayload })\n if (!result.succeeded) {\n if (options.durable && durableArgs) {\n let reconciled: { settled: boolean }\n try {\n reconciled = await options.durable.reconcile({ ...durableArgs, prepared })\n } catch {\n reconciled = { settled: false }\n }\n if (reconciled.settled) return Response.json({ ok: true, idempotent: true })\n if (result.error.status === 404) {\n return Response.json(\n { code: 'INTERACTION_RECONCILIATION_PENDING', error: 'The answer status is still being checked. Retry with the same attempt.' },\n { status: 503 },\n )\n }\n try {\n await options.durable.fail?.({ ...durableArgs, prepared, error: result.error })\n } catch {\n // The upstream failure remains authoritative; a persistence cleanup\n // failure must not replace its client-facing mapping.\n }\n }\n return mapInteractionRespondFailure(result.error, logger)\n }\n\n let remaining = await listSessionInteractions(connection)\n const acknowledgedDuplicateIds: string[] = []\n if (remaining.succeeded && answeredSignature) {\n const remainingDuplicates = remaining.value.filter((item) => {\n if (item.id === validation.id) return false\n return questionInteractionContentSignature(interactionFromWireRequest(item)) === answeredSignature\n })\n for (const duplicate of remainingDuplicates) {\n const duplicateResult = await respondToSessionInteraction(connection, { id: duplicate.id, ...answerPayload })\n if (!duplicateResult.succeeded) break\n acknowledgedDuplicateIds.push(duplicate.id)\n }\n if (remainingDuplicates.length > 0) remaining = await listSessionInteractions(connection)\n }\n\n // Prove the run actually unblocked: neither the answered id nor any\n // content-duplicate may still be outstanding. If one is, the sidecar\n // accepted the POST but did not release the run — report it rather than\n // tell the user it was answered.\n if (remaining.succeeded && remaining.value.some((item) => item.id === validation.id || (\n answeredSignature && questionInteractionContentSignature(interactionFromWireRequest(item)) === answeredSignature\n ))) {\n logger.error('[interactions] respond returned ok but interaction is still pending:', {\n sessionId: connection.sessionId,\n interactionId: validation.id,\n })\n return Response.json(\n { code: 'INTERACTION_STILL_PENDING', error: 'The agent did not accept the answer. Try answering again.' },\n { status: 503 },\n )\n }\n\n if (options.durable && durableArgs) {\n try {\n await options.durable.acknowledge({\n ...durableArgs,\n prepared,\n duplicateIds: acknowledgedDuplicateIds,\n })\n await options.durable.finalize({\n ...durableArgs,\n prepared,\n duplicateIds: acknowledgedDuplicateIds,\n })\n } catch (error) {\n logger.error('[interactions] durable finalize failed:', error)\n return Response.json(\n { code: 'INTERACTION_FINALIZE_FAILED', error: 'The answer was accepted but is still being saved. Retry to reconcile it.' },\n { status: 503 },\n )\n }\n }\n\n return Response.json({ ok: true })\n }\n\n return { list, answer }\n}\n"],"mappings":";;;;;;;AAyCA,IAAM,qBAAqB;AAI3B,SAAS,wBAAwB,OAAwB;AACvD,QAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,SAAO,QACJ,QAAQ,qBAAqB,mBAAmB,EAChD,QAAQ,0CAA0C,gBAAgB;AACvE;AAEA,eAAe,kBACb,YACA,MAC6D;AAC7D,QAAM,UAAU,WAAW,aAAa;AACxC,QAAM,MAAM,GAAG,WAAW,WAAW,QAAQ,OAAO,EAAE,CAAC,oBAAoB,mBAAmB,WAAW,SAAS,CAAC;AACnH,MAAI;AACJ,MAAI;AACF,eAAW,MAAM,QAAQ,KAAK;AAAA,MAC5B,QAAQ,KAAK;AAAA,MACb,SAAS;AAAA,QACP,GAAI,WAAW,YAAY,EAAE,eAAe,UAAU,WAAW,SAAS,GAAG,IAAI,CAAC;AAAA,QAClF,GAAI,KAAK,WAAW,SAAS,EAAE,gBAAgB,mBAAmB,IAAI,CAAC;AAAA,MACzE;AAAA,MACA,GAAI,KAAK,WAAW,SAAS,EAAE,MAAM,KAAK,UAAU,KAAK,IAAI,EAAE,IAAI,CAAC;AAAA,MACpE,QAAQ,YAAY,QAAQ,WAAW,aAAa,kBAAkB;AAAA,IACxE,CAAC;AAAA,EACH,SAAS,KAAK;AACZ,WAAO;AAAA,MACL,WAAW;AAAA,MACX,OAAO,EAAE,MAAM,wBAAwB,SAAS,wBAAwB,GAAG,GAAG,QAAQ,EAAE;AAAA,IAC1F;AAAA,EACF;AACA,QAAM,MAAM,MAAM,SAAS,KAAK,EAAE,MAAM,MAAM,EAAE;AAChD,MAAI,SAAkC,CAAC;AACvC,MAAI;AACF,aAAS,MAAO,KAAK,MAAM,GAAG,IAAgC,CAAC;AAAA,EACjE,QAAQ;AAAA,EAER;AACA,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,gBAAiB,OAAO,SAAS,CAAC;AACxC,WAAO;AAAA,MACL,WAAW;AAAA,MACX,OAAO;AAAA,QACL,MAAM,OAAO,cAAc,SAAS,YAAY,cAAc,OAAO,cAAc,OAAO;AAAA,QAC1F,SAAS;AAAA,UACP,OAAO,cAAc,YAAY,YAAY,cAAc,UACvD,cAAc,UACd,wBAAwB,KAAK,MAAM,YAAY,SAAS,MAAM;AAAA,QACpE;AAAA,QACA,QAAQ,SAAS;AAAA,MACnB;AAAA,IACF;AAAA,EACF;AACA,SAAO,EAAE,WAAW,MAAM,OAAO,OAAO;AAC1C;AAIA,eAAsB,wBACpB,YAC8D;AAC9D,QAAM,SAAS,MAAM,kBAAkB,YAAY,EAAE,QAAQ,MAAM,CAAC;AACpE,MAAI,CAAC,OAAO,UAAW,QAAO;AAC9B,QAAM,OAAO,OAAO,MAAM;AAC1B,MAAI,CAAC,MAAM,QAAQ,MAAM,YAAY,GAAG;AACtC,WAAO;AAAA,MACL,WAAW;AAAA,MACX,OAAO,EAAE,MAAM,sBAAsB,SAAS,+CAA+C,QAAQ,IAAI;AAAA,IAC3G;AAAA,EACF;AACA,SAAO,EAAE,WAAW,MAAM,OAAO,KAAK,aAAyC;AACjF;AAKA,eAAsB,4BACpB,YACA,UAC0C;AAC1C,QAAM,SAAS,MAAM,kBAAkB,YAAY;AAAA,IACjD,QAAQ;AAAA,IACR,MAAM;AAAA,MACJ,IAAI,SAAS;AAAA,MACb,SAAS,SAAS;AAAA,MAClB,GAAI,SAAS,OAAO,EAAE,MAAM,SAAS,KAAK,IAAI,CAAC;AAAA,IACjD;AAAA,EACF,CAAC;AACD,MAAI,CAAC,OAAO,UAAW,QAAO;AAC9B,SAAO,EAAE,WAAW,MAAM,OAAO,OAAU;AAC7C;;;ACjFO,SAAS,8BAA8B,MAAgE;AAC5G,QAAM,KAAK,OAAO,KAAK,OAAO,YAAY,KAAK,KAAK,KAAK,KAAK;AAC9D,MAAI,CAAC,GAAI,QAAO,EAAE,IAAI,OAAO,OAAO,yBAAyB;AAC7D,QAAM,UAAU,KAAK;AACrB,MAAI,YAAY,cAAc,YAAY,YAAY;AACpD,WAAO,EAAE,IAAI,OAAO,OAAO,iDAAiD;AAAA,EAC9E;AACA,MAAI,KAAK,SAAS,OAAW,QAAO,EAAE,IAAI,MAAM,IAAI,QAAQ;AAC5D,MAAI,CAAC,KAAK,QAAQ,OAAO,KAAK,SAAS,YAAY,MAAM,QAAQ,KAAK,IAAI,GAAG;AAC3E,WAAO,EAAE,IAAI,OAAO,OAAO,mDAAmD;AAAA,EAChF;AACA,QAAM,OAAwB,CAAC;AAC/B,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,KAAK,IAAI,GAAG;AACpD,QAAI,CAAC,0BAA0B,GAAG,GAAG;AACnC,aAAO,EAAE,IAAI,OAAO,OAAO,wFAAwF;AAAA,IACrH;AACA,UAAM,aACJ,OAAO,UAAU,YAAY,OAAO,UAAU,YAAY,OAAO,UAAU,aAC1E,MAAM,QAAQ,KAAK,KAAK,MAAM,MAAM,CAAC,SAAS,OAAO,SAAS,QAAQ;AACzE,QAAI,CAAC,YAAY;AACf,aAAO,EAAE,IAAI,OAAO,OAAO,kFAAkF;AAAA,IAC/G;AACA,SAAK,GAAG,IAAI;AAAA,EACd;AACA,SAAO,EAAE,IAAI,MAAM,IAAI,SAAS,KAAK;AACvC;AAQO,SAAS,6BACd,OACA,SAAiC,SACvB;AACV,MAAI,MAAM,SAAS,8BAA8B;AAC/C,WAAO,SAAS;AAAA,MACd,EAAE,MAAM,8BAA8B,OAAO,2FAAsF;AAAA,MACnI,EAAE,QAAQ,IAAI;AAAA,IAChB;AAAA,EACF;AACA,MAAI,MAAM,WAAW,KAAK;AACxB,WAAO,SAAS;AAAA,MACd,EAAE,MAAM,uBAAuB,OAAO,oDAAoD;AAAA,MAC1F,EAAE,QAAQ,IAAI;AAAA,IAChB;AAAA,EACF;AACA,MAAI,MAAM,WAAW,OAAO,MAAM,SAAS,mBAAmB;AAC5D,WAAO,SAAS;AAAA,MACd,EAAE,MAAM,4BAA4B,OAAO,qDAAqD;AAAA,MAChG,EAAE,QAAQ,IAAI;AAAA,IAChB;AAAA,EACF;AACA,SAAO,MAAM,kCAAkC,KAAK;AACpD,SAAO,SAAS;AAAA,IACd,EAAE,MAAM,+BAA+B,OAAO,wCAAwC;AAAA,IACtF,EAAE,QAAQ,IAAI;AAAA,EAChB;AACF;AAgGO,SAAS,6BAA6B,SAAgE;AAC3G,QAAM,SAAS,QAAQ,UAAU;AAEjC,iBAAe,KAAK,SAAqC;AACvD,UAAM,aAAa,MAAM,QAAQ,kBAAkB,EAAE,SAAS,QAAQ,OAAO,CAAC;AAC9E,QAAI,CAAC,WAAW,IAAI;AAClB,UAAI,cAAc,WAAY,QAAO,WAAW;AAChD,aAAO,SAAS,KAAK,EAAE,cAAc,CAAC,GAAG,aAAa,WAAW,YAAY,CAAC;AAAA,IAChF;AACA,UAAM,SAAS,MAAM,wBAAwB,WAAW,UAAU;AAClE,QAAI,CAAC,OAAO,WAAW;AACrB,aAAO,KAAK,+BAA+B,OAAO,KAAK;AACvD,aAAO,SAAS,KAAK,EAAE,cAAc,CAAC,GAAG,aAAa,OAAO,MAAM,KAAK,CAAC;AAAA,IAC3E;AACA,WAAO,SAAS,KAAK,EAAE,cAAc,OAAO,MAAM,CAAC;AAAA,EACrD;AAEA,iBAAe,OAAO,SAAqC;AACzD,UAAM,OAAO,MAAM,QAAQ,KAAK,EAAE,MAAM,MAAM,IAAI;AAClD,QAAI,CAAC,QAAQ,OAAO,SAAS,YAAY,MAAM,QAAQ,IAAI,GAAG;AAC5D,aAAO,SAAS,KAAK,EAAE,OAAO,oBAAoB,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,IACtE;AACA,UAAM,aAAa,8BAA8B,IAAI;AACrD,QAAI,CAAC,WAAW,GAAI,QAAO,SAAS,KAAK,EAAE,OAAO,WAAW,MAAM,GAAG,EAAE,QAAQ,IAAI,CAAC;AACrF,UAAM,aAAa,OAAO,KAAK,eAAe,WAAW,KAAK,WAAW,KAAK,IAAI;AAClF,QAAI,QAAQ,WAAW,CAAC,YAAY;AAClC,aAAO,SAAS,KAAK,EAAE,OAAO,oDAAoD,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,IACtG;AAEA,UAAM,aAAa,MAAM,QAAQ,kBAAkB,EAAE,SAAS,QAAQ,UAAU,KAAK,CAAC;AACtF,QAAI,CAAC,WAAW,IAAI;AAClB,UAAI,cAAc,WAAY,QAAO,WAAW;AAChD,aAAO;AAAA,QACL,EAAE,MAAM,WAAW,aAAa,SAAS,+BAA+B,QAAQ,EAAE;AAAA,QAClF;AAAA,MACF;AAAA,IACF;AACA,UAAM,aAAa,WAAW;AAC9B,UAAM,gBAAgB;AAAA,MACpB,SAAS,WAAW;AAAA,MACpB,GAAI,WAAW,OAAO,EAAE,MAAM,WAAW,KAAK,IAAI,CAAC;AAAA,IACrD;AAKA,UAAM,SAAS,MAAM,wBAAwB,UAAU;AACvD,QAAI,CAAC,OAAO,cAAc,QAAQ,gBAAgB,QAAQ,UAAU;AAClE,aAAO,6BAA6B,OAAO,OAAO,MAAM;AAAA,IAC1D;AACA,UAAM,kBAAkB,OAAO,YAAY,OAAO,MAAM,KAAK,CAAC,SAAS,KAAK,OAAO,WAAW,EAAE,IAAI;AACpG,QAAI,QAAQ,gBAAgB,CAAC,QAAQ,WAAW,CAAC,iBAAiB;AAChE,aAAO;AAAA,QACL,EAAE,MAAM,aAAa,SAAS,yBAAyB,QAAQ,IAAI;AAAA,QACnE;AAAA,MACF;AAAA,IACF;AACA,UAAM,oBAAoB,kBACtB,oCAAoC,2BAA2B,eAAe,CAAC,IAC/E;AACJ,UAAM,oBAAoB,OAAO,aAAa,oBAC1C,OAAO,MAAM,OAAO,CAAC,SAAS,KAAK,OAAO,WAAW,MACnD,oCAAoC,2BAA2B,IAAI,CAAC,MAAM,iBAC3E,IACD,CAAC;AAEL,UAAM,gBAA6C;AAAA,MACjD;AAAA,MACA;AAAA,MACA,QAAQ;AAAA,MACR;AAAA,MACA,aAAa,OAAO,YAAY,OAAO,QAAQ,CAAC;AAAA,MAChD,GAAI,kBAAkB,EAAE,gBAAgB,IAAI,CAAC;AAAA,MAC7C;AAAA,IACF;AAEA,QAAI,QAAQ,gBAAgB,iBAAiB;AAC3C,UAAI;AACF,cAAM,QAAQ,aAAa,aAAa;AAAA,MAC1C,SAAS,OAAO;AACd,eAAO,MAAM,uCAAuC,KAAK;AACzD,eAAO,SAAS;AAAA,UACd,EAAE,MAAM,oCAAoC,OAAO,wCAAwC;AAAA,UAC3F,EAAE,QAAQ,IAAI;AAAA,QAChB;AAAA,MACF;AAAA,IACF;AAEA,QAAI;AACJ,UAAM,cAAc,QAAQ,UACxB,EAAE,GAAG,eAAe,WAAW,IAC/B;AACJ,QAAI,QAAQ,WAAW,aAAa;AAClC,UAAI;AACF,mBAAW,MAAM,QAAQ,QAAQ,QAAQ,WAAW;AAAA,MACtD,SAAS,OAAO;AACd,eAAO,MAAM,0CAA0C,KAAK;AAC5D,eAAO,SAAS;AAAA,UACd,EAAE,MAAM,8BAA8B,OAAO,2CAA2C;AAAA,UACxF,EAAE,QAAQ,IAAI;AAAA,QAChB;AAAA,MACF;AACA,UAAI,CAAC,iBAAiB;AACpB,YAAI;AACJ,YAAI;AACF,uBAAa,MAAM,QAAQ,QAAQ,UAAU,EAAE,GAAG,aAAa,SAAS,CAAC;AAAA,QAC3E,SAAS,OAAO;AACd,iBAAO,MAAM,4CAA4C,KAAK;AAC9D,uBAAa,EAAE,SAAS,MAAM;AAAA,QAChC;AACA,YAAI,WAAW,QAAS,QAAO,SAAS,KAAK,EAAE,IAAI,MAAM,YAAY,KAAK,CAAC;AAC3E,eAAO,SAAS;AAAA,UACd,EAAE,MAAM,sCAAsC,OAAO,yEAAyE;AAAA,UAC9H,EAAE,QAAQ,IAAI;AAAA,QAChB;AAAA,MACF;AAAA,IACF;AAEA,UAAM,SAAS,MAAM,4BAA4B,YAAY,EAAE,IAAI,WAAW,IAAI,GAAG,cAAc,CAAC;AACpG,QAAI,CAAC,OAAO,WAAW;AACrB,UAAI,QAAQ,WAAW,aAAa;AAClC,YAAI;AACJ,YAAI;AACF,uBAAa,MAAM,QAAQ,QAAQ,UAAU,EAAE,GAAG,aAAa,SAAS,CAAC;AAAA,QAC3E,QAAQ;AACN,uBAAa,EAAE,SAAS,MAAM;AAAA,QAChC;AACA,YAAI,WAAW,QAAS,QAAO,SAAS,KAAK,EAAE,IAAI,MAAM,YAAY,KAAK,CAAC;AAC3E,YAAI,OAAO,MAAM,WAAW,KAAK;AAC/B,iBAAO,SAAS;AAAA,YACd,EAAE,MAAM,sCAAsC,OAAO,yEAAyE;AAAA,YAC9H,EAAE,QAAQ,IAAI;AAAA,UAChB;AAAA,QACF;AACA,YAAI;AACF,gBAAM,QAAQ,QAAQ,OAAO,EAAE,GAAG,aAAa,UAAU,OAAO,OAAO,MAAM,CAAC;AAAA,QAChF,QAAQ;AAAA,QAGR;AAAA,MACF;AACA,aAAO,6BAA6B,OAAO,OAAO,MAAM;AAAA,IAC1D;AAEA,QAAI,YAAY,MAAM,wBAAwB,UAAU;AACxD,UAAM,2BAAqC,CAAC;AAC5C,QAAI,UAAU,aAAa,mBAAmB;AAC5C,YAAM,sBAAsB,UAAU,MAAM,OAAO,CAAC,SAAS;AAC3D,YAAI,KAAK,OAAO,WAAW,GAAI,QAAO;AACtC,eAAO,oCAAoC,2BAA2B,IAAI,CAAC,MAAM;AAAA,MACnF,CAAC;AACD,iBAAW,aAAa,qBAAqB;AAC3C,cAAM,kBAAkB,MAAM,4BAA4B,YAAY,EAAE,IAAI,UAAU,IAAI,GAAG,cAAc,CAAC;AAC5G,YAAI,CAAC,gBAAgB,UAAW;AAChC,iCAAyB,KAAK,UAAU,EAAE;AAAA,MAC5C;AACA,UAAI,oBAAoB,SAAS,EAAG,aAAY,MAAM,wBAAwB,UAAU;AAAA,IAC1F;AAMA,QAAI,UAAU,aAAa,UAAU,MAAM,KAAK,CAAC,SAAS,KAAK,OAAO,WAAW,MAC/E,qBAAqB,oCAAoC,2BAA2B,IAAI,CAAC,MAAM,iBAChG,GAAG;AACF,aAAO,MAAM,wEAAwE;AAAA,QACnF,WAAW,WAAW;AAAA,QACtB,eAAe,WAAW;AAAA,MAC5B,CAAC;AACD,aAAO,SAAS;AAAA,QACd,EAAE,MAAM,6BAA6B,OAAO,4DAA4D;AAAA,QACxG,EAAE,QAAQ,IAAI;AAAA,MAChB;AAAA,IACF;AAEA,QAAI,QAAQ,WAAW,aAAa;AAClC,UAAI;AACF,cAAM,QAAQ,QAAQ,YAAY;AAAA,UAChC,GAAG;AAAA,UACH;AAAA,UACA,cAAc;AAAA,QAChB,CAAC;AACD,cAAM,QAAQ,QAAQ,SAAS;AAAA,UAC7B,GAAG;AAAA,UACH;AAAA,UACA,cAAc;AAAA,QAChB,CAAC;AAAA,MACH,SAAS,OAAO;AACd,eAAO,MAAM,2CAA2C,KAAK;AAC7D,eAAO,SAAS;AAAA,UACd,EAAE,MAAM,+BAA+B,OAAO,2EAA2E;AAAA,UACzH,EAAE,QAAQ,IAAI;AAAA,QAChB;AAAA,MACF;AAAA,IACF;AAEA,WAAO,SAAS,KAAK,EAAE,IAAI,KAAK,CAAC;AAAA,EACnC;AAEA,SAAO,EAAE,MAAM,OAAO;AACxB;","names":[]}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|