zidane 8.2.3 → 8.2.5
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/{acp-oYRjlh71.js → acp-BIInKhVI.js} +6 -6
- package/dist/{acp-oYRjlh71.js.map → acp-BIInKhVI.js.map} +1 -1
- package/dist/acp-cli.js +4 -4
- package/dist/acp.d.ts +2 -2
- package/dist/acp.js +1 -1
- package/dist/{agent-CBQglXtH.js → agent-CmhCOmyO.js} +10 -5
- package/dist/{agent-CBQglXtH.js.map → agent-CmhCOmyO.js.map} +1 -1
- package/dist/agent.d.ts +1 -1
- package/dist/agent.js +1 -1
- package/dist/chat/pure.d.ts +4 -4
- package/dist/chat/pure.js +7 -7
- package/dist/chat.d.ts +3 -3
- package/dist/chat.js +16 -16
- package/dist/{cli-shared-E5m_pI8A.js → cli-shared-GOehTeqk.js} +2 -2
- package/dist/{cli-shared-E5m_pI8A.js.map → cli-shared-GOehTeqk.js.map} +1 -1
- package/dist/{client-core-EEEX_u6D.d.ts → client-core-Dz8hELs4.d.ts} +15 -5
- package/dist/client-core-Dz8hELs4.d.ts.map +1 -0
- package/dist/codemode-worker.js +1 -1
- package/dist/codemode.js +1 -1
- package/dist/{connection-loop-CpgfUmuw.d.ts → connection-loop-dm_TN-QD.d.ts} +3 -3
- package/dist/{connection-loop-CpgfUmuw.d.ts.map → connection-loop-dm_TN-QD.d.ts.map} +1 -1
- package/dist/contexts/daytona.d.ts +1 -1
- package/dist/contexts/e2b.d.ts +1 -1
- package/dist/{credentials-B9DfBJP9.js → credentials-DxOQmset.js} +2 -2
- package/dist/{credentials-B9DfBJP9.js.map → credentials-DxOQmset.js.map} +1 -1
- package/dist/daemon-cli.js +2 -2
- package/dist/{dispatcher-Bv9-c6I2.js → dispatcher-D_9_QFO3.js} +22 -18
- package/dist/dispatcher-D_9_QFO3.js.map +1 -0
- package/dist/{engine-XmoPPB6U.js → engine-BsWBWgTB.js} +6 -6
- package/dist/{engine-XmoPPB6U.js.map → engine-BsWBWgTB.js.map} +1 -1
- package/dist/{eval-CfQlBR81.js → eval-CIHIF_Ns.js} +3 -3
- package/dist/{eval-CfQlBR81.js.map → eval-CIHIF_Ns.js.map} +1 -1
- package/dist/eval.d.ts +1 -1
- package/dist/eval.js +1 -1
- package/dist/{executor-BhthPE1q.js → executor-BSesPPcU.js} +3 -3
- package/dist/{executor-BhthPE1q.js.map → executor-BSesPPcU.js.map} +1 -1
- package/dist/{extensions-BgBwogRW.js → extensions-BJof-2mi.js} +3 -3
- package/dist/{extensions-BgBwogRW.js.map → extensions-BJof-2mi.js.map} +1 -1
- package/dist/extensions.d.ts +1 -1
- package/dist/extensions.js +1 -1
- package/dist/{fold-rules-DSypi36k.d.ts → fold-rules-CMpWNPqk.d.ts} +2 -2
- package/dist/{fold-rules-DSypi36k.d.ts.map → fold-rules-CMpWNPqk.d.ts.map} +1 -1
- package/dist/{headless-R4pbpTkm.js → headless-Bs9Lb4vs.js} +4 -4
- package/dist/{headless-R4pbpTkm.js.map → headless-Bs9Lb4vs.js.map} +1 -1
- package/dist/headless.d.ts +1 -1
- package/dist/headless.js +1 -1
- package/dist/history-worker.js +1 -1
- package/dist/{host-scoped-settings-C-Nmb6vr.js → host-scoped-settings-DxxI_yRo.js} +2 -2
- package/dist/{host-scoped-settings-C-Nmb6vr.js.map → host-scoped-settings-DxxI_yRo.js.map} +1 -1
- package/dist/{host-signals-BFudPyCT.js → host-signals-CUKPZZxC.js} +5 -5
- package/dist/{host-signals-BFudPyCT.js.map → host-signals-CUKPZZxC.js.map} +1 -1
- package/dist/{index-DyQyDLX1.d.ts → index-4mDRyTGJ.d.ts} +1722 -1691
- package/dist/index-4mDRyTGJ.d.ts.map +1 -0
- package/dist/{index-CDS7YdUC.d.ts → index-Dlmu8HnG.d.ts} +5 -5
- package/dist/{index-CDS7YdUC.d.ts.map → index-Dlmu8HnG.d.ts.map} +1 -1
- package/dist/{index-AqRZ3gEz.d.ts → index-QsAN9yjZ.d.ts} +3 -3
- package/dist/{index-AqRZ3gEz.d.ts.map → index-QsAN9yjZ.d.ts.map} +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +8 -8
- package/dist/ipc/remote.d.ts +5 -5
- package/dist/ipc/remote.js +3 -3
- package/dist/ipc.d.ts +5 -5
- package/dist/ipc.js +9 -9
- package/dist/{links-rFaWqS2Y.js → links-Bto-5dVu.js} +10 -10
- package/dist/{links-rFaWqS2Y.js.map → links-Bto-5dVu.js.map} +1 -1
- package/dist/{mcp-allowlist-CLXweyxk.js → mcp-allowlist-BbnTBKNN.js} +2 -2
- package/dist/{mcp-allowlist-CLXweyxk.js.map → mcp-allowlist-BbnTBKNN.js.map} +1 -1
- package/dist/mcp.d.ts +1 -1
- package/dist/{oauth-7_48zR7n.js → oauth-BwPiX0hL.js} +66 -32
- package/dist/oauth-BwPiX0hL.js.map +1 -0
- package/dist/output/stream-json.d.ts +1 -1
- package/dist/output/terminal.d.ts +1 -1
- package/dist/plugins.d.ts +1 -1
- package/dist/{prelude-HzY_JEGq.js → prelude-qjPUkw4f.js} +26 -2
- package/dist/prelude-qjPUkw4f.js.map +1 -0
- package/dist/{presets-DXeHsd24.js → presets-C4hkykN-.js} +2 -2
- package/dist/{presets-DXeHsd24.js.map → presets-C4hkykN-.js.map} +1 -1
- package/dist/presets.d.ts +1 -1
- package/dist/presets.js +1 -1
- package/dist/{protocol-BIv1Yuvl.js → protocol-Do_i6Ras.js} +3 -1
- package/dist/protocol-Do_i6Ras.js.map +1 -0
- package/dist/providers/anthropic.d.ts +1 -1
- package/dist/providers/arcee.d.ts +1 -1
- package/dist/providers/baseten.d.ts +1 -1
- package/dist/providers/cerebras.d.ts +1 -1
- package/dist/providers/google.d.ts +1 -1
- package/dist/providers/local.d.ts +1 -1
- package/dist/providers/neuralwatt.d.ts +1 -1
- package/dist/providers/openai-compat.d.ts +1 -1
- package/dist/providers/openai.d.ts +1 -1
- package/dist/providers/openrouter.d.ts +1 -1
- package/dist/providers/xai.d.ts +1 -1
- package/dist/providers.d.ts +1 -1
- package/dist/{registry-eourRLY2.js → registry-DxPP_tAt.js} +3 -3
- package/dist/{registry-eourRLY2.js.map → registry-DxPP_tAt.js.map} +1 -1
- package/dist/{remote-hosts-DY2J07ut.js → remote-hosts-DcCh7fqp.js} +4 -4
- package/dist/{remote-hosts-DY2J07ut.js.map → remote-hosts-DcCh7fqp.js.map} +1 -1
- package/dist/restate.d.ts +1 -1
- package/dist/{secret-shapes-BjW4l6U0.js → secret-shapes-HvaYVzwc.js} +10 -2
- package/dist/secret-shapes-HvaYVzwc.js.map +1 -0
- package/dist/session/sqlite.d.ts +1 -1
- package/dist/{session-7TUHs42_.js → session-CCsKXID6.js} +6 -2
- package/dist/session-CCsKXID6.js.map +1 -0
- package/dist/{session-factory-CMwIXE-7.js → session-factory-Ct7J9CK1.js} +6 -6
- package/dist/{session-factory-CMwIXE-7.js.map → session-factory-Ct7J9CK1.js.map} +1 -1
- package/dist/session.d.ts +2 -2
- package/dist/session.js +1 -1
- package/dist/{settings-keys-CPdmkTz7.js → settings-keys-CnrJgT1T.js} +4 -4
- package/dist/{settings-keys-CPdmkTz7.js.map → settings-keys-CnrJgT1T.js.map} +1 -1
- package/dist/{shell-path-B8b3EOtK.js → shell-path-rJDa0OMv.js} +4 -4
- package/dist/{shell-path-B8b3EOtK.js.map → shell-path-rJDa0OMv.js.map} +1 -1
- package/dist/skills.d.ts +1 -1
- package/dist/{spaces-CyjMh5Zf.js → spaces-C_x2bvEl.js} +14 -4
- package/dist/spaces-C_x2bvEl.js.map +1 -0
- package/dist/{store-L01W0gGI.js → store-BpkWIaSH.js} +10 -30
- package/dist/store-BpkWIaSH.js.map +1 -0
- package/dist/{todo-edits-BERpCRPj.js → todo-edits-DKoxu7Ss.js} +3 -3
- package/dist/{todo-edits-BERpCRPj.js.map → todo-edits-DKoxu7Ss.js.map} +1 -1
- package/dist/tools/fetch-url.d.ts +1 -1
- package/dist/tools/web-search.d.ts +1 -1
- package/dist/{tools-pZVFIJ_K.js → tools-FHEIKGkh.js} +2 -2
- package/dist/{tools-pZVFIJ_K.js.map → tools-FHEIKGkh.js.map} +1 -1
- package/dist/tools.d.ts +1 -1
- package/dist/tools.js +2 -2
- package/dist/{transcript-anchors-jHrg-r-H.js → transcript-anchors-BcFLh3ZA.js} +10 -10
- package/dist/{transcript-anchors-jHrg-r-H.js.map → transcript-anchors-BcFLh3ZA.js.map} +1 -1
- package/dist/{transcript-cache-DXdgVuoy.js → transcript-cache-CdHKtx9y.js} +4 -4
- package/dist/{transcript-cache-DXdgVuoy.js.map → transcript-cache-CdHKtx9y.js.map} +1 -1
- package/dist/{transcript-reconcile-CPdrNbbR.js → transcript-reconcile-D_SWw6dX.js} +11 -3
- package/dist/transcript-reconcile-D_SWw6dX.js.map +1 -0
- package/dist/tui.d.ts +7 -7
- package/dist/tui.js +24 -23
- package/dist/tui.js.map +1 -1
- package/dist/{turn-operations-DuGtKuc_.d.ts → turn-operations-Dbk3xPKu.d.ts} +11 -3
- package/dist/{turn-operations-DuGtKuc_.d.ts.map → turn-operations-Dbk3xPKu.d.ts.map} +1 -1
- package/dist/{types-C0PJmBaO.d.ts → types-CMXR7A0b.d.ts} +2 -2
- package/dist/{types-C0PJmBaO.d.ts.map → types-CMXR7A0b.d.ts.map} +1 -1
- package/dist/types-CzmghX7C.js.map +1 -1
- package/dist/types.d.ts +2 -2
- package/dist/{url-D8KZ7Edw.js → url-D4vG7lzO.js} +2 -2
- package/dist/{url-D8KZ7Edw.js.map → url-D4vG7lzO.js.map} +1 -1
- package/dist/{version-bd3DQJkc.js → version-DOvIuU8M.js} +2 -2
- package/dist/{version-bd3DQJkc.js.map → version-DOvIuU8M.js.map} +1 -1
- package/dist/{workspace-exec-stream-CyfYgqAh.js → workspace-exec-stream-Bzxczzu2.js} +5 -5
- package/dist/{workspace-exec-stream-CyfYgqAh.js.map → workspace-exec-stream-Bzxczzu2.js.map} +1 -1
- package/dist/{write-file-QYrcDdl3.js → write-file-ChtRPdEL.js} +3 -3
- package/dist/{write-file-QYrcDdl3.js.map → write-file-ChtRPdEL.js.map} +1 -1
- package/dist/{ws-CURQ2igk.js → ws-CrD-4Mx6.js} +6 -6
- package/dist/{ws-CURQ2igk.js.map → ws-CrD-4Mx6.js.map} +1 -1
- package/dist/{ws-client-BVljYbdb.js → ws-client-Dond8vT3.js} +4 -4
- package/dist/{ws-client-BVljYbdb.js.map → ws-client-Dond8vT3.js.map} +1 -1
- package/docs/CODEMODE.md +6 -0
- package/docs/IPC.md +2 -0
- package/docs/ONBOARDING.md +1 -1
- package/package.json +1 -1
- package/dist/client-core-EEEX_u6D.d.ts.map +0 -1
- package/dist/dispatcher-Bv9-c6I2.js.map +0 -1
- package/dist/index-DyQyDLX1.d.ts.map +0 -1
- package/dist/oauth-7_48zR7n.js.map +0 -1
- package/dist/prelude-HzY_JEGq.js.map +0 -1
- package/dist/protocol-BIv1Yuvl.js.map +0 -1
- package/dist/secret-shapes-BjW4l6U0.js.map +0 -1
- package/dist/session-7TUHs42_.js.map +0 -1
- package/dist/spaces-CyjMh5Zf.js.map +0 -1
- package/dist/store-L01W0gGI.js.map +0 -1
- package/dist/transcript-reconcile-CPdrNbbR.js.map +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { o as loadSession } from "./session-
|
|
2
|
-
import { h as replayTurns } from "./store-
|
|
3
|
-
import { r as LOAD_EVENTS_MAX_PAGE_TURNS } from "./protocol-
|
|
1
|
+
import { o as loadSession } from "./session-CCsKXID6.js";
|
|
2
|
+
import { h as replayTurns } from "./store-BpkWIaSH.js";
|
|
3
|
+
import { r as LOAD_EVENTS_MAX_PAGE_TURNS } from "./protocol-Do_i6Ras.js";
|
|
4
4
|
//#region src/ipc/daemon/handlers/params.ts
|
|
5
5
|
/**
|
|
6
6
|
* Shape checks for request params: they arrive as untrusted JSON (the
|
|
@@ -402,4 +402,4 @@ function fingerprint(updatedAt, turns, runs) {
|
|
|
402
402
|
//#endregion
|
|
403
403
|
export { isPagedLoad as a, loadOrThrow as c, nonNegativeInt as d, optionalString as f, exchangeBoundaries as i, InvalidParamsError as l, createTranscriptReplayCache as n, transcriptPage as o, sessionIdOf as p, WHOLE_RUN_PAGES as r, turnCutPoints as s, changedSessionOf as t, checkParams as u };
|
|
404
404
|
|
|
405
|
-
//# sourceMappingURL=transcript-cache-
|
|
405
|
+
//# sourceMappingURL=transcript-cache-CdHKtx9y.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transcript-cache-DXdgVuoy.js","names":[],"sources":["../src/ipc/daemon/handlers/params.ts","../src/ipc/daemon/handlers/session-load.ts","../src/ipc/daemon/handlers/transcript-page.ts","../src/ipc/daemon/handlers/transcript-cache.ts"],"sourcesContent":["/**\n * Shape checks for request params: they arrive as untrusted JSON (the\n * `IpcMethods` types are not a runtime guarantee). The dispatcher runs\n * {@link checkParams} on every request and notification before its handler;\n * handlers use the field checks for what they require. A failed check is an\n * {@link InvalidParamsError}, answered as JSON-RPC \"invalid params\".\n */\n\nexport class InvalidParamsError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'InvalidParamsError'\n }\n}\n\n/** Longest session id accepted (minted ids are under 64 characters). */\nconst MAX_SESSION_ID_LENGTH = 1024\n\n/**\n * A session id: a non-empty string that is one plain path segment. Ids name\n * directories on disk (`<data dir>/sessions/<id>/`, removed recursively on\n * delete), so `..`, separators and NUL are refused.\n */\nexport function checkSessionId(value: unknown, name = 'sessionId'): string {\n if (typeof value !== 'string' || value.length === 0 || value.length > MAX_SESSION_ID_LENGTH)\n throw new InvalidParamsError(`${name} must be a non-empty string of at most ${MAX_SESSION_ID_LENGTH} characters.`)\n if (value === '.' || value === '..' || /[/\\\\\\0]/.test(value))\n throw new InvalidParamsError(`${name} must not be a path (no \"/\", \"\\\\\", \".\" or \"..\").`)\n return value\n}\n\n/** The required `sessionId` of `params`. */\nexport function sessionIdOf(params: { sessionId?: unknown } | null | undefined): string {\n return checkSessionId(params?.sessionId)\n}\n\n/** An optional non-negative integer; `undefined` when absent. */\nexport function nonNegativeInt(value: unknown, name: string): number | undefined {\n if (value === undefined)\n return undefined\n if (typeof value !== 'number' || !Number.isSafeInteger(value) || value < 0)\n throw new InvalidParamsError(`${name} must be a non-negative integer.`)\n return value\n}\n\n/** An optional string; `undefined` when absent. */\nexport function optionalString(value: unknown, name: string): string | undefined {\n if (value !== undefined && typeof value !== 'string')\n throw new InvalidParamsError(`${name} must be a string.`)\n return value\n}\n\n/**\n * What every method's params must be: absent, `null`, or an object (never an\n * array or a scalar), whose `sessionId` / `sessionIds`, when present, name\n * sessions ({@link checkSessionId}).\n */\nexport function checkParams(params: unknown): void {\n if (params === undefined || params === null)\n return\n if (typeof params !== 'object' || Array.isArray(params))\n throw new InvalidParamsError('params must be an object.')\n const { sessionId, sessionIds } = params as { sessionId?: unknown, sessionIds?: unknown }\n if (sessionId !== undefined)\n checkSessionId(sessionId)\n if (sessionIds !== undefined) {\n if (!Array.isArray(sessionIds))\n throw new InvalidParamsError('sessionIds must be an array.')\n for (const id of sessionIds)\n checkSessionId(id, 'sessionIds[]')\n }\n}\n","/** A stored session or a \"not found\" error: kept apart from `./sessions` so the history worker loads without the chat host's graph. */\nimport type { SessionData, SessionStore } from '../../../session/index'\n\nexport async function loadOrThrow(store: Pick<SessionStore, 'load'>, sessionId: string): Promise<SessionData> {\n const data = await store.load(sessionId)\n if (!data)\n throw new Error(`Session \"${sessionId}\" not found.`)\n return data\n}\n","/**\n * One page of a transcript for `sessions.loadEvents` paging, in whole runs:\n * everything from a user message to the turn before the next one. The run\n * the page ends in is always whole, and the runs before it join while the\n * page stays within `limit` turns, so scrolling back brings the previous\n * run (or a few small ones) at a time, never part of one. A run longer than\n * {@link WHOLE_RUN_PAGES} pages on its own is the one exception: it comes in\n * pieces of that size, each starting on a turn that keeps a tool call with\n * its result. The GUI's local pager cuts with the same rule.\n */\nimport type { SessionRun } from '../../../session/index'\nimport type { SessionTurn } from '../../../types'\nimport type { LoadEventsPaging } from '../../protocol'\nimport { LOAD_EVENTS_MAX_PAGE_TURNS, LOAD_EVENTS_PAGE_TURNS } from '../../protocol'\nimport { InvalidParamsError, nonNegativeInt, optionalString } from './params'\n\n/**\n * A run longer than this many pages is split (by `limit`, so the client's\n * halving retry on a reply too large still converges).\n */\nexport const WHOLE_RUN_PAGES = 5\n\nexport function isPagedLoad(p: LoadEventsPaging | undefined): boolean {\n return p?.before !== undefined || p?.limit !== undefined || p?.beforeTurnId !== undefined\n}\n\n/**\n * Per turn: does a run start there (a parent-run user turn carrying no tool result)?\n * @param turns - Turns of the session, in order.\n * @param runs - Runs of the session, used to tell child runs from parent runs.\n * @returns One flag per turn.\n */\nexport function exchangeBoundaries(turns: readonly SessionTurn[], runs: readonly SessionRun[]): boolean[] {\n const childRuns = new Set(runs.filter(run => (run.depth ?? 0) > 0 || run.parentRunId !== undefined).map(run => run.id))\n return turns.map(turn => turn.role === 'user'\n && !(turn.runId !== undefined && childRuns.has(turn.runId))\n && !turn.content.some(block => block.type === 'tool_result'))\n}\n\n/**\n * Per turn: can a page start there without leaving a tool call's result behind (not a tool-result turn)?\n * @param turns - Turns of the session, in order.\n * @returns One flag per turn.\n */\nexport function turnCutPoints(turns: readonly SessionTurn[]): boolean[] {\n return turns.map(turn => !(turn.role === 'user' && turn.content.some(block => block.type === 'tool_result')))\n}\n\n/**\n * `[from, to)` of the page, and the cursor of the one before it, over the\n * turns' {@link exchangeBoundaries} (run starts) and {@link turnCutPoints}\n * (where a run too long to send whole may be split; run starts when absent).\n * @param boundaries - Run starts per turn, from {@link exchangeBoundaries}.\n * @param paging - The `before` cursor and `limit` of the request.\n * @param cuts - Allowed cut points per turn, from {@link turnCutPoints}.\n * @param turnIds - Id per turn: where a `beforeTurnId` anchor sits (it wins over `before`).\n * @returns The turn range of the page and the cursor of the page before it.\n */\nexport function transcriptPage(\n boundaries: readonly boolean[],\n paging: LoadEventsPaging,\n cuts: readonly boolean[] = boundaries,\n turnIds?: readonly string[],\n): { from: number, to: number, cursor?: number } {\n const before = anchorIndex(paging.beforeTurnId, turnIds) ?? nonNegativeInt(paging.before, 'before')\n const limit = Math.min(Math.max(nonNegativeInt(paging.limit, 'limit') ?? LOAD_EVENTS_PAGE_TURNS, 1), LOAD_EVENTS_MAX_PAGE_TURNS)\n const to = Math.min(before ?? boundaries.length, boundaries.length)\n if (to === 0)\n return { from: 0, to: 0 }\n /** Where the run holding turn `end - 1` starts (0 when no run start precedes it). */\n const runStart = (end: number): number => {\n let i = end - 1\n while (i > 0 && !boundaries[i])\n i--\n return i\n }\n let from = runStart(to)\n const ceiling = limit * WHOLE_RUN_PAGES\n if (to - from > ceiling) {\n // One run too long to send whole: its last `ceiling` turns, from a turn\n // that keeps a tool call with its result.\n from = to - ceiling\n while (from < to - 1 && !cuts[from])\n from++\n }\n else {\n // The runs before it too, whole, while the page stays within `limit`.\n while (from > 0) {\n const previous = runStart(from)\n if (to - previous > limit)\n break\n from = previous\n }\n }\n return { from, to, ...(from > 0 ? { cursor: from } : {}) }\n}\n\n/** The position of the turn `beforeTurnId` names; `undefined` without one. A turn the transcript doesn't hold is invalid params. */\nfunction anchorIndex(beforeTurnId: unknown, turnIds: readonly string[] | undefined): number | undefined {\n const anchor = optionalString(beforeTurnId, 'beforeTurnId')\n if (anchor === undefined)\n return undefined\n const at = turnIds?.indexOf(anchor) ?? -1\n if (at < 0)\n throw new InvalidParamsError(`beforeTurnId \"${anchor.slice(0, 128)}\" is not a turn of this session.`)\n return at\n}\n","/**\n * Whole-session reads a client pages through, kept per session content\n * version so N pages cost one read of the session, not N:\n *\n * - the replay behind `sessions.loadEvents` pages (each page is a slice of\n * the WHOLE replay: see `replayTurns`);\n * - the document behind `sessions.getTurns` pages and the `sessions.get`\n * `turns: false` head (`document`): loaded, healed and copied once.\n * Every page carries its version, so a client that sees it change\n * mid-load starts over instead of mixing two versions\n * (`loadSessionDocument`).\n *\n * The version: a store with `getMeta` answers it without parsing turns\n * (its change counter `rev`, `updatedAt`, the turn and run counts; a hit\n * then skips the load too). `rev` grows on every write, so a version never\n * comes back after a change, whatever `updatedAt` a writer stamps (another\n * process on the same sessions.db included, which no host signal covers).\n * The version is read again after a miss's load: when it moved meanwhile,\n * what was loaded is of no known version, so it is served under a label no\n * other read gets, and not kept. A store without `rev` keeps the older\n * rule: a version stamped in the millisecond the read started is served\n * but not kept. Any other store's loaded document is fingerprinted (turn\n * ids, roles, block shapes and text lengths, the runs), and so is a live\n * session's in-memory copy (plus its metadata and status). The host's own\n * writes also drop entries by their signals (`observe`), which covers the\n * edits a version cannot see.\n *\n * A client that pages a session itself (the GUI main process over its own\n * store: `replay`) shares this cache with its own load, a version variant\n * for what else that load depends on, and background reads that never evict.\n *\n * Bounded: a few sessions per kind, least recently used first out, and a\n * byte budget (an entry over it is served, not kept). Besides the entries,\n * a session is tracked only while a read of it is in flight (so a drop\n * meanwhile stops that read's result from being kept): a session that is\n * dropped, forgotten or signalled leaves nothing behind.\n */\nimport type { StreamEvent } from '../../../chat/index'\nimport type { Session, SessionData, SessionRun, SessionStore } from '../../../session/index'\nimport type { SessionTurn } from '../../../types'\nimport type { HostSignal, LoadEventsPaging, SessionEventsPage } from '../../protocol'\nimport { replayTurns } from '../../../chat/store'\nimport { loadSession } from '../../../session/index'\nimport { loadOrThrow } from './session-load'\nimport { exchangeBoundaries, transcriptPage, turnCutPoints } from './transcript-page'\n\nconst DEFAULT_MAX_SESSIONS = 4\nconst DEFAULT_MAX_BYTES = 64 * 1024 * 1024\n\n/** Signals that follow a change to a session's turns or runs. */\nconst CHANGE_SIGNALS = new Set<HostSignal['kind']>(['sessions:changed', 'run:start', 'run:end', 'turn:end', 'compacting:end', 'prompt-turns'])\n\ninterface Versioned {\n version: string\n bytes: number\n}\n\n/** A whole-session replay: pages are `transcriptPage` slices of it. */\nexport interface TranscriptReplay extends Versioned {\n /** Every turn's events, in order: what a whole `sessions.loadEvents` returns. */\n events: StreamEvent[]\n /** Where each turn's events start (`[turns]` = the end). */\n turnStarts: number[]\n /** Where each run starts (`exchangeBoundaries`): where a page may start. */\n boundaries: boolean[]\n /** Where a run too long for one page may be split (`turnCutPoints`). */\n cuts: boolean[]\n /** Each turn's id: where a `beforeTurnId` anchor sits. */\n turnIds: string[]\n /** The loaded `seqs`, when the load gave them. */\n seqs?: number[]\n}\n\n/** What a client's own load gives `replay`. */\nexport interface ReplayData {\n /** The session's turns, in order. */\n turns: SessionTurn[]\n /** The session's runs (they tell child runs from parent runs). */\n runs: SessionRun[]\n /** A per-turn position the client keeps with the replay (the GUI store's `seq`). */\n seqs?: number[]\n}\n\n/** A client's own read of a stored session, for `replay`. */\nexport interface ReplayRead {\n /** Loads the session on a miss; `null` when it is unknown. */\n load: () => Promise<ReplayData | null> | ReplayData | null\n /** Appended to the version: what else the load depends on. */\n variant?: string\n /** A read ahead of the user: a hit leaves the order as is, a miss is kept only when that evicts nothing. */\n background?: boolean\n}\n\ninterface ReadOptions {\n variant?: string\n background?: boolean\n}\n\n/** One version of a session's document, as `sessions.get` would send it. */\nexport interface DocumentSnapshot extends Versioned {\n data: SessionData\n}\n\n/** Whole-session replays and documents, kept per session version (see the module header). */\nexport interface TranscriptReplayCache {\n /** One `sessions.loadEvents` page of a stored session, sliced from its replay. Throws when the session is unknown, `InvalidParamsError` for bad paging. */\n page: (store: Pick<SessionStore, 'load' | 'getMeta'>, sessionId: string, paging: LoadEventsPaging) => Promise<SessionEventsPage>\n /** A stored session's replay from the client's own `read.load`, versioned like `page`'s; `null` when unknown. */\n replay: (store: Pick<SessionStore, 'getMeta'>, sessionId: string, read: ReplayRead) => Promise<TranscriptReplay | null>\n /** The replay kept for a session, whatever its version; `touch` counts it as used. */\n cached: (sessionId: string, touch?: boolean) => TranscriptReplay | undefined\n /** The document (the live copy when `live` is given, else the stored one, healed in memory), and its version; `null` when unknown. */\n document: (store: SessionStore, sessionId: string, live: Session | null) => Promise<DocumentSnapshot | null>\n /** A host signal: one that follows a change to a session drops its entries. */\n observe: (signal: HostSignal) => void\n /** Drops the session's entries (it is gone); a read in flight is served but not kept. */\n forget: (sessionId: string) => void\n /** Entries kept and sessions with a read in flight, across both kinds: what the cache holds. */\n sizes: () => { entries: number, inFlight: number }\n}\n\n/** The session a host signal says changed (its turns or runs), if any: its cached entries are stale. */\nexport function changedSessionOf(signal: HostSignal): string | undefined {\n return CHANGE_SIGNALS.has(signal.kind) && 'sessionId' in signal && typeof signal.sessionId === 'string' ? signal.sessionId : undefined\n}\n\n/** A read in flight: a drop of its session meanwhile marks it, and its result is then served but not kept. */\ninterface InFlightRead { dropped: boolean }\n\n/** One kind of entry (replays, documents): LRU by insertion order, bounded by count and bytes. */\nfunction createLru<T extends Versioned>(maxSessions: number, maxBytes: number) {\n const entries = new Map<string, T>()\n let totalBytes = 0\n const drop = (sessionId: string): void => {\n const entry = entries.get(sessionId)\n if (entry) {\n totalBytes -= entry.bytes\n entries.delete(sessionId)\n }\n }\n return {\n size: () => entries.size,\n peek(sessionId: string, touch: boolean): T | undefined {\n const entry = entries.get(sessionId)\n if (entry && touch) {\n entries.delete(sessionId)\n entries.set(sessionId, entry)\n }\n return entry\n },\n hit(sessionId: string, version: string, touch = true): T | undefined {\n const entry = entries.get(sessionId)\n if (!entry || entry.version !== version)\n return undefined\n if (touch) {\n entries.delete(sessionId)\n entries.set(sessionId, entry)\n }\n return entry\n },\n drop,\n /** Replaces the session's entry. `evict: false`: kept only when that pushes nothing out. */\n keep(sessionId: string, entry: T, evict = true): void {\n drop(sessionId)\n if (entry.bytes > maxBytes)\n return\n if (!evict && (entries.size >= maxSessions || totalBytes + entry.bytes > maxBytes))\n return\n entries.set(sessionId, entry)\n totalBytes += entry.bytes\n for (const [id, oldest] of entries) {\n if (entries.size <= maxSessions && totalBytes <= maxBytes)\n break\n entries.delete(id)\n totalBytes -= oldest.bytes\n }\n },\n }\n}\n\n/**\n * A replay and document cache.\n * @param options - Bounds and a seam.\n * @param options.maxSessions - Entries kept per kind (replays, documents). Default 4.\n * @param options.maxBytes - Byte budget per kind, by {@link approxJsonBytes}. Default 64 MiB.\n * @param options.replay - Builds a replay from turns and runs. Default `replayTurns`.\n */\nexport function createTranscriptReplayCache(options: {\n maxSessions?: number\n maxBytes?: number\n /** The replay (a seam for counting it). */\n replay?: typeof replayTurns\n} = {}): TranscriptReplayCache {\n const maxSessions = options.maxSessions ?? DEFAULT_MAX_SESSIONS\n const maxBytes = options.maxBytes ?? DEFAULT_MAX_BYTES\n const replay = options.replay ?? replayTurns\n const replays = createLru<TranscriptReplay>(maxSessions, maxBytes)\n const documents = createLru<DocumentSnapshot>(maxSessions, maxBytes)\n const inFlight = new Map<string, Set<InFlightRead>>()\n /** Labels a read of no known version: never equal to another read's. */\n let unversioned = 0\n\n function drop(sessionId: string): void {\n for (const read of inFlight.get(sessionId) ?? [])\n read.dropped = true\n replays.drop(sessionId)\n documents.drop(sessionId)\n }\n\n /** Run `fn` as an in-flight read of `sessionId`, tracked only while it runs. */\n async function tracked<R>(sessionId: string, fn: (read: InFlightRead) => Promise<R>): Promise<R> {\n const read: InFlightRead = { dropped: false }\n const reads = inFlight.get(sessionId) ?? new Set<InFlightRead>()\n inFlight.set(sessionId, reads.add(read))\n try {\n return await fn(read)\n }\n finally {\n reads.delete(read)\n if (reads.size === 0 && inFlight.get(sessionId) === reads)\n inFlight.delete(sessionId)\n }\n }\n\n /**\n * A stored session's entry of `lru`, built from `load` on a miss. The\n * version comes from `getMeta` when the store has it (see the header),\n * else from the loaded data (`fingerprintOf`).\n */\n function stored<T extends Versioned, D>(\n lru: ReturnType<typeof createLru<T>>,\n store: Pick<SessionStore, 'getMeta'>,\n sessionId: string,\n load: () => Promise<D | null> | D | null,\n build: (data: D, version: string) => T,\n fingerprintOf: (data: D) => string,\n { variant = '', background = false }: ReadOptions = {},\n ): Promise<T | null> {\n return tracked(sessionId, async (read) => {\n if (store.getMeta) {\n const readAt = Date.now()\n const meta = await store.getMeta(sessionId)\n if (!meta)\n return null\n const version = storeVersion(meta) + variant\n const cached = lru.hit(sessionId, version, !background)\n if (cached)\n return cached\n const data = await load()\n if (data === null)\n return null\n let settled: boolean\n if (meta.rev !== undefined) {\n const after = await store.getMeta(sessionId)\n settled = after !== null && storeVersion(after) + variant === version\n }\n else {\n settled = meta.updatedAt < readAt\n }\n const entry = build(data, settled ? version : `${version}~${++unversioned}`)\n // A stale entry goes either way: its version cannot come back. A\n // background read leaves it to the foreground, which may hold a newer one.\n if (settled && !read.dropped)\n lru.keep(sessionId, entry, !background)\n else if (!background)\n lru.drop(sessionId)\n return entry\n }\n const data = await load()\n if (data === null)\n return null\n const version = fingerprintOf(data) + variant\n const cached = lru.hit(sessionId, version, !background)\n if (cached)\n return cached\n const entry = build(data, version)\n if (!read.dropped)\n lru.keep(sessionId, entry, !background)\n return entry\n })\n }\n\n function buildReplay(data: ReplayData, version: string): TranscriptReplay {\n const { events, turnStarts } = replay(data.turns, data.runs)\n return {\n version,\n events,\n turnStarts,\n boundaries: exchangeBoundaries(data.turns, data.runs),\n cuts: turnCutPoints(data.turns),\n turnIds: data.turns.map(turn => turn.id),\n bytes: approxJsonBytes(events),\n ...(data.seqs ? { seqs: data.seqs } : {}),\n }\n }\n\n const snapshotOf = (data: SessionData, version: string): DocumentSnapshot => ({ version, data, bytes: approxJsonBytes(data) })\n\n return {\n async page(store, sessionId, paging) {\n const entry = await stored(replays, store, sessionId, () => loadOrThrow(store, sessionId), buildReplay, data => fingerprint(data.updatedAt, data.turns, data.runs))\n if (!entry)\n throw new Error(`Session \"${sessionId}\" not found.`)\n const { from, to, cursor } = transcriptPage(entry.boundaries, paging, entry.cuts, entry.turnIds)\n const events = entry.events.slice(entry.turnStarts[from], entry.turnStarts[to])\n return {\n events,\n exact: true,\n start: entry.turnStarts[from]!,\n ...(cursor !== undefined ? { cursor } : {}),\n ...(paging.beforeTurnId !== undefined ? { beforeTurnId: paging.beforeTurnId } : {}),\n }\n },\n replay(store, sessionId, read) {\n const options = { variant: read.variant, background: read.background }\n return stored(replays, store, sessionId, read.load, buildReplay, data => fingerprint(0, data.turns, data.runs), options)\n },\n cached: (sessionId, touch = false) => replays.peek(sessionId, touch),\n async document(store, sessionId, live) {\n if (live) {\n // The live copy: ahead of the store mid-run, and holding the todos.\n const version = `live:${fingerprint(0, live.turns, live.runs)}:${hashText(JSON.stringify([live.status, live.metadata]))}`\n return tracked(sessionId, async (read) => {\n const cached = documents.hit(sessionId, version)\n if (cached)\n return cached\n const entry = snapshotOf(live.toJSON(), version)\n if (!read.dropped)\n documents.keep(sessionId, entry)\n return entry\n })\n }\n // A reader: a load-time pairing heal stays in memory, the host's own agent persists the document.\n const load = async (): Promise<SessionData | null> => (await loadSession(store, sessionId, { persistHeal: false }))?.toJSON() ?? null\n return stored(documents, store, sessionId, load, snapshotOf, data => fingerprint(data.updatedAt, data.turns, data.runs))\n },\n observe(signal) {\n const sessionId = changedSessionOf(signal)\n if (sessionId !== undefined)\n drop(sessionId)\n },\n forget: drop,\n sizes: () => ({ entries: replays.size() + documents.size(), inFlight: inFlight.size }),\n }\n}\n\n/**\n * About the length of `JSON.stringify(value)`: what an entry holds, for the\n * byte budget. Walks the value without building the string (several times\n * cheaper on a long session); the budget is a heuristic, exact bytes are not\n * needed.\n */\nexport function approxJsonBytes(value: unknown): number {\n if (typeof value === 'string')\n return value.length + 2\n if (typeof value !== 'object' || value === null)\n return 8\n let bytes = 2\n if (Array.isArray(value)) {\n for (const item of value)\n bytes += approxJsonBytes(item) + 1\n return bytes\n }\n for (const key in value)\n bytes += key.length + 4 + approxJsonBytes((value as Record<string, unknown>)[key])\n return bytes\n}\n\nfunction storeVersion(meta: { rev?: number, updatedAt: number, turnCount: number, runCount: number }): string {\n return `meta:${meta.rev ?? '-'}:${meta.updatedAt}:${meta.turnCount}:${meta.runCount}`\n}\n\n/** A 32-bit FNV-1a: `mix` values in, `digest` (base 36) out. */\nfunction fnv1a() {\n let hash = 0x811C9DC5\n const add = (text: string): void => {\n for (let i = 0; i < text.length; i++)\n hash = Math.imul(hash ^ text.charCodeAt(i), 0x01000193)\n }\n return {\n add,\n /** One value, then a separator: `ab` + `c` never hashes as `a` + `bc`. */\n mix: (value: string | number | undefined): void => {\n add(String(value))\n hash = Math.imul(hash ^ 0x1F, 0x01000193)\n },\n digest: (): string => (hash >>> 0).toString(36),\n }\n}\n\nfunction hashText(text: string): string {\n const hash = fnv1a()\n hash.add(text)\n return hash.digest()\n}\n\n/** FNV-1a over the document's shape: what changes when a turn or run is added, removed, or rewritten. */\nfunction fingerprint(updatedAt: number, turns: readonly SessionTurn[], runs: readonly SessionRun[]): string {\n const { mix, digest } = fnv1a()\n for (const turn of turns) {\n mix(turn.id)\n mix(turn.role)\n mix(turn.runId)\n mix(typeof turn.display === 'string' ? turn.display : '')\n mix(turn.content.length)\n for (const block of turn.content) {\n mix(block.type)\n const fields = block as { text?: unknown, output?: unknown, summary?: unknown }\n for (const field of [fields.text, fields.output, fields.summary])\n mix(typeof field === 'string' ? field.length : Array.isArray(field) ? field.length : '')\n }\n }\n mix(JSON.stringify(runs))\n return `doc:${updatedAt}:${turns.length}:${runs.length}:${digest()}`\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"transcript-cache-CdHKtx9y.js","names":[],"sources":["../src/ipc/daemon/handlers/params.ts","../src/ipc/daemon/handlers/session-load.ts","../src/ipc/daemon/handlers/transcript-page.ts","../src/ipc/daemon/handlers/transcript-cache.ts"],"sourcesContent":["/**\n * Shape checks for request params: they arrive as untrusted JSON (the\n * `IpcMethods` types are not a runtime guarantee). The dispatcher runs\n * {@link checkParams} on every request and notification before its handler;\n * handlers use the field checks for what they require. A failed check is an\n * {@link InvalidParamsError}, answered as JSON-RPC \"invalid params\".\n */\n\nexport class InvalidParamsError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'InvalidParamsError'\n }\n}\n\n/** Longest session id accepted (minted ids are under 64 characters). */\nconst MAX_SESSION_ID_LENGTH = 1024\n\n/**\n * A session id: a non-empty string that is one plain path segment. Ids name\n * directories on disk (`<data dir>/sessions/<id>/`, removed recursively on\n * delete), so `..`, separators and NUL are refused.\n */\nexport function checkSessionId(value: unknown, name = 'sessionId'): string {\n if (typeof value !== 'string' || value.length === 0 || value.length > MAX_SESSION_ID_LENGTH)\n throw new InvalidParamsError(`${name} must be a non-empty string of at most ${MAX_SESSION_ID_LENGTH} characters.`)\n if (value === '.' || value === '..' || /[/\\\\\\0]/.test(value))\n throw new InvalidParamsError(`${name} must not be a path (no \"/\", \"\\\\\", \".\" or \"..\").`)\n return value\n}\n\n/** The required `sessionId` of `params`. */\nexport function sessionIdOf(params: { sessionId?: unknown } | null | undefined): string {\n return checkSessionId(params?.sessionId)\n}\n\n/** An optional non-negative integer; `undefined` when absent. */\nexport function nonNegativeInt(value: unknown, name: string): number | undefined {\n if (value === undefined)\n return undefined\n if (typeof value !== 'number' || !Number.isSafeInteger(value) || value < 0)\n throw new InvalidParamsError(`${name} must be a non-negative integer.`)\n return value\n}\n\n/** An optional string; `undefined` when absent. */\nexport function optionalString(value: unknown, name: string): string | undefined {\n if (value !== undefined && typeof value !== 'string')\n throw new InvalidParamsError(`${name} must be a string.`)\n return value\n}\n\n/**\n * What every method's params must be: absent, `null`, or an object (never an\n * array or a scalar), whose `sessionId` / `sessionIds`, when present, name\n * sessions ({@link checkSessionId}).\n */\nexport function checkParams(params: unknown): void {\n if (params === undefined || params === null)\n return\n if (typeof params !== 'object' || Array.isArray(params))\n throw new InvalidParamsError('params must be an object.')\n const { sessionId, sessionIds } = params as { sessionId?: unknown, sessionIds?: unknown }\n if (sessionId !== undefined)\n checkSessionId(sessionId)\n if (sessionIds !== undefined) {\n if (!Array.isArray(sessionIds))\n throw new InvalidParamsError('sessionIds must be an array.')\n for (const id of sessionIds)\n checkSessionId(id, 'sessionIds[]')\n }\n}\n","/** A stored session or a \"not found\" error: kept apart from `./sessions` so the history worker loads without the chat host's graph. */\nimport type { SessionData, SessionStore } from '../../../session/index'\n\nexport async function loadOrThrow(store: Pick<SessionStore, 'load'>, sessionId: string): Promise<SessionData> {\n const data = await store.load(sessionId)\n if (!data)\n throw new Error(`Session \"${sessionId}\" not found.`)\n return data\n}\n","/**\n * One page of a transcript for `sessions.loadEvents` paging, in whole runs:\n * everything from a user message to the turn before the next one. The run\n * the page ends in is always whole, and the runs before it join while the\n * page stays within `limit` turns, so scrolling back brings the previous\n * run (or a few small ones) at a time, never part of one. A run longer than\n * {@link WHOLE_RUN_PAGES} pages on its own is the one exception: it comes in\n * pieces of that size, each starting on a turn that keeps a tool call with\n * its result. The GUI's local pager cuts with the same rule.\n */\nimport type { SessionRun } from '../../../session/index'\nimport type { SessionTurn } from '../../../types'\nimport type { LoadEventsPaging } from '../../protocol'\nimport { LOAD_EVENTS_MAX_PAGE_TURNS, LOAD_EVENTS_PAGE_TURNS } from '../../protocol'\nimport { InvalidParamsError, nonNegativeInt, optionalString } from './params'\n\n/**\n * A run longer than this many pages is split (by `limit`, so the client's\n * halving retry on a reply too large still converges).\n */\nexport const WHOLE_RUN_PAGES = 5\n\nexport function isPagedLoad(p: LoadEventsPaging | undefined): boolean {\n return p?.before !== undefined || p?.limit !== undefined || p?.beforeTurnId !== undefined\n}\n\n/**\n * Per turn: does a run start there (a parent-run user turn carrying no tool result)?\n * @param turns - Turns of the session, in order.\n * @param runs - Runs of the session, used to tell child runs from parent runs.\n * @returns One flag per turn.\n */\nexport function exchangeBoundaries(turns: readonly SessionTurn[], runs: readonly SessionRun[]): boolean[] {\n const childRuns = new Set(runs.filter(run => (run.depth ?? 0) > 0 || run.parentRunId !== undefined).map(run => run.id))\n return turns.map(turn => turn.role === 'user'\n && !(turn.runId !== undefined && childRuns.has(turn.runId))\n && !turn.content.some(block => block.type === 'tool_result'))\n}\n\n/**\n * Per turn: can a page start there without leaving a tool call's result behind (not a tool-result turn)?\n * @param turns - Turns of the session, in order.\n * @returns One flag per turn.\n */\nexport function turnCutPoints(turns: readonly SessionTurn[]): boolean[] {\n return turns.map(turn => !(turn.role === 'user' && turn.content.some(block => block.type === 'tool_result')))\n}\n\n/**\n * `[from, to)` of the page, and the cursor of the one before it, over the\n * turns' {@link exchangeBoundaries} (run starts) and {@link turnCutPoints}\n * (where a run too long to send whole may be split; run starts when absent).\n * @param boundaries - Run starts per turn, from {@link exchangeBoundaries}.\n * @param paging - The `before` cursor and `limit` of the request.\n * @param cuts - Allowed cut points per turn, from {@link turnCutPoints}.\n * @param turnIds - Id per turn: where a `beforeTurnId` anchor sits (it wins over `before`).\n * @returns The turn range of the page and the cursor of the page before it.\n */\nexport function transcriptPage(\n boundaries: readonly boolean[],\n paging: LoadEventsPaging,\n cuts: readonly boolean[] = boundaries,\n turnIds?: readonly string[],\n): { from: number, to: number, cursor?: number } {\n const before = anchorIndex(paging.beforeTurnId, turnIds) ?? nonNegativeInt(paging.before, 'before')\n const limit = Math.min(Math.max(nonNegativeInt(paging.limit, 'limit') ?? LOAD_EVENTS_PAGE_TURNS, 1), LOAD_EVENTS_MAX_PAGE_TURNS)\n const to = Math.min(before ?? boundaries.length, boundaries.length)\n if (to === 0)\n return { from: 0, to: 0 }\n /** Where the run holding turn `end - 1` starts (0 when no run start precedes it). */\n const runStart = (end: number): number => {\n let i = end - 1\n while (i > 0 && !boundaries[i])\n i--\n return i\n }\n let from = runStart(to)\n const ceiling = limit * WHOLE_RUN_PAGES\n if (to - from > ceiling) {\n // One run too long to send whole: its last `ceiling` turns, from a turn\n // that keeps a tool call with its result.\n from = to - ceiling\n while (from < to - 1 && !cuts[from])\n from++\n }\n else {\n // The runs before it too, whole, while the page stays within `limit`.\n while (from > 0) {\n const previous = runStart(from)\n if (to - previous > limit)\n break\n from = previous\n }\n }\n return { from, to, ...(from > 0 ? { cursor: from } : {}) }\n}\n\n/** The position of the turn `beforeTurnId` names; `undefined` without one. A turn the transcript doesn't hold is invalid params. */\nfunction anchorIndex(beforeTurnId: unknown, turnIds: readonly string[] | undefined): number | undefined {\n const anchor = optionalString(beforeTurnId, 'beforeTurnId')\n if (anchor === undefined)\n return undefined\n const at = turnIds?.indexOf(anchor) ?? -1\n if (at < 0)\n throw new InvalidParamsError(`beforeTurnId \"${anchor.slice(0, 128)}\" is not a turn of this session.`)\n return at\n}\n","/**\n * Whole-session reads a client pages through, kept per session content\n * version so N pages cost one read of the session, not N:\n *\n * - the replay behind `sessions.loadEvents` pages (each page is a slice of\n * the WHOLE replay: see `replayTurns`);\n * - the document behind `sessions.getTurns` pages and the `sessions.get`\n * `turns: false` head (`document`): loaded, healed and copied once.\n * Every page carries its version, so a client that sees it change\n * mid-load starts over instead of mixing two versions\n * (`loadSessionDocument`).\n *\n * The version: a store with `getMeta` answers it without parsing turns\n * (its change counter `rev`, `updatedAt`, the turn and run counts; a hit\n * then skips the load too). `rev` grows on every write, so a version never\n * comes back after a change, whatever `updatedAt` a writer stamps (another\n * process on the same sessions.db included, which no host signal covers).\n * The version is read again after a miss's load: when it moved meanwhile,\n * what was loaded is of no known version, so it is served under a label no\n * other read gets, and not kept. A store without `rev` keeps the older\n * rule: a version stamped in the millisecond the read started is served\n * but not kept. Any other store's loaded document is fingerprinted (turn\n * ids, roles, block shapes and text lengths, the runs), and so is a live\n * session's in-memory copy (plus its metadata and status). The host's own\n * writes also drop entries by their signals (`observe`), which covers the\n * edits a version cannot see.\n *\n * A client that pages a session itself (the GUI main process over its own\n * store: `replay`) shares this cache with its own load, a version variant\n * for what else that load depends on, and background reads that never evict.\n *\n * Bounded: a few sessions per kind, least recently used first out, and a\n * byte budget (an entry over it is served, not kept). Besides the entries,\n * a session is tracked only while a read of it is in flight (so a drop\n * meanwhile stops that read's result from being kept): a session that is\n * dropped, forgotten or signalled leaves nothing behind.\n */\nimport type { StreamEvent } from '../../../chat/index'\nimport type { Session, SessionData, SessionRun, SessionStore } from '../../../session/index'\nimport type { SessionTurn } from '../../../types'\nimport type { HostSignal, LoadEventsPaging, SessionEventsPage } from '../../protocol'\nimport { replayTurns } from '../../../chat/store'\nimport { loadSession } from '../../../session/index'\nimport { loadOrThrow } from './session-load'\nimport { exchangeBoundaries, transcriptPage, turnCutPoints } from './transcript-page'\n\nconst DEFAULT_MAX_SESSIONS = 4\nconst DEFAULT_MAX_BYTES = 64 * 1024 * 1024\n\n/** Signals that follow a change to a session's turns or runs. */\nconst CHANGE_SIGNALS = new Set<HostSignal['kind']>(['sessions:changed', 'run:start', 'run:end', 'turn:end', 'compacting:end', 'prompt-turns'])\n\ninterface Versioned {\n version: string\n bytes: number\n}\n\n/** A whole-session replay: pages are `transcriptPage` slices of it. */\nexport interface TranscriptReplay extends Versioned {\n /** Every turn's events, in order: what a whole `sessions.loadEvents` returns. */\n events: StreamEvent[]\n /** Where each turn's events start (`[turns]` = the end). */\n turnStarts: number[]\n /** Where each run starts (`exchangeBoundaries`): where a page may start. */\n boundaries: boolean[]\n /** Where a run too long for one page may be split (`turnCutPoints`). */\n cuts: boolean[]\n /** Each turn's id: where a `beforeTurnId` anchor sits. */\n turnIds: string[]\n /** The loaded `seqs`, when the load gave them. */\n seqs?: number[]\n}\n\n/** What a client's own load gives `replay`. */\nexport interface ReplayData {\n /** The session's turns, in order. */\n turns: SessionTurn[]\n /** The session's runs (they tell child runs from parent runs). */\n runs: SessionRun[]\n /** A per-turn position the client keeps with the replay (the GUI store's `seq`). */\n seqs?: number[]\n}\n\n/** A client's own read of a stored session, for `replay`. */\nexport interface ReplayRead {\n /** Loads the session on a miss; `null` when it is unknown. */\n load: () => Promise<ReplayData | null> | ReplayData | null\n /** Appended to the version: what else the load depends on. */\n variant?: string\n /** A read ahead of the user: a hit leaves the order as is, a miss is kept only when that evicts nothing. */\n background?: boolean\n}\n\ninterface ReadOptions {\n variant?: string\n background?: boolean\n}\n\n/** One version of a session's document, as `sessions.get` would send it. */\nexport interface DocumentSnapshot extends Versioned {\n data: SessionData\n}\n\n/** Whole-session replays and documents, kept per session version (see the module header). */\nexport interface TranscriptReplayCache {\n /** One `sessions.loadEvents` page of a stored session, sliced from its replay. Throws when the session is unknown, `InvalidParamsError` for bad paging. */\n page: (store: Pick<SessionStore, 'load' | 'getMeta'>, sessionId: string, paging: LoadEventsPaging) => Promise<SessionEventsPage>\n /** A stored session's replay from the client's own `read.load`, versioned like `page`'s; `null` when unknown. */\n replay: (store: Pick<SessionStore, 'getMeta'>, sessionId: string, read: ReplayRead) => Promise<TranscriptReplay | null>\n /** The replay kept for a session, whatever its version; `touch` counts it as used. */\n cached: (sessionId: string, touch?: boolean) => TranscriptReplay | undefined\n /** The document (the live copy when `live` is given, else the stored one, healed in memory), and its version; `null` when unknown. */\n document: (store: SessionStore, sessionId: string, live: Session | null) => Promise<DocumentSnapshot | null>\n /** A host signal: one that follows a change to a session drops its entries. */\n observe: (signal: HostSignal) => void\n /** Drops the session's entries (it is gone); a read in flight is served but not kept. */\n forget: (sessionId: string) => void\n /** Entries kept and sessions with a read in flight, across both kinds: what the cache holds. */\n sizes: () => { entries: number, inFlight: number }\n}\n\n/** The session a host signal says changed (its turns or runs), if any: its cached entries are stale. */\nexport function changedSessionOf(signal: HostSignal): string | undefined {\n return CHANGE_SIGNALS.has(signal.kind) && 'sessionId' in signal && typeof signal.sessionId === 'string' ? signal.sessionId : undefined\n}\n\n/** A read in flight: a drop of its session meanwhile marks it, and its result is then served but not kept. */\ninterface InFlightRead { dropped: boolean }\n\n/** One kind of entry (replays, documents): LRU by insertion order, bounded by count and bytes. */\nfunction createLru<T extends Versioned>(maxSessions: number, maxBytes: number) {\n const entries = new Map<string, T>()\n let totalBytes = 0\n const drop = (sessionId: string): void => {\n const entry = entries.get(sessionId)\n if (entry) {\n totalBytes -= entry.bytes\n entries.delete(sessionId)\n }\n }\n return {\n size: () => entries.size,\n peek(sessionId: string, touch: boolean): T | undefined {\n const entry = entries.get(sessionId)\n if (entry && touch) {\n entries.delete(sessionId)\n entries.set(sessionId, entry)\n }\n return entry\n },\n hit(sessionId: string, version: string, touch = true): T | undefined {\n const entry = entries.get(sessionId)\n if (!entry || entry.version !== version)\n return undefined\n if (touch) {\n entries.delete(sessionId)\n entries.set(sessionId, entry)\n }\n return entry\n },\n drop,\n /** Replaces the session's entry. `evict: false`: kept only when that pushes nothing out. */\n keep(sessionId: string, entry: T, evict = true): void {\n drop(sessionId)\n if (entry.bytes > maxBytes)\n return\n if (!evict && (entries.size >= maxSessions || totalBytes + entry.bytes > maxBytes))\n return\n entries.set(sessionId, entry)\n totalBytes += entry.bytes\n for (const [id, oldest] of entries) {\n if (entries.size <= maxSessions && totalBytes <= maxBytes)\n break\n entries.delete(id)\n totalBytes -= oldest.bytes\n }\n },\n }\n}\n\n/**\n * A replay and document cache.\n * @param options - Bounds and a seam.\n * @param options.maxSessions - Entries kept per kind (replays, documents). Default 4.\n * @param options.maxBytes - Byte budget per kind, by {@link approxJsonBytes}. Default 64 MiB.\n * @param options.replay - Builds a replay from turns and runs. Default `replayTurns`.\n */\nexport function createTranscriptReplayCache(options: {\n maxSessions?: number\n maxBytes?: number\n /** The replay (a seam for counting it). */\n replay?: typeof replayTurns\n} = {}): TranscriptReplayCache {\n const maxSessions = options.maxSessions ?? DEFAULT_MAX_SESSIONS\n const maxBytes = options.maxBytes ?? DEFAULT_MAX_BYTES\n const replay = options.replay ?? replayTurns\n const replays = createLru<TranscriptReplay>(maxSessions, maxBytes)\n const documents = createLru<DocumentSnapshot>(maxSessions, maxBytes)\n const inFlight = new Map<string, Set<InFlightRead>>()\n /** Labels a read of no known version: never equal to another read's. */\n let unversioned = 0\n\n function drop(sessionId: string): void {\n for (const read of inFlight.get(sessionId) ?? [])\n read.dropped = true\n replays.drop(sessionId)\n documents.drop(sessionId)\n }\n\n /** Run `fn` as an in-flight read of `sessionId`, tracked only while it runs. */\n async function tracked<R>(sessionId: string, fn: (read: InFlightRead) => Promise<R>): Promise<R> {\n const read: InFlightRead = { dropped: false }\n const reads = inFlight.get(sessionId) ?? new Set<InFlightRead>()\n inFlight.set(sessionId, reads.add(read))\n try {\n return await fn(read)\n }\n finally {\n reads.delete(read)\n if (reads.size === 0 && inFlight.get(sessionId) === reads)\n inFlight.delete(sessionId)\n }\n }\n\n /**\n * A stored session's entry of `lru`, built from `load` on a miss. The\n * version comes from `getMeta` when the store has it (see the header),\n * else from the loaded data (`fingerprintOf`).\n */\n function stored<T extends Versioned, D>(\n lru: ReturnType<typeof createLru<T>>,\n store: Pick<SessionStore, 'getMeta'>,\n sessionId: string,\n load: () => Promise<D | null> | D | null,\n build: (data: D, version: string) => T,\n fingerprintOf: (data: D) => string,\n { variant = '', background = false }: ReadOptions = {},\n ): Promise<T | null> {\n return tracked(sessionId, async (read) => {\n if (store.getMeta) {\n const readAt = Date.now()\n const meta = await store.getMeta(sessionId)\n if (!meta)\n return null\n const version = storeVersion(meta) + variant\n const cached = lru.hit(sessionId, version, !background)\n if (cached)\n return cached\n const data = await load()\n if (data === null)\n return null\n let settled: boolean\n if (meta.rev !== undefined) {\n const after = await store.getMeta(sessionId)\n settled = after !== null && storeVersion(after) + variant === version\n }\n else {\n settled = meta.updatedAt < readAt\n }\n const entry = build(data, settled ? version : `${version}~${++unversioned}`)\n // A stale entry goes either way: its version cannot come back. A\n // background read leaves it to the foreground, which may hold a newer one.\n if (settled && !read.dropped)\n lru.keep(sessionId, entry, !background)\n else if (!background)\n lru.drop(sessionId)\n return entry\n }\n const data = await load()\n if (data === null)\n return null\n const version = fingerprintOf(data) + variant\n const cached = lru.hit(sessionId, version, !background)\n if (cached)\n return cached\n const entry = build(data, version)\n if (!read.dropped)\n lru.keep(sessionId, entry, !background)\n return entry\n })\n }\n\n function buildReplay(data: ReplayData, version: string): TranscriptReplay {\n const { events, turnStarts } = replay(data.turns, data.runs)\n return {\n version,\n events,\n turnStarts,\n boundaries: exchangeBoundaries(data.turns, data.runs),\n cuts: turnCutPoints(data.turns),\n turnIds: data.turns.map(turn => turn.id),\n bytes: approxJsonBytes(events),\n ...(data.seqs ? { seqs: data.seqs } : {}),\n }\n }\n\n const snapshotOf = (data: SessionData, version: string): DocumentSnapshot => ({ version, data, bytes: approxJsonBytes(data) })\n\n return {\n async page(store, sessionId, paging) {\n const entry = await stored(replays, store, sessionId, () => loadOrThrow(store, sessionId), buildReplay, data => fingerprint(data.updatedAt, data.turns, data.runs))\n if (!entry)\n throw new Error(`Session \"${sessionId}\" not found.`)\n const { from, to, cursor } = transcriptPage(entry.boundaries, paging, entry.cuts, entry.turnIds)\n const events = entry.events.slice(entry.turnStarts[from], entry.turnStarts[to])\n return {\n events,\n exact: true,\n start: entry.turnStarts[from]!,\n ...(cursor !== undefined ? { cursor } : {}),\n ...(paging.beforeTurnId !== undefined ? { beforeTurnId: paging.beforeTurnId } : {}),\n }\n },\n replay(store, sessionId, read) {\n const options = { variant: read.variant, background: read.background }\n return stored(replays, store, sessionId, read.load, buildReplay, data => fingerprint(0, data.turns, data.runs), options)\n },\n cached: (sessionId, touch = false) => replays.peek(sessionId, touch),\n async document(store, sessionId, live) {\n if (live) {\n // The live copy: ahead of the store mid-run, and holding the todos.\n const version = `live:${fingerprint(0, live.turns, live.runs)}:${hashText(JSON.stringify([live.status, live.metadata]))}`\n return tracked(sessionId, async (read) => {\n const cached = documents.hit(sessionId, version)\n if (cached)\n return cached\n const entry = snapshotOf(live.toJSON(), version)\n if (!read.dropped)\n documents.keep(sessionId, entry)\n return entry\n })\n }\n // A reader: a load-time pairing heal stays in memory, the host's own agent persists the document.\n const load = async (): Promise<SessionData | null> => (await loadSession(store, sessionId, { persistHeal: false }))?.toJSON() ?? null\n return stored(documents, store, sessionId, load, snapshotOf, data => fingerprint(data.updatedAt, data.turns, data.runs))\n },\n observe(signal) {\n const sessionId = changedSessionOf(signal)\n if (sessionId !== undefined)\n drop(sessionId)\n },\n forget: drop,\n sizes: () => ({ entries: replays.size() + documents.size(), inFlight: inFlight.size }),\n }\n}\n\n/**\n * About the length of `JSON.stringify(value)`: what an entry holds, for the\n * byte budget. Walks the value without building the string (several times\n * cheaper on a long session); the budget is a heuristic, exact bytes are not\n * needed.\n */\nexport function approxJsonBytes(value: unknown): number {\n if (typeof value === 'string')\n return value.length + 2\n if (typeof value !== 'object' || value === null)\n return 8\n let bytes = 2\n if (Array.isArray(value)) {\n for (const item of value)\n bytes += approxJsonBytes(item) + 1\n return bytes\n }\n for (const key in value)\n bytes += key.length + 4 + approxJsonBytes((value as Record<string, unknown>)[key])\n return bytes\n}\n\nfunction storeVersion(meta: { rev?: number, updatedAt: number, turnCount: number, runCount: number }): string {\n return `meta:${meta.rev ?? '-'}:${meta.updatedAt}:${meta.turnCount}:${meta.runCount}`\n}\n\n/** A 32-bit FNV-1a: `mix` values in, `digest` (base 36) out. */\nfunction fnv1a() {\n let hash = 0x811C9DC5\n const add = (text: string): void => {\n for (let i = 0; i < text.length; i++)\n hash = Math.imul(hash ^ text.charCodeAt(i), 0x01000193)\n }\n return {\n add,\n /** One value, then a separator: `ab` + `c` never hashes as `a` + `bc`. */\n mix: (value: string | number | undefined): void => {\n add(String(value))\n hash = Math.imul(hash ^ 0x1F, 0x01000193)\n },\n digest: (): string => (hash >>> 0).toString(36),\n }\n}\n\nfunction hashText(text: string): string {\n const hash = fnv1a()\n hash.add(text)\n return hash.digest()\n}\n\n/** FNV-1a over the document's shape: what changes when a turn or run is added, removed, or rewritten. */\nfunction fingerprint(updatedAt: number, turns: readonly SessionTurn[], runs: readonly SessionRun[]): string {\n const { mix, digest } = fnv1a()\n for (const turn of turns) {\n mix(turn.id)\n mix(turn.role)\n mix(turn.runId)\n mix(typeof turn.display === 'string' ? turn.display : '')\n mix(turn.content.length)\n for (const block of turn.content) {\n mix(block.type)\n const fields = block as { text?: unknown, output?: unknown, summary?: unknown }\n for (const field of [fields.text, fields.output, fields.summary])\n mix(typeof field === 'string' ? field.length : Array.isArray(field) ? field.length : '')\n }\n }\n mix(JSON.stringify(runs))\n return `doc:${updatedAt}:${turns.length}:${runs.length}:${digest()}`\n}\n"],"mappings":"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"}
|
|
@@ -4,8 +4,8 @@ import { i as readFileInputPaths, t as formatBytes } from "./format-bytes-LHrZVM
|
|
|
4
4
|
import { t as effectiveInputFromTurn } from "./stats-Bmj46D4h.js";
|
|
5
5
|
import { c as formatCount, p as previewLine } from "./format-YgaIcuQ5.js";
|
|
6
6
|
import { a as groupSkillPicks } from "./weights-DksCExeo.js";
|
|
7
|
-
import { H as shortSessionId } from "./spaces-
|
|
8
|
-
import { O as DEFAULT_SETTINGS, f as enforceSettingsInvariants, p as requirementMet, u as SETTINGS_TOGGLES } from "./secret-shapes-
|
|
7
|
+
import { H as shortSessionId } from "./spaces-C_x2bvEl.js";
|
|
8
|
+
import { O as DEFAULT_SETTINGS, f as enforceSettingsInvariants, p as requirementMet, u as SETTINGS_TOGGLES } from "./secret-shapes-HvaYVzwc.js";
|
|
9
9
|
import { Fzf } from "fzf";
|
|
10
10
|
//#region src/chat/todo-glyphs.ts
|
|
11
11
|
/** Glyph shown for each todo status. */
|
|
@@ -1905,6 +1905,14 @@ const ONBOARDING_FEATURES = [
|
|
|
1905
1905
|
unlocks: "Many tool calls in one step. Long tasks take fewer turns, so runs finish faster and cost less.",
|
|
1906
1906
|
prevents: "A context full of small tool results. Only what the script prints goes back to the model."
|
|
1907
1907
|
},
|
|
1908
|
+
{
|
|
1909
|
+
key: "webSearch",
|
|
1910
|
+
group: "work",
|
|
1911
|
+
surfaces: BOTH,
|
|
1912
|
+
example: "For example, a build fails after a library update. The agent searches the error and reads the release notes.",
|
|
1913
|
+
unlocks: "Answers from the web: current docs, error messages, and changes newer than the model.",
|
|
1914
|
+
prevents: "Off, the agent never reaches a search engine, and works only from your files and what it already knows."
|
|
1915
|
+
},
|
|
1908
1916
|
{
|
|
1909
1917
|
key: "inlineAutocomplete",
|
|
1910
1918
|
group: "work",
|
|
@@ -5111,4 +5119,4 @@ function deepEqual(a, b, ignore) {
|
|
|
5111
5119
|
//#endregion
|
|
5112
5120
|
export { usageTone as $, TODO_STATUS_GLYPHS as $n, onboardingFeatures as $t, stepTranscriptCap as A, NATIVE_EXTENSIONS_REPO as An, applySettingsPatch as At, RUN_WAITING_LABEL as B, SKILLS_TRIGGER as Bn, planOnboarding as Bt, isEarlierHiddenMarker as C, isFenceClose as Cn, TUTORIAL_TOPICS as Ct, revealEarlierTranscriptEvents as D, stripHtmlCommentsOutsideCode as Dn, importsSomething as Dt, replaceTranscriptTurnEvents as E, splitMarkdownCodeBlocks as En, defaultImportSelection as Et, spawnLane as F, ONBOARDING_AGENT_BRANDS as Fn, onboardingReducer as Ft, activeSnapshotFor as G, uniqueFilesFromReferences as Gn, transcriptPresetNotice as Gt, runRetryingLabel as H, uniqueSkillNamesFromReferences as Hn, TRANSCRIPT_PRESET_KEYS as Ht, spawnLaneResolver as I, PROVIDER_BRANDS as In, ONBOARDING_STEPS as It, formatUsagePercent as J, blendHsl as Jn, transcriptPresetPaletteItem as Jt, formatBalance as K, COMMANDS_TRIGGER as Kn, transcriptPresetOf as Kt, spawnParents as L, providerBrand as Ln, ONBOARDING_VERSION as Lt, takeChars as M, nativeExtensionByName as Mn, createOnboardingFlow as Mt, turnContextSize as N, nativeExtensionSource as Nn, currentOnboardingStep as Nt, smoothCharsForTick as O, EXCLUDED_NATIVE_EXTENSIONS as On, ONBOARDING_SETTING_KEYS as Ot, withEarlierHidden as P, LOCAL_SERVER_BRANDS as Pn, onboardingProgress as Pt, updatedLabel as Q, accentColor as Qn, onboardingFeatureCopy as Qt, RUN_STATUS_TIME_MS as R, DAEMON_HEALTH_GLYPH as Rn, SETUP_PALETTE_ITEM as Rt, hiddenEarlierTranscriptCount as S, codeTokenHasClosingFence as Sn, TUTORIALS as St, ownerOf as T, parseFenceOpen as Tn, ONBOARDING_PREVIEW_EVENTS as Tt, runStatusKey as U, FILES_TRIGGER as Un, TRANSCRIPT_PRESET_PALETTE_ID as Ut, runFoldStatus as V, createSkillsCompletionProvider as Vn, TRANSCRIPT_PRESETS as Vt, runTailActivity as W, createFilesCompletionProvider as Wn, transcriptPreset as Wt, resetLabel as X, CACHE_HINT_MIN_TOKENS as Xn, ONBOARDING_FEATURES as Xt, mostConstrainedWindow as Y, buildLinearRamp as Yn, transcriptPresetPalettePicker as Yt, showsAccount as Z, cacheHintText as Zn, ONBOARDING_FEATURE_GROUPS as Zt, capTranscriptEvents as _, mcpFailureEvent as _n, ONBOARDING_WORDS as _t, displayNameFor as a, connectorServerConfig as an, effectiveOnboardingMode as at, finalizeStreamingMarkdown as b, chunkMarkdownForRender as bn, joinNames as bt, MAX_TRANSCRIPT_EVENTS as c, filterModelCatalog as cn, migratedOnboardingRecords as ct, SMOOTH_MAX_CPS as d, MCP_KEY_REFUSED_HINT as dn, onboardingRecords as dt, CONNECTORS as en, APPROVAL_MODE_TRADEOFFS as et, STREAMING_MARKDOWN_SEGMENT_CHARS as f, classifyMcpTest as fn, onboardingSettingsChange as ft, appendThinkingLines as g, getMcpAuthStatus as gn, ONBOARDING_AGENT_NAMES as gt, appendMarkdownDelta as h, MCP_STATUS_LABEL as hn, LOCAL_SERVER_NAMES as ht, descriptionLabel as i, connectorInstalled as in, buildOnboardingResult as it, streamTailRoot as j, NATIVE_EXTENSION_GROUPS as jn, canSkipOnboardingStep as jt, smoothCpsForBacklog as k, NATIVE_EXTENSIONS as kn, ONBOARDING_STEP_SETTINGS as kt, SMOOTH_BASE_CPS as l, indexOfEntry as ln, needsOnboarding as lt, TRANSCRIPT_TRIM_TO_EVENTS as m, mcpFailureLine as mn, onboardingSwitchedFeatures as mt, reconcileEvents as n, connectorById as nn, connectorsFromImport as nt, formatToolCall as o, buildModelCatalog as on, isExistingInstall as ot, TRANSCRIPT_TRIM_STEP_EVENTS as p, isMcpAuthRefusal as pn, onboardingImportParts as pt, formatCredits as q, createCommandsCompletionProvider as qn, transcriptPresetOfPaletteItem as qt, TOOL_DISPLAY as r, connectorInputError as rn, createOnboardingRun as rt, toolInputCode as s, customModelTargets as sn, mergeOnboardingState as st, convergeTranscript as t, CONNECTOR_CATEGORIES as tn, SETTING_TRADEOFFS as tt, SMOOTH_MAX_BACKLOG_CHARS as u, parseCustomModelQuery as un, onboardingRecord as ut, coversTranscriptCap as v, reduceMcpAuth as vn, connectorAuthText as vt, mergeTargetIndex as w, normalizeMarkdownCodeFences as wn, ONBOARDING_PREVIEW_ATTACHMENTS as wt, finalizeStreamingMarkdownForOwner as x, closeDanglingCodeFence as xn, nativeExtensionNeedText as xt, discardThinking as y, MARKDOWN_RENDER_CHUNK_TARGET_BYTES as yn, joinFewNames as yt, RUN_WAITING_DELAY_MS as z, DAEMON_HEALTH_STYLE as zn, onboardingStep as zt };
|
|
5113
5121
|
|
|
5114
|
-
//# sourceMappingURL=transcript-reconcile-
|
|
5122
|
+
//# sourceMappingURL=transcript-reconcile-D_SWw6dX.js.map
|