@cortexkit/opencode-magic-context 0.49.7 → 0.49.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/auto-search-worker.js +6 -6
- package/dist/compaction-marker-candidates-worker.js +2 -2
- package/dist/{compaction-marker-candidates-a0edbqrr.js → compaction-marker-candidates-xxz35vwp.js} +3 -3
- package/dist/{conflict-warning-hook-myk5hbt9.js → conflict-warning-hook-w3crzrar.js} +8 -8
- package/dist/{context-ffr7e0g7.js → context-x0ccfv0f.js} +65 -42
- package/dist/{derive-budgets-j4ry8j8n.js → derive-budgets-3nbxsyss.js} +2 -2
- package/dist/embedding-backfill-3h2m5n0q.js +21 -0
- package/dist/embedding-worker-process.js +6 -2
- package/dist/embedding-worker.js +6 -5
- package/dist/features/magic-context/compaction-marker-candidates.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/cron.d.ts +2 -0
- package/dist/features/magic-context/dreamer/cron.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/provider-output-failure.d.ts +1 -0
- package/dist/features/magic-context/dreamer/provider-output-failure.d.ts.map +1 -1
- package/dist/features/magic-context/memory/embedding-local.d.ts.map +1 -1
- package/dist/features/magic-context/memory/embedding-worker-client.d.ts.map +1 -1
- package/dist/features/magic-context/message-index-async.d.ts.map +1 -1
- package/dist/features/magic-context/migration-worker-client.d.ts.map +1 -1
- package/dist/features/magic-context/project-embedding-registry.d.ts.map +1 -1
- package/dist/features/magic-context/smart-notes/wake-plane.d.ts.map +1 -1
- package/dist/features/magic-context/transform-decision-log.d.ts.map +1 -1
- package/dist/history-owner-ty29fz0f.js +244 -0
- package/dist/hooks/auto-update-checker/checker.d.ts.map +1 -1
- package/dist/hooks/magic-context/auto-search-worker-client.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-recomp.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner.d.ts.map +1 -1
- package/dist/hooks/magic-context/edit-marker.d.ts +2 -0
- package/dist/hooks/magic-context/edit-marker.d.ts.map +1 -1
- package/dist/hooks/magic-context/inject-compartments.d.ts.map +1 -1
- package/dist/hooks/magic-context/module-transport.d.ts +1 -0
- package/dist/hooks/magic-context/module-transport.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-chunk.d.ts +8 -4
- package/dist/hooks/magic-context/read-session-chunk.d.ts.map +1 -1
- package/dist/hooks/magic-context/rust-mode-transform.d.ts +1 -0
- package/dist/hooks/magic-context/rust-mode-transform.d.ts.map +1 -1
- package/dist/hooks/magic-context/rust-refusal-recovery.d.ts.map +1 -1
- package/dist/hooks/magic-context/tool-drop-target.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform.d.ts.map +1 -1
- package/dist/hooks/magic-context/unresolved-history-boundary.d.ts +5 -1
- package/dist/hooks/magic-context/unresolved-history-boundary.d.ts.map +1 -1
- package/dist/hooks/magic-context/wrapup-orchestrator.d.ts.map +1 -1
- package/dist/{index-g8qbdb03.js → index-0jz47061.js} +6 -3
- package/dist/{index-4mjhqadz.js → index-150zz6fh.js} +1 -1
- package/dist/{index-j58gqrn2.js → index-2rw244rh.js} +31 -24
- package/dist/{index-0gyq3djm.js → index-4hb8nt93.js} +3 -3
- package/dist/{index-ax2jhztn.js → index-7bjgyaj1.js} +4 -4
- package/dist/{index-h2wc01qk.js → index-8kk7yh6m.js} +2 -2
- package/dist/{index-n5a170gs.js → index-9g1c4bt9.js} +81 -58
- package/dist/{index-w6bd03dc.js → index-a43xq1pg.js} +5 -5
- package/dist/{index-tqf7yg27.js → index-a4b0gbyg.js} +1 -1
- package/dist/{index-37q80veb.js → index-angx1s0k.js} +4 -3
- package/dist/{index-wq16ahsn.js → index-b4gcb3rk.js} +8 -8
- package/dist/{index-z1tjp257.js → index-b64n4d0h.js} +1 -1
- package/dist/{index-1bt88epp.js → index-bd9cjab3.js} +1 -1
- package/dist/{index-gbmqa9x9.js → index-bmwfzz28.js} +9 -6
- package/dist/{index-qx53vezw.js → index-gjvjh960.js} +1 -1
- package/dist/{index-ebnngykq.js → index-gzg9ekc1.js} +19 -18
- package/dist/{index-5tbvdff4.js → index-hxrvx6cy.js} +79 -40
- package/dist/{index-w23dh319.js → index-jw4gbfkv.js} +1 -1
- package/dist/index-knvkbfvh.js +25 -0
- package/dist/{index-vkbqdnkj.js → index-kvw6xew3.js} +6 -3
- package/dist/{index-rzmjkdd6.js → index-mp2kghkv.js} +3 -27
- package/dist/{index-nsjyysj0.js → index-mvvephtj.js} +5 -1
- package/dist/{index-9yyqq3mm.js → index-n78avt2p.js} +1 -1
- package/dist/{index-vt4sf4ep.js → index-pgy3h49n.js} +4 -4
- package/dist/{index-w6vr754t.js → index-pjgzdezw.js} +13 -9
- package/dist/{v2/server-1rfgbjfn.js → index-q28hsbpg.js} +15 -3
- package/dist/{index-a8acx4gc.js → index-q76br5zn.js} +3 -3
- package/dist/{index-j5hce1ab.js → index-qgp5vnt4.js} +5 -5
- package/dist/{index-sf94at64.js → index-rg1cezmj.js} +22 -22
- package/dist/{index-sh91t19a.js → index-s178h9z8.js} +4 -3
- package/dist/{index-tagss15p.js → index-w1ejb9qr.js} +105 -58
- package/dist/{index-k6xvbj2e.js → index-w28y7d0z.js} +2 -0
- package/dist/{index-j8epsc0g.js → index-wafzvyhg.js} +33 -10
- package/dist/{index-rwmpkss5.js → index-xf6k8szp.js} +4 -4
- package/dist/{index-tmtty2x5.js → index-xpn05jxq.js} +4 -4
- package/dist/{index-n7kwfw2r.js → index-ydjgz36f.js} +7 -7
- package/dist/{index-4btknbqh.js → index-zf9nydbd.js} +48 -38
- package/dist/index.js +51 -50
- package/dist/{logger-ewak5q1s.js → logger-wn328tfg.js} +1 -1
- package/dist/{message-index-bounded-04rycpx4.js → message-index-bounded-hxjp56qk.js} +16 -16
- package/dist/{message-index-rqtse28y.js → message-index-zs882h8e.js} +16 -16
- package/dist/{message-time-backfill-a5ytnp53.js → message-time-backfill-nb5hhnrt.js} +3 -3
- package/dist/migration-worker.js +11 -11
- package/dist/plugin/boot-quiet.d.ts.map +1 -1
- package/dist/plugin/dream-timer.d.ts.map +1 -1
- package/dist/plugin/rpc-handlers.d.ts +2 -0
- package/dist/plugin/rpc-handlers.d.ts.map +1 -1
- package/dist/{project-embedding-registry-k0sd9k7v.js → project-embedding-registry-vy7sv9jt.js} +11 -11
- package/dist/raw-ordinal-warmup-worker.js +6 -6
- package/dist/{read-session-chunk-h1btx938.js → read-session-chunk-t9r7r0sg.js} +11 -11
- package/dist/{read-session-raw-vdf4wh78.js → read-session-raw-gm6xj30v.js} +3 -3
- package/dist/recomp-orchestrator-gr36zvd2.js +60 -0
- package/dist/{safe-notification-target-q0cyrx3x.js → safe-notification-target-jdynm677.js} +2 -2
- package/dist/{search-3rbdx6hw.js → search-qjen1pmz.js} +24 -24
- package/dist/{send-session-notification-2tp44tfa.js → send-session-notification-q8ngbap3.js} +6 -6
- package/dist/shared/history-owner.d.ts +12 -0
- package/dist/shared/history-owner.d.ts.map +1 -0
- package/dist/shared/off-thread-migration-clock.d.ts +8 -1
- package/dist/shared/off-thread-migration-clock.d.ts.map +1 -1
- package/dist/shared/redaction.d.ts.map +1 -1
- package/dist/shared/rpc-server.d.ts.map +1 -1
- package/dist/shared/sqlite.d.ts +2 -0
- package/dist/shared/sqlite.d.ts.map +1 -1
- package/dist/shared/user-facing-codes.d.ts +2 -2
- package/dist/{sqlite-j3tvg8r0.js → sqlite-4pqyynrs.js} +3 -1
- package/dist/{storage-memory-8168bgef.js → storage-memory-j3v3hc83.js} +2 -2
- package/dist/{storage-tags-61z5j2f9.js → storage-tags-a513rkj3.js} +5 -5
- package/dist/{transform-postprocess-phase-7qts7h54.js → transform-postprocess-phase-yv463b7y.js} +30 -30
- package/dist/v2/auto-search-worker.js +6 -6
- package/dist/v2/{compaction-marker-candidates-6nypjkpf.js → compaction-marker-candidates-a15w3mqh.js} +3 -3
- package/dist/v2/compaction-marker-candidates-worker.js +2 -2
- package/dist/v2/{context-xq4rtywr.js → context-wd82v9z6.js} +137 -68
- package/dist/v2/{derive-budgets-enckmg7y.js → derive-budgets-0rmpmxjw.js} +3 -3
- package/dist/v2/embedding-backfill-vr7wdtrf.js +20 -0
- package/dist/v2/embedding-worker-process.js +6 -2
- package/dist/v2/embedding-worker.js +6 -5
- package/dist/v2/hidden-completion.d.ts.map +1 -1
- package/dist/v2/history-owner-2cr9py37.js +243 -0
- package/dist/v2/hooks/context.d.ts.map +1 -1
- package/dist/v2/hooks/store.d.ts +1 -0
- package/dist/v2/hooks/store.d.ts.map +1 -1
- package/dist/v2/{logger-pj02s7sr.js → logger-te6e1j72.js} +1 -1
- package/dist/v2/{message-index-bounded-5vh1h2g7.js → message-index-bounded-madg2kfr.js} +16 -16
- package/dist/v2/{message-index-8e5z2xx8.js → message-index-yd94vt9n.js} +16 -16
- package/dist/v2/{message-time-backfill-2z365239.js → message-time-backfill-rz1pnpaj.js} +3 -3
- package/dist/v2/migration-worker.js +11 -11
- package/dist/v2/{project-embedding-registry-b77awytr.js → project-embedding-registry-ja23aygk.js} +11 -11
- package/dist/v2/raw-ordinal-warmup-worker.js +6 -6
- package/dist/v2/{read-session-chunk-4sat83cx.js → read-session-chunk-7qs791f3.js} +11 -11
- package/dist/v2/{read-session-raw-a3hw9jsp.js → read-session-raw-h4azh85b.js} +3 -3
- package/dist/v2/recomp-orchestrator-ee91r9s6.js +59 -0
- package/dist/v2/{safe-notification-target-y3p1hce9.js → safe-notification-target-936374xx.js} +2 -2
- package/dist/v2/search-pn15rr52.js +46 -0
- package/dist/v2/{send-session-notification-ppgc8qdz.js → send-session-notification-6n7chhyp.js} +6 -6
- package/dist/v2/{server-v4fwha43.js → server-08k4zkfk.js} +48 -38
- package/dist/v2/{server-ras2sxnc.js → server-44ryn9rb.js} +9 -6
- package/dist/v2/{server-fw31krgq.js → server-4easnf78.js} +19 -19
- package/dist/v2/{server-hcvcxzx7.js → server-4gz0xkrc.js} +5 -5
- package/dist/v2/{server-d6g4whc2.js → server-4qr18rfg.js} +3 -3
- package/dist/v2/{server-sy4b1sra.js → server-4rs8sm06.js} +5 -5
- package/dist/v2/{server-brhj8qtd.js → server-63ha7f0f.js} +3 -27
- package/dist/v2/{server-3t0q2cqx.js → server-7dv9wt9r.js} +1 -1
- package/dist/v2/{server-cw6521wn.js → server-7e087rvk.js} +2 -0
- package/dist/v2/{server-hb6xhh9q.js → server-988cqjme.js} +6 -3
- package/dist/v2/{server-fpqe39as.js → server-9a6bwc12.js} +4 -4
- package/dist/v2/{server-t4k4qexw.js → server-9e5r8y60.js} +5 -1
- package/dist/v2/{server-7ekna9zs.js → server-adfte03x.js} +2 -2
- package/dist/v2/{server-qcw43339.js → server-ak7w74j9.js} +4 -4
- package/dist/v2/{server-dd0nja67.js → server-bx59ezg6.js} +4 -3
- package/dist/v2/{server-676xw7at.js → server-ckrb5rm8.js} +1 -1
- package/dist/{index-w4mw92w3.js → v2/server-cxsr0ng6.js} +15 -3
- package/dist/v2/{server-t528t8qm.js → server-hn9fb3v0.js} +2 -2
- package/dist/v2/{server-7srtwsa4.js → server-j3dm74ey.js} +9 -9
- package/dist/v2/{server-w3zeywp1.js → server-jjsf29aq.js} +4 -4
- package/dist/v2/server-knvkbfvh.js +25 -0
- package/dist/v2/{server-9yyqq3mm.js → server-n78avt2p.js} +1 -1
- package/dist/v2/{server-kdrezdy0.js → server-njnx39q2.js} +6 -3
- package/dist/v2/{server-x08d1xf3.js → server-npm52h2q.js} +4 -3
- package/dist/v2/{server-vb7pbd9p.js → server-nveratm5.js} +1 -1
- package/dist/v2/{server-mv1w7t6z.js → server-q360kdb8.js} +77 -38
- package/dist/v2/{server-kzns2hbz.js → server-s6jqh8bj.js} +1 -1
- package/dist/v2/{server-6byqfbqf.js → server-shme41gj.js} +1 -1
- package/dist/v2/{server-j8epsc0g.js → server-wafzvyhg.js} +33 -10
- package/dist/v2/{server-gtv9wbhq.js → server-xj4mewze.js} +81 -58
- package/dist/v2/{server-nfan6zb6.js → server-y5g32dhq.js} +31 -24
- package/dist/v2/{server-jdwd03ep.js → server-yak3sxya.js} +7 -7
- package/dist/v2/{server-wkdgjjch.js → server-zrwaj29a.js} +2 -2
- package/dist/v2/server.js +7 -6
- package/dist/v2/{sqlite-j3tvg8r0.js → sqlite-4pqyynrs.js} +3 -1
- package/dist/v2/{storage-memory-8168bgef.js → storage-memory-j3v3hc83.js} +2 -2
- package/dist/v2/{storage-tags-j2fzq3sw.js → storage-tags-spa92sgj.js} +5 -5
- package/dist/v2/store-reader.d.ts.map +1 -1
- package/dist/v2/{wrapup-orchestrator-s92ebfzv.js → wrapup-orchestrator-5wxy1ggv.js} +38 -35
- package/dist/wrapup-orchestrator-gv08c6f9.js +47 -0
- package/package.json +1 -1
- package/src/config/compaction-accessor-guard.test.ts +3 -0
- package/src/features/magic-context/dreamer/cron.ts +8 -0
- package/src/shared/history-owner.test.ts +60 -0
- package/src/shared/history-owner.ts +43 -0
- package/src/shared/host-stall-profiler-node.ts +3 -1
- package/src/shared/host-stall-profiler.ts +3 -1
- package/src/shared/off-thread-migration-clock.test.ts +80 -10
- package/src/shared/off-thread-migration-clock.ts +37 -13
- package/src/shared/redaction.test.ts +16 -0
- package/src/shared/redaction.ts +8 -1
- package/src/shared/root-async-context.probe.mjs +36 -0
- package/src/shared/root-async-context.test.ts +49 -0
- package/src/shared/rpc-server.ts +27 -23
- package/src/shared/sqlite-busy-budget-review.test.ts +291 -0
- package/src/shared/sqlite-foreground-wait.test.ts +253 -1
- package/src/shared/sqlite.ts +55 -14
- package/src/shared/user-facing-codes.ts +2 -2
- package/dist/embedding-backfill-re16xncd.js +0 -21
- package/dist/recomp-orchestrator-trcgmm23.js +0 -60
- package/dist/v2/embedding-backfill-xd9ygzgd.js +0 -20
- package/dist/v2/recomp-orchestrator-n11zv1f1.js +0 -59
- package/dist/v2/search-mvgqtkkz.js +0 -46
- package/dist/wrapup-orchestrator-df61jmz9.js +0 -47
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import"./server-pavzsdc6.js";
|
|
2
2
|
import {
|
|
3
3
|
sessionLog2
|
|
4
|
-
} from "./server-
|
|
5
|
-
import"./server-
|
|
4
|
+
} from "./server-9e5r8y60.js";
|
|
5
|
+
import"./server-cxsr0ng6.js";
|
|
6
6
|
import {
|
|
7
7
|
COMPARTMENT_LEASE_RENEWAL_MS,
|
|
8
8
|
acquireCompartmentLease,
|
|
@@ -19,13 +19,15 @@ import {
|
|
|
19
19
|
registerActiveCompartmentRun,
|
|
20
20
|
setRecompStarting2,
|
|
21
21
|
setRecompTerminal2
|
|
22
|
-
} from "./server-
|
|
23
|
-
import"./server-
|
|
24
|
-
import"./server-
|
|
25
|
-
import
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
import"./server-
|
|
22
|
+
} from "./server-q360kdb8.js";
|
|
23
|
+
import"./server-s6jqh8bj.js";
|
|
24
|
+
import"./server-988cqjme.js";
|
|
25
|
+
import {
|
|
26
|
+
inRootAsyncContext2
|
|
27
|
+
} from "./server-wafzvyhg.js";
|
|
28
|
+
import"./server-63ha7f0f.js";
|
|
29
|
+
import"./server-9a6bwc12.js";
|
|
30
|
+
import"./server-j3dm74ey.js";
|
|
29
31
|
import {
|
|
30
32
|
getWrapupInProgressState,
|
|
31
33
|
acquireWrapupInProgress,
|
|
@@ -34,40 +36,40 @@ import {
|
|
|
34
36
|
getHistorianFailureState,
|
|
35
37
|
clearEmergencyRecovery,
|
|
36
38
|
prepareRawSessionOrdinals2
|
|
37
|
-
} from "./server-
|
|
38
|
-
import"./server-
|
|
39
|
-
import"./server-
|
|
39
|
+
} from "./server-xj4mewze.js";
|
|
40
|
+
import"./server-shme41gj.js";
|
|
41
|
+
import"./server-08k4zkfk.js";
|
|
40
42
|
import"./server-1zx87sdm.js";
|
|
41
|
-
import"./server-
|
|
42
|
-
import"./server-
|
|
43
|
+
import"./server-jjsf29aq.js";
|
|
44
|
+
import"./server-7e087rvk.js";
|
|
43
45
|
import"./server-51779zs2.js";
|
|
44
|
-
import"./server-
|
|
46
|
+
import"./server-bx59ezg6.js";
|
|
45
47
|
import"./server-2ra6pwf3.js";
|
|
46
|
-
import"./server-
|
|
47
|
-
import"./server-
|
|
48
|
+
import"./server-zrwaj29a.js";
|
|
49
|
+
import"./server-adfte03x.js";
|
|
48
50
|
import"./server-fr0wbhdn.js";
|
|
49
|
-
import"./server-
|
|
50
|
-
import"./server-
|
|
51
|
-
import"./server-
|
|
51
|
+
import"./server-4gz0xkrc.js";
|
|
52
|
+
import"./server-njnx39q2.js";
|
|
53
|
+
import"./server-4easnf78.js";
|
|
52
54
|
import"./server-fb3zxn06.js";
|
|
53
|
-
import"./server-
|
|
55
|
+
import"./server-yak3sxya.js";
|
|
54
56
|
import {
|
|
55
57
|
pushNotification2
|
|
56
58
|
} from "./server-x8a7jmkh.js";
|
|
57
|
-
import"./server-
|
|
59
|
+
import"./server-npm52h2q.js";
|
|
58
60
|
import"./server-qt1qqasc.js";
|
|
59
61
|
import"./server-4dhv7mqz.js";
|
|
60
|
-
import"./server-
|
|
61
|
-
import"./server-
|
|
62
|
-
import"./server-
|
|
63
|
-
import"./server-
|
|
64
|
-
import"./server-
|
|
65
|
-
import"./server-
|
|
66
|
-
import"./server-
|
|
62
|
+
import"./server-44ryn9rb.js";
|
|
63
|
+
import"./server-4rs8sm06.js";
|
|
64
|
+
import"./server-n78avt2p.js";
|
|
65
|
+
import"./server-4qr18rfg.js";
|
|
66
|
+
import"./server-nveratm5.js";
|
|
67
|
+
import"./server-hn9fb3v0.js";
|
|
68
|
+
import"./server-ckrb5rm8.js";
|
|
67
69
|
import {
|
|
68
70
|
sendStatusNotification2
|
|
69
|
-
} from "./server-
|
|
70
|
-
import"./server-
|
|
71
|
+
} from "./server-ak7w74j9.js";
|
|
72
|
+
import"./server-7dv9wt9r.js";
|
|
71
73
|
|
|
72
74
|
// src/hooks/magic-context/wrapup-orchestrator.ts
|
|
73
75
|
import * as crypto from "node:crypto";
|
|
@@ -190,7 +192,7 @@ async function runOneWrapupIteration(args) {
|
|
|
190
192
|
if (!acquired.ok)
|
|
191
193
|
return { ran: false, reason: acquired.reason };
|
|
192
194
|
const leaseHolderId = acquired.holderId;
|
|
193
|
-
const renewal = setInterval(() => {
|
|
195
|
+
const renewal = inRootAsyncContext2(() => setInterval(() => {
|
|
194
196
|
try {
|
|
195
197
|
if (!renewCompartmentLease(ctx.db, sessionId, leaseHolderId)) {
|
|
196
198
|
sessionLog2(sessionId, "wrapup: compartment lease renewal failed");
|
|
@@ -198,7 +200,7 @@ async function runOneWrapupIteration(args) {
|
|
|
198
200
|
} catch (err) {
|
|
199
201
|
sessionLog2(sessionId, `wrapup: compartment lease renewal threw; continuing (${err instanceof Error ? err.message : String(err)})`);
|
|
200
202
|
}
|
|
201
|
-
}, COMPARTMENT_LEASE_RENEWAL_MS);
|
|
203
|
+
}, COMPARTMENT_LEASE_RENEWAL_MS));
|
|
202
204
|
const runCompartmentAgentForWrapup = ctx.runCompartmentAgentForWrapup ?? runCompartmentAgent;
|
|
203
205
|
const runnerPromise = runCompartmentAgentForWrapup({
|
|
204
206
|
client: ctx.client,
|
|
@@ -208,6 +210,7 @@ async function runOneWrapupIteration(args) {
|
|
|
208
210
|
sessionId,
|
|
209
211
|
historianChunkTokens: ctx.historianChunkTokens,
|
|
210
212
|
historianTimeoutMs: ctx.historianTimeoutMs,
|
|
213
|
+
historianMaxOutputTokens: ctx.historianMaxOutputTokens,
|
|
211
214
|
boundarySnapshot: plan.snapshot,
|
|
212
215
|
currentContextLimit: ctx.contextLimit,
|
|
213
216
|
directory: ctx.directory,
|
|
@@ -315,7 +318,7 @@ ${message}`;
|
|
|
315
318
|
}
|
|
316
319
|
return true;
|
|
317
320
|
};
|
|
318
|
-
const markerRenewal = setInterval(() => {
|
|
321
|
+
const markerRenewal = inRootAsyncContext2(() => setInterval(() => {
|
|
319
322
|
try {
|
|
320
323
|
renewWrapupMarker({
|
|
321
324
|
lastCompartmentEnd: getLastCompartmentEndMessage(ctx.db, sessionId),
|
|
@@ -324,7 +327,7 @@ ${message}`;
|
|
|
324
327
|
} catch (err) {
|
|
325
328
|
sessionLog2(sessionId, `wrapup: marker renewal threw; continuing (${err instanceof Error ? err.message : String(err)})`);
|
|
326
329
|
}
|
|
327
|
-
}, 60000);
|
|
330
|
+
}, 60000));
|
|
328
331
|
markerRenewal.unref?.();
|
|
329
332
|
try {
|
|
330
333
|
const activeAtStart = await waitForExistingIncrementalRun(sessionId, resolveWrapupLeaseWaitTimeout(ctx));
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import {
|
|
2
|
+
runManagedWrapup2
|
|
3
|
+
} from "./index-pjgzdezw.js";
|
|
4
|
+
import"./index-xf6k8szp.js";
|
|
5
|
+
import"./index-hxrvx6cy.js";
|
|
6
|
+
import"./index-s178h9z8.js";
|
|
7
|
+
import"./index-ydjgz36f.js";
|
|
8
|
+
import"./index-b4gcb3rk.js";
|
|
9
|
+
import"./index-sd3egckz.js";
|
|
10
|
+
import"./index-a43xq1pg.js";
|
|
11
|
+
import"./index-n78avt2p.js";
|
|
12
|
+
import"./index-rg1cezmj.js";
|
|
13
|
+
import"./index-7bjgyaj1.js";
|
|
14
|
+
import"./index-4dhv7mqz.js";
|
|
15
|
+
import"./index-jw4gbfkv.js";
|
|
16
|
+
import"./index-pgy3h49n.js";
|
|
17
|
+
import"./index-qt1qqasc.js";
|
|
18
|
+
import"./index-x8a7jmkh.js";
|
|
19
|
+
import"./index-a4b0gbyg.js";
|
|
20
|
+
import"./index-bmwfzz28.js";
|
|
21
|
+
import"./index-kvw6xew3.js";
|
|
22
|
+
import"./index-zf9nydbd.js";
|
|
23
|
+
import"./index-qgp5vnt4.js";
|
|
24
|
+
import"./index-fb3zxn06.js";
|
|
25
|
+
import"./index-fr0wbhdn.js";
|
|
26
|
+
import"./index-0jz47061.js";
|
|
27
|
+
import"./index-mp2kghkv.js";
|
|
28
|
+
import"./index-q28hsbpg.js";
|
|
29
|
+
import"./index-9g1c4bt9.js";
|
|
30
|
+
import"./index-xpn05jxq.js";
|
|
31
|
+
import"./index-1zx87sdm.js";
|
|
32
|
+
import"./index-q76br5zn.js";
|
|
33
|
+
import"./index-angx1s0k.js";
|
|
34
|
+
import"./index-v0p37hm2.js";
|
|
35
|
+
import"./index-w28y7d0z.js";
|
|
36
|
+
import"./index-8kk7yh6m.js";
|
|
37
|
+
import"./index-bd9cjab3.js";
|
|
38
|
+
import"./index-58e3y90n.js";
|
|
39
|
+
import"./index-150zz6fh.js";
|
|
40
|
+
import"./index-gjvjh960.js";
|
|
41
|
+
import"./index-wafzvyhg.js";
|
|
42
|
+
import"./index-mvvephtj.js";
|
|
43
|
+
import"./index-0sahzkwr.js";
|
|
44
|
+
import"./index-pavzsdc6.js";
|
|
45
|
+
export {
|
|
46
|
+
runManagedWrapup2 as runManagedWrapup
|
|
47
|
+
};
|
package/package.json
CHANGED
|
@@ -32,6 +32,9 @@ const ALLOWED_READERS = new Set<string>([
|
|
|
32
32
|
"packages/cli/src/lib/omp-helpers.ts",
|
|
33
33
|
"packages/cli/src/commands/setup-omp.ts",
|
|
34
34
|
"packages/cli/src/commands/doctor-omp.ts",
|
|
35
|
+
// The privacy projection recognizes the setting's name in diagnostic text;
|
|
36
|
+
// it never reads the parsed configuration value.
|
|
37
|
+
"packages/cli/src/lib/issue-privacy.ts",
|
|
35
38
|
]);
|
|
36
39
|
|
|
37
40
|
function sourceFiles(directory: string): string[] {
|
|
@@ -61,6 +61,13 @@ const MINUTE_MS = 60_000;
|
|
|
61
61
|
*/
|
|
62
62
|
const MAX_SEARCH_MS = 4 * 366 * 24 * 60 * MINUTE_MS;
|
|
63
63
|
|
|
64
|
+
let candidateVisitsForTests: (() => void) | undefined;
|
|
65
|
+
|
|
66
|
+
/** Count searched minutes in tests without affecting normal cron callers. */
|
|
67
|
+
export function __setCronCandidateVisitCounterForTests(counter?: () => void): void {
|
|
68
|
+
candidateVisitsForTests = counter;
|
|
69
|
+
}
|
|
70
|
+
|
|
64
71
|
/** Parse one field into the set of matching values, or null on error. */
|
|
65
72
|
function parseField(token: string, spec: FieldSpec): Set<number> | null {
|
|
66
73
|
const values = new Set<number>();
|
|
@@ -226,6 +233,7 @@ export function nextOccurrence(
|
|
|
226
233
|
const capMs = afterMs + Math.max(0, Math.min(MAX_SEARCH_MS, maxSearchMs));
|
|
227
234
|
|
|
228
235
|
while (cursorMs <= capMs) {
|
|
236
|
+
candidateVisitsForTests?.();
|
|
229
237
|
const candidate = new Date(cursorMs);
|
|
230
238
|
if (matchesCron(cron, candidate)) {
|
|
231
239
|
if (!excludeCivilMinute || civilMinuteKey(candidate) !== excludeCivilMinute) {
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { expect, test } from "bun:test";
|
|
2
|
+
import { handoffHistoryWork } from "./history-owner";
|
|
3
|
+
import type { MagicContextRpcClient } from "./rpc-client";
|
|
4
|
+
|
|
5
|
+
test("moved-session recomp is handed to the current directory before local work starts", async () => {
|
|
6
|
+
const calls: unknown[] = [];
|
|
7
|
+
const result = await handoffHistoryWork({
|
|
8
|
+
storageDir: "/isolated/mc",
|
|
9
|
+
directory: "/old",
|
|
10
|
+
sessionId: "session",
|
|
11
|
+
method: "recomp",
|
|
12
|
+
params: { sessionId: "session" },
|
|
13
|
+
readDirectory: async () => "/new",
|
|
14
|
+
findOwner: async () =>
|
|
15
|
+
({
|
|
16
|
+
call: async (...args: unknown[]) => {
|
|
17
|
+
calls.push(args);
|
|
18
|
+
return { ok: true };
|
|
19
|
+
},
|
|
20
|
+
}) as unknown as MagicContextRpcClient,
|
|
21
|
+
});
|
|
22
|
+
expect(result).toEqual({ ok: true });
|
|
23
|
+
expect(calls).toEqual([
|
|
24
|
+
["recomp", { sessionId: "session", directory: "/new", historyHandoff: true }],
|
|
25
|
+
]);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
test("moved-session recovery explains how to load a missing owner and stops handoff loops", async () => {
|
|
29
|
+
for (const historyHandoff of [false, true]) {
|
|
30
|
+
const result = await handoffHistoryWork({
|
|
31
|
+
storageDir: "/isolated/mc",
|
|
32
|
+
directory: "/old",
|
|
33
|
+
sessionId: "session",
|
|
34
|
+
method: "wrapup",
|
|
35
|
+
params: { sessionId: "session", historyHandoff },
|
|
36
|
+
readDirectory: async () => "/new",
|
|
37
|
+
findOwner: async () => null,
|
|
38
|
+
});
|
|
39
|
+
expect(result?.ok).toBe(false);
|
|
40
|
+
expect(result?.error).toContain(
|
|
41
|
+
"Reopen this session in its current project directory (/new)",
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
test("history recovery remains local when the host still reports this directory", async () => {
|
|
47
|
+
expect(
|
|
48
|
+
await handoffHistoryWork({
|
|
49
|
+
storageDir: "/isolated/mc",
|
|
50
|
+
directory: "/project",
|
|
51
|
+
sessionId: "session",
|
|
52
|
+
method: "recomp",
|
|
53
|
+
params: {},
|
|
54
|
+
readDirectory: async () => "/project",
|
|
55
|
+
findOwner: async () => {
|
|
56
|
+
throw new Error("must not discover");
|
|
57
|
+
},
|
|
58
|
+
}),
|
|
59
|
+
).toBeUndefined();
|
|
60
|
+
});
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { sameProjectDirectory } from "./project-directory-key";
|
|
2
|
+
import { MagicContextRpcClient } from "./rpc-client";
|
|
3
|
+
|
|
4
|
+
/** History-compression children need the current project plugin's prompt and recognition of their run IDs. */
|
|
5
|
+
export async function handoffHistoryWork(args: {
|
|
6
|
+
storageDir: string;
|
|
7
|
+
directory: string;
|
|
8
|
+
sessionId: string;
|
|
9
|
+
method: string;
|
|
10
|
+
params: Record<string, unknown>;
|
|
11
|
+
readDirectory: () => Promise<string | null>;
|
|
12
|
+
findOwner?: typeof MagicContextRpcClient.findSessionOwner;
|
|
13
|
+
}): Promise<Record<string, unknown> | undefined> {
|
|
14
|
+
const current = await args.readDirectory();
|
|
15
|
+
if (current && sameProjectDirectory(current, args.directory)) return undefined;
|
|
16
|
+
const action = `Reopen this session in its current project directory${current ? ` (${current})` : ""}, then run /ctx-recomp.`;
|
|
17
|
+
if (!current || args.params.historyHandoff === true)
|
|
18
|
+
return {
|
|
19
|
+
ok: false,
|
|
20
|
+
error: `History recovery could not locate a stable owning instance. ${action}`,
|
|
21
|
+
};
|
|
22
|
+
const owner = await (args.findOwner ?? MagicContextRpcClient.findSessionOwner)(
|
|
23
|
+
args.storageDir,
|
|
24
|
+
args.sessionId,
|
|
25
|
+
);
|
|
26
|
+
if (!owner)
|
|
27
|
+
return {
|
|
28
|
+
ok: false,
|
|
29
|
+
error: `History recovery needs the instance for ${current}. ${action}`,
|
|
30
|
+
};
|
|
31
|
+
try {
|
|
32
|
+
return await owner.call(args.method, {
|
|
33
|
+
...args.params,
|
|
34
|
+
directory: current,
|
|
35
|
+
historyHandoff: true,
|
|
36
|
+
});
|
|
37
|
+
} catch {
|
|
38
|
+
return {
|
|
39
|
+
ok: false,
|
|
40
|
+
error: `The owning instance could not accept history recovery. ${action}`,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -224,7 +224,7 @@ export function createNodeHostStallProfiler(deps: NodeProfilerDeps): HostStallPr
|
|
|
224
224
|
const api = await deps.createSession();
|
|
225
225
|
if (stopped || !existsSync(enablePath)) return;
|
|
226
226
|
session = api;
|
|
227
|
-
api.connect();
|
|
227
|
+
inRootAsyncContext(() => api.connect());
|
|
228
228
|
await post(api, "Profiler.enable");
|
|
229
229
|
await post(api, "Profiler.setSamplingInterval", {
|
|
230
230
|
interval: Math.round(options.sampleIntervalMs * 1000),
|
|
@@ -272,3 +272,5 @@ export function createNodeHostStallProfiler(deps: NodeProfilerDeps): HostStallPr
|
|
|
272
272
|
isUnavailable: () => unavailable,
|
|
273
273
|
};
|
|
274
274
|
}
|
|
275
|
+
|
|
276
|
+
import { inRootAsyncContext } from "./sqlite";
|
|
@@ -29,7 +29,7 @@ export function startHostStallProfilerSwitch(): void {
|
|
|
29
29
|
now: () => performance.now(),
|
|
30
30
|
wallNow: () => Date.now(),
|
|
31
31
|
setInterval: (callback, ms) => {
|
|
32
|
-
const handle = setInterval(callback, ms);
|
|
32
|
+
const handle = inRootAsyncContext(() => setInterval(callback, ms));
|
|
33
33
|
(handle as { unref?: () => void }).unref?.();
|
|
34
34
|
return handle;
|
|
35
35
|
},
|
|
@@ -55,3 +55,5 @@ export function startHostStallProfilerSwitch(): void {
|
|
|
55
55
|
log("[magic-context] host stall profiler: could not start the enable-file switch", error);
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
|
+
|
|
59
|
+
import { inRootAsyncContext } from "./sqlite";
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { afterEach, describe, expect, test } from "bun:test";
|
|
2
2
|
import {
|
|
3
3
|
__resetOffThreadMigrationClockForTests,
|
|
4
|
+
__setOffThreadMigrationClockForTests,
|
|
4
5
|
beginOffThreadMigration,
|
|
5
6
|
startBootDeadline,
|
|
6
7
|
} from "./off-thread-migration-clock";
|
|
@@ -11,6 +12,49 @@ async function expiredWithin(promise: Promise<void>, ms: number): Promise<boolea
|
|
|
11
12
|
return Promise.race([promise.then(() => true), sleep(ms).then(() => false)]);
|
|
12
13
|
}
|
|
13
14
|
|
|
15
|
+
function createFakeClock() {
|
|
16
|
+
let now = 0;
|
|
17
|
+
let nextTimerId = 0;
|
|
18
|
+
const timers = new Map<number, { at: number; callback: () => void }>();
|
|
19
|
+
let timerCountWaiter: { count: number; resolve: () => void } | undefined;
|
|
20
|
+
|
|
21
|
+
return {
|
|
22
|
+
now: () => now,
|
|
23
|
+
setTimeout: (callback: () => void, delayMs: number) => {
|
|
24
|
+
const id = ++nextTimerId;
|
|
25
|
+
timers.set(id, { at: now + Math.max(0, delayMs), callback });
|
|
26
|
+
if (timerCountWaiter?.count === timers.size) {
|
|
27
|
+
timerCountWaiter.resolve();
|
|
28
|
+
timerCountWaiter = undefined;
|
|
29
|
+
}
|
|
30
|
+
return () => {
|
|
31
|
+
timers.delete(id);
|
|
32
|
+
};
|
|
33
|
+
},
|
|
34
|
+
advanceBy: (ms: number) => {
|
|
35
|
+
now += ms;
|
|
36
|
+
while (true) {
|
|
37
|
+
const next = [...timers.entries()].sort(
|
|
38
|
+
(left, right) => left[1].at - right[1].at,
|
|
39
|
+
)[0];
|
|
40
|
+
if (!next || next[1].at > now) return;
|
|
41
|
+
timers.delete(next[0]);
|
|
42
|
+
next[1].callback();
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
waitForTimerCount: (count: number) => {
|
|
46
|
+
if (timers.size === count) return Promise.resolve();
|
|
47
|
+
return new Promise<void>((resolve) => {
|
|
48
|
+
timerCountWaiter = { count, resolve };
|
|
49
|
+
});
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async function isSettled(promise: Promise<void>): Promise<boolean> {
|
|
55
|
+
return Promise.race([promise.then(() => true), Promise.resolve(false)]);
|
|
56
|
+
}
|
|
57
|
+
|
|
14
58
|
describe("boot deadline that excludes off-thread migration time", () => {
|
|
15
59
|
afterEach(() => __resetOffThreadMigrationClockForTests());
|
|
16
60
|
|
|
@@ -19,32 +63,58 @@ describe("boot deadline that excludes off-thread migration time", () => {
|
|
|
19
63
|
expect(await expiredWithin(deadline.expired, 500)).toBe(true);
|
|
20
64
|
});
|
|
21
65
|
|
|
22
|
-
test("does not
|
|
66
|
+
test("does not count migration time and resumes with only the pre-migration time spent", async () => {
|
|
67
|
+
const clock = createFakeClock();
|
|
68
|
+
__setOffThreadMigrationClockForTests(clock);
|
|
23
69
|
let deferred = 0;
|
|
70
|
+
let signalDeferred!: () => void;
|
|
71
|
+
const wasDeferred = new Promise<void>((resolve) => {
|
|
72
|
+
signalDeferred = resolve;
|
|
73
|
+
});
|
|
24
74
|
const deadline = startBootDeadline(40, () => {
|
|
25
75
|
deferred += 1;
|
|
76
|
+
signalDeferred();
|
|
26
77
|
});
|
|
78
|
+
clock.advanceBy(15);
|
|
27
79
|
const end = beginOffThreadMigration();
|
|
28
|
-
|
|
80
|
+
clock.advanceBy(25);
|
|
81
|
+
await wasDeferred;
|
|
29
82
|
expect(deferred).toBe(1);
|
|
30
83
|
|
|
31
|
-
|
|
84
|
+
clock.advanceBy(1_000_000);
|
|
85
|
+
expect(await isSettled(deadline.expired)).toBe(false);
|
|
86
|
+
|
|
87
|
+
const nextTimer = clock.waitForTimerCount(1).then(() => "scheduled" as const);
|
|
32
88
|
end();
|
|
89
|
+
expect(
|
|
90
|
+
await Promise.race([nextTimer, deadline.expired.then(() => "expired" as const)]),
|
|
91
|
+
).toBe("scheduled");
|
|
92
|
+
|
|
93
|
+
clock.advanceBy(24);
|
|
94
|
+
expect(await isSettled(deadline.expired)).toBe(false);
|
|
95
|
+
clock.advanceBy(1);
|
|
33
96
|
await deadline.expired;
|
|
34
|
-
// Only the few milliseconds before the migration began were counted, so
|
|
35
|
-
// nearly the whole 40ms budget is still left once it ends.
|
|
36
|
-
expect(performance.now() - endedAt).toBeGreaterThanOrEqual(25);
|
|
37
97
|
});
|
|
38
98
|
|
|
39
99
|
test("time between migrations still counts", async () => {
|
|
100
|
+
const clock = createFakeClock();
|
|
101
|
+
__setOffThreadMigrationClockForTests(clock);
|
|
40
102
|
const deadline = startBootDeadline(60);
|
|
41
|
-
|
|
103
|
+
clock.advanceBy(40);
|
|
42
104
|
const end = beginOffThreadMigration();
|
|
43
|
-
|
|
105
|
+
clock.advanceBy(80);
|
|
106
|
+
expect(await isSettled(deadline.expired)).toBe(false);
|
|
107
|
+
|
|
108
|
+
const nextTimer = clock.waitForTimerCount(1).then(() => "scheduled" as const);
|
|
44
109
|
end();
|
|
45
|
-
|
|
110
|
+
expect(
|
|
111
|
+
await Promise.race([nextTimer, deadline.expired.then(() => "expired" as const)]),
|
|
112
|
+
).toBe("scheduled");
|
|
113
|
+
|
|
114
|
+
clock.advanceBy(19);
|
|
115
|
+
expect(await isSettled(deadline.expired)).toBe(false);
|
|
116
|
+
clock.advanceBy(1);
|
|
46
117
|
await deadline.expired;
|
|
47
|
-
expect(performance.now() - endedAt).toBeLessThan(45);
|
|
48
118
|
});
|
|
49
119
|
|
|
50
120
|
test("a cancelled deadline never expires", async () => {
|
|
@@ -19,9 +19,26 @@ let activeSince = 0;
|
|
|
19
19
|
let accumulatedMs = 0;
|
|
20
20
|
let idleWaiters: Array<() => void> = [];
|
|
21
21
|
|
|
22
|
+
interface TestClock {
|
|
23
|
+
now(): number;
|
|
24
|
+
setTimeout(callback: () => void, delayMs: number): () => void;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
let testClock: TestClock | undefined;
|
|
28
|
+
|
|
29
|
+
function now(): number {
|
|
30
|
+
return testClock?.now() ?? performance.now();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function scheduleTimeout(callback: () => void, delayMs: number): () => void {
|
|
34
|
+
if (testClock) return testClock.setTimeout(callback, delayMs);
|
|
35
|
+
const timer = setTimeout(callback, delayMs);
|
|
36
|
+
return () => clearTimeout(timer);
|
|
37
|
+
}
|
|
38
|
+
|
|
22
39
|
/** Total milliseconds any off-thread migration has been running, up to `now`. */
|
|
23
|
-
export function offThreadMigrationMs(
|
|
24
|
-
return accumulatedMs + (activeMigrations > 0 ? Math.max(0,
|
|
40
|
+
export function offThreadMigrationMs(at = now()): number {
|
|
41
|
+
return accumulatedMs + (activeMigrations > 0 ? Math.max(0, at - activeSince) : 0);
|
|
25
42
|
}
|
|
26
43
|
|
|
27
44
|
export function isOffThreadMigrationRunning(): boolean {
|
|
@@ -33,7 +50,7 @@ export function isOffThreadMigrationRunning(): boolean {
|
|
|
33
50
|
* end; calling it more than once has no further effect.
|
|
34
51
|
*/
|
|
35
52
|
export function beginOffThreadMigration(): () => void {
|
|
36
|
-
if (activeMigrations === 0) activeSince =
|
|
53
|
+
if (activeMigrations === 0) activeSince = now();
|
|
37
54
|
activeMigrations += 1;
|
|
38
55
|
let ended = false;
|
|
39
56
|
return () => {
|
|
@@ -41,7 +58,7 @@ export function beginOffThreadMigration(): () => void {
|
|
|
41
58
|
ended = true;
|
|
42
59
|
activeMigrations -= 1;
|
|
43
60
|
if (activeMigrations > 0) return;
|
|
44
|
-
accumulatedMs += Math.max(0,
|
|
61
|
+
accumulatedMs += Math.max(0, now() - activeSince);
|
|
45
62
|
const waiters = idleWaiters;
|
|
46
63
|
idleWaiters = [];
|
|
47
64
|
for (const wake of waiters) wake();
|
|
@@ -66,10 +83,10 @@ export interface BootDeadlineTimer {
|
|
|
66
83
|
* still running.
|
|
67
84
|
*/
|
|
68
85
|
export function startBootDeadline(timeoutMs: number, onDeferred?: () => void): BootDeadlineTimer {
|
|
69
|
-
const startedAt =
|
|
86
|
+
const startedAt = now();
|
|
70
87
|
const migratedAtStart = offThreadMigrationMs(startedAt);
|
|
71
88
|
const budgetMs = Math.max(0, timeoutMs);
|
|
72
|
-
let
|
|
89
|
+
let cancelTimer: (() => void) | undefined;
|
|
73
90
|
let cancelled = false;
|
|
74
91
|
let deferredReported = false;
|
|
75
92
|
let resolveExpired!: () => void;
|
|
@@ -78,13 +95,14 @@ export function startBootDeadline(timeoutMs: number, onDeferred?: () => void): B
|
|
|
78
95
|
});
|
|
79
96
|
|
|
80
97
|
const remainingMs = (): number => {
|
|
81
|
-
const
|
|
82
|
-
const countedMs =
|
|
98
|
+
const currentTime = now();
|
|
99
|
+
const countedMs =
|
|
100
|
+
currentTime - startedAt - (offThreadMigrationMs(currentTime) - migratedAtStart);
|
|
83
101
|
return budgetMs - countedMs;
|
|
84
102
|
};
|
|
85
103
|
|
|
86
104
|
const check = (): void => {
|
|
87
|
-
|
|
105
|
+
cancelTimer = undefined;
|
|
88
106
|
if (cancelled) return;
|
|
89
107
|
if (isOffThreadMigrationRunning()) {
|
|
90
108
|
if (!deferredReported) {
|
|
@@ -96,28 +114,34 @@ export function startBootDeadline(timeoutMs: number, onDeferred?: () => void): B
|
|
|
96
114
|
}
|
|
97
115
|
const left = remainingMs();
|
|
98
116
|
if (left > 0) {
|
|
99
|
-
|
|
117
|
+
cancelTimer = scheduleTimeout(check, left);
|
|
100
118
|
return;
|
|
101
119
|
}
|
|
102
120
|
resolveExpired();
|
|
103
121
|
};
|
|
104
122
|
|
|
105
|
-
|
|
123
|
+
cancelTimer = scheduleTimeout(check, budgetMs);
|
|
106
124
|
return {
|
|
107
125
|
expired,
|
|
108
126
|
cancel: () => {
|
|
109
127
|
cancelled = true;
|
|
110
|
-
|
|
111
|
-
|
|
128
|
+
cancelTimer?.();
|
|
129
|
+
cancelTimer = undefined;
|
|
112
130
|
},
|
|
113
131
|
};
|
|
114
132
|
}
|
|
115
133
|
|
|
134
|
+
/** Inject deterministic time and timers in tests; production uses host APIs. */
|
|
135
|
+
export function __setOffThreadMigrationClockForTests(clock?: TestClock): void {
|
|
136
|
+
testClock = clock;
|
|
137
|
+
}
|
|
138
|
+
|
|
116
139
|
/** Test seam: forget accumulated migration time between isolated tests. */
|
|
117
140
|
export function __resetOffThreadMigrationClockForTests(): void {
|
|
118
141
|
activeMigrations = 0;
|
|
119
142
|
activeSince = 0;
|
|
120
143
|
accumulatedMs = 0;
|
|
144
|
+
testClock = undefined;
|
|
121
145
|
const waiters = idleWaiters;
|
|
122
146
|
idleWaiters = [];
|
|
123
147
|
for (const wake of waiters) wake();
|
|
@@ -132,3 +132,19 @@ describe("redaction gaps: unambiguous secret key names and header/URL credential
|
|
|
132
132
|
expect(apiKey).toContain("x-api-key");
|
|
133
133
|
});
|
|
134
134
|
});
|
|
135
|
+
|
|
136
|
+
describe("public diagnostic credential shapes", () => {
|
|
137
|
+
test("redacts unquoted colon credentials without removing scalar diagnostics", () => {
|
|
138
|
+
expect(redactSecretText("password: colonSecret700 token: anotherSecret700")).toBe(
|
|
139
|
+
"password: <REDACTED:credential> token: <REDACTED:credential>",
|
|
140
|
+
);
|
|
141
|
+
expect(redactSecretText("token: 1234567 secret: false")).toBe(
|
|
142
|
+
"token: 1234567 secret: false",
|
|
143
|
+
);
|
|
144
|
+
});
|
|
145
|
+
test("redacts hyphenated and underscored GitHub token payloads completely", () => {
|
|
146
|
+
expect(redactSecretText("ghp_ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890-extra_payload")).toBe(
|
|
147
|
+
"<GITHUB_TOKEN_REDACTED>",
|
|
148
|
+
);
|
|
149
|
+
});
|
|
150
|
+
});
|
package/src/shared/redaction.ts
CHANGED
|
@@ -152,7 +152,7 @@ const SECRET_TEXT_PATTERNS: Array<{
|
|
|
152
152
|
replacement: "<GITHUB_PAT_REDACTED>",
|
|
153
153
|
},
|
|
154
154
|
{
|
|
155
|
-
pattern: /\b(?:gh[opsu]|ghr)_[A-Za-z0-
|
|
155
|
+
pattern: /\b(?:gh[opsu]|ghr)_[A-Za-z0-9_-]{30,}/g,
|
|
156
156
|
replacement: "<GITHUB_TOKEN_REDACTED>",
|
|
157
157
|
},
|
|
158
158
|
{
|
|
@@ -190,6 +190,13 @@ const SECRET_TEXT_PATTERNS: Array<{
|
|
|
190
190
|
replacement: (full: string, prefix: string, value: string) =>
|
|
191
191
|
isNonSecretScalarValue(value) ? full : `${prefix}<REDACTED:api_key>`,
|
|
192
192
|
},
|
|
193
|
+
{
|
|
194
|
+
// Unquoted diagnostic prose also uses colon-delimited credentials.
|
|
195
|
+
pattern:
|
|
196
|
+
/\b((?:api[_-]?key|client[_-]?secret|access[_-]?token|token|secret|password|passwd|pwd)\s*:\s*)([^\s'"`,;<>]{6,})/gi,
|
|
197
|
+
replacement: (full: string, prefix: string, value: string) =>
|
|
198
|
+
isNonSecretScalarValue(value) ? full : `${prefix}<REDACTED:credential>`,
|
|
199
|
+
},
|
|
193
200
|
{
|
|
194
201
|
// Credentials embedded in a URL: scheme://user:password@host.
|
|
195
202
|
pattern: /\b([a-z][a-z0-9+.-]*:\/\/[^\s/:@]+:)([^\s/@]+)(@)/gi,
|