@openclaw/codex 2026.9.4 → 2026.9.6
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/assets/activity.svg +30 -0
- package/assets/icon.png +0 -0
- package/dist/.setup/account-usage-runtime-Eem_WGqY.mjs +75 -0
- package/dist/{apply-CvT8tW5i.js → .setup/apply-DDOi8uNx.mjs} +24 -30
- package/dist/.setup/async-questions-DdhOCwGi.mjs +27 -0
- package/dist/{attempt-client-cleanup-DKHzbwt5.js → .setup/attempt-client-cleanup-CEv1cKwF.mjs} +79 -49
- package/dist/.setup/attempt-terminal-gZrxQ35N.mjs +5 -0
- package/dist/.setup/attempt-workspace-context-DUVEn_CS.mjs +331 -0
- package/dist/{auth-binding-CWlKVccJ.js → .setup/auth-binding-DhLWa_7K.mjs} +1 -1
- package/dist/{auth-cache-key-7orQae_j.js → .setup/auth-cache-key-B2mpaI9D.mjs} +9 -81
- package/dist/{auth-profile-CwzO4_RG.js → .setup/auth-profile-WqZtZfXN.mjs} +1 -1
- package/dist/.setup/auth-profile-health-oHizqgye.mjs +53 -0
- package/dist/.setup/auth-profile-recovery-BREezV0L.mjs +14 -0
- package/dist/.setup/binding-connection-ThoatDcb.mjs +50 -0
- package/dist/.setup/binding-connection.runtime-yoHrABt-.mjs +48 -0
- package/dist/{bounded-turn-C_Hneydj.js → .setup/bounded-turn-B2HScEgT.mjs} +143 -32
- package/dist/{build-state-BCmg9-5p.js → .setup/build-state-C7EnDVgr.mjs} +1 -1
- package/dist/{capabilities-8vx68WLH.js → .setup/capabilities-CDXOOFdZ.mjs} +1 -1
- package/dist/{client-B57KWPQx.js → .setup/client-Cs08OXVQ.mjs} +705 -512
- package/dist/.setup/client-catalog-response-BMgt_4q4.mjs +285 -0
- package/dist/{command-dispatch-BpduNGVf.js → .setup/command-dispatch-B4JuOsOk.mjs} +8 -4
- package/dist/{command-formatters-lxlkNZgU.js → .setup/command-formatters-Bmqvr9tO.mjs} +8 -4
- package/dist/{command-handlers-tiL9iWj7.js → .setup/command-handlers-DW7Lx9oH.mjs} +137 -186
- package/dist/{command-rpc-CR5EOEZX.js → .setup/command-rpc-DixIj3HW.mjs} +47 -23
- package/dist/{compact-B_H3AOd7.js → .setup/compact-Du5UvtxA.mjs} +29 -51
- package/dist/{config-oIORaQ5T.js → .setup/config-BoTP_mrL.mjs} +5 -4
- package/dist/{config-options-CXMq1T-C.js → .setup/config-options-BvaRs51b.mjs} +50 -446
- package/dist/{protocol-5bh1G-H7.js → .setup/config-parsing-CcB9iPoq.mjs} +9 -51
- package/dist/{config-runtime-D0zGNIHu.js → .setup/config-runtime-C8Rw1m1m.mjs} +2 -2
- package/dist/.setup/config-security-BEReZ6go.mjs +380 -0
- package/dist/{conversation-binding-DsB4-O7U.js → .setup/conversation-binding-DP-gMrBP.mjs} +29 -38
- package/dist/{conversation-binding-data-BiodpIzq.js → .setup/conversation-binding-data-CrcyZk6O.mjs} +1 -1
- package/dist/{conversation-control-CtUu1b3m.js → .setup/conversation-control-uK9Jomlc.mjs} +32 -67
- package/dist/.setup/cyber-failover-DYwbmf1o.mjs +123 -0
- package/dist/.setup/cyber-failover-notice-e9G3J9-e.mjs +17 -0
- package/dist/{dynamic-tools-CmN5RAip.js → .setup/dynamic-tools-BDXl-8Cw.mjs} +936 -620
- package/dist/{effective-mcp-catalog-Bd73bqA8.js → .setup/effective-mcp-catalog-CvnvnGIe.mjs} +3 -3
- package/dist/{ephemeral-turn-D78_VmzO.js → .setup/ephemeral-turn-poidXgek.mjs} +9 -7
- package/dist/{event-projector-assistant-message-BmBM4qBV.js → .setup/event-projector-assistant-message-BsruvNrH.mjs} +8 -7
- package/dist/{event-projector-items-5VhsECCO.js → .setup/event-projector-items-C6L_5ZiT.mjs} +42 -8
- package/dist/{attempt-notifications-C9XufG6l.js → .setup/event-projector-usage-CnBS8Wa3.mjs} +102 -9
- package/dist/{harness-C7rRa7bm.js → .setup/harness-a_MsE4-_.mjs} +81 -21
- package/dist/{inference-context-Dr_mzvk4.js → .setup/inference-context-D96l9-ew.mjs} +1 -1
- package/dist/.setup/inference-proxy-b-aJMSxm.mjs +601 -0
- package/dist/{isolated-completion-DWVb5U2J.js → .setup/isolated-completion-BIZFhTNG.mjs} +18 -11
- package/dist/.setup/launch-args-DbFCehO7.mjs +196 -0
- package/dist/{managed-binary-D22rNEcR.js → .setup/managed-binary-BnshlFag.mjs} +14 -3
- package/dist/{managed-thread-store-D1t5jh3G.js → .setup/managed-thread-store-BMqgThVL.mjs} +48 -14
- package/dist/{model-catalog-Dq2n8f_p.js → .setup/model-catalog-CfXJf9Ay.mjs} +36 -12
- package/dist/{models-PCKOim-h.js → .setup/models-KnqBv0hE.mjs} +3 -3
- package/dist/.setup/native-auth-rWbGbMn3.mjs +57 -0
- package/dist/{native-subagent-history-DjtPloaU.js → .setup/native-subagent-history-0nYYgo0k.mjs} +43 -35
- package/dist/.setup/native-subagent-monitor-D3filLY2.mjs +4859 -0
- package/dist/{native-subagent-task-ids-BzTdT0Uw.js → .setup/native-subagent-task-ids-wb8CKZGN.mjs} +98 -44
- package/dist/{node-cli-sessions-DKaOmVUh.js → .setup/node-cli-sessions-r3avj02l.mjs} +86 -68
- package/dist/.setup/node-exec-server.runtime-BDwWXVpK.mjs +247 -0
- package/dist/{plan-7uG-Fp36.js → .setup/plan-CN3VwfNU.mjs} +133 -119
- package/dist/{plugin-activation-BYQculil.js → .setup/plugin-activation-DT3MNtqj.mjs} +7 -16
- package/dist/{plugin-app-cache-key-d0eKxy7b.js → .setup/plugin-app-cache-key-B2CsSdnV.mjs} +32 -44
- package/dist/{plugin-approval-roundtrip-Bz3FT8W5.js → .setup/plugin-approval-roundtrip-C0MZzCuP.mjs} +1 -1
- package/dist/{plugin-inventory-oL4Na1ZG.js → .setup/plugin-inventory-BoRei8Z4.mjs} +21 -11
- package/dist/{plugin-marketplace-discovery-P-Vndfqq.js → .setup/plugin-marketplace-discovery-CDOi8IFs.mjs} +4 -1
- package/dist/{plugin-metadata-cache-ClPJpRio.js → .setup/plugin-metadata-cache-Ctmo83k_.mjs} +226 -141
- package/dist/.setup/protocol-CANUwXJ3.mjs +17 -0
- package/dist/{provider-MQ8PVkuE.js → .setup/provider-BOsxQHOM.mjs} +9 -5
- package/dist/{provider-capabilities-BvCUL69A.js → .setup/provider-capabilities-BfE88FZ5.mjs} +31 -3
- package/dist/{rate-limits-CBMmWBr9.js → .setup/rate-limits-CMU3DUD0.mjs} +174 -151
- package/dist/{request-B7hEkBGq.js → .setup/request-D2L0zMrq.mjs} +130 -42
- package/dist/{run-attempt-CvsAAGa0.js → .setup/run-attempt-BHu11r7h.mjs} +1628 -966
- package/dist/.setup/run-attempt-lifecycle-B7JbY4-F.mjs +71 -0
- package/dist/{runtime-artifact-BJ0rXBZ_.js → .setup/runtime-artifact-CLZ8udh-.mjs} +29 -45
- package/dist/{sandbox-guard-BxgyoM8M.js → .setup/sandbox-guard-C2sRMOEY.mjs} +3 -3
- package/dist/{session-binding-CI8UuilT.js → .setup/session-binding-Cm0apEbd.mjs} +36 -83
- package/dist/{session-binding-record-Bcvslnhf.js → .setup/session-binding-record-BGoz8wOK.mjs} +202 -5
- package/dist/.setup/session-binding-sidecars-BlB5EvIS.mjs +546 -0
- package/dist/.setup/session-catalog-Pno1xGcl.mjs +2764 -0
- package/dist/{session-catalog-adoption-tcZi1IfX.js → .setup/session-catalog-adoption-BI6UTDZT.mjs} +58 -26
- package/dist/{session-catalog-archive-CwKg8Xz2.js → .setup/session-catalog-archive-lHBqzhaO.mjs} +6 -6
- package/dist/.setup/session-catalog-events-Bj6j94E_.mjs +347 -0
- package/dist/.setup/session-catalog-index-B9_VQIUz.mjs +1170 -0
- package/dist/.setup/session-catalog-index-order-hcdz07yN.mjs +48 -0
- package/dist/.setup/session-catalog-index-state-Dgh8ORJm.mjs +183 -0
- package/dist/{thread-history-page-D0JIp48V.js → .setup/session-catalog-native-projection-DowriLid.mjs} +223 -95
- package/dist/{session-catalog-node-adoption-B1tgDW-m.js → .setup/session-catalog-node-adoption-ITddWx_X.mjs} +25 -13
- package/dist/{session-catalog-node-continue-Ci-DXyJP.js → .setup/session-catalog-node-continue-6g6qi4A9.mjs} +24 -15
- package/dist/.setup/session-catalog-projection-zK_PUsiE.mjs +422 -0
- package/dist/{session-cli-DNN_jhGc.js → .setup/session-cli-irrD-uo7.mjs} +3 -3
- package/dist/{session-history-Cz-tOOYj.js → .setup/session-history-BrqhSCf9.mjs} +19 -19
- package/dist/{session-history-import-DwyijFI6.js → .setup/session-history-import-D-3wAgOP.mjs} +4 -4
- package/dist/{session-history-read-cxPUxyVV.js → .setup/session-history-read-B3ZfSUbF.mjs} +2 -2
- package/dist/{session-history.worker-BeK1YOyT.js → .setup/session-history.worker-CaCh0xF_.mjs} +10 -24
- package/dist/{session-initialization-Ct0_Hzmg.js → .setup/session-initialization-rcgbZiid.mjs} +2 -2
- package/dist/{session-permission-policy-BBmXA8Eg.js → .setup/session-permission-policy-BI1QK_98.mjs} +2 -2
- package/dist/{session-retirement-B2YfbAAT.js → .setup/session-retirement-BH-S6qkJ.mjs} +26 -7
- package/dist/{settled-turn-context-Du6gdUDd.js → .setup/settled-turn-context-fmwouT5I.mjs} +2 -2
- package/dist/{settled-turn-finalizer-Dn91stmc.js → .setup/settled-turn-finalizer-DiAi6Kx6.mjs} +12 -12
- package/dist/{shared-client-CscigXXL.js → .setup/shared-client-DA4VR4Eb.mjs} +332 -221
- package/dist/{side-question-BGMJQf4U.js → .setup/side-question-BJ1wSDcB.mjs} +183 -230
- package/dist/{source-CElXU0Oy.js → .setup/source-CUzJq5WN.mjs} +11 -10
- package/dist/.setup/spawn-error-CL3n6MAa.mjs +57 -0
- package/dist/{thread-archive-guard-DfpBr-Sz.js → .setup/thread-archive-guard-C9frICzX.mjs} +10 -3
- package/dist/.setup/thread-history-page-DoVpnHim.mjs +83 -0
- package/dist/{thread-lifecycle-DXl1-I6b.js → .setup/thread-lifecycle-B3mfz1TG.mjs} +347 -2318
- package/dist/{thread-ownership-BsDRTsyp.js → .setup/thread-ownership-DcTtAcXj.mjs} +6 -4
- package/dist/{thread-policy-BuEQfE0g.js → .setup/thread-policy-DGuQsuFC.mjs} +19 -3
- package/dist/.setup/thread-requests-BLvGkP2R.mjs +2205 -0
- package/dist/{thread-resume-DsDOZpFg.js → .setup/thread-resume-DIBXwOpE.mjs} +8 -5
- package/dist/.setup/timeout-C910MdAB.mjs +80 -0
- package/dist/{transcript-history-projection-v17wXgdK.js → .setup/transcript-history-projection-ZZpkFkJ_.mjs} +96 -61
- package/dist/{transcript-mirror-C5CKgNy6.js → .setup/transcript-mirror-BtHDBp1G.mjs} +224 -195
- package/dist/{transcript-mirror-attestation-DibE0krH.js → .setup/transcript-mirror-attestation-CzM-94NC.mjs} +4 -1
- package/dist/{transport-stdio-BGjHoYLr.js → .setup/transport-stdio-h2VHOskC.mjs} +274 -89
- package/dist/{upstream-session-fork-BZerMte_.js → .setup/upstream-session-fork-BUr4OUbC.mjs} +51 -42
- package/dist/{usage-tCk-mg_x.js → .setup/usage-BML0r-ua.mjs} +5 -4
- package/dist/.setup/usage-limit-error-DUMbefVY.mjs +166 -0
- package/dist/{web-search-provider.runtime-B7bGbGWq.js → .setup/web-search-provider.runtime-CDKlN-Rv.mjs} +4 -3
- package/dist/api.js +23 -12
- package/dist/catalog-page-worker-entrypoint.js +12 -0
- package/dist/catalog-page.worker.js +9 -0
- package/dist/cli-metadata.js +1 -1
- package/dist/doctor-contract-api.js +8 -528
- package/dist/harness.js +1 -1
- package/dist/index.js +306 -215
- package/dist/media-understanding-provider.js +3 -3
- package/dist/migration-provider-api.js +1 -1
- package/dist/native-tool-policy.js +12 -0
- package/dist/provider-discovery.js +18 -0
- package/dist/session-history-worker-runtime.js +36 -35
- package/dist/session-history.worker.js +2 -2
- package/dist/web-search-contract-api.js +1 -1
- package/openclaw.plugin.json +354 -69
- package/package.json +14 -8
- package/dist/attempt-context-D44yeDII.js +0 -636
- package/dist/binding-connection-D3udKbIE.js +0 -60
- package/dist/event-projector-usage-BfXmpOec.js +0 -102
- package/dist/inference-proxy-HGXKUIre.js +0 -311
- package/dist/launch-args-RXQwn8zV.js +0 -90
- package/dist/native-subagent-history-owner-Pcp7JuVF.js +0 -34
- package/dist/native-subagent-monitor-fQ7eIXEf.js +0 -2978
- package/dist/node-exec-server.runtime-Cl2vapEi.js +0 -226
- package/dist/rpc-error-ttN_QjEm.js +0 -30
- package/dist/session-catalog-ct-AH01I.js +0 -1477
- package/dist/session-catalog-home-id-CwhLdC03.js +0 -18
- package/dist/session-catalog-provenance-D-dIfRAH.js +0 -96
- package/dist/timeout-BVw8aaM1.js +0 -33
- package/dist/version-omm6IPI3.js +0 -12
- /package/dist/{auth-profile-selection-DFu9e167.js → .setup/auth-profile-selection-DFu9e167.mjs} +0 -0
- /package/dist/{config-utils-DujwEnhg.js → .setup/config-utils-DujwEnhg.mjs} +0 -0
- /package/dist/{context-compaction-activity-CMla5FPJ.js → .setup/context-compaction-activity-CMla5FPJ.mjs} +0 -0
- /package/dist/{elicitation-input-DPoK8F7w.js → .setup/elicitation-input-DPoK8F7w.mjs} +0 -0
- /package/dist/{history-rejection-B4nOXNXF.js → .setup/history-rejection-B4nOXNXF.mjs} +0 -0
- /package/dist/{image-payload-sanitizer-tupAr-2o.js → .setup/image-payload-sanitizer-tupAr-2o.mjs} +0 -0
- /package/dist/{incognito-session-uhrBF6wJ.js → .setup/incognito-session-uhrBF6wJ.mjs} +0 -0
- /package/dist/{local-runtime-attribution-B_2mnqhb.js → .setup/local-runtime-attribution-B_2mnqhb.mjs} +0 -0
- /package/dist/{native-execution-policy-umd0tgh4.js → .setup/native-execution-policy-umd0tgh4.mjs} +0 -0
- /package/dist/{rolldown-runtime-8H4AJuhK.js → .setup/rolldown-runtime-8H4AJuhK.mjs} +0 -0
- /package/dist/{session-binding-meta-B7aEMU7g.js → .setup/session-binding-meta-B7aEMU7g.mjs} +0 -0
- /package/dist/{session-upstream-marker-D15C9NHp.js → .setup/session-upstream-marker-D15C9NHp.mjs} +0 -0
- /package/dist/{upstream-prompt-provenance-LphB8slG.js → .setup/upstream-prompt-provenance-LphB8slG.mjs} +0 -0
- /package/dist/{web-search-provider.shared-BrZmlqyR.js → .setup/web-search-provider.shared-BrZmlqyR.mjs} +0 -0
|
@@ -0,0 +1,1170 @@
|
|
|
1
|
+
import { C as boundedCatalogString, D as filterCatalogPageByTitle, E as codexCatalogThreadStatus, P as readControlCursor, T as codexCatalogThreadName, U as CODEX_CATALOG_MAX_ROWS, b as MAX_CWD_LENGTH, f as setCodexCatalogSource, k as normalizeLimit, l as getCodexCatalogSource, r as projectCodexCatalogNativeThread, v as CatalogParamsError } from "./session-catalog-native-projection-DowriLid.mjs";
|
|
2
|
+
import { i as subscribeCodexCatalogEvents } from "./session-catalog-events-Bj6j94E_.mjs";
|
|
3
|
+
import { i as retainCodexCatalogRow, n as codexCatalogRowRecency, r as compareCodexCatalogRows, t as CodexCatalogOrdering } from "./session-catalog-index-order-hcdz07yN.mjs";
|
|
4
|
+
import { n as CodexCatalogPersistence, r as codexCatalogMetadataPage } from "./session-catalog-index-state-Dgh8ORJm.mjs";
|
|
5
|
+
import { a as withCodexCatalogListRequest, s as CodexCatalogAvailability } from "./session-catalog-Pno1xGcl.mjs";
|
|
6
|
+
import { a as reportCodexCatalogSpawnFailure, n as findCodexAppServerSpawnError } from "./spawn-error-CL3n6MAa.mjs";
|
|
7
|
+
import { CodexCatalogProjectionCapacityError, CodexCatalogProjections, a as resolveCodexCatalogRolloutFingerprint, i as readCodexCatalogRollout, mergeCodexCatalogRolloutRow, n as indexCodexCatalogRowsByRollout, o as scanCodexCatalogRollouts, projectCodexCatalogThread, r as isCodexCatalogRolloutPathCovered, t as codexCatalogRolloutLogicalPath } from "./session-catalog-projection-zK_PUsiE.mjs";
|
|
8
|
+
import { isRecord } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
9
|
+
import { createHash } from "node:crypto";
|
|
10
|
+
import { isDeepStrictEqual } from "node:util";
|
|
11
|
+
import { embeddedAgentLog } from "openclaw/plugin-sdk/agent-harness-registration";
|
|
12
|
+
import { setImmediate as setImmediate$1 } from "node:timers/promises";
|
|
13
|
+
import { coerceErrorMessage, toErrorObject } from "openclaw/plugin-sdk/error-runtime";
|
|
14
|
+
import { sanitizeTerminalText } from "openclaw/plugin-sdk/text-chunking";
|
|
15
|
+
//#region extensions/codex/src/session-catalog-currency.ts
|
|
16
|
+
const SAFETY_INTERVAL_MS = 9e5;
|
|
17
|
+
/** One periodic reconciliation cycle per home, without a recursive watcher inventory. */
|
|
18
|
+
var CodexCatalogCurrency = class {
|
|
19
|
+
constructor(options) {
|
|
20
|
+
this.options = options;
|
|
21
|
+
this.closed = false;
|
|
22
|
+
this.nativeDirty = false;
|
|
23
|
+
this.nextNativeAt = 0;
|
|
24
|
+
this.nextFilesAt = 0;
|
|
25
|
+
}
|
|
26
|
+
hasActiveWork() {
|
|
27
|
+
return this.hydration !== void 0 || this.initial !== void 0 || this.running !== void 0;
|
|
28
|
+
}
|
|
29
|
+
assertRunnable() {
|
|
30
|
+
if (this.terminalFailure) throw this.terminalFailure;
|
|
31
|
+
}
|
|
32
|
+
stopForTerminalFailure(error) {
|
|
33
|
+
const failure = findCodexAppServerSpawnError(error);
|
|
34
|
+
if (!failure) return false;
|
|
35
|
+
if (!this.closed) {
|
|
36
|
+
this.terminalFailure = failure;
|
|
37
|
+
this.close();
|
|
38
|
+
reportCodexCatalogSpawnFailure(failure);
|
|
39
|
+
}
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
scheduleHydration(run) {
|
|
43
|
+
if (this.closed || this.hydration) return;
|
|
44
|
+
this.hydration = setImmediate(() => {
|
|
45
|
+
this.hydration = void 0;
|
|
46
|
+
(this.options.runBackground ? this.options.runBackground(run) : run()).catch((error) => this.options.report(error));
|
|
47
|
+
});
|
|
48
|
+
this.hydration.unref();
|
|
49
|
+
}
|
|
50
|
+
cancelHydration() {
|
|
51
|
+
clearImmediate(this.hydration);
|
|
52
|
+
this.hydration = void 0;
|
|
53
|
+
}
|
|
54
|
+
requestNativeRefresh() {
|
|
55
|
+
this.nativeDirty = true;
|
|
56
|
+
}
|
|
57
|
+
start() {
|
|
58
|
+
if (this.closed || this.timer) return;
|
|
59
|
+
this.nextNativeAt = Date.now() + SAFETY_INTERVAL_MS;
|
|
60
|
+
this.nextFilesAt = this.nextNativeAt;
|
|
61
|
+
this.timer = setInterval(() => {
|
|
62
|
+
if (this.running) return;
|
|
63
|
+
const startedAt = Date.now();
|
|
64
|
+
const full = startedAt >= this.nextNativeAt;
|
|
65
|
+
const filesDue = this.options.local && startedAt >= this.nextFilesAt;
|
|
66
|
+
if (!full && !filesDue && !this.nativeDirty) return;
|
|
67
|
+
const nativeDue = full || this.nativeDirty;
|
|
68
|
+
this.nativeDirty = false;
|
|
69
|
+
if (full) this.nextNativeAt = startedAt + SAFETY_INTERVAL_MS;
|
|
70
|
+
if (filesDue) this.nextFilesAt = startedAt + SAFETY_INTERVAL_MS;
|
|
71
|
+
const run = async () => {
|
|
72
|
+
if (filesDue) await this.options.reconcileFiles();
|
|
73
|
+
if (nativeDue) await this.options.reconcileNative(full);
|
|
74
|
+
};
|
|
75
|
+
this.running = (this.options.runBackground ? this.options.runBackground(run) : run()).catch((error) => {
|
|
76
|
+
this.options.report(new Error(`Codex catalog reconciliation failed; waiting for new activity or the next safety cycle: ${coerceErrorMessage(error)}`, { cause: error }));
|
|
77
|
+
}).finally(() => {
|
|
78
|
+
this.running = void 0;
|
|
79
|
+
});
|
|
80
|
+
}, 3e4);
|
|
81
|
+
this.timer.unref();
|
|
82
|
+
if (this.options.local) {
|
|
83
|
+
this.initial = setTimeout(() => {
|
|
84
|
+
this.initial = void 0;
|
|
85
|
+
this.options.reconcileFiles().catch((error) => this.options.report(error));
|
|
86
|
+
}, 0);
|
|
87
|
+
this.initial.unref();
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
close() {
|
|
91
|
+
this.closed = true;
|
|
92
|
+
this.cancelHydration();
|
|
93
|
+
clearInterval(this.timer);
|
|
94
|
+
this.timer = void 0;
|
|
95
|
+
clearTimeout(this.initial);
|
|
96
|
+
this.initial = void 0;
|
|
97
|
+
return this.running;
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
//#endregion
|
|
101
|
+
//#region extensions/codex/src/session-catalog-index-cursor.ts
|
|
102
|
+
function readCodexCatalogCursor(homeId, params) {
|
|
103
|
+
const queryId = createHash("sha256").update(JSON.stringify([
|
|
104
|
+
homeId,
|
|
105
|
+
params.cwd?.trim() ?? "",
|
|
106
|
+
params.searchTerm?.trim().toLocaleLowerCase() ?? ""
|
|
107
|
+
])).digest("hex").slice(0, 16);
|
|
108
|
+
const encoded = readControlCursor(params.cursor, "request");
|
|
109
|
+
if (!encoded) return {
|
|
110
|
+
kind: "resident",
|
|
111
|
+
queryId
|
|
112
|
+
};
|
|
113
|
+
const invalid = () => new CatalogParamsError("invalid Codex resident catalog cursor");
|
|
114
|
+
let value;
|
|
115
|
+
try {
|
|
116
|
+
value = JSON.parse(Buffer.from(encoded, "base64url").toString());
|
|
117
|
+
} catch {
|
|
118
|
+
throw invalid();
|
|
119
|
+
}
|
|
120
|
+
if (!Array.isArray(value) || value.length !== 5 || value[0] !== queryId) throw invalid();
|
|
121
|
+
if (value[1] === "native") {
|
|
122
|
+
if (value[2] !== null && typeof value[2] !== "string" || typeof value[3] !== "boolean" || value[4] !== null && (typeof value[4] !== "string" || !value[4] || value[4].length > 256)) throw invalid();
|
|
123
|
+
return {
|
|
124
|
+
kind: "native",
|
|
125
|
+
queryId,
|
|
126
|
+
backwards: value[3],
|
|
127
|
+
...value[2] !== null ? { cursor: readControlCursor(value[2], "native request") } : {},
|
|
128
|
+
...value[4] !== null ? { anchorThreadId: value[4] } : {}
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
if (typeof value[1] !== "number" || !Number.isFinite(value[1]) || typeof value[2] !== "string" || value[2].length > 256 || typeof value[3] !== "number" || !Number.isSafeInteger(value[3]) || typeof value[4] !== "boolean") throw invalid();
|
|
132
|
+
return {
|
|
133
|
+
kind: "resident",
|
|
134
|
+
queryId,
|
|
135
|
+
anchor: {
|
|
136
|
+
updatedAt: value[1],
|
|
137
|
+
recencyAt: value[1],
|
|
138
|
+
threadId: value[2],
|
|
139
|
+
sourceOrder: value[3],
|
|
140
|
+
backwards: value[4]
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
function encodeCodexResidentCursor(queryId, row, backwards) {
|
|
145
|
+
return Buffer.from(JSON.stringify([
|
|
146
|
+
queryId,
|
|
147
|
+
codexCatalogRowRecency(row),
|
|
148
|
+
row.threadId,
|
|
149
|
+
row.sourceOrder ?? 0,
|
|
150
|
+
backwards
|
|
151
|
+
])).toString("base64url");
|
|
152
|
+
}
|
|
153
|
+
function encodeCodexNativeCursor(cursor) {
|
|
154
|
+
const value = Buffer.from(JSON.stringify([
|
|
155
|
+
cursor.queryId,
|
|
156
|
+
"native",
|
|
157
|
+
cursor.cursor ?? null,
|
|
158
|
+
cursor.backwards,
|
|
159
|
+
cursor.anchorThreadId ?? null
|
|
160
|
+
])).toString("base64url");
|
|
161
|
+
readControlCursor(value, "native continuation");
|
|
162
|
+
return value;
|
|
163
|
+
}
|
|
164
|
+
//#endregion
|
|
165
|
+
//#region extensions/codex/src/session-catalog-index-events.ts
|
|
166
|
+
/** Event scheduling only; the index owns row publication and stale-read fencing. */
|
|
167
|
+
var CodexCatalogIndexEvents = class {
|
|
168
|
+
constructor(owner) {
|
|
169
|
+
this.owner = owner;
|
|
170
|
+
this.closed = false;
|
|
171
|
+
this.pending = /* @__PURE__ */ new Map();
|
|
172
|
+
this.upserting = /* @__PURE__ */ new Set();
|
|
173
|
+
}
|
|
174
|
+
hasActiveWork() {
|
|
175
|
+
return this.pending.size > 0 || this.upserting.size > 0;
|
|
176
|
+
}
|
|
177
|
+
handle(event, readThread, source) {
|
|
178
|
+
if (this.closed || !isRecord(event.params)) return;
|
|
179
|
+
const params = event.params;
|
|
180
|
+
if (event.method === "thread/started") {
|
|
181
|
+
if (!isRecord(params.thread) || typeof params.thread.id !== "string") return;
|
|
182
|
+
const thread = params.thread;
|
|
183
|
+
if (!thread.ephemeral && !thread.preview?.trim() && thread.recencyAt == null) return;
|
|
184
|
+
if (!this.hasCapacity()) return;
|
|
185
|
+
const operation = this.owner.upsert(setCodexCatalogSource(thread, source)).catch((error) => this.owner.report(error)).finally(() => this.upserting.delete(operation));
|
|
186
|
+
this.upserting.add(operation);
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
const id = boundedCatalogString(params.threadId, 256);
|
|
190
|
+
if (!id) return;
|
|
191
|
+
if (event.method === "thread/archived" || event.method === "thread/deleted") {
|
|
192
|
+
const pending = this.pending.get(id);
|
|
193
|
+
if (pending) {
|
|
194
|
+
pending.dirty = false;
|
|
195
|
+
pending.sourceOrder = void 0;
|
|
196
|
+
}
|
|
197
|
+
if (event.method === "thread/deleted") this.owner.remove(id);
|
|
198
|
+
else this.owner.archive(id);
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
if (event.method === "thread/name/updated") {
|
|
202
|
+
this.owner.rename(id, codexCatalogThreadName(params.threadName ?? null) ?? null);
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
if (event.method === "thread/status/changed") {
|
|
206
|
+
if (!isRecord(params.status)) return;
|
|
207
|
+
this.owner.updateStatus(id, codexCatalogThreadStatus(params.status), source);
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
if (event.method === "thread/settings/updated") {
|
|
211
|
+
const settings = params.threadSettings;
|
|
212
|
+
if (isRecord(settings)) this.owner.updateSettings(id, {
|
|
213
|
+
...typeof settings.cwd === "string" ? { cwd: settings.cwd } : {},
|
|
214
|
+
...typeof settings.modelProvider === "string" ? { modelProvider: settings.modelProvider } : {}
|
|
215
|
+
}, source);
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
if (event.method === "turn/started" || event.method === "turn/completed" || event.method === "thread/unarchived" || event.method === "thread/reverted") {
|
|
219
|
+
if (event.method !== "thread/unarchived" && this.owner.get(id)?.archived) return;
|
|
220
|
+
this.enqueueRefresh(id, readThread, source, event.method === "turn/started" ? this.owner.reserveTurnStartOrder() : void 0);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
hasCapacity() {
|
|
224
|
+
if (this.pending.size + this.upserting.size < 2e4) return true;
|
|
225
|
+
this.owner.report(/* @__PURE__ */ new Error("Codex catalog event queue reached its resident row limit"));
|
|
226
|
+
return false;
|
|
227
|
+
}
|
|
228
|
+
enqueueRefresh(id, readThread, source, sourceOrder) {
|
|
229
|
+
this.owner.requestNativeRefresh();
|
|
230
|
+
const existing = this.pending.get(id);
|
|
231
|
+
if (existing) {
|
|
232
|
+
existing.readThread = readThread;
|
|
233
|
+
existing.source = source;
|
|
234
|
+
existing.dirty = true;
|
|
235
|
+
existing.sourceOrder = sourceOrder ?? existing.sourceOrder;
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
if (!this.hasCapacity()) return;
|
|
239
|
+
const pending = {
|
|
240
|
+
readThread,
|
|
241
|
+
source,
|
|
242
|
+
dirty: true,
|
|
243
|
+
sourceOrder,
|
|
244
|
+
promise: Promise.resolve()
|
|
245
|
+
};
|
|
246
|
+
this.pending.set(id, pending);
|
|
247
|
+
pending.promise = Promise.resolve().then(async () => {
|
|
248
|
+
try {
|
|
249
|
+
while (!this.closed && pending.dirty) {
|
|
250
|
+
pending.dirty = false;
|
|
251
|
+
const observedSourceOrder = pending.sourceOrder;
|
|
252
|
+
const observedSource = pending.source;
|
|
253
|
+
try {
|
|
254
|
+
if (observedSource.closed) throw new Error("Codex catalog observation source closed before its metadata read");
|
|
255
|
+
const published = await this.owner.refresh(id, pending.readThread, observedSourceOrder);
|
|
256
|
+
if (published && pending.sourceOrder === observedSourceOrder) pending.sourceOrder = void 0;
|
|
257
|
+
else if (!published && pending.sourceOrder !== void 0) pending.dirty = true;
|
|
258
|
+
} catch (error) {
|
|
259
|
+
if (observedSource.closed) {
|
|
260
|
+
if (pending.source === observedSource) pending.dirty = false;
|
|
261
|
+
this.owner.report(new Error("Codex catalog observation interrupted by client closure; metadata refresh deferred to the current catalog owner", { cause: error }));
|
|
262
|
+
} else this.owner.report(error);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
} finally {
|
|
266
|
+
this.pending.delete(id);
|
|
267
|
+
}
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
async close() {
|
|
271
|
+
this.closed = true;
|
|
272
|
+
await Promise.allSettled([...this.upserting, ...[...this.pending.values()].map((entry) => entry.promise)]);
|
|
273
|
+
}
|
|
274
|
+
};
|
|
275
|
+
//#endregion
|
|
276
|
+
//#region extensions/codex/src/session-catalog-index-field.ts
|
|
277
|
+
/** Orders field observations independently from catalog row publication. */
|
|
278
|
+
var CodexCatalogField = class {
|
|
279
|
+
constructor() {
|
|
280
|
+
this.revision = 0;
|
|
281
|
+
this.minimumCapture = 0;
|
|
282
|
+
this.entries = /* @__PURE__ */ new Map();
|
|
283
|
+
}
|
|
284
|
+
capture() {
|
|
285
|
+
return ++this.revision;
|
|
286
|
+
}
|
|
287
|
+
update(threadId, value) {
|
|
288
|
+
this.put(threadId, {
|
|
289
|
+
revision: ++this.revision,
|
|
290
|
+
value
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
observe(threadId, value, capturedRevision) {
|
|
294
|
+
if (capturedRevision < this.minimumCapture || (this.entries.get(threadId)?.revision ?? 0) > capturedRevision) return false;
|
|
295
|
+
this.put(threadId, {
|
|
296
|
+
revision: capturedRevision,
|
|
297
|
+
value
|
|
298
|
+
});
|
|
299
|
+
return true;
|
|
300
|
+
}
|
|
301
|
+
get(threadId) {
|
|
302
|
+
return this.entries.get(threadId)?.value;
|
|
303
|
+
}
|
|
304
|
+
some(predicate) {
|
|
305
|
+
for (const entry of this.entries.values()) if (entry.value !== void 0 && predicate(entry.value)) return true;
|
|
306
|
+
return false;
|
|
307
|
+
}
|
|
308
|
+
delete(threadId) {
|
|
309
|
+
this.put(threadId, { revision: ++this.revision });
|
|
310
|
+
}
|
|
311
|
+
deleteWhere(predicate) {
|
|
312
|
+
for (const [threadId, entry] of this.entries) if (entry.value !== void 0 && predicate(entry.value)) this.delete(threadId);
|
|
313
|
+
}
|
|
314
|
+
invalidate() {
|
|
315
|
+
this.minimumCapture = ++this.revision;
|
|
316
|
+
this.entries.clear();
|
|
317
|
+
}
|
|
318
|
+
put(threadId, entry) {
|
|
319
|
+
const id = boundedCatalogString(threadId, 256);
|
|
320
|
+
if (!id) return;
|
|
321
|
+
this.entries.delete(id);
|
|
322
|
+
this.entries.set(id, entry);
|
|
323
|
+
if (this.entries.size > 2e4) {
|
|
324
|
+
const oldest = this.entries.entries().next().value;
|
|
325
|
+
if (oldest) {
|
|
326
|
+
this.minimumCapture = Math.max(this.minimumCapture, oldest[1].revision);
|
|
327
|
+
this.entries.delete(oldest[0]);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
};
|
|
332
|
+
//#endregion
|
|
333
|
+
//#region extensions/codex/src/session-catalog-index-names.ts
|
|
334
|
+
function applyCodexCatalogName(row, name) {
|
|
335
|
+
if (name === void 0) return row;
|
|
336
|
+
return {
|
|
337
|
+
...row,
|
|
338
|
+
page: { sessions: row.page.sessions.map(({ fallbackName: _fallback, ...session }) => ({
|
|
339
|
+
...session,
|
|
340
|
+
name,
|
|
341
|
+
...!name && row.preview ? { fallbackName: row.preview } : {}
|
|
342
|
+
})) }
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
//#endregion
|
|
346
|
+
//#region extensions/codex/src/session-catalog-index-observations.ts
|
|
347
|
+
/** Fences asynchronous observations against later catalog mutations. */
|
|
348
|
+
var CodexCatalogObservations = class {
|
|
349
|
+
constructor() {
|
|
350
|
+
this.revision = 0;
|
|
351
|
+
this.minimumCapture = 0;
|
|
352
|
+
this.mutations = /* @__PURE__ */ new Map();
|
|
353
|
+
this.observations = /* @__PURE__ */ new Map();
|
|
354
|
+
}
|
|
355
|
+
hasActiveWork() {
|
|
356
|
+
return this.observations.size > 0;
|
|
357
|
+
}
|
|
358
|
+
mark(threadId) {
|
|
359
|
+
this.revision++;
|
|
360
|
+
if (this.observations.size) {
|
|
361
|
+
const id = boundedCatalogString(threadId, 256);
|
|
362
|
+
if (!id) return;
|
|
363
|
+
this.mutations.delete(id);
|
|
364
|
+
this.mutations.set(id, this.revision);
|
|
365
|
+
if (this.mutations.size > 2e4) {
|
|
366
|
+
const oldest = this.mutations.entries().next().value;
|
|
367
|
+
this.minimumCapture = Math.max(this.minimumCapture, oldest[1]);
|
|
368
|
+
this.mutations.delete(oldest[0]);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
async observe(read) {
|
|
373
|
+
const token = Symbol("catalog observation");
|
|
374
|
+
const revision = this.revision;
|
|
375
|
+
this.observations.set(token, revision);
|
|
376
|
+
try {
|
|
377
|
+
return await read((id) => revision >= this.minimumCapture && (this.mutations.get(id) ?? 0) <= revision);
|
|
378
|
+
} finally {
|
|
379
|
+
this.observations.delete(token);
|
|
380
|
+
const oldest = this.observations.values().next().value ?? Infinity;
|
|
381
|
+
for (const [id, changed] of this.mutations) {
|
|
382
|
+
if (changed > oldest) break;
|
|
383
|
+
this.mutations.delete(id);
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
};
|
|
388
|
+
//#endregion
|
|
389
|
+
//#region extensions/codex/src/session-catalog-index-query.ts
|
|
390
|
+
/** Keyset pagination remains valid when the anchor row is archived or deleted. */
|
|
391
|
+
function prepareCodexCatalogQuery(params, prepared) {
|
|
392
|
+
const limit = Math.min(normalizeLimit(params.limit, "limit"), 64);
|
|
393
|
+
const cwd = params.cwd?.trim();
|
|
394
|
+
const search = params.searchTerm?.trim().toLocaleLowerCase();
|
|
395
|
+
const { queryId, anchor } = prepared;
|
|
396
|
+
const cursor = (row, backwards) => encodeCodexResidentCursor(queryId, row, backwards);
|
|
397
|
+
return (ordered, liveStatus, liveSettings, availability) => {
|
|
398
|
+
const { complete, frontier } = availability;
|
|
399
|
+
if (!complete && !frontier) return;
|
|
400
|
+
if (!complete && frontier && anchor?.backwards && compareCodexCatalogRows(frontier, anchor) < 0) return;
|
|
401
|
+
const candidates = complete && !cwd && !search ? ordered : ordered.filter((row) => {
|
|
402
|
+
const session = row.page.sessions[0];
|
|
403
|
+
return session && (complete || !frontier || compareCodexCatalogRows(row, frontier) <= 0) && (!cwd || (liveSettings.get(row.threadId)?.cwd ?? session.cwd) === cwd) && (!search || (session.name ?? session.fallbackName)?.toLocaleLowerCase().includes(search));
|
|
404
|
+
});
|
|
405
|
+
const selected = anchor?.backwards ? candidates.filter((row) => row.threadId !== anchor.threadId) : candidates;
|
|
406
|
+
let start = 0;
|
|
407
|
+
let end;
|
|
408
|
+
const after = (row) => !anchor || compareCodexCatalogRows(row, anchor) > 0;
|
|
409
|
+
if (anchor) {
|
|
410
|
+
const at = selected.findIndex(after);
|
|
411
|
+
const boundary = at < 0 ? selected.length : at;
|
|
412
|
+
if (anchor.backwards) {
|
|
413
|
+
end = boundary;
|
|
414
|
+
start = Math.max(0, boundary - limit);
|
|
415
|
+
} else start = boundary;
|
|
416
|
+
}
|
|
417
|
+
let page = selected.slice(start, end ?? start + limit);
|
|
418
|
+
if (anchor?.backwards && !page.length) {
|
|
419
|
+
start = 0;
|
|
420
|
+
page = candidates.slice(0, limit);
|
|
421
|
+
}
|
|
422
|
+
const first = page[0];
|
|
423
|
+
const last = page.at(-1);
|
|
424
|
+
let continuation = last && (anchor?.backwards ? !complete || candidates.some((row) => compareCodexCatalogRows(row, last) > 0) : start + page.length < selected.length) ? last : void 0;
|
|
425
|
+
if (!complete && !continuation) {
|
|
426
|
+
if (!anchor?.backwards && !last && (!frontier || !after(frontier))) return;
|
|
427
|
+
continuation = frontier && (!last || compareCodexCatalogRows(frontier, last) > 0) ? frontier : last;
|
|
428
|
+
}
|
|
429
|
+
return {
|
|
430
|
+
sessions: page.flatMap((row) => row.page.sessions.map(({ status: _storedStatus, activeFlags: _storedFlags, ...session }) => {
|
|
431
|
+
const live = liveStatus.get(row.threadId);
|
|
432
|
+
return {
|
|
433
|
+
...session,
|
|
434
|
+
...liveSettings.get(row.threadId),
|
|
435
|
+
status: live?.status ?? "notLoaded",
|
|
436
|
+
...live?.activeFlags ? { activeFlags: [...live.activeFlags] } : {}
|
|
437
|
+
};
|
|
438
|
+
})),
|
|
439
|
+
...continuation ? { nextCursor: cursor(continuation, false) } : {},
|
|
440
|
+
...first && start > 0 ? { backwardsCursor: cursor(first, true) } : {}
|
|
441
|
+
};
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
//#endregion
|
|
445
|
+
//#region extensions/codex/src/session-catalog-native-page.ts
|
|
446
|
+
/** Background walks share bounded native pages; the index decides when a prefix is current. */
|
|
447
|
+
async function* readCodexCatalogHydrationPages(read, useStateDbOnly) {
|
|
448
|
+
let cursor;
|
|
449
|
+
let offset = 0;
|
|
450
|
+
const cursors = /* @__PURE__ */ new Set();
|
|
451
|
+
do {
|
|
452
|
+
const page = await read({
|
|
453
|
+
archived: false,
|
|
454
|
+
modelProviders: [],
|
|
455
|
+
sortKey: "recency_at",
|
|
456
|
+
sortDirection: "desc",
|
|
457
|
+
limit: 64,
|
|
458
|
+
...useStateDbOnly ? { useStateDbOnly } : {},
|
|
459
|
+
...cursor ? { cursor } : {}
|
|
460
|
+
}, Math.max(0, CODEX_CATALOG_MAX_ROWS - offset));
|
|
461
|
+
cursor = readControlCursor(page.nextCursor, "hydration response");
|
|
462
|
+
if (cursor && cursors.has(cursor)) throw new Error("Codex catalog repeated a hydration cursor");
|
|
463
|
+
if (cursor) {
|
|
464
|
+
cursors.add(cursor);
|
|
465
|
+
if (cursors.size > 2e4) cursors.delete(cursors.values().next().value);
|
|
466
|
+
}
|
|
467
|
+
yield {
|
|
468
|
+
...page,
|
|
469
|
+
nextCursor: cursor,
|
|
470
|
+
offset
|
|
471
|
+
};
|
|
472
|
+
offset += page.rows.length;
|
|
473
|
+
await setImmediate$1();
|
|
474
|
+
} while (cursor);
|
|
475
|
+
}
|
|
476
|
+
/** The resident limit bounds storage, never authoritative discovery. */
|
|
477
|
+
var CodexCatalogNativePages = class {
|
|
478
|
+
constructor(settings, status) {
|
|
479
|
+
this.settings = settings;
|
|
480
|
+
this.status = status;
|
|
481
|
+
}
|
|
482
|
+
async list(params, prepared, options, request) {
|
|
483
|
+
const limit = Math.min(normalizeLimit(params.limit, "limit"), 64);
|
|
484
|
+
const cwd = params.cwd?.trim();
|
|
485
|
+
let position = prepared.kind === "native" ? prepared : {
|
|
486
|
+
kind: "native",
|
|
487
|
+
queryId: prepared.queryId,
|
|
488
|
+
backwards: prepared.anchor?.backwards ?? false,
|
|
489
|
+
...prepared.anchor ? { anchorThreadId: prepared.anchor.threadId } : {}
|
|
490
|
+
};
|
|
491
|
+
const at = (cursor, backwards, anchorThreadId) => ({
|
|
492
|
+
kind: "native",
|
|
493
|
+
queryId: prepared.queryId,
|
|
494
|
+
backwards,
|
|
495
|
+
...cursor ? { cursor } : {},
|
|
496
|
+
...anchorThreadId ? { anchorThreadId } : {}
|
|
497
|
+
});
|
|
498
|
+
while (request.hasPages) {
|
|
499
|
+
options.assertCurrent();
|
|
500
|
+
const filterCwdLocally = Boolean(cwd && this.settings.hasLiveCwd());
|
|
501
|
+
const ascending = position.backwards && !position.anchorThreadId;
|
|
502
|
+
const pageLimit = position.anchorThreadId ? 64 : limit;
|
|
503
|
+
const statusRevision = this.status.capture();
|
|
504
|
+
const page = await request.read(Number.POSITIVE_INFINITY, () => options.readNative({
|
|
505
|
+
archived: false,
|
|
506
|
+
modelProviders: [],
|
|
507
|
+
useStateDbOnly: true,
|
|
508
|
+
sortKey: "recency_at",
|
|
509
|
+
sortDirection: ascending ? "asc" : "desc",
|
|
510
|
+
limit: pageLimit,
|
|
511
|
+
...cwd && !filterCwdLocally ? { cwd } : {},
|
|
512
|
+
...position.cursor ? { cursor: position.cursor } : {}
|
|
513
|
+
}, pageLimit, request));
|
|
514
|
+
options.assertCurrent();
|
|
515
|
+
for (const row of page.rows) this.status.observe(row, statusRevision);
|
|
516
|
+
if (cwd && !filterCwdLocally && this.settings.hasLiveCwd()) continue;
|
|
517
|
+
let rows = ascending ? page.rows.toReversed() : page.rows;
|
|
518
|
+
let next = (ascending ? page.backwardsCursor : page.nextCursor) ? at(ascending ? page.backwardsCursor : page.nextCursor, false) : void 0;
|
|
519
|
+
let previous = (ascending ? page.nextCursor : page.backwardsCursor) ? at(ascending ? page.nextCursor : page.backwardsCursor, true) : void 0;
|
|
520
|
+
if (position.anchorThreadId) {
|
|
521
|
+
const anchor = rows.findIndex((row) => row.threadId === position.anchorThreadId);
|
|
522
|
+
if (anchor < 0) {
|
|
523
|
+
if (!page.nextCursor || page.nextCursor === position.cursor) throw new CatalogParamsError("Codex catalog changed; refresh before continuing this page");
|
|
524
|
+
position = at(page.nextCursor, position.backwards, position.anchorThreadId);
|
|
525
|
+
continue;
|
|
526
|
+
}
|
|
527
|
+
const start = position.backwards ? Math.max(0, anchor - limit) : anchor + 1;
|
|
528
|
+
const end = position.backwards ? anchor : Math.min(rows.length, start + limit);
|
|
529
|
+
const selected = rows.slice(start, end);
|
|
530
|
+
if (!selected.length) {
|
|
531
|
+
const continuation = position.backwards ? previous : next;
|
|
532
|
+
if (continuation) {
|
|
533
|
+
position = continuation;
|
|
534
|
+
continue;
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
const first = selected[0];
|
|
538
|
+
const last = selected.at(-1);
|
|
539
|
+
if (first && last) {
|
|
540
|
+
next = end < rows.length ? at(position.cursor, false, last.threadId) : next;
|
|
541
|
+
previous = start > 0 ? at(position.cursor, true, first.threadId) : previous;
|
|
542
|
+
}
|
|
543
|
+
rows = selected;
|
|
544
|
+
} else if (!position.cursor && !position.backwards) previous = void 0;
|
|
545
|
+
const projected = filterCatalogPageByTitle({ sessions: rows.flatMap((row) => row.page.sessions).map(({ status: _storedStatus, activeFlags: _storedFlags, ...session }) => {
|
|
546
|
+
const live = this.status.get(session.threadId);
|
|
547
|
+
return Object.assign(session, this.settings.get(session.threadId), {
|
|
548
|
+
status: live?.status ?? "notLoaded",
|
|
549
|
+
...live?.activeFlags ? { activeFlags: [...live.activeFlags] } : {}
|
|
550
|
+
});
|
|
551
|
+
}).filter((session) => !cwd || session.cwd === cwd) }, params.searchTerm);
|
|
552
|
+
const continuation = position.backwards ? previous : next;
|
|
553
|
+
if ((params.searchTerm || filterCwdLocally) && !projected.sessions.length && continuation) {
|
|
554
|
+
if (encodeCodexNativeCursor(continuation) === encodeCodexNativeCursor(position)) throw new CatalogParamsError("Codex catalog repeated a native continuation");
|
|
555
|
+
position = continuation;
|
|
556
|
+
continue;
|
|
557
|
+
}
|
|
558
|
+
const managedThreads = rows.flatMap((row) => row.page.managedThreads ?? []);
|
|
559
|
+
return {
|
|
560
|
+
...projected,
|
|
561
|
+
...managedThreads.length ? { managedThreads } : {},
|
|
562
|
+
...next ? { nextCursor: encodeCodexNativeCursor(next) } : {},
|
|
563
|
+
...previous ? { backwardsCursor: encodeCodexNativeCursor(previous) } : {}
|
|
564
|
+
};
|
|
565
|
+
}
|
|
566
|
+
const continuation = encodeCodexNativeCursor(position);
|
|
567
|
+
return {
|
|
568
|
+
sessions: [],
|
|
569
|
+
...position.backwards ? { backwardsCursor: continuation } : { nextCursor: continuation }
|
|
570
|
+
};
|
|
571
|
+
}
|
|
572
|
+
};
|
|
573
|
+
//#endregion
|
|
574
|
+
//#region extensions/codex/src/session-catalog-settings.ts
|
|
575
|
+
const MAX_SETTINGS_SOURCE_WITNESSES = 64;
|
|
576
|
+
/** Live settings overlay native stored metadata only while a supporting source stays open. */
|
|
577
|
+
var CodexCatalogSettingsIndex = class {
|
|
578
|
+
constructor() {
|
|
579
|
+
this.values = new CodexCatalogField();
|
|
580
|
+
}
|
|
581
|
+
update(threadId, settings, source) {
|
|
582
|
+
if (source.closed) return;
|
|
583
|
+
const cwd = boundedCatalogString(settings.cwd, MAX_CWD_LENGTH);
|
|
584
|
+
const modelProvider = boundedCatalogString(settings.modelProvider, 500, "truncate");
|
|
585
|
+
if (!cwd && !modelProvider) return;
|
|
586
|
+
const bounded = {
|
|
587
|
+
...cwd ? { cwd } : {},
|
|
588
|
+
...modelProvider ? { modelProvider } : {}
|
|
589
|
+
};
|
|
590
|
+
const current = this.values.get(threadId);
|
|
591
|
+
const sources = /* @__PURE__ */ new Set();
|
|
592
|
+
if (current && current.settings.cwd === bounded.cwd && current.settings.modelProvider === bounded.modelProvider) {
|
|
593
|
+
for (const witness of current.sources) if (!witness.closed) sources.add(witness);
|
|
594
|
+
}
|
|
595
|
+
if (sources.size < MAX_SETTINGS_SOURCE_WITNESSES) sources.add(source);
|
|
596
|
+
this.values.update(threadId, {
|
|
597
|
+
settings: bounded,
|
|
598
|
+
sources
|
|
599
|
+
});
|
|
600
|
+
}
|
|
601
|
+
get(threadId) {
|
|
602
|
+
const current = this.values.get(threadId);
|
|
603
|
+
if (current) {
|
|
604
|
+
for (const source of current.sources) if (!source.closed) return current.settings;
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
hasLiveCwd() {
|
|
608
|
+
return this.values.some(({ settings, sources }) => {
|
|
609
|
+
if (settings.cwd) {
|
|
610
|
+
for (const source of sources) if (!source.closed) return true;
|
|
611
|
+
}
|
|
612
|
+
return false;
|
|
613
|
+
});
|
|
614
|
+
}
|
|
615
|
+
delete(threadId) {
|
|
616
|
+
this.values.delete(threadId);
|
|
617
|
+
}
|
|
618
|
+
withdraw(threadId, source) {
|
|
619
|
+
const current = this.values.get(threadId);
|
|
620
|
+
if (!current?.sources.delete(source)) return;
|
|
621
|
+
for (const witness of current.sources) if (!witness.closed) return;
|
|
622
|
+
this.values.delete(threadId);
|
|
623
|
+
}
|
|
624
|
+
invalidate(source) {
|
|
625
|
+
if (!source) {
|
|
626
|
+
this.values.invalidate();
|
|
627
|
+
return;
|
|
628
|
+
}
|
|
629
|
+
this.values.deleteWhere((entry) => {
|
|
630
|
+
entry.sources.delete(source);
|
|
631
|
+
for (const witness of entry.sources) if (!witness.closed) return false;
|
|
632
|
+
return true;
|
|
633
|
+
});
|
|
634
|
+
}
|
|
635
|
+
};
|
|
636
|
+
//#endregion
|
|
637
|
+
//#region extensions/codex/src/session-catalog-status.ts
|
|
638
|
+
const MAX_STATUS_SOURCE_WITNESSES = 64;
|
|
639
|
+
/** Equivalent broadcasts retain at most 64 source witnesses for each bounded resident row. */
|
|
640
|
+
var CodexCatalogStatusIndex = class {
|
|
641
|
+
constructor() {
|
|
642
|
+
this.values = new CodexCatalogField();
|
|
643
|
+
}
|
|
644
|
+
capture() {
|
|
645
|
+
return this.values.capture();
|
|
646
|
+
}
|
|
647
|
+
update(threadId, status, source) {
|
|
648
|
+
const next = this.next(threadId, status, source);
|
|
649
|
+
if (next) this.values.update(threadId, next);
|
|
650
|
+
}
|
|
651
|
+
observe(row, revision) {
|
|
652
|
+
const session = row.page.sessions[0];
|
|
653
|
+
const source = getCodexCatalogSource(row);
|
|
654
|
+
if (session && source) {
|
|
655
|
+
const next = this.next(row.threadId, {
|
|
656
|
+
status: session.status,
|
|
657
|
+
...session.activeFlags ? { activeFlags: session.activeFlags } : {}
|
|
658
|
+
}, source);
|
|
659
|
+
if (next) this.values.observe(row.threadId, next, revision);
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
get(threadId) {
|
|
663
|
+
const current = this.values.get(threadId);
|
|
664
|
+
if (current) {
|
|
665
|
+
for (const source of current.sources) if (!source.closed) return current.status;
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
delete(threadId) {
|
|
669
|
+
this.values.delete(threadId);
|
|
670
|
+
}
|
|
671
|
+
invalidate(source) {
|
|
672
|
+
if (!source) {
|
|
673
|
+
this.values.invalidate();
|
|
674
|
+
return;
|
|
675
|
+
}
|
|
676
|
+
this.values.deleteWhere((entry) => {
|
|
677
|
+
entry.sources.delete(source);
|
|
678
|
+
for (const witness of entry.sources) if (!witness.closed) return false;
|
|
679
|
+
return true;
|
|
680
|
+
});
|
|
681
|
+
}
|
|
682
|
+
next(threadId, status, source) {
|
|
683
|
+
if (source.closed) return;
|
|
684
|
+
const current = this.values.get(threadId);
|
|
685
|
+
const sources = new Set([...current?.sources ?? []].filter((witness) => !witness.closed));
|
|
686
|
+
if (status.status === "notLoaded" && current && current.status.status !== "notLoaded" && sources.size) {
|
|
687
|
+
sources.delete(source);
|
|
688
|
+
if (sources.size) return {
|
|
689
|
+
status: current.status,
|
|
690
|
+
sources
|
|
691
|
+
};
|
|
692
|
+
}
|
|
693
|
+
const flags = status.activeFlags ?? [];
|
|
694
|
+
const previousFlags = current?.status.activeFlags ?? [];
|
|
695
|
+
if (current?.status.status === status.status && flags.length === previousFlags.length && flags.every((flag, index) => flag === previousFlags[index])) {
|
|
696
|
+
if (sources.size < MAX_STATUS_SOURCE_WITNESSES) sources.add(source);
|
|
697
|
+
return {
|
|
698
|
+
status,
|
|
699
|
+
sources
|
|
700
|
+
};
|
|
701
|
+
}
|
|
702
|
+
return {
|
|
703
|
+
status,
|
|
704
|
+
sources: /* @__PURE__ */ new Set([source])
|
|
705
|
+
};
|
|
706
|
+
}
|
|
707
|
+
};
|
|
708
|
+
//#endregion
|
|
709
|
+
//#region extensions/codex/src/session-catalog-index.ts
|
|
710
|
+
/** One home owns resident queries and authoritative overflow discovery. */
|
|
711
|
+
var CodexCatalogIndex = class {
|
|
712
|
+
constructor(options) {
|
|
713
|
+
this.options = options;
|
|
714
|
+
this.rows = /* @__PURE__ */ new Map();
|
|
715
|
+
this.availability = new CodexCatalogAvailability();
|
|
716
|
+
this.liveStatus = new CodexCatalogStatusIndex();
|
|
717
|
+
this.liveSettings = new CodexCatalogSettingsIndex();
|
|
718
|
+
this.nativePages = new CodexCatalogNativePages(this.liveSettings, this.liveStatus);
|
|
719
|
+
this.names = new CodexCatalogField();
|
|
720
|
+
this.initialized = false;
|
|
721
|
+
this.overflow = false;
|
|
722
|
+
this.needsNativeRefresh = false;
|
|
723
|
+
this.restored = false;
|
|
724
|
+
this.closed = false;
|
|
725
|
+
this.projections = new CodexCatalogProjections();
|
|
726
|
+
this.observedFiles = /* @__PURE__ */ new Map();
|
|
727
|
+
this.obsoleteStoredKeys = /* @__PURE__ */ new Set();
|
|
728
|
+
this.sourceRevision = 0;
|
|
729
|
+
this.ordering = new CodexCatalogOrdering();
|
|
730
|
+
this.observations = new CodexCatalogObservations();
|
|
731
|
+
this.currency = new CodexCatalogCurrency({
|
|
732
|
+
local: Boolean(options.localSessionsRoot),
|
|
733
|
+
reconcileFiles: () => this.reconcile(),
|
|
734
|
+
reconcileNative: (full) => this.reconcileNative(full),
|
|
735
|
+
runBackground: options.runBackground,
|
|
736
|
+
report: (error) => this.report(error)
|
|
737
|
+
});
|
|
738
|
+
this.persistence = new CodexCatalogPersistence(options.state, (error) => this.report(error));
|
|
739
|
+
this.events = new CodexCatalogIndexEvents({
|
|
740
|
+
get: (id) => this.rows.get(id),
|
|
741
|
+
updateStatus: (id, status, source) => {
|
|
742
|
+
this.liveStatus.update(id, status, source);
|
|
743
|
+
if (status.status === "notLoaded") this.liveSettings.withdraw(id, source);
|
|
744
|
+
},
|
|
745
|
+
updateSettings: (id, settings, source) => this.liveSettings.update(id, settings, source),
|
|
746
|
+
rename: (id, name) => {
|
|
747
|
+
this.currency.requestNativeRefresh();
|
|
748
|
+
this.names.update(id, name);
|
|
749
|
+
const row = this.rows.get(id);
|
|
750
|
+
if (row && !this.closed) this.put(row);
|
|
751
|
+
},
|
|
752
|
+
upsert: (thread) => this.upsertThread(thread),
|
|
753
|
+
reserveTurnStartOrder: () => this.ordering.reserveEvent(),
|
|
754
|
+
requestNativeRefresh: () => this.currency.requestNativeRefresh(),
|
|
755
|
+
refresh: (id, readThread, sourceOrder) => this.refreshThread(id, readThread, sourceOrder),
|
|
756
|
+
archive: (id) => this.archive(id),
|
|
757
|
+
remove: (id) => {
|
|
758
|
+
this.currency.requestNativeRefresh();
|
|
759
|
+
this.remove(id);
|
|
760
|
+
},
|
|
761
|
+
report: (error) => this.report(error)
|
|
762
|
+
});
|
|
763
|
+
this.unsubscribe = subscribeCodexCatalogEvents(options.homeId, (event, readThread, source) => this.events.handle(event, readThread, source), {
|
|
764
|
+
onEphemeralThread: (id) => this.remove(id),
|
|
765
|
+
onClose: (source) => {
|
|
766
|
+
this.liveStatus.invalidate(source);
|
|
767
|
+
this.liveSettings.invalidate(source);
|
|
768
|
+
},
|
|
769
|
+
onResume: (response, source) => {
|
|
770
|
+
this.liveSettings.update(response.thread.id, response, source);
|
|
771
|
+
return this.upsertThread(setCodexCatalogSource(response.thread, source));
|
|
772
|
+
},
|
|
773
|
+
onRemoteReady: () => {
|
|
774
|
+
if (this.closed || options.localSessionsRoot) return;
|
|
775
|
+
this.sourceRevision++;
|
|
776
|
+
if (!this.initializing) {
|
|
777
|
+
this.initialized = false;
|
|
778
|
+
this.scheduleHydration();
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
});
|
|
782
|
+
}
|
|
783
|
+
assertCurrent() {
|
|
784
|
+
if (this.closed) throw new Error("Codex resident catalog is closed");
|
|
785
|
+
try {
|
|
786
|
+
this.options.assertCurrent();
|
|
787
|
+
} catch (error) {
|
|
788
|
+
this.close();
|
|
789
|
+
throw error;
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
report(error) {
|
|
793
|
+
if (!this.closed && !this.currency.stopForTerminalFailure(error)) embeddedAgentLog.warn("Codex resident catalog background update failed", { error });
|
|
794
|
+
}
|
|
795
|
+
withName(row) {
|
|
796
|
+
const known = this.names.get(row.threadId);
|
|
797
|
+
return applyCodexCatalogName(row, known !== void 0 ? known : this.rows.get(row.threadId)?.page.sessions[0]?.name);
|
|
798
|
+
}
|
|
799
|
+
put(candidate) {
|
|
800
|
+
if (this.closed) return;
|
|
801
|
+
const previous = this.rows.get(candidate.threadId);
|
|
802
|
+
const preview = candidate.preview ?? previous?.preview;
|
|
803
|
+
const patched = this.withName({
|
|
804
|
+
...candidate,
|
|
805
|
+
...preview !== void 0 ? { preview } : {}
|
|
806
|
+
});
|
|
807
|
+
const row = {
|
|
808
|
+
...patched,
|
|
809
|
+
page: codexCatalogMetadataPage(patched.page),
|
|
810
|
+
...patched.rolloutPath ? { rolloutPath: codexCatalogRolloutLogicalPath(patched.rolloutPath) } : {},
|
|
811
|
+
sourceOrder: this.ordering.position(patched, previous)
|
|
812
|
+
};
|
|
813
|
+
if (isDeepStrictEqual(previous, row)) return;
|
|
814
|
+
const oldest = retainCodexCatalogRow(this.rows, row);
|
|
815
|
+
this.overflow ||= this.rows.size >= CODEX_CATALOG_MAX_ROWS;
|
|
816
|
+
this.ordering.invalidate();
|
|
817
|
+
if (oldest?.threadId === row.threadId) return;
|
|
818
|
+
if (oldest) this.evict(oldest.threadId);
|
|
819
|
+
this.persistence.put(row);
|
|
820
|
+
}
|
|
821
|
+
evict(threadId) {
|
|
822
|
+
this.rows.delete(threadId);
|
|
823
|
+
this.ordering.invalidate();
|
|
824
|
+
this.persistence.remove(threadId);
|
|
825
|
+
}
|
|
826
|
+
remove(threadId) {
|
|
827
|
+
this.observations.mark(threadId);
|
|
828
|
+
this.evict(threadId);
|
|
829
|
+
this.liveStatus.delete(threadId);
|
|
830
|
+
this.liveSettings.delete(threadId);
|
|
831
|
+
this.names.delete(threadId);
|
|
832
|
+
}
|
|
833
|
+
async initialize() {
|
|
834
|
+
this.assertCurrent();
|
|
835
|
+
this.currency.assertRunnable();
|
|
836
|
+
this.currency.cancelHydration();
|
|
837
|
+
if (this.initialized && !this.needsNativeRefresh) return;
|
|
838
|
+
if (!this.initializing) {
|
|
839
|
+
this.availability.begin();
|
|
840
|
+
const sourceRevision = this.sourceRevision;
|
|
841
|
+
this.initializing = (async () => {
|
|
842
|
+
await this.restore();
|
|
843
|
+
await this.persistence.pruneObsolete(this.obsoleteStoredKeys, this.rows.values());
|
|
844
|
+
this.obsoleteStoredKeys.clear();
|
|
845
|
+
await this.reconcilingNative?.catch((error) => this.report(error));
|
|
846
|
+
if (!this.initialized) {
|
|
847
|
+
let observedRevision;
|
|
848
|
+
do
|
|
849
|
+
observedRevision = await this.hydrate(this.availability.complete);
|
|
850
|
+
while (observedRevision !== this.sourceRevision);
|
|
851
|
+
this.needsNativeRefresh = false;
|
|
852
|
+
}
|
|
853
|
+
if (this.needsNativeRefresh) {
|
|
854
|
+
await this.reconcile();
|
|
855
|
+
await this.reconcileNative();
|
|
856
|
+
this.needsNativeRefresh = false;
|
|
857
|
+
}
|
|
858
|
+
this.initialized = true;
|
|
859
|
+
this.failure = void 0;
|
|
860
|
+
this.currency.start();
|
|
861
|
+
})().catch((error) => {
|
|
862
|
+
this.failure = { error };
|
|
863
|
+
this.availability.fail(error);
|
|
864
|
+
this.currency.stopForTerminalFailure(error);
|
|
865
|
+
throw error;
|
|
866
|
+
}).finally(() => {
|
|
867
|
+
this.initializing = void 0;
|
|
868
|
+
if (this.failure && sourceRevision !== this.sourceRevision) this.scheduleHydration();
|
|
869
|
+
});
|
|
870
|
+
}
|
|
871
|
+
return this.initializing;
|
|
872
|
+
}
|
|
873
|
+
async restore() {
|
|
874
|
+
if (this.restored) return;
|
|
875
|
+
this.restoring ??= this.observations.observe(async (isCurrent) => {
|
|
876
|
+
try {
|
|
877
|
+
const snapshot = await this.persistence.readSnapshot();
|
|
878
|
+
this.assertCurrent();
|
|
879
|
+
if (snapshot.cleanupIncomplete) this.persistence.invalidate(/* @__PURE__ */ new Error("Codex catalog obsolete snapshot exceeds its cleanup limit"));
|
|
880
|
+
for (const key of snapshot.obsolete) this.obsoleteStoredKeys.add(key);
|
|
881
|
+
for (const row of snapshot.rows) if (isCurrent(row.threadId)) {
|
|
882
|
+
const restored = row.rolloutPath ? {
|
|
883
|
+
...row,
|
|
884
|
+
rolloutPath: codexCatalogRolloutLogicalPath(row.rolloutPath)
|
|
885
|
+
} : row;
|
|
886
|
+
const patched = this.withName(restored);
|
|
887
|
+
if (patched !== restored) this.persistence.put(patched);
|
|
888
|
+
const evicted = retainCodexCatalogRow(this.rows, patched);
|
|
889
|
+
if (evicted) this.evict(evicted.threadId);
|
|
890
|
+
this.ordering.restore(row);
|
|
891
|
+
}
|
|
892
|
+
this.overflow ||= snapshot.overflow || this.rows.size >= 2e4;
|
|
893
|
+
if (snapshot.complete) {
|
|
894
|
+
this.availability.publish(void 0, true);
|
|
895
|
+
this.initialized = true;
|
|
896
|
+
this.needsNativeRefresh = true;
|
|
897
|
+
this.currency.start();
|
|
898
|
+
}
|
|
899
|
+
} catch (error) {
|
|
900
|
+
this.persistence.invalidate(error);
|
|
901
|
+
}
|
|
902
|
+
this.restored = true;
|
|
903
|
+
});
|
|
904
|
+
await this.restoring;
|
|
905
|
+
}
|
|
906
|
+
scheduleHydration() {
|
|
907
|
+
if (this.initialized && !this.needsNativeRefresh || this.initializing || this.closed) return;
|
|
908
|
+
this.currency.scheduleHydration(() => this.initialize());
|
|
909
|
+
}
|
|
910
|
+
captureFields() {
|
|
911
|
+
return {
|
|
912
|
+
status: this.liveStatus.capture(),
|
|
913
|
+
name: this.names.capture()
|
|
914
|
+
};
|
|
915
|
+
}
|
|
916
|
+
observeFields(row, revision) {
|
|
917
|
+
const session = row.page.sessions[0];
|
|
918
|
+
if (!session) return;
|
|
919
|
+
this.liveStatus.observe(row, revision.status);
|
|
920
|
+
if (session.name !== void 0 && this.names.observe(row.threadId, session.name, revision.name)) {
|
|
921
|
+
const current = this.rows.get(row.threadId);
|
|
922
|
+
if (current && current.page.sessions[0]?.name !== session.name) this.put(current);
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
reconcileNative(full = true) {
|
|
926
|
+
if (!this.options.localSessionsRoot && this.initializing && !this.initialized) return this.initializing;
|
|
927
|
+
if (!this.reconcilingNative) this.reconcilingNative = this.hydrate(true, !full).then(() => void 0).finally(() => {
|
|
928
|
+
this.reconcilingNative = void 0;
|
|
929
|
+
});
|
|
930
|
+
return this.reconcilingNative;
|
|
931
|
+
}
|
|
932
|
+
hydrate(useStateDbOnly = false, incremental = false) {
|
|
933
|
+
const run = () => this.observations.observe((isCurrent) => this.hydratePages(isCurrent, useStateDbOnly, incremental));
|
|
934
|
+
return this.options.runNativeWalk?.(run) ?? run();
|
|
935
|
+
}
|
|
936
|
+
async hydratePages(isCurrent, useStateDbOnly, incremental) {
|
|
937
|
+
this.assertCurrent();
|
|
938
|
+
const files = this.options.localSessionsRoot && !useStateDbOnly ? (await scanCodexCatalogRollouts(this.options.localSessionsRoot, /* @__PURE__ */ new Set())).files : /* @__PURE__ */ new Map();
|
|
939
|
+
let observedRevision;
|
|
940
|
+
let frontier;
|
|
941
|
+
const batchOrder = this.ordering.captureBatch(this.availability.complete);
|
|
942
|
+
const remaining = incremental ? void 0 : new Map(this.rows);
|
|
943
|
+
const pages = readCodexCatalogHydrationPages(async (params, remainingRows) => {
|
|
944
|
+
this.assertCurrent();
|
|
945
|
+
const fieldRevision = this.captureFields();
|
|
946
|
+
return {
|
|
947
|
+
...await this.options.readNative(params, remainingRows),
|
|
948
|
+
fieldRevision,
|
|
949
|
+
sourceRevision: this.sourceRevision
|
|
950
|
+
};
|
|
951
|
+
}, useStateDbOnly);
|
|
952
|
+
for await (const page of pages) {
|
|
953
|
+
this.assertCurrent();
|
|
954
|
+
observedRevision ??= page.sourceRevision;
|
|
955
|
+
let sourceOrder = page.offset;
|
|
956
|
+
let changed = false;
|
|
957
|
+
for (const id of page.excludedThreadIds ?? []) if (isCurrent(id)) {
|
|
958
|
+
changed ||= this.rows.has(id);
|
|
959
|
+
this.remove(id);
|
|
960
|
+
}
|
|
961
|
+
for (const row of page.rows) {
|
|
962
|
+
const position = sourceOrder++;
|
|
963
|
+
if (position >= 2e4) continue;
|
|
964
|
+
remaining?.delete(row.threadId);
|
|
965
|
+
const previous = this.rows.get(row.threadId);
|
|
966
|
+
this.observeFields(row, page.fieldRevision);
|
|
967
|
+
if (!isCurrent(row.threadId)) {
|
|
968
|
+
changed = true;
|
|
969
|
+
continue;
|
|
970
|
+
}
|
|
971
|
+
const fingerprint = resolveCodexCatalogRolloutFingerprint(row.rolloutPath, useStateDbOnly ? previous : void 0, files);
|
|
972
|
+
this.observations.mark(row.threadId);
|
|
973
|
+
this.put({
|
|
974
|
+
...row,
|
|
975
|
+
sourceOrder: batchOrder(row, previous, position),
|
|
976
|
+
...fingerprint ? { fingerprint } : {}
|
|
977
|
+
});
|
|
978
|
+
changed ||= this.rows.get(row.threadId) !== previous;
|
|
979
|
+
frontier = this.rows.get(row.threadId) ?? frontier;
|
|
980
|
+
}
|
|
981
|
+
if (incremental && (!changed && page.rows.length > 0 || sourceOrder >= 2e4)) break;
|
|
982
|
+
if (page.nextCursor) this.availability.publish(frontier);
|
|
983
|
+
}
|
|
984
|
+
if (remaining && (!useStateDbOnly || !this.options.localSessionsRoot)) {
|
|
985
|
+
for (const [id, row] of remaining) if (isCurrent(id) && this.rows.get(id) === row) this.remove(id);
|
|
986
|
+
}
|
|
987
|
+
this.availability.publish(frontier, true);
|
|
988
|
+
await this.persistence.finishHydration(this.overflow);
|
|
989
|
+
return observedRevision ?? this.sourceRevision;
|
|
990
|
+
}
|
|
991
|
+
reconcile() {
|
|
992
|
+
if (!this.reconciling) this.reconciling = this.observations.observe((isCurrent) => this.reconcileFiles(isCurrent)).finally(() => {
|
|
993
|
+
this.reconciling = void 0;
|
|
994
|
+
});
|
|
995
|
+
return this.reconciling;
|
|
996
|
+
}
|
|
997
|
+
async reconcileFiles(isCurrent) {
|
|
998
|
+
const root = this.options.localSessionsRoot;
|
|
999
|
+
if (!root || !this.initialized || this.closed) return;
|
|
1000
|
+
this.assertCurrent();
|
|
1001
|
+
const byPath = indexCodexCatalogRowsByRollout(this.rows.values());
|
|
1002
|
+
const { files, present } = await scanCodexCatalogRollouts(root, new Set(byPath.keys()));
|
|
1003
|
+
this.assertCurrent();
|
|
1004
|
+
const observed = new Map(files);
|
|
1005
|
+
for (const [file, fingerprint] of files) {
|
|
1006
|
+
const previous = byPath.get(codexCatalogRolloutLogicalPath(file));
|
|
1007
|
+
const known = this.observedFiles.get(file) ?? previous?.fingerprint;
|
|
1008
|
+
if (known?.mtimeMs === fingerprint.mtimeMs && known.size === fingerprint.size) continue;
|
|
1009
|
+
this.currency.requestNativeRefresh();
|
|
1010
|
+
observed.delete(file);
|
|
1011
|
+
if (known) observed.set(file, known);
|
|
1012
|
+
let thread;
|
|
1013
|
+
try {
|
|
1014
|
+
thread = await readCodexCatalogRollout(root, file);
|
|
1015
|
+
} catch (error) {
|
|
1016
|
+
this.assertCurrent();
|
|
1017
|
+
this.report(error);
|
|
1018
|
+
continue;
|
|
1019
|
+
}
|
|
1020
|
+
this.assertCurrent();
|
|
1021
|
+
if (!thread) {
|
|
1022
|
+
observed.set(file, fingerprint);
|
|
1023
|
+
continue;
|
|
1024
|
+
}
|
|
1025
|
+
if (!isCurrent(thread.id)) continue;
|
|
1026
|
+
const existing = this.rows.get(thread.id);
|
|
1027
|
+
if (existing?.rolloutPath && codexCatalogRolloutLogicalPath(existing.rolloutPath) !== codexCatalogRolloutLogicalPath(file)) {
|
|
1028
|
+
observed.set(file, fingerprint);
|
|
1029
|
+
continue;
|
|
1030
|
+
}
|
|
1031
|
+
if (!existing && !thread.preview) {
|
|
1032
|
+
observed.set(file, fingerprint);
|
|
1033
|
+
continue;
|
|
1034
|
+
}
|
|
1035
|
+
thread.preview ||= existing?.preview;
|
|
1036
|
+
const projected = await projectCodexCatalogThread(thread, root);
|
|
1037
|
+
this.assertCurrent();
|
|
1038
|
+
if (!isCurrent(thread.id)) continue;
|
|
1039
|
+
observed.set(file, fingerprint);
|
|
1040
|
+
const row = projected.rows[0];
|
|
1041
|
+
if (!row) continue;
|
|
1042
|
+
this.observations.mark(row.threadId);
|
|
1043
|
+
this.put(mergeCodexCatalogRolloutRow(row, existing, fingerprint));
|
|
1044
|
+
await setImmediate$1();
|
|
1045
|
+
}
|
|
1046
|
+
for (const row of byPath.values()) if (row.rolloutPath && isCodexCatalogRolloutPathCovered(root, row.rolloutPath) && !present.has(codexCatalogRolloutLogicalPath(row.rolloutPath)) && this.rows.get(row.threadId) === row) {
|
|
1047
|
+
this.currency.requestNativeRefresh();
|
|
1048
|
+
this.remove(row.threadId);
|
|
1049
|
+
}
|
|
1050
|
+
this.observedFiles = observed;
|
|
1051
|
+
}
|
|
1052
|
+
upsertThread(thread) {
|
|
1053
|
+
if (this.closed) return Promise.resolve();
|
|
1054
|
+
try {
|
|
1055
|
+
this.assertCurrent();
|
|
1056
|
+
} catch {
|
|
1057
|
+
return Promise.resolve();
|
|
1058
|
+
}
|
|
1059
|
+
try {
|
|
1060
|
+
this.currency.requestNativeRefresh();
|
|
1061
|
+
return this.upsertPreparedThread(projectCodexCatalogNativeThread(thread, sanitizeTerminalText));
|
|
1062
|
+
} catch (error) {
|
|
1063
|
+
return Promise.reject(toErrorObject(error, "Codex catalog projection failed"));
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
1066
|
+
upsertPreparedThread(prepared) {
|
|
1067
|
+
return this.projections.run(() => {
|
|
1068
|
+
this.observations.mark(prepared.id);
|
|
1069
|
+
const fields = this.captureFields();
|
|
1070
|
+
return this.observations.observe((isCurrent) => this.projectThread(prepared, isCurrent, fields));
|
|
1071
|
+
}).then(() => void 0).catch((error) => {
|
|
1072
|
+
if (!(error instanceof CodexCatalogProjectionCapacityError)) throw error;
|
|
1073
|
+
this.report(error);
|
|
1074
|
+
});
|
|
1075
|
+
}
|
|
1076
|
+
refreshThread(id, readThread, sourceOrder) {
|
|
1077
|
+
this.assertCurrent();
|
|
1078
|
+
this.observations.mark(id);
|
|
1079
|
+
const fields = this.captureFields();
|
|
1080
|
+
return this.projections.run(() => this.observations.observe((isCurrent) => readThread(id).then((thread) => {
|
|
1081
|
+
const prepared = projectCodexCatalogNativeThread(thread, sanitizeTerminalText);
|
|
1082
|
+
if (prepared.id !== id) throw new Error("Codex catalog refresh returned a different thread");
|
|
1083
|
+
return this.closed ? true : this.projectThread(prepared, isCurrent, fields, sourceOrder);
|
|
1084
|
+
})));
|
|
1085
|
+
}
|
|
1086
|
+
async projectThread(thread, isCurrent, fieldRevision, sourceOrder) {
|
|
1087
|
+
const projected = await projectCodexCatalogThread(thread, this.options.localSessionsRoot);
|
|
1088
|
+
if (this.closed) return true;
|
|
1089
|
+
const row = projected.rows[0];
|
|
1090
|
+
if (row) this.observeFields(row, fieldRevision);
|
|
1091
|
+
if (!isCurrent(thread.id)) return false;
|
|
1092
|
+
if (projected.excludedThreadIds?.includes(thread.id)) this.remove(thread.id);
|
|
1093
|
+
if (row) {
|
|
1094
|
+
const previous = this.rows.get(thread.id);
|
|
1095
|
+
const fingerprint = resolveCodexCatalogRolloutFingerprint(row.rolloutPath, previous);
|
|
1096
|
+
this.observations.mark(thread.id);
|
|
1097
|
+
this.put({
|
|
1098
|
+
...row,
|
|
1099
|
+
...sourceOrder !== void 0 ? { sourceOrder } : {},
|
|
1100
|
+
...fingerprint ? { fingerprint } : {}
|
|
1101
|
+
});
|
|
1102
|
+
}
|
|
1103
|
+
return true;
|
|
1104
|
+
}
|
|
1105
|
+
archive(threadId) {
|
|
1106
|
+
if (this.closed) return;
|
|
1107
|
+
this.currency.requestNativeRefresh();
|
|
1108
|
+
this.observations.mark(threadId);
|
|
1109
|
+
this.liveStatus.delete(threadId);
|
|
1110
|
+
this.liveSettings.delete(threadId);
|
|
1111
|
+
this.names.delete(threadId);
|
|
1112
|
+
const row = this.rows.get(threadId);
|
|
1113
|
+
if (row) this.put({
|
|
1114
|
+
...row,
|
|
1115
|
+
archived: true
|
|
1116
|
+
});
|
|
1117
|
+
else this.persistence.remove(threadId);
|
|
1118
|
+
}
|
|
1119
|
+
get(threadId) {
|
|
1120
|
+
return this.rows.get(threadId);
|
|
1121
|
+
}
|
|
1122
|
+
hasActiveWork() {
|
|
1123
|
+
return Boolean(this.initializing || !this.restored && this.restoring || this.reconciling || this.reconcilingNative || this.currency.hasActiveWork() || this.observations.hasActiveWork() || this.events.hasActiveWork() || this.persistence.hasActiveWork());
|
|
1124
|
+
}
|
|
1125
|
+
async list(params, deadline = performance.now() + (this.options.requestTimeoutMs ?? 6e4)) {
|
|
1126
|
+
return await withCodexCatalogListRequest(async (request) => {
|
|
1127
|
+
const expiresAt = request.constrainDeadline(deadline);
|
|
1128
|
+
const cursor = readCodexCatalogCursor(this.options.homeId, params);
|
|
1129
|
+
const query = cursor.kind === "resident" ? prepareCodexCatalogQuery(params, cursor) : void 0;
|
|
1130
|
+
await this.availability.until(this.restore(), expiresAt);
|
|
1131
|
+
this.assertCurrent();
|
|
1132
|
+
this.scheduleHydration();
|
|
1133
|
+
for (;;) {
|
|
1134
|
+
this.assertCurrent();
|
|
1135
|
+
const ordered = this.ordering.read(this.rows);
|
|
1136
|
+
const page = query?.(ordered, this.liveStatus, this.liveSettings, this.availability);
|
|
1137
|
+
if (cursor.kind === "native" || this.overflow && (params.cwd || params.searchTerm || page && !page.nextCursor)) return await this.nativePages.list(params, cursor, this.options, request);
|
|
1138
|
+
if (page) return page;
|
|
1139
|
+
await this.availability.next(expiresAt);
|
|
1140
|
+
}
|
|
1141
|
+
});
|
|
1142
|
+
}
|
|
1143
|
+
/** Fence future publications before a replacement opens the same persisted home. */
|
|
1144
|
+
retire() {
|
|
1145
|
+
this.closed = true;
|
|
1146
|
+
this.availability.fail(/* @__PURE__ */ new Error("Codex resident catalog is closed"));
|
|
1147
|
+
this.liveStatus.invalidate();
|
|
1148
|
+
this.liveSettings.invalidate();
|
|
1149
|
+
this.unsubscribe();
|
|
1150
|
+
this.currency.close();
|
|
1151
|
+
return this.persistence.retire();
|
|
1152
|
+
}
|
|
1153
|
+
async close() {
|
|
1154
|
+
const writes = this.retire();
|
|
1155
|
+
await Promise.allSettled([
|
|
1156
|
+
this.initializing,
|
|
1157
|
+
this.restoring,
|
|
1158
|
+
this.reconciling,
|
|
1159
|
+
this.reconcilingNative,
|
|
1160
|
+
this.currency.close(),
|
|
1161
|
+
writes,
|
|
1162
|
+
this.events.close()
|
|
1163
|
+
]);
|
|
1164
|
+
this.rows.clear();
|
|
1165
|
+
this.observedFiles.clear();
|
|
1166
|
+
this.ordering.invalidate();
|
|
1167
|
+
}
|
|
1168
|
+
};
|
|
1169
|
+
//#endregion
|
|
1170
|
+
export { CodexCatalogIndex };
|