@cortexkit/opencode-magic-context 0.49.35 → 0.49.36
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/README.md +1 -1
- package/dist/auto-search-worker.js +163 -160
- package/dist/chunk-embedding-write-worker.js +58 -56
- package/dist/{compaction-marker-candidates-g0p67ced.js → compaction-marker-candidates-5p1qkve9.js} +3 -1
- package/dist/compaction-marker-candidates-worker.js +24 -23
- package/dist/{compartment-chunk-embedding-y4136are.js → compartment-chunk-embedding-ypktm0tk.js} +5 -4
- package/dist/{conflict-warning-hook-hhw8z5ak.js → conflict-warning-hook-b75jn458.js} +6 -5
- package/dist/{context-fk8e3h9p.js → context-969z683s.js} +485 -91
- package/dist/{embedding-backfill-q6n72sy0.js → embedding-backfill-rma0v2ct.js} +9 -8
- package/dist/embedding-worker.js +2 -2
- package/dist/features/magic-context/compaction-marker-candidates.d.ts.map +1 -1
- package/dist/features/magic-context/compaction-marker.d.ts +5 -3
- package/dist/features/magic-context/compaction-marker.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/task-gates.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/verify-gate.d.ts +2 -0
- package/dist/features/magic-context/dreamer/verify-gate.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/verify-state.d.ts +9 -0
- package/dist/features/magic-context/dreamer/verify-state.d.ts.map +1 -0
- package/dist/features/magic-context/dreamer/verify.d.ts +2 -1
- package/dist/features/magic-context/dreamer/verify.d.ts.map +1 -1
- package/dist/features/magic-context/migration-worker-client.d.ts +3 -0
- package/dist/features/magic-context/migration-worker-client.d.ts.map +1 -1
- package/dist/features/magic-context/migration-worker.d.ts +15 -0
- package/dist/features/magic-context/migration-worker.d.ts.map +1 -1
- package/dist/features/magic-context/overflow-detection.d.ts +2 -2
- package/dist/features/magic-context/overflow-detection.d.ts.map +1 -1
- package/dist/features/magic-context/search-rerank.d.ts.map +1 -1
- package/dist/features/magic-context/storage-meta-persisted.d.ts +1 -0
- package/dist/features/magic-context/storage-meta-persisted.d.ts.map +1 -1
- package/dist/features/magic-context/storage-tags.d.ts +4 -0
- package/dist/features/magic-context/storage-tags.d.ts.map +1 -1
- package/dist/features/magic-context/work-metrics-carry-storage.d.ts +10 -0
- package/dist/features/magic-context/work-metrics-carry-storage.d.ts.map +1 -0
- package/dist/hooks/magic-context/auto-search-worker-client.d.ts +5 -1
- package/dist/hooks/magic-context/auto-search-worker-client.d.ts.map +1 -1
- package/dist/hooks/magic-context/compaction-marker-publication.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-historian.d.ts.map +1 -1
- package/dist/hooks/magic-context/issue-423-fixture.d.ts +1 -1
- package/dist/hooks/magic-context/issue-423-fixture.d.ts.map +1 -1
- package/dist/hooks/magic-context/issue-424-fixture.d.ts +1 -1
- package/dist/hooks/magic-context/issue-424-fixture.d.ts.map +1 -1
- package/dist/hooks/magic-context/project-structural-sentinels.d.ts +25 -0
- package/dist/hooks/magic-context/project-structural-sentinels.d.ts.map +1 -0
- package/dist/hooks/magic-context/protected-tail-boundary.d.ts +8 -1
- package/dist/hooks/magic-context/protected-tail-boundary.d.ts.map +1 -1
- package/dist/hooks/magic-context/raw-ordinal-warmup.d.ts.map +1 -1
- package/dist/hooks/magic-context/read-session-true-raw-tokens.d.ts +2 -0
- package/dist/hooks/magic-context/read-session-true-raw-tokens.d.ts.map +1 -1
- package/dist/hooks/magic-context/release-recovery-prefix.d.ts +9 -0
- package/dist/hooks/magic-context/release-recovery-prefix.d.ts.map +1 -0
- package/dist/hooks/magic-context/strip-structural-noise.d.ts +6 -3
- package/dist/hooks/magic-context/strip-structural-noise.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform-context-state.d.ts +3 -0
- package/dist/hooks/magic-context/transform-context-state.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform-postprocess-phase.d.ts +3 -0
- package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform.d.ts.map +1 -1
- package/dist/{index-cpjk5jd2.js → index-1d042x6w.js} +16 -14
- package/dist/{index-jn0ddrhp.js → index-21fgrfrf.js} +8 -6
- package/dist/{index-pq0dpwrc.js → index-2rs7912w.js} +2 -2
- package/dist/{index-ezv6dz3y.js → index-4ks89h5a.js} +4 -4
- package/dist/{index-vzhhr1ht.js → index-4y35msh5.js} +1 -2
- package/dist/{index-f297z1n8.js → index-72czy45z.js} +5 -5
- package/dist/index-7v05d9b7.js +58 -0
- package/dist/{index-f9b3vtt1.js → index-850vthn3.js} +8 -2
- package/dist/{index-ksv0a31x.js → index-8jjjmhab.js} +12 -1
- package/dist/index-96ztjvkn.js +204 -0
- package/dist/{index-gyaa159j.js → index-9fgmkfaf.js} +6 -3
- package/dist/{index-4bgk5ztz.js → index-9tdvbdv1.js} +187 -90
- package/dist/{index-2v6nvy3k.js → index-ae1ar4v1.js} +1 -1
- package/dist/{index-faxb7mck.js → index-b1ydbp95.js} +1 -1
- package/dist/{index-nxrsns5x.js → index-c5dzns43.js} +75 -75
- package/dist/{index-zhqwda72.js → index-dcjkw41m.js} +1 -1
- package/dist/{index-x2mrq5xv.js → index-dfdg2cgg.js} +179 -49
- package/dist/{index-87ctnzz9.js → index-dz48h1wx.js} +2 -2
- package/dist/{index-b6xz3qbe.js → index-gnmhbyyc.js} +366 -83
- package/dist/{index-qx8j6kds.js → index-j105mf16.js} +2 -2
- package/dist/{index-p56dszfp.js → index-jggt5gf2.js} +1 -1
- package/dist/{index-xwwsbsd3.js → index-pp8vdn01.js} +5 -5
- package/dist/{index-dy7w6wm4.js → index-prw8apnc.js} +5 -5
- package/dist/{index-qncw9hey.js → index-r2epb000.js} +33 -3
- package/dist/{index-brg2w6qc.js → index-tn9drm1a.js} +16 -14
- package/dist/{index-pswsyf1w.js → index-ty4vhe4n.js} +3 -3
- package/dist/{index-pztqab6k.js → index-vd2ywmfe.js} +1 -1
- package/dist/{index-3j9t1v4n.js → index-wcwhhtdh.js} +10 -9
- package/dist/{index-1rhgxqs8.js → index-xd2p95m7.js} +1 -1
- package/dist/{index-0c7p8mq5.js → index-xnm0wq1r.js} +1 -1
- package/dist/{index-3d3872c6.js → index-ys7j6679.js} +4 -4
- package/dist/index.js +38 -37
- package/dist/{message-fts-rowid-map-xg7hr0mk.js → message-fts-rowid-map-t6qsyg9s.js} +4 -3
- package/dist/{message-index-bounded-narw7bnz.js → message-index-bounded-wfk6aqxk.js} +9 -8
- package/dist/migration-worker.js +45 -40
- package/dist/plugin/rpc-handlers.d.ts.map +1 -1
- package/dist/{project-embedding-registry-tdz7985n.js → project-embedding-registry-3yyegjma.js} +8 -7
- package/dist/raw-ordinal-warmup-worker.js +114 -118
- package/dist/{read-session-chunk-vmg1zjg0.js → read-session-chunk-26yrrhyz.js} +7 -6
- package/dist/{read-session-raw-mncmzbm9.js → read-session-raw-j7c9w57v.js} +3 -2
- package/dist/{recomp-orchestrator-qyyhnc9b.js → recomp-orchestrator-wk509qkp.js} +20 -19
- package/dist/{render-c5p0k846.js → render-h1qarr8a.js} +13 -12
- package/dist/{search-f6hwvcxk.js → search-5h9fydyq.js} +16 -15
- package/dist/{search-archive-0ny7p3bw.js → search-archive-q79hyqxs.js} +9 -8
- package/dist/{send-session-notification-0gwcz3fw.js → send-session-notification-14p3yje4.js} +5 -4
- package/dist/shared/model-suggestion-retry.d.ts +7 -0
- package/dist/shared/model-suggestion-retry.d.ts.map +1 -1
- package/dist/shared/prompt-async-transport.d.ts.map +1 -1
- package/dist/shared/reusable-worker-entry.d.ts +4 -0
- package/dist/shared/reusable-worker-entry.d.ts.map +1 -0
- package/dist/shared/reusable-worker.d.ts +6 -0
- package/dist/shared/reusable-worker.d.ts.map +1 -0
- package/dist/shared/reusable-worker.fixture.d.ts +2 -0
- package/dist/shared/reusable-worker.fixture.d.ts.map +1 -0
- package/dist/shared/worker-shutdown.d.ts +1 -1
- package/dist/shared/worker-shutdown.d.ts.map +1 -1
- package/dist/{storage-tags-zx1023km.js → storage-tags-vj0yj7ed.js} +1 -1
- package/dist/{store-620rjzt9.js → store-s3eykdjt.js} +1 -1
- package/dist/{transform-postprocess-phase-807ff6t2.js → transform-postprocess-phase-4gj0mtcg.js} +21 -20
- package/dist/v2/auto-search-worker.js +163 -160
- package/dist/v2/chunk-embedding-write-worker.js +59 -57
- package/dist/v2/compaction-marker-candidates-worker.js +24 -23
- package/dist/v2/{compaction-marker-candidates-t1aq6gsj.js → compaction-marker-candidates-yeb2ky46.js} +4 -2
- package/dist/v2/{compartment-chunk-embedding-ncsk0r9e.js → compartment-chunk-embedding-qfk791bd.js} +6 -5
- package/dist/v2/{context-znqfkap4.js → context-bxr039be.js} +1011 -209
- package/dist/v2/{embedding-backfill-11j425e0.js → embedding-backfill-00tw59rx.js} +10 -9
- package/dist/v2/embedding-worker.js +2 -2
- package/dist/v2/fold/code-mode-catalog.d.ts +3 -0
- package/dist/v2/fold/code-mode-catalog.d.ts.map +1 -0
- package/dist/v2/fold/idle.d.ts +1 -0
- package/dist/v2/fold/idle.d.ts.map +1 -1
- package/dist/v2/fold/manual-baseline.d.ts +8 -0
- package/dist/v2/fold/manual-baseline.d.ts.map +1 -0
- package/dist/v2/fold/native-replay-v3.d.ts +7 -0
- package/dist/v2/fold/native-replay-v3.d.ts.map +1 -1
- package/dist/v2/fold/native-replay.d.ts +24 -7
- package/dist/v2/fold/native-replay.d.ts.map +1 -1
- package/dist/v2/fold/restore.d.ts.map +1 -1
- package/dist/v2/fold/summary.d.ts +4 -0
- package/dist/v2/fold/summary.d.ts.map +1 -0
- package/dist/v2/hidden-completion.d.ts.map +1 -1
- package/dist/v2/hooks/channel2.d.ts +6 -0
- package/dist/v2/hooks/channel2.d.ts.map +1 -1
- package/dist/v2/hooks/context.d.ts.map +1 -1
- package/dist/v2/hooks/restore-rows.d.ts +12 -2
- package/dist/v2/hooks/restore-rows.d.ts.map +1 -1
- package/dist/v2/hooks/synthetic-admission.d.ts +7 -0
- package/dist/v2/hooks/synthetic-admission.d.ts.map +1 -0
- package/dist/v2/hooks/usage-persist.d.ts.map +1 -1
- package/dist/v2/{message-fts-rowid-map-rmk571mb.js → message-fts-rowid-map-z86avy0n.js} +5 -4
- package/dist/v2/{message-index-bounded-620bppw7.js → message-index-bounded-w14496s9.js} +9 -8
- package/dist/v2/migration-worker.js +46 -41
- package/dist/v2/{project-embedding-registry-bm5fe1a8.js → project-embedding-registry-jqq2qeqb.js} +9 -8
- package/dist/v2/raw-ordinal-warmup-worker.js +114 -118
- package/dist/v2/{read-session-chunk-qfwv1k71.js → read-session-chunk-tqnh1ret.js} +7 -6
- package/dist/v2/{read-session-raw-q294t8xs.js → read-session-raw-qpp6x9kg.js} +4 -3
- package/dist/v2/{recomp-orchestrator-fcnjref7.js → recomp-orchestrator-9cjk6aej.js} +19 -18
- package/dist/v2/{render-98a1qv0b.js → render-5dz1knf2.js} +13 -12
- package/dist/v2/{search-z1zqzsmh.js → search-8yfet25y.js} +15 -14
- package/dist/v2/{search-archive-r0y1bafr.js → search-archive-z6z9jqwf.js} +9 -8
- package/dist/v2/{send-session-notification-fst6hkg7.js → send-session-notification-kxp47tsw.js} +4 -3
- package/dist/v2/{server-cpjk5jd2.js → server-1d042x6w.js} +16 -14
- package/dist/v2/{server-fqj6ddpr.js → server-5by3vdzs.js} +186 -89
- package/dist/v2/{server-5jp38p98.js → server-6emy0v9a.js} +1 -2
- package/dist/v2/{server-rktnzs89.js → server-6vzh6wej.js} +1 -1
- package/dist/v2/{server-qa74bj91.js → server-7094pk3w.js} +9 -8
- package/dist/v2/{server-bxpz2dcn.js → server-7acq7815.js} +8 -6
- package/dist/v2/server-7v05d9b7.js +58 -0
- package/dist/v2/{server-24g8r2d0.js → server-7zacmty5.js} +75 -75
- package/dist/v2/server-96ztjvkn.js +204 -0
- package/dist/v2/{server-hnknwaz8.js → server-a9w5f0yw.js} +3 -3
- package/dist/v2/{server-9k0mjef7.js → server-avdveykk.js} +1 -1
- package/dist/v2/{server-hsf0qsn5.js → server-cp1a03vc.js} +1 -1
- package/dist/v2/{server-r3chnxs5.js → server-dfq5vb8j.js} +2 -2
- package/dist/v2/{server-x4m6xcn4.js → server-e51xmr4d.js} +6 -6
- package/dist/v2/{server-7ccxt4nq.js → server-g3gqq4ac.js} +6 -3
- package/dist/v2/{server-kkxzwa6w.js → server-gkse1wyz.js} +3 -3
- package/dist/v2/{server-1xesqm5h.js → server-jd7vzwn4.js} +15 -13
- package/dist/v2/{server-ws5exe6q.js → server-nmyganc8.js} +1 -1
- package/dist/v2/{server-q0z2q2dx.js → server-nq3cb7be.js} +1 -1
- package/dist/v2/{server-55v5hpth.js → server-qjyp27vf.js} +2 -2
- package/dist/v2/{server-xbtw0p9t.js → server-r4430x9m.js} +9 -3
- package/dist/v2/{server-qf2kzsh2.js → server-t8y64xj7.js} +4 -4
- package/dist/v2/{server-s9xgyyj9.js → server-tnzbk64q.js} +34 -4
- package/dist/v2/{server-51779zs2.js → server-v0p37hm2.js} +4 -1
- package/dist/v2/{server-bpvsvtph.js → server-xfjjbrkt.js} +12 -1
- package/dist/v2/server.js +4 -4
- package/dist/v2/{storage-tags-19s0ebf0.js → storage-tags-cw07ky67.js} +1 -1
- package/dist/v2/{store-vdm8v3jd.js → store-z3qe67cg.js} +1 -1
- package/dist/v2/{v2-archive-reader-t2c0eypn.js → v2-archive-reader-z7wr42ry.js} +3 -3
- package/dist/v2/{wrapup-orchestrator-aqpqsveg.js → wrapup-orchestrator-j1v62bkj.js} +19 -18
- package/dist/{v2-archive-reader-tm2eayp2.js → v2-archive-reader-028z6kck.js} +2 -2
- package/dist/{wrapup-orchestrator-k5yp19a6.js → wrapup-orchestrator-xg9avt2p.js} +21 -20
- package/package.json +1 -1
- package/src/shared/model-suggestion-retry.ts +1 -1
- package/src/shared/prompt-async-transport.test.ts +64 -3
- package/src/shared/prompt-async-transport.ts +61 -16
- package/src/shared/reusable-worker-entry.ts +58 -0
- package/src/shared/reusable-worker-reset.test.ts +108 -0
- package/src/shared/reusable-worker.fixture.ts +35 -0
- package/src/shared/reusable-worker.test.ts +253 -0
- package/src/shared/reusable-worker.ts +240 -0
- package/src/shared/worker-shutdown.ts +21 -17
|
@@ -2554,7 +2554,9 @@ function getAllStatusTagTokenTotalsFlat2(db, sessionId, floor = 0, calibration =
|
|
|
2554
2554
|
FROM tags
|
|
2555
2555
|
WHERE session_id = ?`).all(sessionId);
|
|
2556
2556
|
const totals = new Map;
|
|
2557
|
+
const summaryRemovedTotals = new Map;
|
|
2557
2558
|
const nullMessageIds = new Set;
|
|
2559
|
+
const nullSummaryRemovedMessageIds = new Set;
|
|
2558
2560
|
for (const row of rows) {
|
|
2559
2561
|
if (row.type === "tool" && row.tool_owner_message_id === null)
|
|
2560
2562
|
continue;
|
|
@@ -2564,6 +2566,7 @@ function getAllStatusTagTokenTotalsFlat2(db, sessionId, floor = 0, calibration =
|
|
|
2564
2566
|
if (row.token_count === null) {
|
|
2565
2567
|
nullMessageIds.add(owner);
|
|
2566
2568
|
totals.delete(owner);
|
|
2569
|
+
summaryRemovedTotals.delete(owner);
|
|
2567
2570
|
continue;
|
|
2568
2571
|
}
|
|
2569
2572
|
if (nullMessageIds.has(owner))
|
|
@@ -2571,8 +2574,16 @@ function getAllStatusTagTokenTotalsFlat2(db, sessionId, floor = 0, calibration =
|
|
|
2571
2574
|
const ratio = row.type === "tool" ? calibration.toolsRatio : calibration.proseRatio;
|
|
2572
2575
|
const weight = ((row.token_count ?? 0) + (row.input_token_count ?? 0)) * ratio + (row.reasoning_token_count ?? 0) * calibration.proseRatio;
|
|
2573
2576
|
totals.set(owner, (totals.get(owner) ?? 0) + weight);
|
|
2577
|
+
if (row.type === "tool" && row.input_token_count === null) {
|
|
2578
|
+
nullSummaryRemovedMessageIds.add(owner);
|
|
2579
|
+
summaryRemovedTotals.delete(owner);
|
|
2580
|
+
}
|
|
2581
|
+
if (!nullSummaryRemovedMessageIds.has(owner)) {
|
|
2582
|
+
const removedWeight = row.type === "tool" ? (row.input_token_count ?? 0) * calibration.toolsRatio : row.type === "message" ? row.token_count * calibration.proseRatio : 0;
|
|
2583
|
+
summaryRemovedTotals.set(owner, (summaryRemovedTotals.get(owner) ?? 0) + removedWeight);
|
|
2584
|
+
}
|
|
2574
2585
|
}
|
|
2575
|
-
return { totals, nullMessageIds };
|
|
2586
|
+
return { totals, summaryRemovedTotals, nullMessageIds };
|
|
2576
2587
|
}
|
|
2577
2588
|
function getReasoningTokenEstimatesByMessage2(db, sessionId, proseRatio) {
|
|
2578
2589
|
const summary = readTagOwnerSummary(db, sessionId, proseRatio);
|
package/dist/v2/server.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
loadPluginConfigDetailed
|
|
3
|
-
} from "./server-
|
|
3
|
+
} from "./server-avdveykk.js";
|
|
4
4
|
import {
|
|
5
5
|
setHarness2
|
|
6
6
|
} from "./server-pavzsdc6.js";
|
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
union,
|
|
23
23
|
tuple,
|
|
24
24
|
record
|
|
25
|
-
} from "./server-
|
|
25
|
+
} from "./server-7zacmty5.js";
|
|
26
26
|
import {
|
|
27
27
|
pushNotification2
|
|
28
28
|
} from "./server-x8a7jmkh.js";
|
|
@@ -7875,7 +7875,7 @@ var require_src2 = __commonJS(function(exports, module) {
|
|
|
7875
7875
|
// package.json
|
|
7876
7876
|
var package_default = {
|
|
7877
7877
|
name: "@cortexkit/opencode-magic-context",
|
|
7878
|
-
version: "0.49.
|
|
7878
|
+
version: "0.49.36",
|
|
7879
7879
|
type: "module",
|
|
7880
7880
|
description: "OpenCode plugin for Magic Context — cross-session memory and context management",
|
|
7881
7881
|
main: "dist/index.js",
|
|
@@ -8196,7 +8196,7 @@ async function setup(context) {
|
|
|
8196
8196
|
if (claimStorageBackupWarningCheck() && isMagicContextStorageOutsideEngram(storageDir)) {
|
|
8197
8197
|
log2(`[magic-context] Magic Context storage is at ${storageDir}, outside the folder Engram backs up (~/.local/share/cortexkit/magic-context). It is not included in CortexKit backups.`);
|
|
8198
8198
|
}
|
|
8199
|
-
const { registerContext } = await import("./context-
|
|
8199
|
+
const { registerContext } = await import("./context-bxr039be.js");
|
|
8200
8200
|
setHarness2("opencode2");
|
|
8201
8201
|
bindStaleBuildNotice({}, import.meta.url, "opencode2");
|
|
8202
8202
|
const duties = await registerContext(context);
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
readV2RawMessagePagesForConversion2,
|
|
6
6
|
createV2RawMessageReader2,
|
|
7
7
|
createV2RawMessageProvider2
|
|
8
|
-
} from "./server-
|
|
8
|
+
} from "./server-6emy0v9a.js";
|
|
9
9
|
import"./server-ef1mskas.js";
|
|
10
10
|
import"./server-468mya5v.js";
|
|
11
11
|
import"./server-2ra6pwf3.js";
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
readV2ArchiveOffThread2,
|
|
3
3
|
serveV2ArchiveReads2
|
|
4
|
-
} from "./server-
|
|
5
|
-
import"./server-
|
|
4
|
+
} from "./server-e51xmr4d.js";
|
|
5
|
+
import"./server-v0p37hm2.js";
|
|
6
6
|
import"./server-gzy5w8ya.js";
|
|
7
|
-
import"./server-
|
|
7
|
+
import"./server-1d042x6w.js";
|
|
8
8
|
export {
|
|
9
9
|
readV2ArchiveOffThread2 as readV2ArchiveOffThread,
|
|
10
10
|
serveV2ArchiveReads2 as serveV2ArchiveReads
|
|
@@ -11,19 +11,20 @@ import {
|
|
|
11
11
|
releaseCompartmentLeaseBestEffort,
|
|
12
12
|
getCompartments,
|
|
13
13
|
getLastCompartmentEndMessage
|
|
14
|
-
} from "./server-
|
|
14
|
+
} from "./server-t8y64xj7.js";
|
|
15
15
|
import"./server-2amn2s73.js";
|
|
16
16
|
import"./server-969cdpmg.js";
|
|
17
17
|
import"./server-zzgtgqmd.js";
|
|
18
18
|
import {
|
|
19
19
|
inRootAsyncContext2
|
|
20
20
|
} from "./server-gzy5w8ya.js";
|
|
21
|
-
import"./server-
|
|
22
|
-
import"./server-
|
|
23
|
-
import"./server-
|
|
24
|
-
import"./server-
|
|
25
|
-
import"./server-
|
|
26
|
-
import"./server-
|
|
21
|
+
import"./server-v0p37hm2.js";
|
|
22
|
+
import"./server-96ztjvkn.js";
|
|
23
|
+
import"./server-1d042x6w.js";
|
|
24
|
+
import"./server-tnzbk64q.js";
|
|
25
|
+
import"./server-nmyganc8.js";
|
|
26
|
+
import"./server-cp1a03vc.js";
|
|
27
|
+
import"./server-dfq5vb8j.js";
|
|
27
28
|
import {
|
|
28
29
|
getWrapupInProgressState,
|
|
29
30
|
acquireWrapupInProgress,
|
|
@@ -32,12 +33,12 @@ import {
|
|
|
32
33
|
getHistorianFailureState,
|
|
33
34
|
clearEmergencyRecovery,
|
|
34
35
|
prepareRawSessionOrdinals2
|
|
35
|
-
} from "./server-
|
|
36
|
+
} from "./server-jd7vzwn4.js";
|
|
36
37
|
import"./server-tpt7bwq8.js";
|
|
37
|
-
import"./server-
|
|
38
|
+
import"./server-g3gqq4ac.js";
|
|
38
39
|
import"./server-1zx87sdm.js";
|
|
39
|
-
import"./server-
|
|
40
|
-
import"./server-
|
|
40
|
+
import"./server-xfjjbrkt.js";
|
|
41
|
+
import"./server-7zacmty5.js";
|
|
41
42
|
import"./server-2ra6pwf3.js";
|
|
42
43
|
import"./server-mfn1yf9d.js";
|
|
43
44
|
import"./server-xy7w7hrd.js";
|
|
@@ -51,7 +52,7 @@ import"./server-ypf1ap0v.js";
|
|
|
51
52
|
import {
|
|
52
53
|
pushNotification2
|
|
53
54
|
} from "./server-x8a7jmkh.js";
|
|
54
|
-
import"./server-
|
|
55
|
+
import"./server-r4430x9m.js";
|
|
55
56
|
import {
|
|
56
57
|
describeBoundaryDiagnostics,
|
|
57
58
|
resolveWrapupProtectedTailBoundary,
|
|
@@ -62,16 +63,16 @@ import {
|
|
|
62
63
|
registerActiveCompartmentRun,
|
|
63
64
|
setRecompStarting2,
|
|
64
65
|
setRecompTerminal2
|
|
65
|
-
} from "./server-
|
|
66
|
+
} from "./server-5by3vdzs.js";
|
|
66
67
|
import"./server-qt1qqasc.js";
|
|
67
|
-
import"./server-
|
|
68
|
+
import"./server-7acq7815.js";
|
|
68
69
|
import"./server-dcws5831.js";
|
|
69
70
|
import"./server-4dhv7mqz.js";
|
|
70
|
-
import"./server-
|
|
71
|
-
import"./server-
|
|
71
|
+
import"./server-6vzh6wej.js";
|
|
72
|
+
import"./server-gkse1wyz.js";
|
|
72
73
|
import"./server-jjvbk92s.js";
|
|
73
|
-
import"./server-
|
|
74
|
-
import"./server-
|
|
74
|
+
import"./server-nq3cb7be.js";
|
|
75
|
+
import"./server-avdveykk.js";
|
|
75
76
|
import"./server-qxzbmtqt.js";
|
|
76
77
|
import"./server-sd8hvzte.js";
|
|
77
78
|
import"./server-f0j864ma.js";
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
readV2ArchiveOffThread2,
|
|
3
3
|
serveV2ArchiveReads2
|
|
4
|
-
} from "./index-
|
|
4
|
+
} from "./index-prw8apnc.js";
|
|
5
5
|
import"./index-v0p37hm2.js";
|
|
6
6
|
import"./index-gzy5w8ya.js";
|
|
7
|
-
import"./index-
|
|
7
|
+
import"./index-1d042x6w.js";
|
|
8
8
|
export {
|
|
9
9
|
readV2ArchiveOffThread2 as readV2ArchiveOffThread,
|
|
10
10
|
serveV2ArchiveReads2 as serveV2ArchiveReads
|
|
@@ -1,45 +1,46 @@
|
|
|
1
1
|
import {
|
|
2
2
|
runManagedWrapup2
|
|
3
|
-
} from "./index-
|
|
4
|
-
import"./index-
|
|
5
|
-
import"./index-
|
|
6
|
-
import"./index-
|
|
3
|
+
} from "./index-pp8vdn01.js";
|
|
4
|
+
import"./index-ys7j6679.js";
|
|
5
|
+
import"./index-9tdvbdv1.js";
|
|
6
|
+
import"./index-850vthn3.js";
|
|
7
7
|
import"./index-sd3egckz.js";
|
|
8
|
-
import"./index-
|
|
9
|
-
import"./index-
|
|
8
|
+
import"./index-xnm0wq1r.js";
|
|
9
|
+
import"./index-ty4vhe4n.js";
|
|
10
10
|
import"./index-jjvbk92s.js";
|
|
11
|
-
import"./index-
|
|
11
|
+
import"./index-21fgrfrf.js";
|
|
12
12
|
import"./index-4dhv7mqz.js";
|
|
13
|
-
import"./index-
|
|
13
|
+
import"./index-72czy45z.js";
|
|
14
14
|
import"./index-2qbtqg1w.js";
|
|
15
|
-
import"./index-
|
|
15
|
+
import"./index-2rs7912w.js";
|
|
16
16
|
import"./index-2amn2s73.js";
|
|
17
17
|
import"./index-66a50f3e.js";
|
|
18
18
|
import"./index-dnqqqc5f.js";
|
|
19
|
-
import"./index-
|
|
19
|
+
import"./index-ae1ar4v1.js";
|
|
20
20
|
import"./index-qt1qqasc.js";
|
|
21
|
-
import"./index-
|
|
22
|
-
import"./index-
|
|
21
|
+
import"./index-tn9drm1a.js";
|
|
22
|
+
import"./index-8jjjmhab.js";
|
|
23
23
|
import"./index-1zx87sdm.js";
|
|
24
|
-
import"./index-
|
|
24
|
+
import"./index-vd2ywmfe.js";
|
|
25
25
|
import"./index-x8a7jmkh.js";
|
|
26
26
|
import"./index-fw42ms3m.js";
|
|
27
|
-
import"./index-
|
|
28
|
-
import"./index-
|
|
27
|
+
import"./index-xd2p95m7.js";
|
|
28
|
+
import"./index-c5dzns43.js";
|
|
29
29
|
import"./index-jz5bk7xd.js";
|
|
30
|
-
import"./index-
|
|
30
|
+
import"./index-dcjkw41m.js";
|
|
31
31
|
import"./index-g4t7850m.js";
|
|
32
|
-
import"./index-
|
|
32
|
+
import"./index-9fgmkfaf.js";
|
|
33
33
|
import"./index-fb3zxn06.js";
|
|
34
34
|
import"./index-nj360hcs.js";
|
|
35
35
|
import"./index-fr0wbhdn.js";
|
|
36
36
|
import"./index-txs8tce6.js";
|
|
37
|
-
import"./index-
|
|
37
|
+
import"./index-b1ydbp95.js";
|
|
38
38
|
import"./index-wh9fxds5.js";
|
|
39
39
|
import"./index-2p37txes.js";
|
|
40
40
|
import"./index-jkanybgq.js";
|
|
41
41
|
import"./index-9wnbnx8f.js";
|
|
42
|
-
import"./index-
|
|
42
|
+
import"./index-r2epb000.js";
|
|
43
|
+
import"./index-96ztjvkn.js";
|
|
43
44
|
import"./index-v0p37hm2.js";
|
|
44
45
|
import"./index-58e3y90n.js";
|
|
45
46
|
import"./index-fxbk7gk3.js";
|
|
@@ -49,7 +50,7 @@ import"./index-jrfre9ah.js";
|
|
|
49
50
|
import"./index-g2q4htwp.js";
|
|
50
51
|
import"./index-pavzsdc6.js";
|
|
51
52
|
import"./index-z4p0ry94.js";
|
|
52
|
-
import"./index-
|
|
53
|
+
import"./index-1d042x6w.js";
|
|
53
54
|
export {
|
|
54
55
|
runManagedWrapup2 as runManagedWrapup
|
|
55
56
|
};
|
package/package.json
CHANGED
|
@@ -429,7 +429,7 @@ async function promptWithTimeout(
|
|
|
429
429
|
* instance-scoped fiber that `POST /session/{id}/abort` interrupts. Best-effort —
|
|
430
430
|
* a failure here must not mask the original timeout/abort error.
|
|
431
431
|
*/
|
|
432
|
-
async function abortChildRun(client: Client, sessionId: string): Promise<void> {
|
|
432
|
+
export async function abortChildRun(client: Client, sessionId: string): Promise<void> {
|
|
433
433
|
if (!client) return;
|
|
434
434
|
try {
|
|
435
435
|
// Bound the abort call: it's best-effort cleanup, and if the abort
|
|
@@ -17,7 +17,7 @@ type Message = {
|
|
|
17
17
|
finish?: string;
|
|
18
18
|
error?: unknown;
|
|
19
19
|
};
|
|
20
|
-
parts: Array<{ type: string; text?: string }>;
|
|
20
|
+
parts: Array<{ type: string; text?: string; error?: unknown }>;
|
|
21
21
|
};
|
|
22
22
|
|
|
23
23
|
/**
|
|
@@ -165,6 +165,42 @@ describe("promptAsyncAndWaitForIdle", () => {
|
|
|
165
165
|
).rejects.toThrow("did not start a run");
|
|
166
166
|
});
|
|
167
167
|
|
|
168
|
+
test("ignores provider errors and retry parts from before the current send", async () => {
|
|
169
|
+
const host = asyncHost({
|
|
170
|
+
plan: ["busy", "settle"],
|
|
171
|
+
initialMessages: [
|
|
172
|
+
{
|
|
173
|
+
info: {
|
|
174
|
+
id: "old-error",
|
|
175
|
+
role: "assistant",
|
|
176
|
+
time: { created: 0 },
|
|
177
|
+
error: { name: "APIError" },
|
|
178
|
+
},
|
|
179
|
+
parts: [{ type: "retry", error: { name: "APIError" } }],
|
|
180
|
+
},
|
|
181
|
+
],
|
|
182
|
+
});
|
|
183
|
+
await promptAsyncAndWaitForIdle(host.client, request(), { pollIntervalMs: 1 });
|
|
184
|
+
expect(host.polls()).toBe(2);
|
|
185
|
+
expect(host.abort).not.toHaveBeenCalled();
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
test("accepts a successfully settled assistant that retains an earlier retry part", async () => {
|
|
189
|
+
const host = asyncHost({ plan: ["settle"] });
|
|
190
|
+
const read = host.list.getMockImplementation()!;
|
|
191
|
+
host.list.mockImplementation(async () => {
|
|
192
|
+
const result = await read();
|
|
193
|
+
const last = result.data.at(-1);
|
|
194
|
+
if (last?.info.finish === "stop") {
|
|
195
|
+
last.parts.push({ type: "retry", error: { name: "APIError" } });
|
|
196
|
+
}
|
|
197
|
+
return result;
|
|
198
|
+
});
|
|
199
|
+
await promptAsyncAndWaitForIdle(host.client, request(), { pollIntervalMs: 1 });
|
|
200
|
+
expect(host.polls()).toBe(1);
|
|
201
|
+
expect(host.abort).not.toHaveBeenCalled();
|
|
202
|
+
});
|
|
203
|
+
|
|
168
204
|
test("surfaces a rejected prompt_async request", async () => {
|
|
169
205
|
const host = asyncHost({ plan: ["settle"] });
|
|
170
206
|
host.promptAsync.mockImplementation(async () => ({
|
|
@@ -653,9 +689,11 @@ describe("prompt_async transport and the first-output deadline", () => {
|
|
|
653
689
|
* busy forever; "partial" streams a text part and then stays busy; "answer"
|
|
654
690
|
* settles with a final assistant message on the next poll.
|
|
655
691
|
*/
|
|
656
|
-
function modelHost(
|
|
692
|
+
function modelHost(
|
|
693
|
+
behaviours: Record<string, "dead" | "partial" | "answer" | "error" | "retry">,
|
|
694
|
+
) {
|
|
657
695
|
const messages: Message[] = [];
|
|
658
|
-
let current: "dead" | "partial" | "answer" | null = null;
|
|
696
|
+
let current: "dead" | "partial" | "answer" | "error" | "retry" | null = null;
|
|
659
697
|
const sent: string[] = [];
|
|
660
698
|
const promptAsync = mock(
|
|
661
699
|
async (request: { body: { model?: { providerID: string; modelID: string } } }) => {
|
|
@@ -684,6 +722,16 @@ describe("prompt_async transport and the first-output deadline", () => {
|
|
|
684
722
|
return { data: true };
|
|
685
723
|
});
|
|
686
724
|
const status = mock(async () => {
|
|
725
|
+
if (current === "error" || current === "retry") {
|
|
726
|
+
const last = messages.at(-1)!;
|
|
727
|
+
const error = {
|
|
728
|
+
name: "APIError",
|
|
729
|
+
data: { statusCode: 429, message: "Free usage limit reached" },
|
|
730
|
+
};
|
|
731
|
+
if (current === "error") last.info.error = error;
|
|
732
|
+
else last.parts = [{ type: "retry", error }];
|
|
733
|
+
return { data: { "ses-child": { type: current === "retry" ? "retry" : "busy" } } };
|
|
734
|
+
}
|
|
687
735
|
if (current === "dead" || current === "partial")
|
|
688
736
|
return { data: { "ses-child": { type: "busy" } } };
|
|
689
737
|
if (current === "answer") {
|
|
@@ -751,4 +799,17 @@ describe("prompt_async transport and the first-output deadline", () => {
|
|
|
751
799
|
await expect(runChain(host, 200, 40)).rejects.toThrow("prompt timed out after 200ms");
|
|
752
800
|
expect(host.sent).toEqual(["opencode/free-model"]);
|
|
753
801
|
});
|
|
802
|
+
|
|
803
|
+
for (const failure of ["error", "retry"] as const) {
|
|
804
|
+
test(`a recorded provider ${failure} stops the host retry loop and immediately tries the fallback`, async () => {
|
|
805
|
+
const host = modelHost({ "opencode/free-model": failure });
|
|
806
|
+
const startedAt = Date.now();
|
|
807
|
+
const result = await runChain(host, 5_000, 5_000);
|
|
808
|
+
expect(result.attempt.label).toBe("anthropic/claude-sonnet-5-5");
|
|
809
|
+
expect(host.sent).toEqual(["opencode/free-model", "anthropic/claude-sonnet-5-5"]);
|
|
810
|
+
expect(host.abort).toHaveBeenCalledTimes(1);
|
|
811
|
+
expect(host.abort).toHaveBeenCalledWith({ path: { id: "ses-child" } });
|
|
812
|
+
expect(Date.now() - startedAt).toBeLessThan(2_000);
|
|
813
|
+
});
|
|
814
|
+
}
|
|
754
815
|
});
|
|
@@ -14,7 +14,11 @@ import {
|
|
|
14
14
|
import { describeAssistantError } from "./assistant-message-extractor";
|
|
15
15
|
import { sessionLog } from "./logger";
|
|
16
16
|
import type { PromptArgs, PromptTransport } from "./model-suggestion-retry";
|
|
17
|
-
import {
|
|
17
|
+
import {
|
|
18
|
+
abortChildRun,
|
|
19
|
+
noteModelActivityMonitored,
|
|
20
|
+
noteModelOutputReceived,
|
|
21
|
+
} from "./model-suggestion-retry";
|
|
18
22
|
|
|
19
23
|
type Client = ReturnType<typeof createOpencodeClient> | undefined;
|
|
20
24
|
|
|
@@ -196,6 +200,28 @@ function messageId(message: unknown): string | null {
|
|
|
196
200
|
return typeof id === "string" ? id : null;
|
|
197
201
|
}
|
|
198
202
|
|
|
203
|
+
function recordedAssistantError(message: unknown): unknown {
|
|
204
|
+
const info = infoOf(message);
|
|
205
|
+
if (info.error != null) return info.error;
|
|
206
|
+
// A completed step can retain retry parts from a provider attempt that
|
|
207
|
+
// already recovered before this poll. Its successful settlement wins.
|
|
208
|
+
if (isSettledAssistant(message)) return undefined;
|
|
209
|
+
const parts = (message as { parts?: unknown[] } | null)?.parts;
|
|
210
|
+
if (!Array.isArray(parts)) return undefined;
|
|
211
|
+
// OpenCode records a failed provider attempt as a retry part before it
|
|
212
|
+
// settles the assistant row or emits session.error.
|
|
213
|
+
const retry = parts
|
|
214
|
+
.slice()
|
|
215
|
+
.reverse()
|
|
216
|
+
.find(
|
|
217
|
+
(part) =>
|
|
218
|
+
part !== null &&
|
|
219
|
+
typeof part === "object" &&
|
|
220
|
+
(part as { type?: unknown }).type === "retry",
|
|
221
|
+
) as { error?: unknown } | undefined;
|
|
222
|
+
return retry?.error ?? undefined;
|
|
223
|
+
}
|
|
224
|
+
|
|
199
225
|
/** An assistant message the host has finished writing, successfully or not. */
|
|
200
226
|
function isSettledAssistant(message: unknown): boolean {
|
|
201
227
|
const info = infoOf(message);
|
|
@@ -355,6 +381,26 @@ export async function promptAsyncAndWaitForIdle(
|
|
|
355
381
|
// Dispatch can fail before an assistant row exists. The plugin event hook
|
|
356
382
|
// retains that provider/model error while this child is actively awaited.
|
|
357
383
|
activeSessionErrors.set(sessionId, undefined);
|
|
384
|
+
const failForHostError = async (hostError: unknown): Promise<never> => {
|
|
385
|
+
// Stop the host's retry loop before handing the attempt to our model
|
|
386
|
+
// chain; otherwise the failed model keeps making requests in parallel.
|
|
387
|
+
await abortChildRun(client, sessionId);
|
|
388
|
+
const error = new Error(
|
|
389
|
+
`Host recorded session error: ${describeAssistantError(hostError)}`,
|
|
390
|
+
);
|
|
391
|
+
Object.assign(error, {
|
|
392
|
+
name: "DreamerProviderOutputFailureError",
|
|
393
|
+
transient: true,
|
|
394
|
+
[HOST_SESSION_ERROR]: true,
|
|
395
|
+
hostError,
|
|
396
|
+
});
|
|
397
|
+
annotateSubagentInvocationError(error, {
|
|
398
|
+
attemptedModel: requestModelRef(request),
|
|
399
|
+
modelConfigKey: options.modelConfigKey,
|
|
400
|
+
hostError,
|
|
401
|
+
});
|
|
402
|
+
throw error;
|
|
403
|
+
};
|
|
358
404
|
try {
|
|
359
405
|
let sent: unknown;
|
|
360
406
|
try {
|
|
@@ -395,24 +441,23 @@ export async function promptAsyncAndWaitForIdle(
|
|
|
395
441
|
await sleep(pollIntervalMs, signal);
|
|
396
442
|
const hostError = activeSessionErrors.get(sessionId);
|
|
397
443
|
if (hostError !== undefined) {
|
|
398
|
-
|
|
399
|
-
`Host recorded session error: ${describeAssistantError(hostError)}`,
|
|
400
|
-
);
|
|
401
|
-
Object.assign(error, {
|
|
402
|
-
name: "DreamerProviderOutputFailureError",
|
|
403
|
-
transient: true,
|
|
404
|
-
[HOST_SESSION_ERROR]: true,
|
|
405
|
-
hostError,
|
|
406
|
-
});
|
|
407
|
-
annotateSubagentInvocationError(error, {
|
|
408
|
-
attemptedModel: requestModelRef(request),
|
|
409
|
-
modelConfigKey: options.modelConfigKey,
|
|
410
|
-
hostError,
|
|
411
|
-
});
|
|
412
|
-
throw error;
|
|
444
|
+
await failForHostError(hostError);
|
|
413
445
|
}
|
|
414
446
|
const status = await readStatus(session, sessionId, dir, signal);
|
|
415
447
|
const messages = await readMessages(session, sessionId, dir, signal);
|
|
448
|
+
const latestAssistant = messages
|
|
449
|
+
.slice()
|
|
450
|
+
.reverse()
|
|
451
|
+
.find((message) => {
|
|
452
|
+
const id = messageId(message);
|
|
453
|
+
return (
|
|
454
|
+
id !== null &&
|
|
455
|
+
!completionBaseline.has(id) &&
|
|
456
|
+
infoOf(message).role === "assistant"
|
|
457
|
+
);
|
|
458
|
+
});
|
|
459
|
+
const assistantError = recordedAssistantError(latestAssistant);
|
|
460
|
+
if (assistantError !== undefined) await failForHostError(assistantError);
|
|
416
461
|
if (
|
|
417
462
|
!sawOutput &&
|
|
418
463
|
messages.some((message) => {
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { EventEmitter } from "node:events";
|
|
2
|
+
import { type MessagePort, parentPort, workerData } from "node:worker_threads";
|
|
3
|
+
|
|
4
|
+
/** Dispatch each job with new per-job state and a port whose messages are matched by job id. */
|
|
5
|
+
export function serveWorkerJobs<T>(
|
|
6
|
+
run: (data: T, port: MessagePort) => Promise<void> | void,
|
|
7
|
+
autoClose = true,
|
|
8
|
+
): void {
|
|
9
|
+
if (!parentPort) throw new Error("worker requires a parent port");
|
|
10
|
+
const parent = parentPort;
|
|
11
|
+
if (!workerData?.reusableWorker) {
|
|
12
|
+
void Promise.resolve(run(workerData, parent)).catch(rethrow);
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
let active: { id: number; port: EventEmitter } | undefined;
|
|
16
|
+
parent.on("message", (message: { jobId: number; start?: T; value?: unknown }) => {
|
|
17
|
+
if (!("start" in message)) {
|
|
18
|
+
if (active?.id === message.jobId) active.port.emit("message", message.value);
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
if (active) throw new Error("reusable worker received overlapping jobs");
|
|
22
|
+
const id = message.jobId;
|
|
23
|
+
let closed = false;
|
|
24
|
+
const port = Object.assign(new EventEmitter(), {
|
|
25
|
+
postMessage(value: unknown, transferList?: readonly object[]) {
|
|
26
|
+
if (!closed) parent.postMessage({ jobId: id, value }, transferList as never);
|
|
27
|
+
},
|
|
28
|
+
close() {
|
|
29
|
+
if (closed) return;
|
|
30
|
+
closed = true;
|
|
31
|
+
port.removeAllListeners();
|
|
32
|
+
active = undefined;
|
|
33
|
+
parent.postMessage({
|
|
34
|
+
jobId: id,
|
|
35
|
+
finished: true,
|
|
36
|
+
code: Number(process.exitCode) || 0,
|
|
37
|
+
});
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
active = { id, port };
|
|
41
|
+
try {
|
|
42
|
+
void Promise.resolve(run(message.start as T, port as unknown as MessagePort))
|
|
43
|
+
.then(() => {
|
|
44
|
+
if (autoClose) port.close();
|
|
45
|
+
})
|
|
46
|
+
.catch(rethrow);
|
|
47
|
+
} catch (error) {
|
|
48
|
+
rethrow(error);
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function rethrow(error: unknown): void {
|
|
54
|
+
// Bun 1.3 aborts the host for a microtask throw; a timer reports a Worker error.
|
|
55
|
+
setTimeout(() => {
|
|
56
|
+
throw error;
|
|
57
|
+
});
|
|
58
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { expect, spyOn, test } from "bun:test";
|
|
2
|
+
import { spawnSync } from "node:child_process";
|
|
3
|
+
import { once } from "node:events";
|
|
4
|
+
import { writeFileSync } from "node:fs";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
import * as timers from "node:timers";
|
|
7
|
+
import { fileURLToPath } from "node:url";
|
|
8
|
+
import { resetReusableWorkersForTests, reuseWorker } from "./reusable-worker";
|
|
9
|
+
import { withTestTempDir } from "./test-temp-dir";
|
|
10
|
+
|
|
11
|
+
test("a temporary caller clock cannot replace the pool's idle timer", async () => {
|
|
12
|
+
const clock = spyOn(globalThis, "setTimeout").mockReturnValue(
|
|
13
|
+
0 as unknown as ReturnType<typeof setTimeout>,
|
|
14
|
+
);
|
|
15
|
+
try {
|
|
16
|
+
const worker = reuseWorker(new URL("./reusable-worker.fixture.ts", import.meta.url), {
|
|
17
|
+
workerData: { path: "caller-clock" },
|
|
18
|
+
});
|
|
19
|
+
const message = once(worker, "message");
|
|
20
|
+
const exit = once(worker, "exit");
|
|
21
|
+
await message;
|
|
22
|
+
await exit;
|
|
23
|
+
expect(clock).not.toHaveBeenCalled();
|
|
24
|
+
} finally {
|
|
25
|
+
clock.mockRestore();
|
|
26
|
+
await resetReusableWorkersForTests();
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
test("reset clears idle timers and waits for active and queued leases to exit", async () => {
|
|
31
|
+
const entry = new URL("./reusable-worker.fixture.ts", import.meta.url);
|
|
32
|
+
const schedules = spyOn(timers, "setTimeout");
|
|
33
|
+
const cancellations = spyOn(timers, "clearTimeout");
|
|
34
|
+
const idleMs = 12_345;
|
|
35
|
+
async function runIdle() {
|
|
36
|
+
const worker = reuseWorker(entry, { workerData: { path: "reset-idle" } }, idleMs);
|
|
37
|
+
const message = once(worker, "message");
|
|
38
|
+
const exit = once(worker, "exit");
|
|
39
|
+
const [reply] = await message;
|
|
40
|
+
await exit;
|
|
41
|
+
return reply.threadId as number;
|
|
42
|
+
}
|
|
43
|
+
try {
|
|
44
|
+
const previousThread = await runIdle();
|
|
45
|
+
const timerIndex = schedules.mock.calls.findIndex(([, delay]) => delay === idleMs);
|
|
46
|
+
expect(timerIndex).toBeGreaterThanOrEqual(0);
|
|
47
|
+
const idleTimer = schedules.mock.results[timerIndex]?.value;
|
|
48
|
+
const active = reuseWorker(entry, { workerData: { path: "reset-active", hang: true } });
|
|
49
|
+
const queued = reuseWorker(entry, {
|
|
50
|
+
workerData: { path: "reset-active", value: "queued" },
|
|
51
|
+
});
|
|
52
|
+
const replies: unknown[] = [];
|
|
53
|
+
queued.on("message", (message) => replies.push(message));
|
|
54
|
+
const activeExit = once(active, "exit");
|
|
55
|
+
const queuedExit = once(queued, "exit");
|
|
56
|
+
await Promise.resolve();
|
|
57
|
+
await Promise.all([resetReusableWorkersForTests(), activeExit, queuedExit]);
|
|
58
|
+
expect(cancellations).toHaveBeenCalledWith(idleTimer);
|
|
59
|
+
expect(replies).toEqual([]);
|
|
60
|
+
expect(await runIdle()).not.toBe(previousThread);
|
|
61
|
+
} finally {
|
|
62
|
+
schedules.mockRestore();
|
|
63
|
+
cancellations.mockRestore();
|
|
64
|
+
await resetReusableWorkersForTests();
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
test("the shared preload stops pooled workers between test cases", () => {
|
|
69
|
+
withTestTempDir("reusable-worker-boundaries-", (dir) => {
|
|
70
|
+
writeFileSync(
|
|
71
|
+
join(dir, "boundaries.test.ts"),
|
|
72
|
+
`import { expect, test } from "bun:test";
|
|
73
|
+
import { once } from "node:events";
|
|
74
|
+
import { reuseWorker } from ${JSON.stringify(new URL("./reusable-worker.ts", import.meta.url).href)};
|
|
75
|
+
const entry = new URL(${JSON.stringify(new URL("./reusable-worker.fixture.ts", import.meta.url).href)});
|
|
76
|
+
let previousThread;
|
|
77
|
+
async function run() {
|
|
78
|
+
const worker = reuseWorker(entry, { workerData: { path: "test-boundaries" } });
|
|
79
|
+
const message = once(worker, "message");
|
|
80
|
+
const exit = once(worker, "exit");
|
|
81
|
+
const [reply] = await message;
|
|
82
|
+
await exit;
|
|
83
|
+
return reply.threadId;
|
|
84
|
+
}
|
|
85
|
+
test("finishes with an idle pooled worker", async () => {
|
|
86
|
+
previousThread = await run();
|
|
87
|
+
expect(previousThread).toBeGreaterThan(0);
|
|
88
|
+
});
|
|
89
|
+
test("cannot inherit the previous test's pooled worker", async () => {
|
|
90
|
+
expect(await run()).not.toBe(previousThread);
|
|
91
|
+
});`,
|
|
92
|
+
);
|
|
93
|
+
const child = spawnSync(
|
|
94
|
+
process.execPath,
|
|
95
|
+
[
|
|
96
|
+
"test",
|
|
97
|
+
"--preload",
|
|
98
|
+
fileURLToPath(new URL("../../test-preload.ts", import.meta.url)),
|
|
99
|
+
join(dir, "boundaries.test.ts"),
|
|
100
|
+
],
|
|
101
|
+
{ cwd: dir, encoding: "utf8", timeout: 5_000, windowsHide: true },
|
|
102
|
+
);
|
|
103
|
+
const output = child.stdout + child.stderr;
|
|
104
|
+
expect(output).toContain("2 pass");
|
|
105
|
+
expect(output).toContain("0 fail");
|
|
106
|
+
expect(child.status).toBe(0);
|
|
107
|
+
});
|
|
108
|
+
}, 10_000);
|