@retaw106/mmc-oc 1.2.1 → 1.2.2

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.
@@ -1,56 +0,0 @@
1
- import {
2
- hasMeaningfulUserText2,
3
- extractTexts2,
4
- resolveHostServedBoundaryId2,
5
- hasRawMessageProvider2,
6
- setBoundedRawMessageProvider2,
7
- cleanUserText2,
8
- withRawSessionMessageCache2,
9
- readRawSessionMessages2,
10
- readRawSessionMessagePage2,
11
- getRawSessionMessageOrdinalCount2,
12
- visitRawSessionMessages2,
13
- readRawSessionMessageRange2,
14
- primeTailRawMessageCache2,
15
- getCachedAbsoluteMessageCount2,
16
- primeInMemoryTailRawMessageCache2,
17
- readRawSessionMessageIdOrdinalsForRange2,
18
- hasRawSessionMessageById2,
19
- readRawSessionMessageOrdinalById2,
20
- compareRawSessionMessageOrder2,
21
- readRawSessionMessageById2,
22
- getRawSessionMessageCount2,
23
- getRawSessionTagKeysThrough2,
24
- getLegacyProtectedTailStartOrdinal2,
25
- readSessionChunk2
26
- } from "./index-qkdksr6f.js";
27
- import"./index-977gxfz0.js";
28
- import"./index-fg34g6a5.js";
29
- import"./index-3wagyrnj.js";
30
- import"./index-qbkzdkk0.js";
31
- export {
32
- cleanUserText2 as cleanUserText,
33
- compareRawSessionMessageOrder2 as compareRawSessionMessageOrder,
34
- extractTexts2 as extractTexts,
35
- getCachedAbsoluteMessageCount2 as getCachedAbsoluteMessageCount,
36
- getLegacyProtectedTailStartOrdinal2 as getLegacyProtectedTailStartOrdinal,
37
- getRawSessionMessageCount2 as getRawSessionMessageCount,
38
- getRawSessionMessageOrdinalCount2 as getRawSessionMessageOrdinalCount,
39
- getRawSessionTagKeysThrough2 as getRawSessionTagKeysThrough,
40
- hasMeaningfulUserText2 as hasMeaningfulUserText,
41
- hasRawMessageProvider2 as hasRawMessageProvider,
42
- hasRawSessionMessageById2 as hasRawSessionMessageById,
43
- primeInMemoryTailRawMessageCache2 as primeInMemoryTailRawMessageCache,
44
- primeTailRawMessageCache2 as primeTailRawMessageCache,
45
- readRawSessionMessageById2 as readRawSessionMessageById,
46
- readRawSessionMessageIdOrdinalsForRange2 as readRawSessionMessageIdOrdinalsForRange,
47
- readRawSessionMessageOrdinalById2 as readRawSessionMessageOrdinalById,
48
- readRawSessionMessagePage2 as readRawSessionMessagePage,
49
- readRawSessionMessageRange2 as readRawSessionMessageRange,
50
- readRawSessionMessages2 as readRawSessionMessages,
51
- readSessionChunk2 as readSessionChunk,
52
- resolveHostServedBoundaryId2 as resolveHostServedBoundaryId,
53
- setBoundedRawMessageProvider2 as setBoundedRawMessageProvider,
54
- visitRawSessionMessages2 as visitRawSessionMessages,
55
- withRawSessionMessageCache2 as withRawSessionMessageCache
56
- };
@@ -1,56 +0,0 @@
1
- import {
2
- hasMeaningfulUserText2,
3
- extractTexts2,
4
- resolveHostServedBoundaryId2,
5
- hasRawMessageProvider2,
6
- setBoundedRawMessageProvider2,
7
- cleanUserText2,
8
- withRawSessionMessageCache2,
9
- readRawSessionMessages2,
10
- readRawSessionMessagePage2,
11
- getRawSessionMessageOrdinalCount2,
12
- visitRawSessionMessages2,
13
- readRawSessionMessageRange2,
14
- primeTailRawMessageCache2,
15
- getCachedAbsoluteMessageCount2,
16
- primeInMemoryTailRawMessageCache2,
17
- readRawSessionMessageIdOrdinalsForRange2,
18
- hasRawSessionMessageById2,
19
- readRawSessionMessageOrdinalById2,
20
- compareRawSessionMessageOrder2,
21
- readRawSessionMessageById2,
22
- getRawSessionMessageCount2,
23
- getRawSessionTagKeysThrough2,
24
- getLegacyProtectedTailStartOrdinal2,
25
- readSessionChunk2
26
- } from "./index-2axapwjs.js";
27
- import"./index-977gxfz0.js";
28
- import"./index-fg34g6a5.js";
29
- import"./index-3wagyrnj.js";
30
- import"./index-qbkzdkk0.js";
31
- export {
32
- cleanUserText2 as cleanUserText,
33
- compareRawSessionMessageOrder2 as compareRawSessionMessageOrder,
34
- extractTexts2 as extractTexts,
35
- getCachedAbsoluteMessageCount2 as getCachedAbsoluteMessageCount,
36
- getLegacyProtectedTailStartOrdinal2 as getLegacyProtectedTailStartOrdinal,
37
- getRawSessionMessageCount2 as getRawSessionMessageCount,
38
- getRawSessionMessageOrdinalCount2 as getRawSessionMessageOrdinalCount,
39
- getRawSessionTagKeysThrough2 as getRawSessionTagKeysThrough,
40
- hasMeaningfulUserText2 as hasMeaningfulUserText,
41
- hasRawMessageProvider2 as hasRawMessageProvider,
42
- hasRawSessionMessageById2 as hasRawSessionMessageById,
43
- primeInMemoryTailRawMessageCache2 as primeInMemoryTailRawMessageCache,
44
- primeTailRawMessageCache2 as primeTailRawMessageCache,
45
- readRawSessionMessageById2 as readRawSessionMessageById,
46
- readRawSessionMessageIdOrdinalsForRange2 as readRawSessionMessageIdOrdinalsForRange,
47
- readRawSessionMessageOrdinalById2 as readRawSessionMessageOrdinalById,
48
- readRawSessionMessagePage2 as readRawSessionMessagePage,
49
- readRawSessionMessageRange2 as readRawSessionMessageRange,
50
- readRawSessionMessages2 as readRawSessionMessages,
51
- readSessionChunk2 as readSessionChunk,
52
- resolveHostServedBoundaryId2 as resolveHostServedBoundaryId,
53
- setBoundedRawMessageProvider2 as setBoundedRawMessageProvider,
54
- visitRawSessionMessages2 as visitRawSessionMessages,
55
- withRawSessionMessageCache2 as withRawSessionMessageCache
56
- };
@@ -1,21 +0,0 @@
1
- import {
2
- setRecompStarting2,
3
- setRecompTerminal2,
4
- runManagedRecomp2
5
- } from "./index-7dgv6pzg.js";
6
- import"./index-46j0tj1s.js";
7
- import"./index-5pg0acf7.js";
8
- import"./index-qkdksr6f.js";
9
- import"./index-977gxfz0.js";
10
- import"./index-e1q8002h.js";
11
- import"./index-fg34g6a5.js";
12
- import"./index-jdxxq8cz.js";
13
- import"./index-53g38ggt.js";
14
- import"./index-zx63j2e2.js";
15
- import"./index-3wagyrnj.js";
16
- import"./index-qbkzdkk0.js";
17
- export {
18
- runManagedRecomp2 as runManagedRecomp,
19
- setRecompStarting2 as setRecompStarting,
20
- setRecompTerminal2 as setRecompTerminal
21
- };
@@ -1,21 +0,0 @@
1
- import {
2
- setRecompStarting2,
3
- setRecompTerminal2,
4
- runManagedRecomp2
5
- } from "./index-5s9w99sf.js";
6
- import"./index-xyjcjq10.js";
7
- import"./index-5pg0acf7.js";
8
- import"./index-2axapwjs.js";
9
- import"./index-977gxfz0.js";
10
- import"./index-e1q8002h.js";
11
- import"./index-fg34g6a5.js";
12
- import"./index-jdxxq8cz.js";
13
- import"./index-53g38ggt.js";
14
- import"./index-zx63j2e2.js";
15
- import"./index-3wagyrnj.js";
16
- import"./index-qbkzdkk0.js";
17
- export {
18
- runManagedRecomp2 as runManagedRecomp,
19
- setRecompStarting2 as setRecompStarting,
20
- setRecompTerminal2 as setRecompTerminal
21
- };
@@ -1,420 +0,0 @@
1
- import {
2
- sessionLog
3
- } from "./index-qbkzdkk0.js";
4
- import {
5
- COMPARTMENT_LEASE_RENEWAL_MS,
6
- acquireCompartmentLease,
7
- renewCompartmentLease,
8
- releaseCompartmentLeaseBestEffort,
9
- getCompartments,
10
- getLastCompartmentEndMessage,
11
- getWrapupInProgressState,
12
- acquireWrapupInProgress,
13
- updateWrapupInProgress,
14
- releaseWrapupInProgress,
15
- getHistorianFailureState,
16
- clearEmergencyRecovery,
17
- describeBoundaryDiagnostics,
18
- resolveWrapupProtectedTailBoundary,
19
- hasRunnableCompartmentWindow,
20
- runCompartmentAgent,
21
- getActiveCompartmentRun,
22
- markActiveCompartmentRunPublished,
23
- registerActiveCompartmentRun
24
- } from "./index-xyjcjq10.js";
25
- import"./index-fg34g6a5.js";
26
- import"./index-2axapwjs.js";
27
- import"./index-977gxfz0.js";
28
- import"./index-3wagyrnj.js";
29
- import {
30
- pushNotification2
31
- } from "./index-jdxxq8cz.js";
32
- import"./index-zx63j2e2.js";
33
- import"./index-53g38ggt.js";
34
- import {
35
- sendStatusNotification2
36
- } from "./index-5pg0acf7.js";
37
- import {
38
- setRecompStarting2,
39
- setRecompTerminal2
40
- } from "./index-5s9w99sf.js";
41
- import"./index-e1q8002h.js";
42
-
43
- // src/hooks/magic-context/wrapup-orchestrator.ts
44
- import * as crypto from "node:crypto";
45
- var WAIT_FOR_LEASE_MS = 1000;
46
- var MAX_WRAPUP_LEASE_WAIT_MS = 10 * 60 * 1000;
47
- function sleep(ms) {
48
- return new Promise((resolve) => setTimeout(resolve, ms));
49
- }
50
- function plural(value, word) {
51
- return `${value} ${word}${value === 1 ? "" : "s"}`;
52
- }
53
- function resolveWrapupLeaseWaitTimeout(ctx) {
54
- const configured = ctx.wrapupLeaseWaitTimeoutMs ?? MAX_WRAPUP_LEASE_WAIT_MS;
55
- return Number.isFinite(configured) && configured >= 0 ? configured : MAX_WRAPUP_LEASE_WAIT_MS;
56
- }
57
- async function waitForActiveRunWithin(promise, timeoutMs) {
58
- if (timeoutMs <= 0)
59
- return "timeout";
60
- let timer;
61
- const timedOut = new Promise((resolve) => {
62
- timer = setTimeout(() => resolve("timeout"), timeoutMs);
63
- });
64
- try {
65
- return await Promise.race([
66
- promise.then(() => "settled", () => "settled"),
67
- timedOut
68
- ]);
69
- } finally {
70
- clearTimeout(timer);
71
- }
72
- }
73
- function formatAlreadyRunningMessage(state) {
74
- if (!state)
75
- return "/mmc-wrapup is already running for this session.";
76
- const chunk = state.expectedChunks > 0 ? ` chunk ${state.chunkIndex}/${state.expectedChunks}` : "";
77
- const through = state.lastCompartmentEnd > 0 ? ` through message ${state.lastCompartmentEnd}` : "";
78
- return `/mmc-wrapup is already running for this session${chunk}${through}. Wait for it to finish, then run /mmc-wrapup again if more history remains.`;
79
- }
80
- function appendFlushHint(ctx, sessionId, message) {
81
- if (ctx.hasPendingNaturalBust?.(sessionId))
82
- return message;
83
- return `${message} If you want it applied on the very next message, run /mmc-flush first.`;
84
- }
85
- function buildPlan(ctx, sessionId, messagesToKeep, anchorRawMessageCount) {
86
- return resolveWrapupProtectedTailBoundary({
87
- db: ctx.db,
88
- sessionId,
89
- mode: "manual-wrapup",
90
- contextLimit: ctx.contextLimit,
91
- executeThresholdPercentage: ctx.executeThresholdPercentage,
92
- usage: null,
93
- usageSource: "manual-none",
94
- providerShapeVersion: "opencode-v1",
95
- cacheNamespace: `opencode:${sessionId}`,
96
- messagesToKeep,
97
- anchorRawMessageCount
98
- });
99
- }
100
- function emitWrapupProgress(ctx, sessionId, progress) {
101
- const current = ctx.liveSessionState.recompProgressBySession.get(sessionId);
102
- ctx.liveSessionState.recompProgressBySession.set(sessionId, {
103
- sessionId,
104
- kind: "wrapup",
105
- phase: "recomp",
106
- processedMessages: progress.processedMessages ?? current?.processedMessages ?? 0,
107
- totalMessages: progress.totalMessages ?? current?.totalMessages ?? 0,
108
- passCount: progress.passCount ?? current?.passCount ?? 0,
109
- compartmentsCreated: progress.compartmentsCreated ?? current?.compartmentsCreated ?? 0,
110
- startedAt: current?.startedAt ?? Date.now(),
111
- updatedAt: Date.now(),
112
- note: progress.note
113
- });
114
- }
115
- async function waitForExistingIncrementalRun(sessionId, maxWaitMs) {
116
- const active = getActiveCompartmentRun(sessionId);
117
- if (!active)
118
- return "ok";
119
- if (active.kind === "recomp" || active.kind === "wrapup")
120
- return "busy";
121
- const outcome = await waitForActiveRunWithin(active.promise, maxWaitMs);
122
- if (outcome === "timeout")
123
- return "timeout";
124
- return "ok";
125
- }
126
- async function acquireCompartmentLeaseForWrapup(ctx, sessionId, renewWrapupMarker) {
127
- const holderId = crypto.randomUUID();
128
- const waitStartedAt = Date.now();
129
- const maxWaitMs = resolveWrapupLeaseWaitTimeout(ctx);
130
- const remainingMs = () => Math.max(0, waitStartedAt + maxWaitMs - Date.now());
131
- for (;; ) {
132
- if (remainingMs() <= 0) {
133
- sessionLog(sessionId, "wrapup: timed out waiting for the compartment-state lease");
134
- return { ok: false, reason: "timeout" };
135
- }
136
- const active = getActiveCompartmentRun(sessionId);
137
- if (active?.kind === "recomp" || active?.kind === "wrapup") {
138
- return { ok: false, reason: "busy" };
139
- }
140
- if (active) {
141
- emitWrapupProgress(ctx, sessionId, { note: "Waiting for the active historian run…" });
142
- const outcome = await waitForActiveRunWithin(active.promise, remainingMs());
143
- if (outcome === "timeout") {
144
- sessionLog(sessionId, "wrapup: timed out waiting for the active historian run");
145
- return { ok: false, reason: "timeout" };
146
- }
147
- continue;
148
- }
149
- const lease = acquireCompartmentLease(ctx.db, sessionId, holderId);
150
- if (lease)
151
- return { ok: true, holderId };
152
- emitWrapupProgress(ctx, sessionId, { note: "Waiting for the compartment-state lease…" });
153
- if (!renewWrapupMarker({}))
154
- return { ok: false, reason: "ownership_lost" };
155
- await sleep(Math.min(WAIT_FOR_LEASE_MS, remainingMs()));
156
- }
157
- }
158
- async function runOneWrapupIteration(args) {
159
- const { ctx, sessionId, plan, messagesToKeep, anchorRawMessageCount } = args;
160
- const acquired = await acquireCompartmentLeaseForWrapup(ctx, sessionId, args.renewWrapupMarker);
161
- if (!acquired.ok)
162
- return { ran: false, reason: acquired.reason };
163
- const leaseHolderId = acquired.holderId;
164
- const renewal = setInterval(() => {
165
- try {
166
- if (!renewCompartmentLease(ctx.db, sessionId, leaseHolderId)) {
167
- sessionLog(sessionId, "wrapup: compartment lease renewal failed");
168
- }
169
- } catch (err) {
170
- sessionLog(sessionId, `wrapup: compartment lease renewal threw; continuing (${err instanceof Error ? err.message : String(err)})`);
171
- }
172
- }, COMPARTMENT_LEASE_RENEWAL_MS);
173
- const runCompartmentAgentForWrapup = ctx.runCompartmentAgentForWrapup ?? runCompartmentAgent;
174
- const runnerPromise = runCompartmentAgentForWrapup({
175
- client: ctx.client,
176
- hiddenCompletionExecutor: ctx.hiddenCompletionExecutor,
177
- db: ctx.db,
178
- sessionId,
179
- historianChunkTokens: ctx.historianChunkTokens,
180
- historianTimeoutMs: ctx.historianTimeoutMs,
181
- boundarySnapshot: plan.snapshot,
182
- currentContextLimit: ctx.contextLimit,
183
- directory: ctx.directory,
184
- model: ctx.historianModel,
185
- fallbackModels: ctx.fallbackModels,
186
- fallbackModelId: ctx.fallbackModelId,
187
- language: ctx.language,
188
- historianTwoPass: ctx.historianTwoPass,
189
- historianExpandTools: ctx.historianExpandTools,
190
- memoryEnabled: ctx.memoryEnabled,
191
- autoPromote: ctx.autoPromote,
192
- ensureProjectRegistered: ctx.ensureProjectRegistered,
193
- getNotificationParams: () => ctx.getNotificationParams(sessionId),
194
- preserveInjectionCacheUntilConsumed: true,
195
- compartmentLeaseHolderId: leaseHolderId,
196
- forceDrainQuota: true,
197
- forceKeepLastCompartment: plan.snapshot.eligibleEndOrdinal >= plan.targetEligibleEndOrdinal,
198
- refreshBoundarySnapshot: () => buildPlan(ctx, sessionId, messagesToKeep, anchorRawMessageCount).snapshot,
199
- onCompartmentStatePublished: (sid) => {
200
- markActiveCompartmentRunPublished(sid);
201
- ctx.liveSessionState.deferredHistoryRefreshSessions.add(sid);
202
- ctx.liveSessionState.deferredMaterializationSessions.add(sid);
203
- },
204
- onDeferredMarkerPending: (sid) => {
205
- ctx.liveSessionState.deferredHistoryRefreshSessions.add(sid);
206
- }
207
- });
208
- registerActiveCompartmentRun(sessionId, runnerPromise, "wrapup").promise.catch(() => {});
209
- try {
210
- await runnerPromise;
211
- return { ran: true };
212
- } finally {
213
- clearInterval(renewal);
214
- releaseCompartmentLeaseBestEffort(ctx.db, sessionId, leaseHolderId, sessionLog);
215
- }
216
- }
217
- async function runManagedWrapup(ctx, sessionId, options) {
218
- const messagesToKeep = Math.max(1, Math.floor(options.messagesToKeep));
219
- setRecompStarting2(ctx.liveSessionState, sessionId, "Estimating wrapup…", "wrapup");
220
- try {
221
- return await runStartedWrapup(ctx, sessionId, messagesToKeep);
222
- } catch (error) {
223
- const reason = error instanceof Error ? error.message : String(error);
224
- setRecompTerminal2(ctx.liveSessionState, sessionId, "failed", `Wrapup stopped: ${reason}. Run /mmc-wrapup again to continue.`);
225
- throw error;
226
- }
227
- }
228
- async function runStartedWrapup(ctx, sessionId, messagesToKeep) {
229
- const existingWrapup = getWrapupInProgressState(ctx.db, sessionId);
230
- if (existingWrapup) {
231
- const message = formatAlreadyRunningMessage(existingWrapup);
232
- setRecompTerminal2(ctx.liveSessionState, sessionId, "skipped", message);
233
- return `## Magic Wrapup — Skipped
234
-
235
- ${message}`;
236
- }
237
- const initialPlan = buildPlan(ctx, sessionId, messagesToKeep);
238
- if (initialPlan.rawMessagesAboveLastCompartment <= messagesToKeep || !hasRunnableCompartmentWindow(initialPlan.snapshot)) {
239
- const message = `Nothing to wrap up — only ${initialPlan.rawMessagesAboveLastCompartment} messages above the last compartment.`;
240
- setRecompTerminal2(ctx.liveSessionState, sessionId, "done", message);
241
- return message;
242
- }
243
- const expectedChunks = Math.max(1, Math.ceil(initialPlan.snapshot.trueRawEligibleTokens / Math.max(1, ctx.historianChunkTokens)));
244
- const wrapupHolderId = crypto.randomUUID();
245
- const acquired = acquireWrapupInProgress(ctx.db, sessionId, {
246
- holderId: wrapupHolderId,
247
- messagesToKeep,
248
- anchorRawMessageCount: initialPlan.anchorRawMessageCount,
249
- targetEligibleEndOrdinal: initialPlan.targetEligibleEndOrdinal,
250
- lastCompartmentEnd: getLastCompartmentEndMessage(ctx.db, sessionId),
251
- chunkIndex: 0,
252
- expectedChunks
253
- });
254
- if (!acquired.ok) {
255
- const message = formatAlreadyRunningMessage(acquired.state);
256
- setRecompTerminal2(ctx.liveSessionState, sessionId, "skipped", message);
257
- return `## Magic Wrapup — Skipped
258
-
259
- ${message}`;
260
- }
261
- const startLastEnd = getLastCompartmentEndMessage(ctx.db, sessionId);
262
- const startCompartmentCount = getCompartments(ctx.db, sessionId).length;
263
- let chunkIndex = 0;
264
- let lastEnd = startLastEnd;
265
- let stoppedForFailure = false;
266
- let stoppedReason = "";
267
- let ownershipLost = false;
268
- const ownershipLostReason = "another process took over this session's wrapup.";
269
- const markOwnershipLost = () => {
270
- if (ownershipLost)
271
- return;
272
- ownershipLost = true;
273
- sessionLog(sessionId, "wrapup: durable marker ownership lost; aborting loop");
274
- };
275
- const renewWrapupMarker = (updates) => {
276
- const updated = updateWrapupInProgress(ctx.db, sessionId, wrapupHolderId, updates);
277
- if (!updated) {
278
- markOwnershipLost();
279
- return false;
280
- }
281
- return true;
282
- };
283
- const markerRenewal = setInterval(() => {
284
- try {
285
- renewWrapupMarker({
286
- lastCompartmentEnd: getLastCompartmentEndMessage(ctx.db, sessionId),
287
- chunkIndex
288
- });
289
- } catch (err) {
290
- sessionLog(sessionId, `wrapup: marker renewal threw; continuing (${err instanceof Error ? err.message : String(err)})`);
291
- }
292
- }, 60000);
293
- markerRenewal.unref?.();
294
- try {
295
- const activeAtStart = await waitForExistingIncrementalRun(sessionId, resolveWrapupLeaseWaitTimeout(ctx));
296
- if (activeAtStart === "busy") {
297
- const message = "Another Magic Context rebuild is already running for this session.";
298
- setRecompTerminal2(ctx.liveSessionState, sessionId, "skipped", message);
299
- return `## Magic Wrapup — Skipped
300
-
301
- ${message}`;
302
- }
303
- if (activeAtStart === "timeout") {
304
- stoppedForFailure = true;
305
- stoppedReason = "Timed out waiting for the active historian run.";
306
- }
307
- if (!stoppedForFailure) {
308
- try {
309
- sendStatusNotification2(ctx.client, sessionId, `Magic Wrapup started — compacting about ${plural(expectedChunks, "chunk")} of history. This can take a few minutes; the result posts here when done.`, ctx.getNotificationParams(sessionId));
310
- } catch {}
311
- try {
312
- pushNotification2("action", { action: "wrapup-progress-kick" }, sessionId);
313
- } catch {}
314
- }
315
- if (!stoppedForFailure && ownershipLost) {
316
- stoppedForFailure = true;
317
- stoppedReason = ownershipLostReason;
318
- } else if (!stoppedForFailure) {
319
- emitWrapupProgress(ctx, sessionId, {
320
- processedMessages: Math.max(0, lastEnd),
321
- totalMessages: Math.max(0, initialPlan.targetEligibleEndOrdinal - 1),
322
- passCount: 0,
323
- compartmentsCreated: 0,
324
- note: `Eligible ${plural(initialPlan.snapshot.trueRawEligibleTokens, "token")} across about ${plural(expectedChunks, "chunk")}.`
325
- });
326
- for (;; ) {
327
- if (ownershipLost) {
328
- stoppedForFailure = true;
329
- stoppedReason = ownershipLostReason;
330
- break;
331
- }
332
- if (!renewWrapupMarker({
333
- lastCompartmentEnd: getLastCompartmentEndMessage(ctx.db, sessionId),
334
- chunkIndex,
335
- expectedChunks
336
- })) {
337
- stoppedForFailure = true;
338
- stoppedReason = ownershipLostReason;
339
- break;
340
- }
341
- const plan = buildPlan(ctx, sessionId, messagesToKeep, initialPlan.anchorRawMessageCount);
342
- lastEnd = getLastCompartmentEndMessage(ctx.db, sessionId);
343
- if (lastEnd + 1 >= plan.targetEligibleEndOrdinal)
344
- break;
345
- chunkIndex += 1;
346
- sessionLog(sessionId, `wrapup chunk ${chunkIndex}: ${describeBoundaryDiagnostics(plan.snapshot)}`);
347
- emitWrapupProgress(ctx, sessionId, {
348
- processedMessages: Math.max(0, lastEnd),
349
- totalMessages: Math.max(0, plan.targetEligibleEndOrdinal - 1),
350
- passCount: chunkIndex - 1,
351
- compartmentsCreated: Math.max(0, getCompartments(ctx.db, sessionId).length - startCompartmentCount),
352
- note: `Chunk ${chunkIndex}/${expectedChunks}: messages ${plan.snapshot.offset}-${plan.snapshot.eligibleEndOrdinal - 1}…`
353
- });
354
- if (!renewWrapupMarker({
355
- lastCompartmentEnd: lastEnd,
356
- chunkIndex,
357
- expectedChunks,
358
- targetEligibleEndOrdinal: plan.targetEligibleEndOrdinal
359
- })) {
360
- stoppedForFailure = true;
361
- stoppedReason = ownershipLostReason;
362
- break;
363
- }
364
- const beforeEnd = lastEnd;
365
- const beforeFailures = getHistorianFailureState(ctx.db, sessionId).failureCount;
366
- const iteration = await runOneWrapupIteration({
367
- ctx,
368
- sessionId,
369
- plan,
370
- messagesToKeep,
371
- anchorRawMessageCount: initialPlan.anchorRawMessageCount,
372
- renewWrapupMarker
373
- });
374
- if (!iteration.ran) {
375
- stoppedForFailure = true;
376
- stoppedReason = ownershipLost || iteration.reason === "ownership_lost" ? ownershipLostReason : iteration.reason === "timeout" ? "Timed out waiting for another process to release the compartment-state lease." : "Another Magic Context rebuild started while wrapup was waiting.";
377
- break;
378
- }
379
- const afterEnd = getLastCompartmentEndMessage(ctx.db, sessionId);
380
- const afterFailures = getHistorianFailureState(ctx.db, sessionId).failureCount;
381
- if (afterEnd <= beforeEnd) {
382
- stoppedForFailure = true;
383
- stoppedReason = afterFailures > beforeFailures ? "The historian failed on the current chunk." : "The historian made no forward progress on the current chunk.";
384
- break;
385
- }
386
- lastEnd = afterEnd;
387
- emitWrapupProgress(ctx, sessionId, {
388
- processedMessages: Math.max(0, lastEnd),
389
- totalMessages: Math.max(0, plan.targetEligibleEndOrdinal - 1),
390
- passCount: chunkIndex,
391
- compartmentsCreated: Math.max(0, getCompartments(ctx.db, sessionId).length - startCompartmentCount),
392
- note: `Wrapped through message ${lastEnd}.`
393
- });
394
- }
395
- }
396
- } finally {
397
- clearInterval(markerRenewal);
398
- releaseWrapupInProgress(ctx.db, sessionId, wrapupHolderId);
399
- }
400
- const finalEnd = getLastCompartmentEndMessage(ctx.db, sessionId);
401
- const compartmentsCreated = Math.max(0, getCompartments(ctx.db, sessionId).length - startCompartmentCount);
402
- const messagesWrapped = Math.max(0, finalEnd - Math.max(0, startLastEnd));
403
- if (stoppedForFailure) {
404
- const message = `Wrapped up through message ${Math.max(0, finalEnd)} (${plural(messagesWrapped, "message")} into ${plural(compartmentsCreated, "compartment")}). ${stoppedReason} Run /mmc-wrapup again to continue.`;
405
- setRecompTerminal2(ctx.liveSessionState, sessionId, "failed", message);
406
- return `## Magic Wrapup — Partial
407
-
408
- ${message}`;
409
- }
410
- try {
411
- clearEmergencyRecovery(ctx.db, sessionId);
412
- } catch {}
413
- const base = `Wrapped up ${messagesWrapped} messages into ${compartmentsCreated} compartments. The compacted history is queued and materializes on your next message.`;
414
- const message = appendFlushHint(ctx, sessionId, base);
415
- setRecompTerminal2(ctx.liveSessionState, sessionId, "done", message);
416
- return message;
417
- }
418
- export {
419
- runManagedWrapup
420
- };