@cortexkit/opencode-magic-context 0.42.4 → 0.42.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/config/index.d.ts +9 -0
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/schema/magic-context.d.ts +1 -0
- package/dist/config/schema/magic-context.d.ts.map +1 -1
- package/dist/{conflict-warning-hook-jyj54gbe.js → conflict-warning-hook-aktepwpz.js} +3 -3
- package/dist/features/magic-context/compaction-marker.d.ts.map +1 -1
- package/dist/features/magic-context/context-authority.d.ts +28 -1
- package/dist/features/magic-context/context-authority.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/curate-category-rotation.d.ts +26 -0
- package/dist/features/magic-context/dreamer/curate-category-rotation.d.ts.map +1 -0
- package/dist/features/magic-context/dreamer/open-opencode-db.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/storage-task-schedule.d.ts +7 -5
- package/dist/features/magic-context/dreamer/storage-task-schedule.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/task-executor.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/task-gates.d.ts +1 -0
- package/dist/features/magic-context/dreamer/task-gates.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/task-prompts.d.ts +3 -0
- package/dist/features/magic-context/dreamer/task-prompts.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/task-registry.d.ts +6 -0
- package/dist/features/magic-context/dreamer/task-registry.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/task-scheduler.d.ts +5 -1
- package/dist/features/magic-context/dreamer/task-scheduler.d.ts.map +1 -1
- package/dist/features/magic-context/memory/embedding-local.d.ts +12 -0
- package/dist/features/magic-context/memory/embedding-local.d.ts.map +1 -1
- package/dist/features/magic-context/memory/embedding.d.ts +1 -1
- package/dist/features/magic-context/memory/embedding.d.ts.map +1 -1
- package/dist/features/magic-context/message-index.d.ts.map +1 -1
- package/dist/features/magic-context/migrations.d.ts +12 -0
- package/dist/features/magic-context/migrations.d.ts.map +1 -1
- package/dist/features/magic-context/project-embedding-registry.d.ts +1 -0
- package/dist/features/magic-context/project-embedding-registry.d.ts.map +1 -1
- package/dist/features/magic-context/session-project-backfill.d.ts.map +1 -1
- package/dist/features/magic-context/storage-db.d.ts +1 -1
- package/dist/features/magic-context/tool-owner-backfill.d.ts.map +1 -1
- package/dist/hooks/auto-update-checker/index.d.ts.map +1 -1
- package/dist/hooks/magic-context/cache-busting-signals.d.ts +0 -1
- package/dist/hooks/magic-context/cache-busting-signals.d.ts.map +1 -1
- package/dist/hooks/magic-context/channel2-delivery.d.ts +8 -0
- package/dist/hooks/magic-context/channel2-delivery.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-incremental.d.ts +12 -0
- package/dist/hooks/magic-context/compartment-runner-incremental.d.ts.map +1 -1
- package/dist/hooks/magic-context/hook.d.ts +4 -4
- package/dist/hooks/magic-context/hook.d.ts.map +1 -1
- package/dist/hooks/magic-context/module-state-sync.d.ts +3 -0
- package/dist/hooks/magic-context/module-state-sync.d.ts.map +1 -1
- package/dist/hooks/magic-context/module-transport.d.ts +24 -2
- package/dist/hooks/magic-context/module-transport.d.ts.map +1 -1
- package/dist/hooks/magic-context/module-wire.d.ts +1 -1
- package/dist/hooks/magic-context/module-wire.d.ts.map +1 -1
- package/dist/hooks/magic-context/producer-window-guard.d.ts +31 -1
- package/dist/hooks/magic-context/producer-window-guard.d.ts.map +1 -1
- package/dist/hooks/magic-context/read-session-chunk.d.ts +6 -0
- package/dist/hooks/magic-context/read-session-chunk.d.ts.map +1 -1
- package/dist/hooks/magic-context/read-session-db.d.ts +8 -0
- package/dist/hooks/magic-context/read-session-db.d.ts.map +1 -1
- package/dist/hooks/magic-context/read-session-formatting.d.ts +6 -0
- package/dist/hooks/magic-context/read-session-formatting.d.ts.map +1 -1
- package/dist/hooks/magic-context/rust-mode-transform.d.ts +30 -0
- package/dist/hooks/magic-context/rust-mode-transform.d.ts.map +1 -1
- package/dist/hooks/magic-context/rust-refusal-recovery.d.ts +28 -0
- package/dist/hooks/magic-context/rust-refusal-recovery.d.ts.map +1 -0
- package/dist/hooks/magic-context/tail-hygiene-walk.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform.d.ts +7 -0
- package/dist/hooks/magic-context/transform.d.ts.map +1 -1
- package/dist/{index-bkg2fdj1.js → index-4wwr6cz0.js} +3 -0
- package/dist/{index-jkrqhc7y.js → index-a9ssj59b.js} +94 -15
- package/dist/{index-faay035c.js → index-djp6rwz6.js} +484 -57
- package/dist/{index-p474rw9p.js → index-ngjmj6xx.js} +1 -1
- package/dist/{index-d8mgqezq.js → index-s61hh7gv.js} +50 -17
- package/dist/{index-1ar7b3e9.js → index-znraa0kv.js} +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1667 -380
- package/dist/plugin/embedding-bootstrap.d.ts.map +1 -1
- package/dist/plugin/hooks/create-session-hooks.d.ts.map +1 -1
- package/dist/plugin/memory-id-translation.d.ts +23 -0
- package/dist/plugin/memory-id-translation.d.ts.map +1 -0
- package/dist/plugin/rust-tool-backends.d.ts +1 -1
- package/dist/plugin/rust-tool-backends.d.ts.map +1 -1
- package/dist/{recomp-orchestrator-c4sa354a.js → recomp-orchestrator-0xx1364v.js} +4 -4
- package/dist/{send-session-notification-xnypkxpx.js → send-session-notification-jbxknvar.js} +2 -2
- package/dist/shared/auto-update-provenance.d.ts +9 -0
- package/dist/shared/auto-update-provenance.d.ts.map +1 -0
- package/dist/shared/conflict-detector.d.ts +5 -1
- package/dist/shared/conflict-detector.d.ts.map +1 -1
- package/dist/shared/opencode-db-path.d.ts +31 -2
- package/dist/shared/opencode-db-path.d.ts.map +1 -1
- package/dist/shared/prompt-surface-runtime.d.ts +3 -3
- package/dist/shared/prompt-surface-runtime.d.ts.map +1 -1
- package/dist/{storage-meta-session-x3j0q9qy.js → storage-meta-session-z818pn1e.js} +2 -2
- package/dist/{task-config-ys0arma5.js → task-config-cv8k9y8r.js} +1 -1
- package/dist/tools/ctx-expand/mode.d.ts +31 -0
- package/dist/tools/ctx-expand/mode.d.ts.map +1 -0
- package/dist/tools/ctx-expand/tools.d.ts.map +1 -1
- package/dist/tools/ctx-memory/tools.d.ts.map +1 -1
- package/dist/tools/ctx-note/constants.d.ts +1 -1
- package/dist/tools/ctx-note/constants.d.ts.map +1 -1
- package/dist/tools/ctx-note/tools.d.ts.map +1 -1
- package/dist/tools/ctx-note/types.d.ts +1 -1
- package/dist/tools/ctx-note/types.d.ts.map +1 -1
- package/dist/tools/ctx-reduce/constants.d.ts +1 -1
- package/dist/tools/ctx-reduce/constants.d.ts.map +1 -1
- package/dist/tools/ctx-search/types.d.ts +1 -1
- package/dist/tools/ctx-search/types.d.ts.map +1 -1
- package/dist/tools/light-descriptions.d.ts +2 -2
- package/dist/tools/light-descriptions.d.ts.map +1 -1
- package/dist/v2/hidden-completion.d.ts +69 -13
- package/dist/v2/hidden-completion.d.ts.map +1 -1
- package/dist/v2/hooks/context.d.ts +13 -1
- package/dist/v2/hooks/context.d.ts.map +1 -1
- package/dist/v2/hooks/hidden-child.d.ts +31 -0
- package/dist/v2/hooks/hidden-child.d.ts.map +1 -0
- package/dist/v2/hooks/store.d.ts.map +1 -1
- package/dist/v2/hooks/types.d.ts +99 -19
- package/dist/v2/hooks/types.d.ts.map +1 -1
- package/dist/v2/server.d.ts +19 -0
- package/dist/v2/server.d.ts.map +1 -1
- package/dist/v2/server.js +2311 -2724
- package/dist/v2/store-reader.d.ts +11 -5
- package/dist/v2/store-reader.d.ts.map +1 -1
- package/dist/v2/tui/index.d.ts +10 -0
- package/dist/v2/tui/index.d.ts.map +1 -0
- package/dist/v2/tui/types.d.ts +80 -0
- package/dist/v2/tui/types.d.ts.map +1 -0
- package/package.json +5 -4
- package/src/agents/magic-context-prompt.ts +1 -1
- package/src/config/index.ts +31 -1
- package/src/config/protected-tokens.test.ts +40 -0
- package/src/config/schema/magic-context.ts +8 -3
- package/src/features/magic-context/dreamer/task-registry.ts +10 -0
- package/src/shared/auto-update-provenance.ts +42 -0
- package/src/shared/conflict-detector.test.ts +53 -0
- package/src/shared/conflict-detector.ts +88 -19
- package/src/shared/models-dev-cache.test.ts +25 -0
- package/src/shared/opencode-db-path.test.ts +96 -0
- package/src/shared/opencode-db-path.ts +146 -15
- package/src/shared/prompt-surface-a1-golden.md +12 -16
- package/src/shared/prompt-surface-runtime.test.ts +20 -0
- package/src/shared/prompt-surface-runtime.ts +7 -5
- package/src/tui/entry.mjs +11 -1
- package/src/v2/tui/host-contract.test.ts +202 -0
- package/src/v2/tui/index.ts +270 -0
- package/src/v2/tui/types.ts +67 -0
package/dist/index.js
CHANGED
|
@@ -32,6 +32,7 @@ import {
|
|
|
32
32
|
resolveModelConfigOrDefault,
|
|
33
33
|
DEFAULT_EXECUTE_THRESHOLD_PERCENTAGE,
|
|
34
34
|
DEFAULT_HISTORIAN_TIMEOUT_MS,
|
|
35
|
+
PROTECTED_TOKENS_MIN,
|
|
35
36
|
DEFAULT_LOCAL_EMBEDDING_MODEL,
|
|
36
37
|
PER_HARNESS_MIGRATION_INVENTORY,
|
|
37
38
|
PER_HARNESS_MODEL_KEYS,
|
|
@@ -72,7 +73,10 @@ import {
|
|
|
72
73
|
prepareAuthority,
|
|
73
74
|
drainAuthority,
|
|
74
75
|
getMemoryMirrorStatus,
|
|
76
|
+
moduleMemoryIdentityForHostId,
|
|
77
|
+
hostMemoryIdentityForModuleId,
|
|
75
78
|
applyMirroredNoteCompileFields,
|
|
79
|
+
applyTargetedMemoryMirrorRow,
|
|
76
80
|
drainMirrorPages,
|
|
77
81
|
pullMemoryMirrorOnce,
|
|
78
82
|
V2_MEMORY_CATEGORIES,
|
|
@@ -207,6 +211,7 @@ import {
|
|
|
207
211
|
primeInMemoryTailRawMessageCache,
|
|
208
212
|
readRawSessionMessageOrdinalPage,
|
|
209
213
|
getRawSessionStoredMessageCount,
|
|
214
|
+
readRawSessionMessageIdOrdinals,
|
|
210
215
|
readRawSessionMessagePartsById,
|
|
211
216
|
readRawSessionMessageOrdinalById,
|
|
212
217
|
readRawSessionMessageById,
|
|
@@ -365,11 +370,13 @@ import {
|
|
|
365
370
|
detectThinkingBindingMismatch,
|
|
366
371
|
isFable51ThinkingBindingModel,
|
|
367
372
|
detectOverflow,
|
|
373
|
+
parseProviderModel,
|
|
368
374
|
modelBodyField,
|
|
369
375
|
toModelEntry,
|
|
370
376
|
getPromptFailureDetail,
|
|
371
377
|
promptSyncWithValidatedOutputRetry,
|
|
372
378
|
normalizeSDKResponse,
|
|
379
|
+
ACTIVE_TOOL_IDS,
|
|
373
380
|
promptSurfaceHashMaterial,
|
|
374
381
|
createPromptSurfaceRuntime,
|
|
375
382
|
createPromptSurfaceGuidanceEpochCache,
|
|
@@ -422,6 +429,7 @@ import {
|
|
|
422
429
|
embedShadowTextForProject,
|
|
423
430
|
enqueueShadowEmbeddingItems,
|
|
424
431
|
registerProjectInObservationMode,
|
|
432
|
+
unregisterProjectShadowEmbedding,
|
|
425
433
|
getProjectEmbeddingSnapshot,
|
|
426
434
|
embedTextForProject,
|
|
427
435
|
embedBatchForProject,
|
|
@@ -547,7 +555,7 @@ import {
|
|
|
547
555
|
setRecompTerminal2,
|
|
548
556
|
runManagedRecomp2,
|
|
549
557
|
runManagedUpgrade2
|
|
550
|
-
} from "./index-
|
|
558
|
+
} from "./index-djp6rwz6.js";
|
|
551
559
|
import {
|
|
552
560
|
stripJsonComments,
|
|
553
561
|
isPrototypePollutionKey,
|
|
@@ -576,6 +584,7 @@ import {
|
|
|
576
584
|
} from "./index-f9gem5cr.js";
|
|
577
585
|
import {
|
|
578
586
|
resolveOpenCodeDbPath,
|
|
587
|
+
assertOpenCodeStoreGeneration,
|
|
579
588
|
openCodeDbPathExists,
|
|
580
589
|
formatOpenCodeDbMissingBanner,
|
|
581
590
|
formatOpenCodeDbMissingStatusLine,
|
|
@@ -592,9 +601,10 @@ import {
|
|
|
592
601
|
observeOpenCodeTurnEvent,
|
|
593
602
|
clearTrackedOpenCodeSession,
|
|
594
603
|
assistantAwaitingTools,
|
|
604
|
+
latestPersistedMessageForRecovery,
|
|
595
605
|
getMessageTimesFromOpenCodeDb,
|
|
596
606
|
findLastAssistantModelFromOpenCodeDb
|
|
597
|
-
} from "./index-
|
|
607
|
+
} from "./index-a9ssj59b.js";
|
|
598
608
|
import {
|
|
599
609
|
getErrorMessage,
|
|
600
610
|
describeError,
|
|
@@ -603,13 +613,13 @@ import {
|
|
|
603
613
|
clearIgnoredMessages2,
|
|
604
614
|
observeIgnoredNotificationEvent2,
|
|
605
615
|
sendStatusNotification2
|
|
606
|
-
} from "./index-
|
|
616
|
+
} from "./index-ngjmj6xx.js";
|
|
607
617
|
import {
|
|
608
618
|
detectConflicts,
|
|
609
619
|
resolveCompactionForBoot,
|
|
610
620
|
sendConflictWarning2,
|
|
611
621
|
cleanupConflictWarnings2
|
|
612
|
-
} from "./index-
|
|
622
|
+
} from "./index-s61hh7gv.js";
|
|
613
623
|
import {
|
|
614
624
|
resolveHistorianModel2,
|
|
615
625
|
resolveOpenCodeAgentOverrides2,
|
|
@@ -626,7 +636,7 @@ import {
|
|
|
626
636
|
compareTaskOrder,
|
|
627
637
|
buildDreamTaskRuntimeConfigs2,
|
|
628
638
|
userMemoryCollectionEnabled2
|
|
629
|
-
} from "./index-
|
|
639
|
+
} from "./index-4wwr6cz0.js";
|
|
630
640
|
import {
|
|
631
641
|
logSlowWriteTransaction,
|
|
632
642
|
getOrCreateSessionMeta2,
|
|
@@ -636,7 +646,7 @@ import {
|
|
|
636
646
|
retryPendingSessionCleanups2,
|
|
637
647
|
retryPendingRustSessionCleanupsForProject2,
|
|
638
648
|
clearSession2
|
|
639
|
-
} from "./index-
|
|
649
|
+
} from "./index-znraa0kv.js";
|
|
640
650
|
import {
|
|
641
651
|
registerNotificationSink2,
|
|
642
652
|
pushNotification2,
|
|
@@ -10370,6 +10380,9 @@ function redactConfigValue(value) {
|
|
|
10370
10380
|
return typeof value;
|
|
10371
10381
|
}
|
|
10372
10382
|
var warnedProtectedTagsDeprecation = false;
|
|
10383
|
+
function formatProtectedTokensBelowMinWarning(value) {
|
|
10384
|
+
return `protected_tokens is a token floor (minimum ${PROTECTED_TOKENS_MIN}, default derived from the context window); ${value} looks like the old protected_tags count. Remove the key to use the default, or set a token count such as 16000.`;
|
|
10385
|
+
}
|
|
10373
10386
|
function warnProtectedTagsDeprecationOnce() {
|
|
10374
10387
|
if (!warnedProtectedTagsDeprecation) {
|
|
10375
10388
|
warnedProtectedTagsDeprecation = true;
|
|
@@ -10460,6 +10473,11 @@ function parsePluginConfig(rawConfig, recoveredTopLevelKeys = []) {
|
|
|
10460
10473
|
delete patched[key];
|
|
10461
10474
|
const defaultVal = defaults[key];
|
|
10462
10475
|
const reason = customMessagesByKey.get(key);
|
|
10476
|
+
const invalidRawValue = rawConfig[key];
|
|
10477
|
+
if (key === "protected_tokens" && typeof invalidRawValue === "number" && invalidRawValue < PROTECTED_TOKENS_MIN) {
|
|
10478
|
+
warnings.push(formatProtectedTokensBelowMinWarning(invalidRawValue));
|
|
10479
|
+
continue;
|
|
10480
|
+
}
|
|
10463
10481
|
warnings.push(`"${key}": invalid value (${redactConfigValue(rawConfig[key])}), using default ${JSON.stringify(defaultVal)}.${reason ? ` ${reason}` : ""}`);
|
|
10464
10482
|
}
|
|
10465
10483
|
const retryMigrated = migrateLegacyAgentEnabledInMemory(migrateDreamerV2(migrateLegacyExperimental(patched, preMigrationWarnings), preMigrationWarnings), preMigrationWarnings);
|
|
@@ -10702,6 +10720,12 @@ function openOpenCodeDb() {
|
|
|
10702
10720
|
}
|
|
10703
10721
|
try {
|
|
10704
10722
|
const db = new Database(dbPath, { readonly: true });
|
|
10723
|
+
try {
|
|
10724
|
+
assertOpenCodeStoreGeneration(db, "v1", dbPath);
|
|
10725
|
+
} catch (error) {
|
|
10726
|
+
db.close();
|
|
10727
|
+
throw error;
|
|
10728
|
+
}
|
|
10705
10729
|
db.exec("PRAGMA busy_timeout = 5000");
|
|
10706
10730
|
clearOpenCodeDbReadFailure();
|
|
10707
10731
|
return db;
|
|
@@ -10781,9 +10805,11 @@ function buildCuratePrompt(args) {
|
|
|
10781
10805
|
|
|
10782
10806
|
**Project:** ${args.projectPath}
|
|
10783
10807
|
|
|
10808
|
+
This run covers the whole of the \`${args.category}\` category (the other categories run in later windows).
|
|
10809
|
+
|
|
10784
10810
|
The memories below are assumed ACCURATE (a separate verify task keeps them true). Your job is pool QUALITY: remove duplicates, tighten wording, and consolidate redundant entries that waste the ~6000-token injection budget. Explain each action in one line first. Do NOT mint new facts (that is the historian's job).
|
|
10785
10811
|
|
|
10786
|
-
Work ALL THREE phases below in order (A → B → C) over
|
|
10812
|
+
Work ALL THREE phases below in order (A → B → C) over this category. Do NOT stop after consolidating — a run that only merges and never improves or archives is incomplete.
|
|
10787
10813
|
|
|
10788
10814
|
### Phase A — Consolidate duplicates
|
|
10789
10815
|
Group by category, then merge near-identical / superset-subset / same-fact-different-angle clusters into one canonical memory with \`ctx_memory(action="merge", ids=[...], content="...", category="...")\`. Preserve every unique detail; terse present tense; paths/keys verbatim. Every id in a merge MUST share the same category — the system rejects cross-category merges. If two similar memories sit in different categories they are NOT duplicates; do not archive either as a consolidation. One fact per memory.
|
|
@@ -11003,6 +11029,7 @@ function buildDreamTaskPrompt(task, args) {
|
|
|
11003
11029
|
case "curate":
|
|
11004
11030
|
return buildCuratePrompt({
|
|
11005
11031
|
projectPath: args.projectPath,
|
|
11032
|
+
category: args.curate?.category ?? "PROJECT_RULES",
|
|
11006
11033
|
memories: args.curate?.memories ?? []
|
|
11007
11034
|
});
|
|
11008
11035
|
case "maintain-docs":
|
|
@@ -11189,7 +11216,19 @@ async function runSessionProjectBackfill(db, source, options = {}) {
|
|
|
11189
11216
|
let identityResolutionsSinceYield = 0;
|
|
11190
11217
|
let afterSessionId = null;
|
|
11191
11218
|
for (;; ) {
|
|
11192
|
-
|
|
11219
|
+
let sourcePage;
|
|
11220
|
+
try {
|
|
11221
|
+
sourcePage = await readPage(afterSessionId, SESSION_PAGE_SIZE);
|
|
11222
|
+
} catch (error) {
|
|
11223
|
+
try {
|
|
11224
|
+
if (!markBackfillRetryPending(db, harness, holderId, now())) {
|
|
11225
|
+
log("[session-projects] backfill lease changed before failure cleanup");
|
|
11226
|
+
}
|
|
11227
|
+
} catch (releaseError) {
|
|
11228
|
+
log(`[session-projects] failed to make backfill lease retryable after discovery failed: ${releaseError}`);
|
|
11229
|
+
}
|
|
11230
|
+
throw error;
|
|
11231
|
+
}
|
|
11193
11232
|
if (sourcePage.length === 0)
|
|
11194
11233
|
break;
|
|
11195
11234
|
afterSessionId = sourcePage.at(-1)?.sessionId ?? afterSessionId;
|
|
@@ -11520,17 +11559,47 @@ async function runDeferredV22Backfill(db, options = {}) {
|
|
|
11520
11559
|
}
|
|
11521
11560
|
|
|
11522
11561
|
// src/hooks/auto-update-checker/index.ts
|
|
11523
|
-
import { existsSync as
|
|
11562
|
+
import { existsSync as existsSync7, mkdirSync, readFileSync as readFileSync5, renameSync as renameSync3, rmSync, writeFileSync as writeFileSync3 } from "node:fs";
|
|
11524
11563
|
import { dirname as dirname4, join as join4 } from "node:path";
|
|
11525
11564
|
|
|
11565
|
+
// src/shared/auto-update-provenance.ts
|
|
11566
|
+
import { existsSync as existsSync5, readFileSync as readFileSync3 } from "node:fs";
|
|
11567
|
+
var AUTO_UPDATE_CHECK_STATE_FILENAME = "last-update-check.json";
|
|
11568
|
+
function readAutoUpdateCheckState(path) {
|
|
11569
|
+
if (!existsSync5(path))
|
|
11570
|
+
return null;
|
|
11571
|
+
try {
|
|
11572
|
+
const value = JSON.parse(readFileSync3(path, "utf-8"));
|
|
11573
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
11574
|
+
return null;
|
|
11575
|
+
const raw = value;
|
|
11576
|
+
const state = {};
|
|
11577
|
+
if (typeof raw.lastCheckedMs === "number" && Number.isFinite(raw.lastCheckedMs)) {
|
|
11578
|
+
state.lastCheckedMs = raw.lastCheckedMs;
|
|
11579
|
+
}
|
|
11580
|
+
if (typeof raw.updaterPinnedSpec === "string" && raw.updaterPinnedSpec.length > 0) {
|
|
11581
|
+
state.updaterPinnedSpec = raw.updaterPinnedSpec;
|
|
11582
|
+
}
|
|
11583
|
+
if (typeof raw.updaterPinnedAt === "number" && Number.isFinite(raw.updaterPinnedAt)) {
|
|
11584
|
+
state.updaterPinnedAt = raw.updaterPinnedAt;
|
|
11585
|
+
}
|
|
11586
|
+
return state;
|
|
11587
|
+
} catch {
|
|
11588
|
+
return null;
|
|
11589
|
+
}
|
|
11590
|
+
}
|
|
11591
|
+
function isUpdaterPinnedSpec(state, configuredSpec) {
|
|
11592
|
+
return state?.updaterPinnedSpec === configuredSpec && typeof state.updaterPinnedAt === "number" && Number.isFinite(state.updaterPinnedAt);
|
|
11593
|
+
}
|
|
11594
|
+
|
|
11526
11595
|
// src/hooks/auto-update-checker/checker.ts
|
|
11527
11596
|
var import_comment_json = __toESM(require_src2(), 1);
|
|
11528
11597
|
import { spawn } from "node:child_process";
|
|
11529
11598
|
import {
|
|
11530
11599
|
accessSync,
|
|
11531
|
-
existsSync as
|
|
11600
|
+
existsSync as existsSync6,
|
|
11532
11601
|
constants as fsConstants,
|
|
11533
|
-
readFileSync as
|
|
11602
|
+
readFileSync as readFileSync4,
|
|
11534
11603
|
renameSync as renameSync2,
|
|
11535
11604
|
statSync as statSync2,
|
|
11536
11605
|
writeFileSync as writeFileSync2
|
|
@@ -11640,9 +11709,9 @@ function getWinningConfig(directory, surface) {
|
|
|
11640
11709
|
let winner = null;
|
|
11641
11710
|
for (const path of getSurfaceConfigPaths(directory, surface)) {
|
|
11642
11711
|
try {
|
|
11643
|
-
if (!
|
|
11712
|
+
if (!existsSync6(path))
|
|
11644
11713
|
continue;
|
|
11645
|
-
const parsed = parseJsonConfig(
|
|
11714
|
+
const parsed = parseJsonConfig(readFileSync4(path, "utf-8"));
|
|
11646
11715
|
const entries = getPluginEntries(parsed);
|
|
11647
11716
|
if (entries.some((entry) => entry === PACKAGE_NAME || entry.startsWith(`${PACKAGE_NAME}@`))) {
|
|
11648
11717
|
if (winner) {
|
|
@@ -11675,9 +11744,9 @@ function findPackageJsonUp(startPath) {
|
|
|
11675
11744
|
let dir = stat.isDirectory() ? startPath : dirname3(startPath);
|
|
11676
11745
|
for (let i = 0;i < 10; i++) {
|
|
11677
11746
|
const pkgPath = join3(dir, "package.json");
|
|
11678
|
-
if (
|
|
11747
|
+
if (existsSync6(pkgPath)) {
|
|
11679
11748
|
try {
|
|
11680
|
-
const pkg = PackageJsonSchema.safeParse(JSON.parse(
|
|
11749
|
+
const pkg = PackageJsonSchema.safeParse(JSON.parse(readFileSync4(pkgPath, "utf-8")));
|
|
11681
11750
|
if (pkg.success && pkg.data.name === PACKAGE_NAME)
|
|
11682
11751
|
return pkgPath;
|
|
11683
11752
|
} catch {}
|
|
@@ -11693,9 +11762,9 @@ function findPackageJsonUp(startPath) {
|
|
|
11693
11762
|
function getLocalDevPath(directory) {
|
|
11694
11763
|
for (const configPath of getConfigPaths(directory)) {
|
|
11695
11764
|
try {
|
|
11696
|
-
if (!
|
|
11765
|
+
if (!existsSync6(configPath))
|
|
11697
11766
|
continue;
|
|
11698
|
-
const rawConfig = parseJsonConfig(
|
|
11767
|
+
const rawConfig = parseJsonConfig(readFileSync4(configPath, "utf-8"));
|
|
11699
11768
|
const plugins = getPluginEntries(rawConfig);
|
|
11700
11769
|
for (const entry of plugins) {
|
|
11701
11770
|
if (entry === PACKAGE_NAME || entry.startsWith(`${PACKAGE_NAME}@`))
|
|
@@ -11705,7 +11774,7 @@ function getLocalDevPath(directory) {
|
|
|
11705
11774
|
const pkgPath = findPackageJsonUp(localPath);
|
|
11706
11775
|
if (!pkgPath)
|
|
11707
11776
|
continue;
|
|
11708
|
-
const pkg = PackageJsonSchema.safeParse(JSON.parse(
|
|
11777
|
+
const pkg = PackageJsonSchema.safeParse(JSON.parse(readFileSync4(pkgPath, "utf-8")));
|
|
11709
11778
|
if (pkg.success && pkg.data.name === PACKAGE_NAME)
|
|
11710
11779
|
return localPath;
|
|
11711
11780
|
}
|
|
@@ -11722,7 +11791,7 @@ function getLocalDevVersion(directory) {
|
|
|
11722
11791
|
const pkgPath = findPackageJsonUp(localPath);
|
|
11723
11792
|
if (!pkgPath)
|
|
11724
11793
|
return null;
|
|
11725
|
-
const pkg = PackageJsonSchema.safeParse(JSON.parse(
|
|
11794
|
+
const pkg = PackageJsonSchema.safeParse(JSON.parse(readFileSync4(pkgPath, "utf-8")));
|
|
11726
11795
|
return pkg.success ? pkg.data.version ?? null : null;
|
|
11727
11796
|
} catch {
|
|
11728
11797
|
return null;
|
|
@@ -11779,7 +11848,7 @@ function preflightConfigUpdates(paths, version) {
|
|
|
11779
11848
|
for (const path of paths) {
|
|
11780
11849
|
try {
|
|
11781
11850
|
accessSync(path, fsConstants.W_OK);
|
|
11782
|
-
const original =
|
|
11851
|
+
const original = readFileSync4(path, "utf-8");
|
|
11783
11852
|
const updated = configUpdateContent(original, version);
|
|
11784
11853
|
if (!updated)
|
|
11785
11854
|
return null;
|
|
@@ -11808,7 +11877,7 @@ function restoreConfigs(snapshots) {
|
|
|
11808
11877
|
function configsHaveSpec(paths, spec) {
|
|
11809
11878
|
return paths.every((path) => {
|
|
11810
11879
|
try {
|
|
11811
|
-
const parsed = parseJsonConfig(
|
|
11880
|
+
const parsed = parseJsonConfig(readFileSync4(path, "utf-8"));
|
|
11812
11881
|
return getPluginEntries(parsed).includes(spec);
|
|
11813
11882
|
} catch {
|
|
11814
11883
|
return false;
|
|
@@ -11898,9 +11967,9 @@ function getCachedVersion(_spec) {
|
|
|
11898
11967
|
const candidates = [getCurrentRuntimePackageJsonPath()].filter(isString);
|
|
11899
11968
|
for (const packageJsonPath of candidates) {
|
|
11900
11969
|
try {
|
|
11901
|
-
if (!
|
|
11970
|
+
if (!existsSync6(packageJsonPath))
|
|
11902
11971
|
continue;
|
|
11903
|
-
const pkg = PackageJsonSchema.safeParse(JSON.parse(
|
|
11972
|
+
const pkg = PackageJsonSchema.safeParse(JSON.parse(readFileSync4(packageJsonPath, "utf-8")));
|
|
11904
11973
|
if (pkg.success && pkg.data.version) {
|
|
11905
11974
|
if (!_spec)
|
|
11906
11975
|
cachedPackageVersion = pkg.data.version;
|
|
@@ -11942,7 +12011,6 @@ async function getLatestVersion(channel = "latest", options = {}) {
|
|
|
11942
12011
|
// src/hooks/auto-update-checker/index.ts
|
|
11943
12012
|
var DEFAULT_CHECK_INTERVAL_MS = 60 * 60 * 1000;
|
|
11944
12013
|
var DEFAULT_INIT_DELAY_MS = 5000;
|
|
11945
|
-
var TIMESTAMP_FILENAME = "last-update-check.json";
|
|
11946
12014
|
var PENDING_UPDATE_FILENAME = "pending-plugin-update.json";
|
|
11947
12015
|
var PENDING_UPDATE_MAX_AGE_MS = 7 * 24 * 60 * 60 * 1000;
|
|
11948
12016
|
function warn2(message) {
|
|
@@ -11994,34 +12062,50 @@ async function maybeRunCheck(ctx, options) {
|
|
|
11994
12062
|
}
|
|
11995
12063
|
await runStartupCheck(ctx, options);
|
|
11996
12064
|
}
|
|
12065
|
+
function checkStatePath(storageDir) {
|
|
12066
|
+
return join4(storageDir ?? getOpenCodeStorageDir(), AUTO_UPDATE_CHECK_STATE_FILENAME);
|
|
12067
|
+
}
|
|
12068
|
+
function writeCheckState(path, state) {
|
|
12069
|
+
mkdirSync(dirname4(path), { recursive: true });
|
|
12070
|
+
const tmp = `${path}.tmp.${process.pid}`;
|
|
12071
|
+
writeFileSync3(tmp, `${JSON.stringify(state, null, 2)}
|
|
12072
|
+
`, "utf-8");
|
|
12073
|
+
renameSync3(tmp, path);
|
|
12074
|
+
}
|
|
11997
12075
|
function claimCheckSlot(storageDir, intervalMs) {
|
|
11998
12076
|
if (!storageDir)
|
|
11999
12077
|
return true;
|
|
12000
12078
|
try {
|
|
12001
|
-
const file =
|
|
12002
|
-
|
|
12003
|
-
|
|
12004
|
-
|
|
12005
|
-
|
|
12006
|
-
|
|
12007
|
-
return false;
|
|
12008
|
-
}
|
|
12009
|
-
} catch {}
|
|
12010
|
-
}
|
|
12011
|
-
mkdirSync(dirname4(file), { recursive: true });
|
|
12012
|
-
const tmp = `${file}.tmp.${process.pid}`;
|
|
12013
|
-
writeFileSync3(tmp, JSON.stringify({ lastCheckedMs: Date.now() }), "utf-8");
|
|
12014
|
-
renameSync3(tmp, file);
|
|
12079
|
+
const file = checkStatePath(storageDir);
|
|
12080
|
+
const previous = readAutoUpdateCheckState(file) ?? {};
|
|
12081
|
+
const last = previous.lastCheckedMs ?? 0;
|
|
12082
|
+
if (Date.now() - last < intervalMs)
|
|
12083
|
+
return false;
|
|
12084
|
+
writeCheckState(file, { ...previous, lastCheckedMs: Date.now() });
|
|
12015
12085
|
return true;
|
|
12016
12086
|
} catch (err) {
|
|
12017
12087
|
warn2(`[auto-update-checker] Could not coordinate via timestamp file: ${String(err)}`);
|
|
12018
12088
|
return true;
|
|
12019
12089
|
}
|
|
12020
12090
|
}
|
|
12091
|
+
function recordUpdaterPinnedSpec(storageDir, spec) {
|
|
12092
|
+
try {
|
|
12093
|
+
const path = checkStatePath(storageDir);
|
|
12094
|
+
const previous = readAutoUpdateCheckState(path) ?? {};
|
|
12095
|
+
writeCheckState(path, {
|
|
12096
|
+
...previous,
|
|
12097
|
+
updaterPinnedSpec: spec,
|
|
12098
|
+
updaterPinnedAt: Date.now()
|
|
12099
|
+
});
|
|
12100
|
+
} catch (err) {
|
|
12101
|
+
warn2(`[auto-update-checker] Could not record updater pin provenance: ${String(err)}`);
|
|
12102
|
+
}
|
|
12103
|
+
}
|
|
12021
12104
|
function pendingMarkerPath(storageDir) {
|
|
12022
12105
|
return join4(storageDir ?? getOpenCodeStorageDir(), PENDING_UPDATE_FILENAME);
|
|
12023
12106
|
}
|
|
12024
12107
|
function writePendingUpdateMarker(storageDir, update, version) {
|
|
12108
|
+
recordUpdaterPinnedSpec(storageDir, update.spec);
|
|
12025
12109
|
try {
|
|
12026
12110
|
const dir = storageDir ?? dirname4(pendingMarkerPath(storageDir));
|
|
12027
12111
|
mkdirSync(dir, { recursive: true });
|
|
@@ -12036,10 +12120,10 @@ function writePendingUpdateMarker(storageDir, update, version) {
|
|
|
12036
12120
|
}
|
|
12037
12121
|
function consumePendingUpdateMarker(storageDir, loadedVersion) {
|
|
12038
12122
|
const path = pendingMarkerPath(storageDir);
|
|
12039
|
-
if (!
|
|
12123
|
+
if (!existsSync7(path))
|
|
12040
12124
|
return;
|
|
12041
12125
|
try {
|
|
12042
|
-
const marker = JSON.parse(
|
|
12126
|
+
const marker = JSON.parse(readFileSync5(path, "utf-8"));
|
|
12043
12127
|
const age = Date.now() - (marker.writtenAt ?? 0);
|
|
12044
12128
|
const olderThanLoaded = typeof marker.version === "string" && typeof loadedVersion === "string" && (compareSemverCore(marker.version, loadedVersion) ?? 0) < 0;
|
|
12045
12129
|
if (marker.version === loadedVersion && marker.spec === `${PACKAGE_NAME}@${loadedVersion}` && Array.isArray(marker.configPaths) && marker.configPaths.length === 2) {
|
|
@@ -12111,11 +12195,15 @@ async function runBackgroundUpdateCheck(ctx, options) {
|
|
|
12111
12195
|
return;
|
|
12112
12196
|
}
|
|
12113
12197
|
log(`[auto-update-checker] Update available (${channel}): ${currentVersion} → ${latestVersion}`);
|
|
12114
|
-
|
|
12115
|
-
|
|
12116
|
-
|
|
12198
|
+
const updaterOwnedPin = pluginInfo.isPinned && isUpdaterPinnedSpec(readAutoUpdateCheckState(checkStatePath(options.storageDir)), pluginInfo.entry);
|
|
12199
|
+
if (pluginInfo.isPinned && !updaterOwnedPin) {
|
|
12200
|
+
showToast(ctx, `Magic Context ${latestVersion}`, `v${latestVersion} available. This version was pinned by you; update your OpenCode plugin config to upgrade.`, "info", 8000);
|
|
12201
|
+
log("[auto-update-checker] Version was pinned by you; skipping auto-update");
|
|
12117
12202
|
return;
|
|
12118
12203
|
}
|
|
12204
|
+
if (updaterOwnedPin) {
|
|
12205
|
+
log("[auto-update-checker] Version was pinned by the updater; continuing auto-update");
|
|
12206
|
+
}
|
|
12119
12207
|
if (!options.autoUpdate) {
|
|
12120
12208
|
showToast(ctx, `Magic Context ${latestVersion}`, `v${latestVersion} available. Auto-update is disabled.`, "info", 8000);
|
|
12121
12209
|
log("[auto-update-checker] Auto-update disabled, notification only");
|
|
@@ -12449,9 +12537,11 @@ class SubcModuleTransport {
|
|
|
12449
12537
|
this.wrapupSessions.delete(args.sessionId);
|
|
12450
12538
|
};
|
|
12451
12539
|
const laneDeadlineMs = Date.now() + attemptTimeoutMs;
|
|
12452
|
-
let releaseLane;
|
|
12540
|
+
let releaseLane = () => {};
|
|
12453
12541
|
try {
|
|
12454
|
-
|
|
12542
|
+
if (!args.bypassSessionLane) {
|
|
12543
|
+
releaseLane = await this.acquireCorrectnessLane(args.sessionId, args.signal, laneDeadlineMs);
|
|
12544
|
+
}
|
|
12455
12545
|
} catch (error) {
|
|
12456
12546
|
finishWrapupTracking();
|
|
12457
12547
|
if (args.method === "state_sync" && isDeadlineFailure(error)) {
|
|
@@ -12553,12 +12643,13 @@ class SubcModuleTransport {
|
|
|
12553
12643
|
args.onTimings?.(timings);
|
|
12554
12644
|
}
|
|
12555
12645
|
}
|
|
12556
|
-
async authorityRequest(sessionId, projectRoot, method, body) {
|
|
12646
|
+
async authorityRequest(sessionId, projectRoot, method, body, timeoutMs) {
|
|
12557
12647
|
const response = await this.call({
|
|
12558
12648
|
sessionId,
|
|
12559
12649
|
projectRoot,
|
|
12560
12650
|
method,
|
|
12561
|
-
body: { ...body, method, v: 1 }
|
|
12651
|
+
body: { ...body, method, v: 1 },
|
|
12652
|
+
timeoutMs
|
|
12562
12653
|
});
|
|
12563
12654
|
if (isRecord(response) && isRecord(response.result))
|
|
12564
12655
|
return response.result;
|
|
@@ -12618,6 +12709,20 @@ class SubcModuleTransport {
|
|
|
12618
12709
|
throw new Error("mirror.pull omitted page");
|
|
12619
12710
|
return { page: response.page };
|
|
12620
12711
|
}
|
|
12712
|
+
async mirrorMemory(args) {
|
|
12713
|
+
const { projectRoot, ...body } = args;
|
|
12714
|
+
const response = await this.authorityRequest(`mirror-memory:${args.module_row_id}`, projectRoot ?? this.bindRootForAuthority(), "mirror.memory", body, 1900);
|
|
12715
|
+
return {
|
|
12716
|
+
row: isRecord(response.row) ? response.row : null
|
|
12717
|
+
};
|
|
12718
|
+
}
|
|
12719
|
+
async memoryIdentityAck(args) {
|
|
12720
|
+
const { projectRoot, ...body } = args;
|
|
12721
|
+
const response = await this.authorityRequest(`memory-identity:${args.project}`, projectRoot ?? this.bindRootForAuthority(), "memory.identity.ack", body);
|
|
12722
|
+
return {
|
|
12723
|
+
acknowledged: typeof response.acknowledged === "number" ? response.acknowledged : 0
|
|
12724
|
+
};
|
|
12725
|
+
}
|
|
12621
12726
|
async deleteSession(sessionId, projectRoot) {
|
|
12622
12727
|
await this.call({
|
|
12623
12728
|
sessionId,
|
|
@@ -13567,6 +13672,7 @@ function toRow(r) {
|
|
|
13567
13672
|
lastStatus: r.last_status ?? null,
|
|
13568
13673
|
lastError: r.last_error,
|
|
13569
13674
|
retryCount: r.retry_count ?? 0,
|
|
13675
|
+
taskStateJson: r.last_checked_commit ?? null,
|
|
13570
13676
|
lastCheckedCommit: r.last_checked_commit ?? null,
|
|
13571
13677
|
lastBroadRunAt: r.last_broad_run_at ?? null,
|
|
13572
13678
|
retrospectiveWatermarkMs: r.retrospective_watermark_ms ?? null
|
|
@@ -13610,7 +13716,12 @@ function writeTaskScheduleState(db, row) {
|
|
|
13610
13716
|
retry_count = excluded.retry_count,
|
|
13611
13717
|
last_checked_commit = COALESCE(excluded.last_checked_commit, task_schedule_state.last_checked_commit),
|
|
13612
13718
|
${broadCycleUpdate},
|
|
13613
|
-
retrospective_watermark_ms = COALESCE(excluded.retrospective_watermark_ms, task_schedule_state.retrospective_watermark_ms)`).run(row.projectPath, row.task, row.lastRunAt, row.nextDueAt, row.schedule, row.lastStatus, row.lastError, row.retryCount, row.lastCheckedCommit ?? null, row.lastBroadRunAt ?? null, row.retrospectiveWatermarkMs ?? null);
|
|
13719
|
+
retrospective_watermark_ms = COALESCE(excluded.retrospective_watermark_ms, task_schedule_state.retrospective_watermark_ms)`).run(row.projectPath, row.task, row.lastRunAt, row.nextDueAt, row.schedule, row.lastStatus, row.lastError, row.retryCount, row.taskStateJson ?? row.lastCheckedCommit ?? null, row.lastBroadRunAt ?? null, row.retrospectiveWatermarkMs ?? null);
|
|
13720
|
+
}
|
|
13721
|
+
function writeTaskStateJson(db, projectPath, task, taskStateJson) {
|
|
13722
|
+
db.prepare(`INSERT INTO task_schedule_state (project_path, task, last_checked_commit)
|
|
13723
|
+
VALUES (?, ?, ?)
|
|
13724
|
+
ON CONFLICT(project_path, task) DO UPDATE SET last_checked_commit = excluded.last_checked_commit`).run(projectPath, task, taskStateJson);
|
|
13614
13725
|
}
|
|
13615
13726
|
function isRetrospectiveWindowProcessed(db, projectPath, windowKey) {
|
|
13616
13727
|
const row = db.prepare("SELECT 1 AS one FROM retrospective_processed_windows WHERE project_path = ? AND window_key = ?").get(projectPath, windowKey);
|
|
@@ -13622,7 +13733,7 @@ function recordRetrospectiveWindowProcessed(db, projectPath, windowKey) {
|
|
|
13622
13733
|
|
|
13623
13734
|
// src/features/magic-context/dreamer/task-executor.ts
|
|
13624
13735
|
import { createHash as createHash8 } from "node:crypto";
|
|
13625
|
-
import { existsSync as
|
|
13736
|
+
import { existsSync as existsSync10 } from "node:fs";
|
|
13626
13737
|
|
|
13627
13738
|
// src/agents/dreamer.ts
|
|
13628
13739
|
var DREAMER_AGENT = "dreamer";
|
|
@@ -15046,6 +15157,104 @@ function recordInvocation(args, startedAt, params) {
|
|
|
15046
15157
|
});
|
|
15047
15158
|
}
|
|
15048
15159
|
|
|
15160
|
+
// src/features/magic-context/dreamer/curate-category-rotation.ts
|
|
15161
|
+
var CURATE_MEMORY_CATEGORIES = [
|
|
15162
|
+
"PROJECT_RULES",
|
|
15163
|
+
"ARCHITECTURE",
|
|
15164
|
+
"CONSTRAINTS",
|
|
15165
|
+
"CONFIG_VALUES",
|
|
15166
|
+
"NAMING"
|
|
15167
|
+
];
|
|
15168
|
+
var LEGACY_CURATE_CATEGORY_BUCKETS = {
|
|
15169
|
+
ARCHITECTURE_DECISIONS: "ARCHITECTURE",
|
|
15170
|
+
CONFIG_DEFAULTS: "CONFIG_VALUES",
|
|
15171
|
+
ENVIRONMENT: "CONFIG_VALUES",
|
|
15172
|
+
KNOWN_ISSUES: "CONSTRAINTS",
|
|
15173
|
+
USER_DIRECTIVES: "PROJECT_RULES",
|
|
15174
|
+
USER_PREFERENCES: "PROJECT_RULES",
|
|
15175
|
+
WORKFLOW_RULES: "PROJECT_RULES"
|
|
15176
|
+
};
|
|
15177
|
+
function curateCategoryForMemoryCategory(category) {
|
|
15178
|
+
return isCurateMemoryCategory(category) ? category : LEGACY_CURATE_CATEGORY_BUCKETS[category] ?? null;
|
|
15179
|
+
}
|
|
15180
|
+
function isCurateMemoryCategory(value) {
|
|
15181
|
+
return CURATE_MEMORY_CATEGORIES.includes(value);
|
|
15182
|
+
}
|
|
15183
|
+
function parseTaskState(raw) {
|
|
15184
|
+
if (!raw)
|
|
15185
|
+
return {};
|
|
15186
|
+
try {
|
|
15187
|
+
const parsed = JSON.parse(raw);
|
|
15188
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
|
|
15189
|
+
} catch {
|
|
15190
|
+
return {};
|
|
15191
|
+
}
|
|
15192
|
+
}
|
|
15193
|
+
function normalizedCursor(value) {
|
|
15194
|
+
return typeof value === "number" && Number.isInteger(value) && value >= 0 ? value % CURATE_MEMORY_CATEGORIES.length : 0;
|
|
15195
|
+
}
|
|
15196
|
+
function readState(db, projectIdentity) {
|
|
15197
|
+
return parseTaskState(getTaskScheduleState(db, projectIdentity, "curate")?.taskStateJson);
|
|
15198
|
+
}
|
|
15199
|
+
function categoryStartIndex(state, populated) {
|
|
15200
|
+
const active = state.curate?.activeCategory;
|
|
15201
|
+
if (isCurateMemoryCategory(active)) {
|
|
15202
|
+
const activeIndex = CURATE_MEMORY_CATEGORIES.indexOf(active);
|
|
15203
|
+
return populated.has(active) ? activeIndex : (activeIndex + 1) % CURATE_MEMORY_CATEGORIES.length;
|
|
15204
|
+
}
|
|
15205
|
+
return normalizedCursor(state.curate?.cursor);
|
|
15206
|
+
}
|
|
15207
|
+
function peekCurateCategoryScope(db, projectIdentity, memories) {
|
|
15208
|
+
const populated = new Set(memories.map((memory) => curateCategoryForMemoryCategory(memory.category)).filter((category) => category !== null));
|
|
15209
|
+
const start = categoryStartIndex(readState(db, projectIdentity), populated);
|
|
15210
|
+
for (let offset = 0;offset < CURATE_MEMORY_CATEGORIES.length; offset += 1) {
|
|
15211
|
+
const category = CURATE_MEMORY_CATEGORIES[(start + offset) % CURATE_MEMORY_CATEGORIES.length];
|
|
15212
|
+
const scoped = memories.filter((memory) => curateCategoryForMemoryCategory(memory.category) === category);
|
|
15213
|
+
if (scoped.length > 0)
|
|
15214
|
+
return { category, memories: scoped };
|
|
15215
|
+
}
|
|
15216
|
+
return null;
|
|
15217
|
+
}
|
|
15218
|
+
function beginCurateCategoryRun(db, projectIdentity, memories) {
|
|
15219
|
+
const scope = peekCurateCategoryScope(db, projectIdentity, memories);
|
|
15220
|
+
if (!scope)
|
|
15221
|
+
return null;
|
|
15222
|
+
const state = readState(db, projectIdentity);
|
|
15223
|
+
writeTaskStateJson(db, projectIdentity, "curate", JSON.stringify({
|
|
15224
|
+
...state,
|
|
15225
|
+
curate: {
|
|
15226
|
+
cursor: normalizedCursor(state.curate?.cursor),
|
|
15227
|
+
activeCategory: scope.category
|
|
15228
|
+
}
|
|
15229
|
+
}));
|
|
15230
|
+
return scope;
|
|
15231
|
+
}
|
|
15232
|
+
function curateTaskStateAfterSuccess(db, projectIdentity, category) {
|
|
15233
|
+
const state = readState(db, projectIdentity);
|
|
15234
|
+
return JSON.stringify({
|
|
15235
|
+
...state,
|
|
15236
|
+
curate: {
|
|
15237
|
+
cursor: (CURATE_MEMORY_CATEGORIES.indexOf(category) + 1) % CURATE_MEMORY_CATEGORIES.length
|
|
15238
|
+
}
|
|
15239
|
+
});
|
|
15240
|
+
}
|
|
15241
|
+
function getActiveCurateCategory(db, projectIdentity) {
|
|
15242
|
+
const active = readState(db, projectIdentity).curate?.activeCategory;
|
|
15243
|
+
return isCurateMemoryCategory(active) ? active : null;
|
|
15244
|
+
}
|
|
15245
|
+
function getCurateCategoryScopeRefusal(args) {
|
|
15246
|
+
if (args.requestedCategory && args.requestedCategory !== args.scope) {
|
|
15247
|
+
return `Error: Curate scope is ${args.scope}; ${args.action} cannot target category ${args.requestedCategory}.`;
|
|
15248
|
+
}
|
|
15249
|
+
for (const id of args.ids ?? []) {
|
|
15250
|
+
const category = args.categoryForId(id);
|
|
15251
|
+
if (category && category !== args.scope) {
|
|
15252
|
+
return `Error: Curate scope is ${args.scope}; memory ID ${id} is outside the scoped category.`;
|
|
15253
|
+
}
|
|
15254
|
+
}
|
|
15255
|
+
return null;
|
|
15256
|
+
}
|
|
15257
|
+
|
|
15049
15258
|
// src/features/magic-context/dreamer/memory-claim-safety.ts
|
|
15050
15259
|
var POLICY_SENTENCE_START = /(?:^|[.!?]\s+|\n\s*)(?:[-*]\s+|\d+[.)]\s+)?(?:you\s+|we\s+)?(?:must(?:\s+not)?|never|always|do\s+not|don't|shall\s+not)\b/i;
|
|
15051
15260
|
var ACTOR_POLICY = /\b(?:you|we|agents?|masons?|workers?|operators?|users?|maintainers?)\s+(?:must(?:\s+not)?|should(?:\s+not)?|need\s+to|shall(?:\s+not)?|cannot|can't|may\s+not)\b/i;
|
|
@@ -17028,7 +17237,7 @@ async function archiveExpiredMemories(args) {
|
|
|
17028
17237
|
}
|
|
17029
17238
|
|
|
17030
17239
|
// src/features/magic-context/dreamer/maintain-docs-protected-enforcement.ts
|
|
17031
|
-
import { existsSync as
|
|
17240
|
+
import { existsSync as existsSync8, readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "node:fs";
|
|
17032
17241
|
import { join as join7 } from "node:path";
|
|
17033
17242
|
|
|
17034
17243
|
// src/features/magic-context/dreamer/protected-regions.ts
|
|
@@ -17132,8 +17341,8 @@ function snapshotMaintainDocsFiles(docsDir) {
|
|
|
17132
17341
|
for (const name of MAINTAIN_DOCS_SNAPSHOT_FILES) {
|
|
17133
17342
|
const path = join7(docsDir, name);
|
|
17134
17343
|
try {
|
|
17135
|
-
if (
|
|
17136
|
-
snapshot.set(name,
|
|
17344
|
+
if (existsSync8(path)) {
|
|
17345
|
+
snapshot.set(name, readFileSync6(path, "utf8"));
|
|
17137
17346
|
}
|
|
17138
17347
|
} catch {}
|
|
17139
17348
|
}
|
|
@@ -17143,7 +17352,7 @@ function enforceMaintainDocsProtectedRegions(args) {
|
|
|
17143
17352
|
for (const [fileName, original] of args.snapshot) {
|
|
17144
17353
|
const path = join7(args.docsDir, fileName);
|
|
17145
17354
|
try {
|
|
17146
|
-
const current =
|
|
17355
|
+
const current = readFileSync6(path, "utf8");
|
|
17147
17356
|
const { text, violated } = enforceProtectedRegions(original, current);
|
|
17148
17357
|
if (!violated) {
|
|
17149
17358
|
continue;
|
|
@@ -17160,7 +17369,7 @@ function enforceMaintainDocsProtectedRegions(args) {
|
|
|
17160
17369
|
import { createHash as createHash6 } from "node:crypto";
|
|
17161
17370
|
|
|
17162
17371
|
// src/features/magic-context/dreamer/map-memories-prompt.ts
|
|
17163
|
-
import { existsSync as
|
|
17372
|
+
import { existsSync as existsSync9, statSync as statSync3 } from "node:fs";
|
|
17164
17373
|
import path3 from "node:path";
|
|
17165
17374
|
var MAP_MEMORIES_SYSTEM_PROMPT = `You are a memory mapper for the magic-context system. You map project memories to the repository files that back them.
|
|
17166
17375
|
|
|
@@ -17198,7 +17407,7 @@ function extractMemoryCandidatePaths(content, repoDir) {
|
|
|
17198
17407
|
if (!abs.startsWith(`${root}/`))
|
|
17199
17408
|
continue;
|
|
17200
17409
|
try {
|
|
17201
|
-
if (
|
|
17410
|
+
if (existsSync9(abs) && statSync3(abs).isFile())
|
|
17202
17411
|
found.add(rel);
|
|
17203
17412
|
} catch {}
|
|
17204
17413
|
if (found.size >= MAX_SEED_PATHS_PER_MEMORY)
|
|
@@ -18338,12 +18547,13 @@ function countActiveMemories(db, projectPath) {
|
|
|
18338
18547
|
}
|
|
18339
18548
|
function countLiveMemories(db, projectPath, options = {}) {
|
|
18340
18549
|
const unclassified = options.unclassifiedOnly && hasMemoryClassifiedAtColumn(db);
|
|
18341
|
-
const
|
|
18342
|
-
|
|
18343
|
-
|
|
18344
|
-
|
|
18345
|
-
|
|
18346
|
-
|
|
18550
|
+
const sql = `SELECT COUNT(*) AS cnt
|
|
18551
|
+
FROM memories
|
|
18552
|
+
WHERE project_path = ?
|
|
18553
|
+
AND status IN ('active','permanent')
|
|
18554
|
+
AND (expires_at IS NULL OR expires_at > ?)
|
|
18555
|
+
${unclassified ? "AND classified_at IS NULL" : ""}`;
|
|
18556
|
+
const row = options.category ? db.prepare(`${sql} AND category = ?`).get(projectPath, Date.now(), options.category) : db.prepare(sql).get(projectPath, Date.now());
|
|
18347
18557
|
return row?.cnt ?? 0;
|
|
18348
18558
|
}
|
|
18349
18559
|
function countUnmappedActiveMemories(db, projectPath) {
|
|
@@ -18454,8 +18664,13 @@ function getDreamTaskBacklog(db, projectPath, task, options = {}) {
|
|
|
18454
18664
|
return { pending, total };
|
|
18455
18665
|
}
|
|
18456
18666
|
case "curate": {
|
|
18457
|
-
const
|
|
18458
|
-
|
|
18667
|
+
const categories = db.prepare(`SELECT category FROM memories
|
|
18668
|
+
WHERE project_path = ?
|
|
18669
|
+
AND status IN ('active','permanent')
|
|
18670
|
+
AND (expires_at IS NULL OR expires_at > ?)`).all(projectPath, Date.now());
|
|
18671
|
+
const scope = peekCurateCategoryScope(db, projectPath, categories);
|
|
18672
|
+
const total = scope?.memories.length ?? 0;
|
|
18673
|
+
return scope ? { pending: total, total, category: scope.category } : { pending: 0, total: 0 };
|
|
18459
18674
|
}
|
|
18460
18675
|
case "compress-cues": {
|
|
18461
18676
|
const total = countLiveMemories(db, projectPath);
|
|
@@ -19307,6 +19522,7 @@ function createDreamTaskExecutor(deps) {
|
|
|
19307
19522
|
processed: Math.max(0, processed),
|
|
19308
19523
|
total: backlogAtStart.pending,
|
|
19309
19524
|
startedAt,
|
|
19525
|
+
...backlogAtStart.category ? { category: backlogAtStart.category } : {},
|
|
19310
19526
|
...refused === undefined ? {} : { refused: Math.max(0, refused) }
|
|
19311
19527
|
});
|
|
19312
19528
|
};
|
|
@@ -19359,7 +19575,8 @@ function createDreamTaskExecutor(deps) {
|
|
|
19359
19575
|
totalAtStart: backlogAtStart.total,
|
|
19360
19576
|
pendingAtEnd: end.pending,
|
|
19361
19577
|
totalAtEnd: end.total,
|
|
19362
|
-
processed
|
|
19578
|
+
processed,
|
|
19579
|
+
...backlogAtStart.category ? { category: backlogAtStart.category } : {}
|
|
19363
19580
|
};
|
|
19364
19581
|
return value;
|
|
19365
19582
|
})()
|
|
@@ -19951,8 +20168,8 @@ async function runAgenticTask(config, ctx, helpers) {
|
|
|
19951
20168
|
const lastRunAt = getTaskScheduleState(db, projectIdentity, config.task)?.lastRunAt ?? null;
|
|
19952
20169
|
const maintainDocsSnapshot = task === "maintain-docs" ? snapshotMaintainDocsFiles(docsDir) : undefined;
|
|
19953
20170
|
const existingDocs = task === "maintain-docs" ? {
|
|
19954
|
-
architecture:
|
|
19955
|
-
structure:
|
|
20171
|
+
architecture: existsSync10(`${docsDir}/ARCHITECTURE.md`),
|
|
20172
|
+
structure: existsSync10(`${docsDir}/STRUCTURE.md`)
|
|
19956
20173
|
} : undefined;
|
|
19957
20174
|
const abortController = new AbortController;
|
|
19958
20175
|
let leaseLost = false;
|
|
@@ -19965,6 +20182,7 @@ async function runAgenticTask(config, ctx, helpers) {
|
|
|
19965
20182
|
let expiredArchived = 0;
|
|
19966
20183
|
try {
|
|
19967
20184
|
let curateMemories;
|
|
20185
|
+
let curateCategory;
|
|
19968
20186
|
if (task === "curate") {
|
|
19969
20187
|
expiredArchived = await archiveExpiredMemories({
|
|
19970
20188
|
db,
|
|
@@ -19976,10 +20194,12 @@ async function runAgenticTask(config, ctx, helpers) {
|
|
|
19976
20194
|
});
|
|
19977
20195
|
if (leaseLost)
|
|
19978
20196
|
throw new Error("Dream lease lost during expired-memory archive");
|
|
19979
|
-
|
|
19980
|
-
|
|
19981
|
-
|
|
19982
|
-
|
|
20197
|
+
const scope = beginCurateCategoryRun(db, projectIdentity, loadActiveMemoryPromptMemories(db, projectIdentity));
|
|
20198
|
+
curateMemories = scope?.memories ?? [];
|
|
20199
|
+
curateCategory = scope?.category;
|
|
20200
|
+
log(`[dreamer] curate pool: category=${curateCategory ?? "none"} in_scope=${curateMemories.length} expired_archived=${expiredArchived}`);
|
|
20201
|
+
if (curateMemories.length === 0) {
|
|
20202
|
+
const progress = expiredArchived > 0 ? formatExpiredArchiveProgress(expiredArchived) : "curate: no populated project-memory category";
|
|
19983
20203
|
helpers.recordRun("completed", null, {
|
|
19984
20204
|
memoryChanges: helpers.computeMemoryDelta(memoryBefore),
|
|
19985
20205
|
progress
|
|
@@ -19991,7 +20211,7 @@ async function runAgenticTask(config, ctx, helpers) {
|
|
|
19991
20211
|
projectPath: projectIdentity,
|
|
19992
20212
|
lastDreamAt: lastRunAt ? String(lastRunAt) : null,
|
|
19993
20213
|
existingDocs,
|
|
19994
|
-
curate: curateMemories ? { memories: curateMemories } : undefined
|
|
20214
|
+
curate: curateMemories && curateCategory ? { category: curateCategory, memories: curateMemories } : undefined
|
|
19995
20215
|
});
|
|
19996
20216
|
const createResponse = await createChildSessionWithFence({
|
|
19997
20217
|
client: requireDreamClient(deps.client),
|
|
@@ -20083,16 +20303,34 @@ async function runAgenticTask(config, ctx, helpers) {
|
|
|
20083
20303
|
}
|
|
20084
20304
|
}
|
|
20085
20305
|
const curateOutput = task === "curate" ? run.validated : undefined;
|
|
20306
|
+
const curateScopeProgress = task === "curate" && curateCategory && curateMemories ? `curate: ${curateCategory} (${curateMemories.length})` : null;
|
|
20086
20307
|
const progress = [
|
|
20308
|
+
curateScopeProgress,
|
|
20087
20309
|
expiredArchived > 0 ? formatExpiredArchiveProgress(expiredArchived) : null,
|
|
20088
20310
|
curateOutput && curateOutput.memoryOperations.completedActions.length > 0 ? formatCurateMemoryOperations(curateOutput.memoryOperations.completedActions) : null,
|
|
20089
20311
|
curateRefused > 0 ? `curate: refused ${curateRefused} unsafe mutation(s)` : null
|
|
20090
20312
|
].filter((value) => Boolean(value)).join("; ");
|
|
20313
|
+
const curateCount = task === "curate" && curateCategory ? loadActiveMemoryPromptMemories(db, projectIdentity).filter((memory) => curateCategoryForMemoryCategory(memory.category) === curateCategory).length : undefined;
|
|
20314
|
+
const curateBacklog = curateCount !== undefined && curateCategory ? {
|
|
20315
|
+
pending: curateCount,
|
|
20316
|
+
total: curateCount,
|
|
20317
|
+
category: curateCategory
|
|
20318
|
+
} : undefined;
|
|
20091
20319
|
helpers.recordRun("completed", null, {
|
|
20092
20320
|
memoryChanges: helpers.computeMemoryDelta(memoryBefore),
|
|
20093
|
-
progress: progress || null
|
|
20321
|
+
progress: progress || null,
|
|
20322
|
+
backlogAfter: curateBacklog
|
|
20094
20323
|
});
|
|
20095
|
-
return {
|
|
20324
|
+
return {
|
|
20325
|
+
status: "completed",
|
|
20326
|
+
...progress ? { detail: progress } : {},
|
|
20327
|
+
...curateBacklog ? { backlog: curateBacklog } : {},
|
|
20328
|
+
...curateCategory ? {
|
|
20329
|
+
schedulePatch: {
|
|
20330
|
+
taskStateJson: curateTaskStateAfterSuccess(db, projectIdentity, curateCategory)
|
|
20331
|
+
}
|
|
20332
|
+
} : {}
|
|
20333
|
+
};
|
|
20096
20334
|
} finally {
|
|
20097
20335
|
heartbeat.stop();
|
|
20098
20336
|
if (childSessionId)
|
|
@@ -20157,16 +20395,17 @@ function planDueTasks(db, projectIdentity, tasks, now) {
|
|
|
20157
20395
|
}
|
|
20158
20396
|
return due;
|
|
20159
20397
|
}
|
|
20160
|
-
function advanceAfterRun(db, projectIdentity, due, finishedAt, status, error, schedulePatch) {
|
|
20398
|
+
function advanceAfterRun(db, projectIdentity, due, finishedAt, status, error, schedulePatch, startedAt) {
|
|
20161
20399
|
writeTaskScheduleState(db, {
|
|
20162
20400
|
projectPath: projectIdentity,
|
|
20163
20401
|
task: due.config.task,
|
|
20164
|
-
lastRunAt: status === "completed" ? finishedAt : readLastRunAt(db, projectIdentity, due.config.task),
|
|
20402
|
+
lastRunAt: status === "completed" ? startedAt ?? finishedAt : readLastRunAt(db, projectIdentity, due.config.task),
|
|
20165
20403
|
nextDueAt: nextDueAtMs(due.config.schedule, finishedAt, due.scheduledAt),
|
|
20166
20404
|
schedule: due.config.schedule,
|
|
20167
20405
|
lastStatus: status,
|
|
20168
20406
|
lastError: error,
|
|
20169
20407
|
retryCount: 0,
|
|
20408
|
+
taskStateJson: schedulePatch?.taskStateJson,
|
|
20170
20409
|
retrospectiveWatermarkMs: schedulePatch?.retrospectiveWatermarkMs
|
|
20171
20410
|
});
|
|
20172
20411
|
}
|
|
@@ -20245,6 +20484,7 @@ async function runDomainGroup(deps, group, cb) {
|
|
|
20245
20484
|
}
|
|
20246
20485
|
}
|
|
20247
20486
|
let outcome;
|
|
20487
|
+
const startedAt = Date.now();
|
|
20248
20488
|
try {
|
|
20249
20489
|
outcome = await executor(due.config, {
|
|
20250
20490
|
db,
|
|
@@ -20258,8 +20498,8 @@ async function runDomainGroup(deps, group, cb) {
|
|
|
20258
20498
|
}
|
|
20259
20499
|
const finishedAt = Date.now();
|
|
20260
20500
|
if (outcome.status === "completed") {
|
|
20261
|
-
advanceAfterRun(db, projectIdentity, due, finishedAt, "completed", null, outcome.schedulePatch);
|
|
20262
|
-
cb?.onRan?.(due.config.task, outcome.detail);
|
|
20501
|
+
advanceAfterRun(db, projectIdentity, due, finishedAt, "completed", null, outcome.schedulePatch, startedAt);
|
|
20502
|
+
cb?.onRan?.(due.config.task, outcome.detail, outcome.backlog);
|
|
20263
20503
|
} else if (outcome.transient) {
|
|
20264
20504
|
recordTransientFailure(db, projectIdentity, due, finishedAt, outcome.error ?? null);
|
|
20265
20505
|
cb?.onFailed?.(due.config.task, outcome.failureDetail ?? outcome.error);
|
|
@@ -20326,6 +20566,7 @@ async function runManualDream(deps) {
|
|
|
20326
20566
|
return result;
|
|
20327
20567
|
}
|
|
20328
20568
|
const groups = new Map;
|
|
20569
|
+
const runLocalBacklogs = {};
|
|
20329
20570
|
for (const d of gated) {
|
|
20330
20571
|
const kind = leaseKindFor(d.config.task);
|
|
20331
20572
|
const arr = groups.get(kind) ?? [];
|
|
@@ -20335,10 +20576,12 @@ async function runManualDream(deps) {
|
|
|
20335
20576
|
await Promise.all([...groups.values()].map((group) => runDomainGroup({ ...deps, executor: deps.executor }, group, {
|
|
20336
20577
|
forceGate,
|
|
20337
20578
|
leaseWaitMs: MANUAL_RUN_LEASE_WAIT_MS,
|
|
20338
|
-
onRan: (t, detail) => {
|
|
20579
|
+
onRan: (t, detail, backlog) => {
|
|
20339
20580
|
result.ran.push(t);
|
|
20340
20581
|
if (detail)
|
|
20341
20582
|
result.details?.push(detail);
|
|
20583
|
+
if (backlog)
|
|
20584
|
+
runLocalBacklogs[t] = backlog;
|
|
20342
20585
|
},
|
|
20343
20586
|
onFailed: (task, error) => {
|
|
20344
20587
|
result.failed.push(task);
|
|
@@ -20347,7 +20590,10 @@ async function runManualDream(deps) {
|
|
|
20347
20590
|
},
|
|
20348
20591
|
onBusy: (t) => result.deferredBusy.push(t)
|
|
20349
20592
|
})));
|
|
20350
|
-
result.backlogAfter =
|
|
20593
|
+
result.backlogAfter = {
|
|
20594
|
+
...getDreamTaskBacklogs(deps.db, deps.projectIdentity, selectedTaskNames),
|
|
20595
|
+
...runLocalBacklogs
|
|
20596
|
+
};
|
|
20351
20597
|
return result;
|
|
20352
20598
|
}
|
|
20353
20599
|
async function runDueTasksForProject(deps) {
|
|
@@ -21380,6 +21626,8 @@ async function ensureProjectRegisteredFromOpenCodeDirectory(directory, db) {
|
|
|
21380
21626
|
registerProjectEmbedding(db, projectIdentity, routing.primary, features, directory);
|
|
21381
21627
|
if (routing.shadow) {
|
|
21382
21628
|
registerProjectShadowEmbedding(db, projectIdentity, routing.shadow, directory);
|
|
21629
|
+
} else {
|
|
21630
|
+
unregisterProjectShadowEmbedding(projectIdentity);
|
|
21383
21631
|
}
|
|
21384
21632
|
}
|
|
21385
21633
|
|
|
@@ -22081,6 +22329,56 @@ function createTagger() {
|
|
|
22081
22329
|
};
|
|
22082
22330
|
}
|
|
22083
22331
|
|
|
22332
|
+
// src/plugin/memory-id-translation.ts
|
|
22333
|
+
function unmappedMemoryIdMessage(id) {
|
|
22334
|
+
return `Error: memory id ${id} has no module mapping yet — it was written seconds ago or the mirror is behind; retry or use the id shown in <project-memory>.`;
|
|
22335
|
+
}
|
|
22336
|
+
function translateHostMemoryIds(db, hostIds) {
|
|
22337
|
+
const moduleIds = [];
|
|
22338
|
+
for (const hostId of hostIds) {
|
|
22339
|
+
const identity = moduleMemoryIdentityForHostId(db, hostId);
|
|
22340
|
+
if (!identity)
|
|
22341
|
+
return { error: unmappedMemoryIdMessage(hostId) };
|
|
22342
|
+
moduleIds.push(identity.moduleRowId);
|
|
22343
|
+
}
|
|
22344
|
+
return { moduleIds };
|
|
22345
|
+
}
|
|
22346
|
+
function moduleMemoryOperation(response, depth = 0) {
|
|
22347
|
+
if (depth > 4 || response === null || typeof response !== "object")
|
|
22348
|
+
return null;
|
|
22349
|
+
if (Array.isArray(response)) {
|
|
22350
|
+
for (const item of response) {
|
|
22351
|
+
const operation = moduleMemoryOperation(item, depth + 1);
|
|
22352
|
+
if (operation)
|
|
22353
|
+
return operation;
|
|
22354
|
+
}
|
|
22355
|
+
return null;
|
|
22356
|
+
}
|
|
22357
|
+
const record = response;
|
|
22358
|
+
if (record.memory_operation !== null && typeof record.memory_operation === "object" && typeof record.memory_operation.action === "string") {
|
|
22359
|
+
return record.memory_operation;
|
|
22360
|
+
}
|
|
22361
|
+
return moduleMemoryOperation(record.result, depth + 1);
|
|
22362
|
+
}
|
|
22363
|
+
function translateModuleMemoryMutationReply(args) {
|
|
22364
|
+
const operation = moduleMemoryOperation(args.response);
|
|
22365
|
+
if (operation?.action === "write" && operation.module_id !== undefined) {
|
|
22366
|
+
const identity = hostMemoryIdentityForModuleId(args.db, args.moduleProject, operation.module_id);
|
|
22367
|
+
const category = operation.category ?? args.requestedCategory;
|
|
22368
|
+
return identity ? `Saved memory [ID: ${identity.contextRowId}] in ${category}.` : `Saved memory in ${category}. Its id will appear in <project-memory> on the next pass.`;
|
|
22369
|
+
}
|
|
22370
|
+
if (operation?.action === "merge" && operation.canonical_module_id !== undefined) {
|
|
22371
|
+
const canonical = hostMemoryIdentityForModuleId(args.db, args.moduleProject, operation.canonical_module_id);
|
|
22372
|
+
const superseded = (operation.superseded_module_ids ?? []).map((moduleId) => hostMemoryIdentityForModuleId(args.db, args.moduleProject, moduleId)?.contextRowId).filter((id) => id !== undefined);
|
|
22373
|
+
const category = operation.category ?? args.requestedCategory;
|
|
22374
|
+
if (canonical) {
|
|
22375
|
+
return `Merged memories [${args.requestedHostIds.join(", ")}] into canonical memory [ID: ${canonical.contextRowId}] in ${category}; superseded [${superseded.join(", ")}].`;
|
|
22376
|
+
}
|
|
22377
|
+
return `Merged memories [${args.requestedHostIds.join(", ")}] into a canonical memory in ${category}. Its id will appear in <project-memory> on the next pass.`;
|
|
22378
|
+
}
|
|
22379
|
+
return null;
|
|
22380
|
+
}
|
|
22381
|
+
|
|
22084
22382
|
// src/plugin/rpc-handlers.ts
|
|
22085
22383
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
22086
22384
|
import { once } from "node:events";
|
|
@@ -26971,11 +27269,35 @@ function toFlatModuleWireBody(payload) {
|
|
|
26971
27269
|
function moduleWireBodyBytes(payload) {
|
|
26972
27270
|
return Buffer.byteLength(JSON.stringify(toFlatModuleWireBody(payload)));
|
|
26973
27271
|
}
|
|
26974
|
-
function buildPagedModuleTransformPayloads(body, pageMaxBytes = MODULE_PAGE_MAX_BYTES) {
|
|
27272
|
+
function buildPagedModuleTransformPayloads(body, pageMaxBytes = MODULE_PAGE_MAX_BYTES, forcePageEnvelope = false) {
|
|
26975
27273
|
const serializedBody = JSON.stringify(body);
|
|
26976
27274
|
const unpagedBytes = Buffer.byteLength(serializedBody);
|
|
26977
|
-
if (unpagedBytes <= pageMaxBytes)
|
|
26978
|
-
|
|
27275
|
+
if (unpagedBytes <= pageMaxBytes) {
|
|
27276
|
+
if (!forcePageEnvelope)
|
|
27277
|
+
return [{ page: body, bytes: unpagedBytes }];
|
|
27278
|
+
const pageContent = Object.fromEntries([
|
|
27279
|
+
"input",
|
|
27280
|
+
"messages",
|
|
27281
|
+
"native_messages",
|
|
27282
|
+
"ts_output",
|
|
27283
|
+
"ts_ck_messages",
|
|
27284
|
+
"normalizations",
|
|
27285
|
+
"tool_input_key_orders"
|
|
27286
|
+
].filter((field) => {
|
|
27287
|
+
const value = body[field];
|
|
27288
|
+
return Array.isArray(value) || value !== null && typeof value === "object" && field === "tool_input_key_orders";
|
|
27289
|
+
}).map((field) => [field, body[field]]));
|
|
27290
|
+
const page = {
|
|
27291
|
+
transform_page_id: crypto2.createHash("sha256").update(serializedBody).digest("hex"),
|
|
27292
|
+
transform_generation: body.shadow_generation ?? 0,
|
|
27293
|
+
transform_page_index: 0,
|
|
27294
|
+
transform_page_total: 1,
|
|
27295
|
+
transform_page_complete: true,
|
|
27296
|
+
transform_page_digest: transformPageDigest(pageContent),
|
|
27297
|
+
...body
|
|
27298
|
+
};
|
|
27299
|
+
return [{ page, bytes: Buffer.byteLength(JSON.stringify(page)) }];
|
|
27300
|
+
}
|
|
26979
27301
|
const arrayFields = [
|
|
26980
27302
|
"input",
|
|
26981
27303
|
"messages",
|
|
@@ -27625,36 +27947,43 @@ function canonicalOrdinalForMessageId(args) {
|
|
|
27625
27947
|
args.state.idOrdinalMemo.set(args.messageId, canonical);
|
|
27626
27948
|
return canonical;
|
|
27627
27949
|
}
|
|
27628
|
-
|
|
27950
|
+
var boundaryDiagnosticObserverForTest = null;
|
|
27951
|
+
function logBoundaryDiagnostic(sessionId, message) {
|
|
27952
|
+
sessionLog(sessionId, message);
|
|
27953
|
+
boundaryDiagnosticObserverForTest?.(message);
|
|
27954
|
+
}
|
|
27955
|
+
function readCompartmentBoundaryResolution(args) {
|
|
27629
27956
|
const startRaw = args.readRawById(args.compartment.startMessageId);
|
|
27630
27957
|
const endRaw = args.readRawById(args.compartment.endMessageId);
|
|
27631
|
-
|
|
27632
|
-
|
|
27633
|
-
|
|
27634
|
-
|
|
27635
|
-
|
|
27636
|
-
|
|
27637
|
-
|
|
27638
|
-
|
|
27639
|
-
|
|
27640
|
-
|
|
27641
|
-
|
|
27642
|
-
|
|
27643
|
-
|
|
27644
|
-
|
|
27645
|
-
|
|
27646
|
-
|
|
27647
|
-
|
|
27648
|
-
|
|
27649
|
-
|
|
27650
|
-
|
|
27958
|
+
return {
|
|
27959
|
+
startRaw,
|
|
27960
|
+
endRaw,
|
|
27961
|
+
startOrdinal: canonicalOrdinalForMessageId({
|
|
27962
|
+
sessionId: args.sessionId,
|
|
27963
|
+
raw: startRaw,
|
|
27964
|
+
messageId: args.compartment.startMessageId,
|
|
27965
|
+
generation: args.state.moduleGeneration,
|
|
27966
|
+
state: args.state
|
|
27967
|
+
}),
|
|
27968
|
+
endOrdinal: canonicalOrdinalForMessageId({
|
|
27969
|
+
sessionId: args.sessionId,
|
|
27970
|
+
raw: endRaw,
|
|
27971
|
+
messageId: args.compartment.endMessageId,
|
|
27972
|
+
generation: args.state.moduleGeneration,
|
|
27973
|
+
state: args.state
|
|
27974
|
+
})
|
|
27975
|
+
};
|
|
27976
|
+
}
|
|
27977
|
+
function serializeCompartment(args) {
|
|
27978
|
+
const startCreatedAt = args.startRaw?.createdAt;
|
|
27979
|
+
const endCreatedAt = args.endRaw?.createdAt;
|
|
27651
27980
|
const dateRange = typeof startCreatedAt === "number" && typeof endCreatedAt === "number" ? { start_date: formatDate(startCreatedAt), end_date: formatDate(endCreatedAt) } : {};
|
|
27652
27981
|
return {
|
|
27653
27982
|
sequence: args.compartment.sequence,
|
|
27654
|
-
start_message: startOrdinal,
|
|
27655
|
-
end_message: endOrdinal,
|
|
27656
|
-
start_message_id: flatBlockIdForRawMessage(args.compartment.startMessageId, startRaw, "start"),
|
|
27657
|
-
end_message_id: flatBlockIdForRawMessage(args.compartment.endMessageId, endRaw, "end"),
|
|
27983
|
+
start_message: args.startOrdinal,
|
|
27984
|
+
end_message: args.endOrdinal,
|
|
27985
|
+
start_message_id: flatBlockIdForRawMessage(args.compartment.startMessageId, args.startRaw, "start"),
|
|
27986
|
+
end_message_id: flatBlockIdForRawMessage(args.compartment.endMessageId, args.endRaw, "end"),
|
|
27658
27987
|
...dateRange,
|
|
27659
27988
|
title: args.compartment.title,
|
|
27660
27989
|
content: args.compartment.content,
|
|
@@ -27668,6 +27997,15 @@ function serializeCompartment(args) {
|
|
|
27668
27997
|
created_at: args.compartment.createdAt
|
|
27669
27998
|
};
|
|
27670
27999
|
}
|
|
28000
|
+
function adjacentCompartmentBoundaryId(args) {
|
|
28001
|
+
const previous = args.direction === "previous";
|
|
28002
|
+
const row = args.db.prepare(`SELECT ${previous ? "end_message_id" : "start_message_id"} AS message_id
|
|
28003
|
+
FROM compartments
|
|
28004
|
+
WHERE session_id = ? AND sequence ${previous ? "<" : ">"} ?
|
|
28005
|
+
ORDER BY sequence ${previous ? "DESC" : "ASC"}
|
|
28006
|
+
LIMIT 1`).get(args.sessionId, args.sequence);
|
|
28007
|
+
return typeof row?.message_id === "string" && row.message_id.length > 0 ? row.message_id : null;
|
|
28008
|
+
}
|
|
27671
28009
|
function seedBoundaryFromSerializedCompartments(compartments) {
|
|
27672
28010
|
const serialized = compartments.filter(isRecord).filter((compartment) => typeof compartment.sequence === "number" && typeof compartment.end_message_id === "string");
|
|
27673
28011
|
serialized.sort((left, right) => left.sequence - right.sequence);
|
|
@@ -28140,21 +28478,102 @@ async function buildModuleStateSyncPayload(args) {
|
|
|
28140
28478
|
const compartments = [];
|
|
28141
28479
|
let serializedCount = 0;
|
|
28142
28480
|
const compartmentsToSerialize = compartmentsChanged ? args.force ? inventory ? readCompartmentsAfterSequence(args.pass.db, args.pass.sessionId, inventory.maxCompartmentSequence) : getCompartments(args.pass.db, args.pass.sessionId) : readCompartmentsAfterSequence(args.pass.db, args.pass.sessionId, acked.compartment_sequence) : [];
|
|
28143
|
-
|
|
28144
|
-
|
|
28145
|
-
|
|
28146
|
-
|
|
28147
|
-
|
|
28481
|
+
const boundaryResolutions = new Map;
|
|
28482
|
+
const resolveBoundary = (compartment) => {
|
|
28483
|
+
const cached = boundaryResolutions.get(compartment.sequence);
|
|
28484
|
+
if (cached)
|
|
28485
|
+
return cached;
|
|
28486
|
+
const resolved = readCompartmentBoundaryResolution({
|
|
28148
28487
|
compartment,
|
|
28149
28488
|
sessionId: args.pass.sessionId,
|
|
28150
28489
|
readRawById,
|
|
28151
28490
|
state: args.state
|
|
28152
28491
|
});
|
|
28153
|
-
|
|
28492
|
+
boundaryResolutions.set(compartment.sequence, resolved);
|
|
28493
|
+
return resolved;
|
|
28494
|
+
};
|
|
28495
|
+
const canonicalOrdinalForAdjacentId = (messageId) => {
|
|
28496
|
+
if (!messageId)
|
|
28497
|
+
return null;
|
|
28498
|
+
const raw = readRawById(messageId);
|
|
28499
|
+
return canonicalOrdinalForMessageId({
|
|
28500
|
+
sessionId: args.pass.sessionId,
|
|
28501
|
+
raw,
|
|
28502
|
+
messageId,
|
|
28503
|
+
generation: args.state.moduleGeneration,
|
|
28504
|
+
state: args.state
|
|
28505
|
+
});
|
|
28506
|
+
};
|
|
28507
|
+
let firstRawOrdinal;
|
|
28508
|
+
for (const [index, compartment] of compartmentsToSerialize.entries()) {
|
|
28509
|
+
args.options?.beforeSerializeCompartment?.();
|
|
28510
|
+
if (args.options?.shouldAbortSeed?.())
|
|
28511
|
+
return "seed_budget";
|
|
28512
|
+
const boundary = resolveBoundary(compartment);
|
|
28513
|
+
if (boundary.startOrdinal === "mismatch" || boundary.endOrdinal === "mismatch") {
|
|
28154
28514
|
return "mismatch";
|
|
28155
|
-
|
|
28156
|
-
|
|
28157
|
-
|
|
28515
|
+
}
|
|
28516
|
+
const startMissing = boundary.startOrdinal === null;
|
|
28517
|
+
const endMissing = boundary.endOrdinal === null;
|
|
28518
|
+
if (startMissing && endMissing) {
|
|
28519
|
+
logBoundaryDiagnostic(args.pass.sessionId, `state-sync compartment skipped session=${args.pass.sessionId} sequence=${compartment.sequence} missing_start_id=${compartment.startMessageId} missing_end_id=${compartment.endMessageId} method=both_boundaries_dangling`);
|
|
28520
|
+
continue;
|
|
28521
|
+
}
|
|
28522
|
+
let startOrdinal = boundary.startOrdinal;
|
|
28523
|
+
if (startOrdinal === null) {
|
|
28524
|
+
const previous = compartmentsToSerialize[index - 1];
|
|
28525
|
+
const previousBoundaryId = previous ? previous.endMessageId : adjacentCompartmentBoundaryId({
|
|
28526
|
+
db: args.pass.db,
|
|
28527
|
+
sessionId: args.pass.sessionId,
|
|
28528
|
+
sequence: compartment.sequence,
|
|
28529
|
+
direction: "previous"
|
|
28530
|
+
});
|
|
28531
|
+
const previousEnd = previous ? resolveBoundary(previous).endOrdinal : canonicalOrdinalForAdjacentId(previousBoundaryId);
|
|
28532
|
+
if (previousEnd === "mismatch")
|
|
28533
|
+
return "mismatch";
|
|
28534
|
+
if (typeof previousEnd === "number") {
|
|
28535
|
+
startOrdinal = previousEnd + 1;
|
|
28536
|
+
logBoundaryDiagnostic(args.pass.sessionId, `state-sync boundary repaired session=${args.pass.sessionId} sequence=${compartment.sequence} side=start missing_id=${compartment.startMessageId} resolved_ordinal=${startOrdinal} method=previous_compartment_end_plus_one`);
|
|
28537
|
+
} else if (previousBoundaryId === null) {
|
|
28538
|
+
if (firstRawOrdinal === undefined) {
|
|
28539
|
+
const ordinals = [
|
|
28540
|
+
...readRawSessionMessageIdOrdinals(args.pass.sessionId).values()
|
|
28541
|
+
].filter((ordinal) => ordinal >= 1).sort((left, right) => left - right);
|
|
28542
|
+
firstRawOrdinal = ordinals[0] ?? null;
|
|
28543
|
+
}
|
|
28544
|
+
startOrdinal = firstRawOrdinal;
|
|
28545
|
+
if (startOrdinal !== null) {
|
|
28546
|
+
logBoundaryDiagnostic(args.pass.sessionId, `state-sync boundary repaired session=${args.pass.sessionId} sequence=${compartment.sequence} side=start missing_id=${compartment.startMessageId} resolved_ordinal=${startOrdinal} method=raw_store_first_ordinal`);
|
|
28547
|
+
}
|
|
28548
|
+
}
|
|
28549
|
+
}
|
|
28550
|
+
let endOrdinal = boundary.endOrdinal;
|
|
28551
|
+
if (endOrdinal === null) {
|
|
28552
|
+
const next = compartmentsToSerialize[index + 1];
|
|
28553
|
+
const nextStart = next ? resolveBoundary(next).startOrdinal : canonicalOrdinalForAdjacentId(adjacentCompartmentBoundaryId({
|
|
28554
|
+
db: args.pass.db,
|
|
28555
|
+
sessionId: args.pass.sessionId,
|
|
28556
|
+
sequence: compartment.sequence,
|
|
28557
|
+
direction: "next"
|
|
28558
|
+
}));
|
|
28559
|
+
if (nextStart === "mismatch")
|
|
28560
|
+
return "mismatch";
|
|
28561
|
+
if (typeof nextStart === "number") {
|
|
28562
|
+
endOrdinal = nextStart - 1;
|
|
28563
|
+
logBoundaryDiagnostic(args.pass.sessionId, `state-sync boundary repaired session=${args.pass.sessionId} sequence=${compartment.sequence} side=end missing_id=${compartment.endMessageId} resolved_ordinal=${endOrdinal} method=next_compartment_start_minus_one`);
|
|
28564
|
+
}
|
|
28565
|
+
}
|
|
28566
|
+
if (startOrdinal === null || endOrdinal === null || startOrdinal > endOrdinal) {
|
|
28567
|
+
logBoundaryDiagnostic(args.pass.sessionId, `state-sync compartment skipped session=${args.pass.sessionId} sequence=${compartment.sequence} missing_start_id=${startMissing ? compartment.startMessageId : "none"} missing_end_id=${endMissing ? compartment.endMessageId : "none"} method=${startOrdinal !== null && endOrdinal !== null ? "invalid_repaired_range" : "no_adjacent_canonical_boundary"}`);
|
|
28568
|
+
continue;
|
|
28569
|
+
}
|
|
28570
|
+
compartments.push(serializeCompartment({
|
|
28571
|
+
compartment,
|
|
28572
|
+
startRaw: boundary.startRaw,
|
|
28573
|
+
endRaw: boundary.endRaw,
|
|
28574
|
+
startOrdinal,
|
|
28575
|
+
endOrdinal
|
|
28576
|
+
}));
|
|
28158
28577
|
serializedCount += 1;
|
|
28159
28578
|
const yieldEvery = Math.max(1, args.options?.yieldEveryCompartments ?? 10);
|
|
28160
28579
|
if (serializedCount % yieldEvery === 0) {
|
|
@@ -29517,7 +29936,7 @@ function registerRpcHandlers(rpcServer, args) {
|
|
|
29517
29936
|
const buildManagedCtx = async (db) => {
|
|
29518
29937
|
const { deriveHistorianChunkTokens, resolveHistorianContextLimit } = await import("./derive-budgets-v1fkhjjr.js");
|
|
29519
29938
|
const { resolveHistorianModel } = await import("./model-resolution-dxatzjde.js");
|
|
29520
|
-
const { userMemoryCollectionEnabled } = await import("./task-config-
|
|
29939
|
+
const { userMemoryCollectionEnabled } = await import("./task-config-cv8k9y8r.js");
|
|
29521
29940
|
const DEFAULT_HISTORIAN_TIMEOUT_MS = 600000;
|
|
29522
29941
|
const historianModel = resolveHistorianModel(config, "opencode");
|
|
29523
29942
|
return {
|
|
@@ -29548,8 +29967,8 @@ function registerRpcHandlers(rpcServer, args) {
|
|
|
29548
29967
|
const db = getDb();
|
|
29549
29968
|
if (!db)
|
|
29550
29969
|
return { ok: false, error: "db unavailable" };
|
|
29551
|
-
const { runManagedRecomp } = await import("./recomp-orchestrator-
|
|
29552
|
-
const { sendIgnoredMessage } = await import("./send-session-notification-
|
|
29970
|
+
const { runManagedRecomp } = await import("./recomp-orchestrator-0xx1364v.js");
|
|
29971
|
+
const { sendIgnoredMessage } = await import("./send-session-notification-jbxknvar.js");
|
|
29553
29972
|
log(`[rpc] recomp requested for session ${sessionId}`);
|
|
29554
29973
|
const ctx = await buildManagedCtx(db);
|
|
29555
29974
|
runManagedRecomp(ctx, sessionId).then((message) => {
|
|
@@ -29567,8 +29986,8 @@ function registerRpcHandlers(rpcServer, args) {
|
|
|
29567
29986
|
const db = getDb();
|
|
29568
29987
|
if (!db)
|
|
29569
29988
|
return { ok: false, error: "db unavailable" };
|
|
29570
|
-
const { runManagedUpgrade } = await import("./recomp-orchestrator-
|
|
29571
|
-
const { sendIgnoredMessage } = await import("./send-session-notification-
|
|
29989
|
+
const { runManagedUpgrade } = await import("./recomp-orchestrator-0xx1364v.js");
|
|
29990
|
+
const { sendIgnoredMessage } = await import("./send-session-notification-jbxknvar.js");
|
|
29572
29991
|
log(`[rpc] session-upgrade requested for session ${sessionId}`);
|
|
29573
29992
|
const ctx = await buildManagedCtx(db);
|
|
29574
29993
|
runManagedUpgrade(ctx, sessionId).then((message) => {
|
|
@@ -29584,7 +30003,7 @@ function registerRpcHandlers(rpcServer, args) {
|
|
|
29584
30003
|
if (!db)
|
|
29585
30004
|
return { ok: false, error: "db unavailable" };
|
|
29586
30005
|
try {
|
|
29587
|
-
const { updateSessionMeta } = await import("./storage-meta-session-
|
|
30006
|
+
const { updateSessionMeta } = await import("./storage-meta-session-z818pn1e.js");
|
|
29588
30007
|
updateSessionMeta(db, sessionId, { upgradeRemindedAt: Date.now() });
|
|
29589
30008
|
return { ok: true };
|
|
29590
30009
|
} catch (error) {
|
|
@@ -30100,6 +30519,31 @@ function releaseClaimWithoutDelivery(db, sessionId, claimToken) {
|
|
|
30100
30519
|
sessionLog(sessionId, "channel2 terminal-run claim release failed; lease will heal:", error);
|
|
30101
30520
|
}
|
|
30102
30521
|
}
|
|
30522
|
+
async function deliverSyntheticUserMessage(sessionId, deps) {
|
|
30523
|
+
const promptContext = await resolvePromptContext2(deps.client, sessionId);
|
|
30524
|
+
const body = {
|
|
30525
|
+
noReply: false,
|
|
30526
|
+
parts: [{ type: "text", text: deps.text, synthetic: true }]
|
|
30527
|
+
};
|
|
30528
|
+
if (promptContext?.agent)
|
|
30529
|
+
body.agent = promptContext.agent;
|
|
30530
|
+
if (promptContext?.model) {
|
|
30531
|
+
body.model = {
|
|
30532
|
+
providerID: promptContext.model.providerID,
|
|
30533
|
+
modelID: promptContext.model.modelID
|
|
30534
|
+
};
|
|
30535
|
+
}
|
|
30536
|
+
if (promptContext?.variant)
|
|
30537
|
+
body.variant = promptContext.variant;
|
|
30538
|
+
if (deps.beforeSend && !deps.beforeSend())
|
|
30539
|
+
return false;
|
|
30540
|
+
const session = deps.client.session;
|
|
30541
|
+
if (typeof session?.promptAsync !== "function") {
|
|
30542
|
+
throw new Error("client has no session.promptAsync");
|
|
30543
|
+
}
|
|
30544
|
+
await session.promptAsync({ path: { id: sessionId }, body });
|
|
30545
|
+
return true;
|
|
30546
|
+
}
|
|
30103
30547
|
async function maybeDeliverChannel2(sessionId, deps) {
|
|
30104
30548
|
let state;
|
|
30105
30549
|
try {
|
|
@@ -30138,36 +30582,25 @@ async function maybeDeliverChannel2(sessionId, deps) {
|
|
|
30138
30582
|
return false;
|
|
30139
30583
|
}
|
|
30140
30584
|
try {
|
|
30141
|
-
const promptContext = await resolvePromptContext2(client, sessionId);
|
|
30142
30585
|
const reminder = deps.directiveText ?? buildChannel2Reminder(effectiveU, reclaimableToolOutputCount(deps.baseline?.baselineParts ?? []), deps.oldestReclaimableToolTags);
|
|
30143
|
-
const
|
|
30144
|
-
|
|
30145
|
-
|
|
30146
|
-
|
|
30147
|
-
|
|
30148
|
-
|
|
30149
|
-
|
|
30150
|
-
|
|
30151
|
-
|
|
30152
|
-
|
|
30153
|
-
|
|
30154
|
-
|
|
30155
|
-
|
|
30156
|
-
|
|
30157
|
-
|
|
30158
|
-
|
|
30159
|
-
|
|
30160
|
-
}
|
|
30161
|
-
const claim = getChannel2NudgeClaim(deps.db, sessionId);
|
|
30162
|
-
if (claim.state !== "claimed" || claim.claimToken !== claimToken) {
|
|
30163
|
-
sessionLog(sessionId, `channel2 ceiling nudge delivery skipped: claim no longer owned before send (state=${claim.state || "empty"})`);
|
|
30164
|
-
return false;
|
|
30165
|
-
}
|
|
30166
|
-
if (!subagentRunIsActive(deps, sessionId)) {
|
|
30167
|
-
releaseClaimWithoutDelivery(deps.db, sessionId, claimToken);
|
|
30586
|
+
const sent = await deliverSyntheticUserMessage(sessionId, {
|
|
30587
|
+
client,
|
|
30588
|
+
text: reminder,
|
|
30589
|
+
beforeSend: () => {
|
|
30590
|
+
const claim = getChannel2NudgeClaim(deps.db, sessionId);
|
|
30591
|
+
if (claim.state !== "claimed" || claim.claimToken !== claimToken) {
|
|
30592
|
+
sessionLog(sessionId, `channel2 ceiling nudge delivery skipped: claim no longer owned before send (state=${claim.state || "empty"})`);
|
|
30593
|
+
return false;
|
|
30594
|
+
}
|
|
30595
|
+
if (!subagentRunIsActive(deps, sessionId)) {
|
|
30596
|
+
releaseClaimWithoutDelivery(deps.db, sessionId, claimToken);
|
|
30597
|
+
return false;
|
|
30598
|
+
}
|
|
30599
|
+
return true;
|
|
30600
|
+
}
|
|
30601
|
+
});
|
|
30602
|
+
if (!sent)
|
|
30168
30603
|
return false;
|
|
30169
|
-
}
|
|
30170
|
-
await session.promptAsync({ path: { id: sessionId }, body });
|
|
30171
30604
|
} catch (error) {
|
|
30172
30605
|
try {
|
|
30173
30606
|
const restored = casChannel2NudgeClaim(deps.db, sessionId, "pending", claimToken);
|
|
@@ -30203,7 +30636,7 @@ function canConsumeDeferredOnThisPass(args) {
|
|
|
30203
30636
|
return args.schedulerDecision === "execute" || args.contextPercentage >= (args.forceMaterializationPercentage ?? escalationBands(65).forceMaterializationPercentage);
|
|
30204
30637
|
}
|
|
30205
30638
|
function hasReclaimRide(signals) {
|
|
30206
|
-
return signals.hardFold || signals.force || signals.explicitFlush || signals.publishedHistory
|
|
30639
|
+
return signals.hardFold || signals.force || signals.explicitFlush || signals.publishedHistory;
|
|
30207
30640
|
}
|
|
30208
30641
|
|
|
30209
30642
|
// src/hooks/magic-context/caveman-cleanup.ts
|
|
@@ -30325,7 +30758,7 @@ function replayCavemanCompression(sessionId, db, targets, tags) {
|
|
|
30325
30758
|
}
|
|
30326
30759
|
|
|
30327
30760
|
// src/hooks/magic-context/compaction-off-transition.ts
|
|
30328
|
-
import { existsSync as
|
|
30761
|
+
import { existsSync as existsSync12 } from "node:fs";
|
|
30329
30762
|
var loggedUnverifiedMarkerCleanupRetry = false;
|
|
30330
30763
|
var COMPACTION_OFF_FLIP_NOTICE = [
|
|
30331
30764
|
"## Magic Context — compaction-off mode is now active",
|
|
@@ -30360,7 +30793,7 @@ function clearCachedM0Baseline(db, sessionId) {
|
|
|
30360
30793
|
return (result.changes ?? 0) > 0;
|
|
30361
30794
|
}
|
|
30362
30795
|
function cleanupOffMarkers(sessionId) {
|
|
30363
|
-
if (!
|
|
30796
|
+
if (!existsSync12(getOpenCodeDbPath())) {
|
|
30364
30797
|
return { verified: true, removedLineages: 0, removedRows: 0, retainedLineages: 0 };
|
|
30365
30798
|
}
|
|
30366
30799
|
return removeMcOwnedCompactionMarkers(sessionId, MARKER_SUMMARY_TEXT);
|
|
@@ -31297,7 +31730,7 @@ function createPassOutcome() {
|
|
|
31297
31730
|
}
|
|
31298
31731
|
|
|
31299
31732
|
// src/hooks/magic-context/rust-mode-transform.ts
|
|
31300
|
-
import { createHash as createHash12 } from "node:crypto";
|
|
31733
|
+
import { createHash as createHash12, randomUUID as randomUUID6 } from "node:crypto";
|
|
31301
31734
|
|
|
31302
31735
|
// src/hooks/magic-context/raw-fallback-context-limit.ts
|
|
31303
31736
|
class RawFallbackContextLimitError extends Error {
|
|
@@ -33813,7 +34246,8 @@ async function runPostTransformPhase(args) {
|
|
|
33813
34246
|
const firstRenderBust = m0M1EnabledForFold && !completeCachedPrefixAvailable;
|
|
33814
34247
|
let foldExecutedThisPass = false;
|
|
33815
34248
|
let publishedM1RefreshedThisPass = false;
|
|
33816
|
-
|
|
34249
|
+
let prefixPreflightFailed = false;
|
|
34250
|
+
const softRefreshOpportunity = args.schedulerDecision === "execute" || deferredMaterialize;
|
|
33817
34251
|
let m0RematerializedThisPass = false;
|
|
33818
34252
|
const m0CoverageBeforeFold = args.sessionMeta.cachedM0Bytes === null ? -1 : args.sessionMeta.cachedM0MaxCompartmentSeq;
|
|
33819
34253
|
let m0MaterializeReason = null;
|
|
@@ -33840,6 +34274,7 @@ async function runPostTransformPhase(args) {
|
|
|
33840
34274
|
compactionOff
|
|
33841
34275
|
});
|
|
33842
34276
|
preparedPrefix = foldResult;
|
|
34277
|
+
prefixPreflightFailed = foldResult.materializationContentionRetryExhausted === true;
|
|
33843
34278
|
foldExecutedThisPass = foldExecutesThisPass(foldDueDecision.value || softRefreshOpportunity, foldResult.m0RematerializedThisPass);
|
|
33844
34279
|
publishedM1RefreshedThisPass = !foldResult.materializationContentionRetryExhausted && previousM1 !== args.sessionMeta.cachedM1Bytes?.toString("utf8");
|
|
33845
34280
|
m0RematerializedThisPass = foldResult.m0RematerializedThisPass;
|
|
@@ -33861,29 +34296,29 @@ async function runPostTransformPhase(args) {
|
|
|
33861
34296
|
}
|
|
33862
34297
|
} catch (error) {
|
|
33863
34298
|
preparedPrefix = cachedPrefixBeforePreflight;
|
|
34299
|
+
prefixPreflightFailed = true;
|
|
33864
34300
|
args.passOutcome?.record("m0-m1-fold-preexecution-degradation");
|
|
33865
34301
|
sessionLog(args.sessionId, "transform: m[0] HARD fold pre-execution failed:", getErrorMessage(error));
|
|
33866
34302
|
}
|
|
33867
34303
|
sessionLog(args.sessionId, `m[0] HARD fold decision: reason=${foldDueDecision.reason ?? "unknown"} executed=${foldExecutedThisPass}`);
|
|
33868
34304
|
}
|
|
33869
|
-
const
|
|
33870
|
-
const shouldReadPendingOps = !compactionOff && (materializationRequested || args.schedulerDecision === "execute" || forceMaterialization || foldExecutedThisPass || firstRenderBust || compartmentRunning);
|
|
34305
|
+
const shouldReadPendingOps = !compactionOff && (materializationRequested || publishedM1RefreshedThisPass || args.schedulerDecision === "execute" || forceMaterialization || foldExecutedThisPass || firstRenderBust || compartmentRunning);
|
|
33871
34306
|
const pendingOps = shouldReadPendingOps ? getPendingOps(args.db, args.sessionId) : [];
|
|
33872
34307
|
const hasPendingUserOps = pendingOps.length > 0;
|
|
33873
34308
|
const formatPendingOpsDepth = () => {
|
|
33874
34309
|
const depth = getPendingOpsCount(args.db, args.sessionId);
|
|
33875
34310
|
return depth === null ? "not loaded (deferred pass)" : String(depth);
|
|
33876
34311
|
};
|
|
33877
|
-
const shouldApplyPendingOps = !compactionOff && (args.schedulerDecision === "execute" || materializationRequested || forceMaterialization || foldExecutedThisPass || firstRenderBust) && publishedWorkDrainAllowed;
|
|
33878
34312
|
const rideSignals = {
|
|
33879
34313
|
hardFold: foldExecutedThisPass || firstRenderBust,
|
|
33880
|
-
force:
|
|
33881
|
-
explicitFlush: isExplicitFlush,
|
|
33882
|
-
publishedHistory: publishedM1RefreshedThisPass || !m0M1EnabledForFold && (args.pendingCompartmentInjection?.compartmentCount ?? 0) > 0 && (args.historyRebuiltThisPass || args.rebuiltHistoryFromInitialPrepare || args.canConsumeDeferredLate && args.deferredHistoryWasPendingAtPassStart)
|
|
33883
|
-
|
|
33884
|
-
|
|
33885
|
-
|
|
33886
|
-
|
|
34314
|
+
force: emergencyDropEligible && (args.contextUsage.percentage >= 95 || getEmergencyInputSample(args.db, args.sessionId) === 0),
|
|
34315
|
+
explicitFlush: isExplicitFlush || deferredMaterialize && !prefixPreflightFailed,
|
|
34316
|
+
publishedHistory: publishedM1RefreshedThisPass || !m0M1EnabledForFold && (args.pendingCompartmentInjection?.compartmentCount ?? 0) > 0 && (args.historyRebuiltThisPass || args.rebuiltHistoryFromInitialPrepare || args.canConsumeDeferredLate && args.deferredHistoryWasPendingAtPassStart)
|
|
34317
|
+
};
|
|
34318
|
+
const publishedWorkDrainAllowed = !compactionOff && hasReclaimRide(rideSignals);
|
|
34319
|
+
const shouldApplyPendingOps = publishedWorkDrainAllowed;
|
|
34320
|
+
const shouldRunHeuristics = !compactionOff && hasReclaimRide(rideSignals) && (rideSignals.publishedHistory || materializationRequested || forceMaterialization || foldExecutedThisPass || firstRenderBust || emergencyDropEligible || args.schedulerDecision === "execute" && (!alreadyRanThisTurn || !args.fullFeatureMode));
|
|
34321
|
+
const isCacheBustingPass = publishedWorkDrainAllowed;
|
|
33887
34322
|
if (isCacheBustingPass && args.client && args.ctxReduceAvailability.callable && !hasLoggedCtxReducePermissionDeny(args.sessionId)) {
|
|
33888
34323
|
try {
|
|
33889
34324
|
const denied = await resolveToolPermissionDenied(args.client, args.sessionId, "ctx_reduce", args.activeAgent);
|
|
@@ -33909,13 +34344,8 @@ async function runPostTransformPhase(args) {
|
|
|
33909
34344
|
if (!shouldApplyPendingOps && args.schedulerDeferReason !== undefined && args.schedulerDeferReason !== null) {
|
|
33910
34345
|
sessionLog(args.sessionId, `pending ops WILL NOT APPLY — reason=${args.schedulerDeferReason} pendingOps=${formatPendingOpsDepth()} context=${args.contextUsage.percentage.toFixed(1)}%`);
|
|
33911
34346
|
}
|
|
33912
|
-
if (
|
|
33913
|
-
|
|
33914
|
-
const bypassReason = forceMaterialization ? `emergency >=${args.forceMaterializationPercentage}%` : "m0 hard fold";
|
|
33915
|
-
sessionLog(args.sessionId, `transform: compartment-gate bypass (${bypassReason}) — applying ${pendingOps.length} pending ops while compartment agent runs (${args.contextUsage.percentage.toFixed(1)}%)`);
|
|
33916
|
-
} else {
|
|
33917
|
-
sessionLog(args.sessionId, "transform: deferring pending ops — compartment agent in progress");
|
|
33918
|
-
}
|
|
34347
|
+
if (hasPendingUserOps && !shouldApplyPendingOps) {
|
|
34348
|
+
sessionLog(args.sessionId, `pending ops held — reason=no originating cache-bust opportunity; scheduler=${args.schedulerDecision}, historianRunning=${compartmentRunning}`);
|
|
33919
34349
|
}
|
|
33920
34350
|
let explicitMaterializedSuccessfully = false;
|
|
33921
34351
|
let deferredMaterializedSuccessfully = false;
|
|
@@ -33947,9 +34377,6 @@ async function runPostTransformPhase(args) {
|
|
|
33947
34377
|
const tApply = performance.now();
|
|
33948
34378
|
pendingOpsDidMutate = applyPendingOperations(args.sessionId, args.db, args.targets, args.contextUsage.percentage >= 95 ? newestCtxReduceTagNumbers(getTagsBySession(args.db, args.sessionId)) : args.protectedTagIds, undefined, pendingOps, [], new Set, (reduction) => droppedTokenReductions.push(reduction));
|
|
33949
34379
|
if (pendingOpsDidMutate) {
|
|
33950
|
-
rideSignals.agentDrop = true;
|
|
33951
|
-
isCacheBustingPass = hasReclaimRide(rideSignals);
|
|
33952
|
-
shouldRunHeuristics = isCacheBustingPass;
|
|
33953
34380
|
droppedCount += pendingOps.length;
|
|
33954
34381
|
for (const pendingOp of pendingOps) {
|
|
33955
34382
|
const message = args.targets.get(pendingOp.tagId)?.message;
|
|
@@ -34711,6 +35138,8 @@ var RUST_PARK_RETRY_INTERVAL = 5;
|
|
|
34711
35138
|
var RUST_EMERGENCY_WALL_PCT = 95;
|
|
34712
35139
|
var RUST_PARK_PROBE_PRESSURE_BYPASS_PCT = 90;
|
|
34713
35140
|
var RUST_SEND_TIMEOUT_MS = 15000;
|
|
35141
|
+
var RUST_SILENT_RESEND_AFTER_MS = 1e4;
|
|
35142
|
+
var RUST_HEALTH_PROBE_TIMEOUT_MS = 2000;
|
|
34714
35143
|
var RUST_LKG_FROZEN_HEALTHY_PASS_LIMIT = 8;
|
|
34715
35144
|
var RUST_LKG_FROZEN_RAW_TAIL_GROWTH_LIMIT = 16;
|
|
34716
35145
|
function activeAgentFromMessages(messages) {
|
|
@@ -35620,6 +36049,64 @@ function createRustModeTransform(deps, options) {
|
|
|
35620
36049
|
clearTimeout(timer);
|
|
35621
36050
|
}
|
|
35622
36051
|
};
|
|
36052
|
+
const callTransformWithSilentResend = async (args, attemptTimeoutMs) => {
|
|
36053
|
+
const startedAtMs = Date.now();
|
|
36054
|
+
const deadlineMs = startedAtMs + attemptTimeoutMs;
|
|
36055
|
+
const silentAfterMs = options.silentResendAfterMsForTests ?? RUST_SILENT_RESEND_AFTER_MS;
|
|
36056
|
+
const probeTimeoutMs = options.healthProbeTimeoutMsForTests ?? RUST_HEALTH_PROBE_TIMEOUT_MS;
|
|
36057
|
+
const originalAttemptId = randomUUID6();
|
|
36058
|
+
const originalBody = isRecord4(args.body) ? { ...args.body, attempt_id: originalAttemptId } : args.body;
|
|
36059
|
+
const original = callModule({ ...args, body: originalBody }, attemptTimeoutMs);
|
|
36060
|
+
if (attemptTimeoutMs <= silentAfterMs)
|
|
36061
|
+
return original;
|
|
36062
|
+
let silentTimer;
|
|
36063
|
+
const first = await Promise.race([
|
|
36064
|
+
original.then((response) => ({ kind: "response", response }), (error) => ({ kind: "error", error })),
|
|
36065
|
+
new Promise((resolve) => {
|
|
36066
|
+
silentTimer = setTimeout(() => resolve({ kind: "silent" }), silentAfterMs);
|
|
36067
|
+
})
|
|
36068
|
+
]);
|
|
36069
|
+
if (first.kind !== "silent")
|
|
36070
|
+
clearTimeout(silentTimer);
|
|
36071
|
+
if (first.kind === "response")
|
|
36072
|
+
return first.response;
|
|
36073
|
+
if (first.kind === "error")
|
|
36074
|
+
throw first.error;
|
|
36075
|
+
const probeBudgetMs = Math.min(probeTimeoutMs, Math.max(0, deadlineMs - Date.now()));
|
|
36076
|
+
if (probeBudgetMs <= 0)
|
|
36077
|
+
return original;
|
|
36078
|
+
try {
|
|
36079
|
+
await callModule({
|
|
36080
|
+
sessionId: args.sessionId,
|
|
36081
|
+
projectRoot: args.projectRoot,
|
|
36082
|
+
method: "session.status",
|
|
36083
|
+
body: {
|
|
36084
|
+
method: "session.status",
|
|
36085
|
+
v: 1,
|
|
36086
|
+
session_id: args.sessionId
|
|
36087
|
+
},
|
|
36088
|
+
bypassSessionLane: true
|
|
36089
|
+
}, probeBudgetMs);
|
|
36090
|
+
} catch {
|
|
36091
|
+
return original;
|
|
36092
|
+
}
|
|
36093
|
+
const remainingMs = Math.max(0, deadlineMs - Date.now());
|
|
36094
|
+
if (remainingMs <= 0)
|
|
36095
|
+
return original;
|
|
36096
|
+
const resendAttemptId = randomUUID6();
|
|
36097
|
+
sessionLog(args.sessionId, `rust silent resend original_attempt=${originalAttemptId} resend_attempt=${resendAttemptId} silent_gap_ms=${Date.now() - startedAtMs}`);
|
|
36098
|
+
const resendBody = isRecord4(args.body) ? {
|
|
36099
|
+
...args.body,
|
|
36100
|
+
attempt_id: resendAttemptId,
|
|
36101
|
+
original_attempt_id: originalAttemptId,
|
|
36102
|
+
resend: true
|
|
36103
|
+
} : args.body;
|
|
36104
|
+
return callModule({
|
|
36105
|
+
...args,
|
|
36106
|
+
body: resendBody,
|
|
36107
|
+
bypassSessionLane: true
|
|
36108
|
+
}, remainingMs);
|
|
36109
|
+
};
|
|
35623
36110
|
const markFailure = (sessionId, state, error) => {
|
|
35624
36111
|
state.consecutiveFailures = isNonRetryableStateSyncFailure(error) ? Math.max(RUST_FAILURE_PARK_THRESHOLD, state.consecutiveFailures + 1) : state.consecutiveFailures + 1;
|
|
35625
36112
|
state.failureCount += 1;
|
|
@@ -35836,6 +36323,8 @@ function createRustModeTransform(deps, options) {
|
|
|
35836
36323
|
} catch {}
|
|
35837
36324
|
let appliedAt;
|
|
35838
36325
|
let emergencyFailClosed = false;
|
|
36326
|
+
let providerProvenEmergency = false;
|
|
36327
|
+
let recoveryProjectRoot = options.projectRoot ?? deps.directory ?? "";
|
|
35839
36328
|
const passUsageSnapshot = loadContextUsage(deps.contextUsageMap, deps.db, sessionId);
|
|
35840
36329
|
requestInputTokens = Math.max(0, Math.floor(passUsageSnapshot.inputTokens));
|
|
35841
36330
|
let preflightError;
|
|
@@ -35869,11 +36358,15 @@ function createRustModeTransform(deps, options) {
|
|
|
35869
36358
|
}
|
|
35870
36359
|
const transformGeometry = transformGeometryForWire(resolvedWindowGeometry);
|
|
35871
36360
|
const hasTrustedEmergencyWall = transformGeometry ? transformGeometry.usable_hard > 0 : resolvedContextLimit !== undefined && resolvedContextLimit > 0;
|
|
35872
|
-
|
|
36361
|
+
const hardWallPercentage = hardWallUsagePercentage(passUsageSnapshot, transformGeometry);
|
|
36362
|
+
const providerOverflowProven = isProviderOverflowFailClosedProven(sessionId);
|
|
36363
|
+
emergencyFailClosed = providerOverflowProven || hardWallPercentage >= RUST_EMERGENCY_WALL_PCT && hasTrustedEmergencyWall;
|
|
35873
36364
|
if (overflowState) {
|
|
35874
36365
|
const detectedLimitMatchesModel = overflowState.detectedContextLimitModelKey === null || canonicalModelIdentity(overflowState.detectedContextLimitModelKey) === canonicalModelIdentity(modelKey ?? "");
|
|
35875
36366
|
const hasProviderProof = overflowState.detectedContextLimit > 0 && detectedLimitMatchesModel || isProviderOverflowReconfirmed(sessionId);
|
|
35876
|
-
|
|
36367
|
+
const persistedProviderEmergency = overflowState.needsEmergencyRecovery && overflowState.emergencyRecoveryOrigin === "provider_overflow" && hasProviderProof;
|
|
36368
|
+
emergencyFailClosed ||= persistedProviderEmergency;
|
|
36369
|
+
providerProvenEmergency = hardWallPercentage >= RUST_EMERGENCY_WALL_PCT && (providerOverflowProven || persistedProviderEmergency);
|
|
35877
36370
|
}
|
|
35878
36371
|
const serveRawFallback = (cause) => {
|
|
35879
36372
|
const contextLimit = transformGeometry?.usable_hard ?? resolvedContextLimit ?? (overflowState && overflowState.detectedContextLimit > 0 ? overflowState.detectedContextLimit : undefined);
|
|
@@ -36176,6 +36669,7 @@ function createRustModeTransform(deps, options) {
|
|
|
36176
36669
|
nowMs: Date.now()
|
|
36177
36670
|
};
|
|
36178
36671
|
const projectRoot = options.projectRoot ?? directory;
|
|
36672
|
+
recoveryProjectRoot = projectRoot;
|
|
36179
36673
|
const authoritySeqAdoption = { used: false };
|
|
36180
36674
|
const memorySyncRequested = options.memorySyncRequestedSessions?.delete(sessionId) === true;
|
|
36181
36675
|
const currentStateSyncInputSignature = stateSyncInputSignature({
|
|
@@ -36370,7 +36864,7 @@ function createRustModeTransform(deps, options) {
|
|
|
36370
36864
|
logStage(sessionId, "wireBuild", wireBuildStartedAt, timings, wireDelta ? `mode=tail_delta input=${encodedInput.length}` : "mode=full");
|
|
36371
36865
|
const sendTransformSeries = async (payload, detail = "") => {
|
|
36372
36866
|
const pagingStartedAt = performance.now();
|
|
36373
|
-
const pages = buildPagedModuleTransformPayloads(payload, options.modulePageMaxBytes);
|
|
36867
|
+
const pages = buildPagedModuleTransformPayloads(payload, options.modulePageMaxBytes, true);
|
|
36374
36868
|
timings.paging += performance.now() - pagingStartedAt;
|
|
36375
36869
|
const seedMessageCount = Array.isArray(payload.input) ? payload.input.length : Array.isArray(payload.messages) ? payload.messages.length : 0;
|
|
36376
36870
|
const paged = pages.some((entry) => typeof entry.page.transform_page_id === "string");
|
|
@@ -36381,7 +36875,7 @@ function createRustModeTransform(deps, options) {
|
|
|
36381
36875
|
try {
|
|
36382
36876
|
const attemptClass = paged ? index === pages.length - 1 ? "transform_series_execute" : "transform_page_upload" : undefined;
|
|
36383
36877
|
const attemptTimeoutMs = options.moduleTimeoutMs ?? (attemptClass === "transform_series_execute" ? transformColdStartExecuteTimeoutMs(seedMessageCount) : attemptClass === "transform_page_upload" ? TRANSFORM_PAGE_UPLOAD_TIMEOUT_MS : timeoutMs);
|
|
36384
|
-
|
|
36878
|
+
const callArgs = {
|
|
36385
36879
|
sessionId,
|
|
36386
36880
|
projectRoot,
|
|
36387
36881
|
method: "transform",
|
|
@@ -36392,7 +36886,8 @@ function createRustModeTransform(deps, options) {
|
|
|
36392
36886
|
},
|
|
36393
36887
|
generationSensitive: paged && index > 0,
|
|
36394
36888
|
attemptClass
|
|
36395
|
-
}
|
|
36889
|
+
};
|
|
36890
|
+
moduleResponse = page.transform_page_complete ? await callTransformWithSilentResend(callArgs, attemptTimeoutMs) : await callModule(callArgs, attemptTimeoutMs);
|
|
36396
36891
|
} catch (error) {
|
|
36397
36892
|
if (paged && isTransformPageAttemptMismatch(error)) {
|
|
36398
36893
|
return {
|
|
@@ -36918,6 +37413,21 @@ function createRustModeTransform(deps, options) {
|
|
|
36918
37413
|
sessionLog(sessionId, "mc_rust_emergency_refusal before_lkg");
|
|
36919
37414
|
markFailure(sessionId, state, error);
|
|
36920
37415
|
finishPass(false, false);
|
|
37416
|
+
const refusedUser = newestUserMessage(messages);
|
|
37417
|
+
const refusedUserMessageId = refusedUser ? messageIdOf(refusedUser) : null;
|
|
37418
|
+
if (refusedUserMessageId) {
|
|
37419
|
+
try {
|
|
37420
|
+
options.onEngineReconnectRefusal?.({
|
|
37421
|
+
sessionId,
|
|
37422
|
+
projectRoot: recoveryProjectRoot,
|
|
37423
|
+
refusedUserMessageId,
|
|
37424
|
+
providerProvenEmergency,
|
|
37425
|
+
compactionOff: deps.compactionOff === true
|
|
37426
|
+
});
|
|
37427
|
+
} catch (recoveryError) {
|
|
37428
|
+
sessionLog(sessionId, "rust refusal recovery failed to arm:", recoveryError);
|
|
37429
|
+
}
|
|
37430
|
+
}
|
|
36921
37431
|
throw new EmergencyFailClosedError(ENGINE_RECONNECTING_USER_MESSAGE, {
|
|
36922
37432
|
cause: error
|
|
36923
37433
|
});
|
|
@@ -37414,6 +37924,7 @@ function createTransform(deps) {
|
|
|
37414
37924
|
projectRoot: deps.rustModeProjectRoot,
|
|
37415
37925
|
notifyParked: deps.onRustModeParked,
|
|
37416
37926
|
onProjectPrepared: deps.onRustModeProjectPrepared,
|
|
37927
|
+
onEngineReconnectRefusal: deps.onRustEngineReconnectRefusal,
|
|
37417
37928
|
memorySyncRequestedSessions: deps.rustMemorySyncRequestedSessions,
|
|
37418
37929
|
allowAuthorityProtocolBypassForTests: deps.rustModeAllowAuthorityProtocolBypassForTests
|
|
37419
37930
|
}) : undefined;
|
|
@@ -38832,6 +39343,142 @@ function formatEmbedFailureSummary(embedded, remaining, failure, style = "markdo
|
|
|
38832
39343
|
return `${progress} ${renderEmbeddingFailure(failure?.class ?? "empty_result", style)}`;
|
|
38833
39344
|
}
|
|
38834
39345
|
|
|
39346
|
+
// src/hooks/magic-context/rust-refusal-recovery.ts
|
|
39347
|
+
var RUST_REFUSAL_RECOVERY_PROMPT = "Magic Context's engine reconnected. Continue from where you stopped.";
|
|
39348
|
+
var RUST_REFUSAL_RECOVERY_POLL_MS = 2000;
|
|
39349
|
+
var RUST_REFUSAL_RECOVERY_MAX_MS = 5 * 60000;
|
|
39350
|
+
var RUST_REFUSAL_RECOVERY_PROBE_TIMEOUT_MS = 2000;
|
|
39351
|
+
function errorContainsReconnectRefusal(error) {
|
|
39352
|
+
try {
|
|
39353
|
+
return JSON.stringify(error).includes(ENGINE_RECONNECTING_USER_MESSAGE);
|
|
39354
|
+
} catch {
|
|
39355
|
+
return false;
|
|
39356
|
+
}
|
|
39357
|
+
}
|
|
39358
|
+
function createRustRefusalRecovery(options) {
|
|
39359
|
+
const watchers = new Map;
|
|
39360
|
+
const latestRefusalBySession = new Map;
|
|
39361
|
+
const pollIntervalMs = options.pollIntervalMs ?? RUST_REFUSAL_RECOVERY_POLL_MS;
|
|
39362
|
+
const maxDurationMs = options.maxDurationMs ?? RUST_REFUSAL_RECOVERY_MAX_MS;
|
|
39363
|
+
const probeTimeoutMs = options.probeTimeoutMs ?? RUST_REFUSAL_RECOVERY_PROBE_TIMEOUT_MS;
|
|
39364
|
+
const readLatestMessage = options.readLatestMessage ?? latestPersistedMessageForRecovery;
|
|
39365
|
+
const cancel = (sessionId) => {
|
|
39366
|
+
const watcher = watchers.get(sessionId);
|
|
39367
|
+
if (!watcher)
|
|
39368
|
+
return;
|
|
39369
|
+
clearTimeout(watcher.timer);
|
|
39370
|
+
watchers.delete(sessionId);
|
|
39371
|
+
};
|
|
39372
|
+
const schedule = (sessionId, watcher) => {
|
|
39373
|
+
watcher.timer = setTimeout(() => void poll(sessionId, watcher), pollIntervalMs);
|
|
39374
|
+
};
|
|
39375
|
+
const probe = async (watcher, sessionId) => {
|
|
39376
|
+
const controller = new AbortController;
|
|
39377
|
+
const timeoutError = new Error("rust refusal recovery probe timed out");
|
|
39378
|
+
const timer = setTimeout(() => controller.abort(timeoutError), probeTimeoutMs);
|
|
39379
|
+
try {
|
|
39380
|
+
await Promise.race([
|
|
39381
|
+
options.moduleClient.call({
|
|
39382
|
+
sessionId,
|
|
39383
|
+
projectRoot: watcher.projectRoot,
|
|
39384
|
+
method: "session.status",
|
|
39385
|
+
body: { method: "session.status", v: 1, session_id: sessionId },
|
|
39386
|
+
signal: controller.signal,
|
|
39387
|
+
timeoutMs: probeTimeoutMs,
|
|
39388
|
+
bypassSessionLane: true
|
|
39389
|
+
}),
|
|
39390
|
+
new Promise((_resolve, reject) => {
|
|
39391
|
+
controller.signal.addEventListener("abort", () => reject(controller.signal.reason ?? timeoutError), { once: true });
|
|
39392
|
+
})
|
|
39393
|
+
]);
|
|
39394
|
+
return true;
|
|
39395
|
+
} catch {
|
|
39396
|
+
return false;
|
|
39397
|
+
} finally {
|
|
39398
|
+
clearTimeout(timer);
|
|
39399
|
+
}
|
|
39400
|
+
};
|
|
39401
|
+
const poll = async (sessionId, watcher) => {
|
|
39402
|
+
if (watchers.get(sessionId) !== watcher)
|
|
39403
|
+
return;
|
|
39404
|
+
if (Date.now() - watcher.armedAtMs >= maxDurationMs) {
|
|
39405
|
+
cancel(sessionId);
|
|
39406
|
+
sessionLog(sessionId, "rust refusal recovery expired before the module became healthy");
|
|
39407
|
+
return;
|
|
39408
|
+
}
|
|
39409
|
+
if (!await probe(watcher, sessionId)) {
|
|
39410
|
+
schedule(sessionId, watcher);
|
|
39411
|
+
return;
|
|
39412
|
+
}
|
|
39413
|
+
let latest;
|
|
39414
|
+
try {
|
|
39415
|
+
latest = readLatestMessage(sessionId);
|
|
39416
|
+
} catch (error) {
|
|
39417
|
+
sessionLog(sessionId, "rust refusal recovery could not read persisted history:", error);
|
|
39418
|
+
schedule(sessionId, watcher);
|
|
39419
|
+
return;
|
|
39420
|
+
}
|
|
39421
|
+
const matchingAssistant = latest?.role === "assistant" && (latest.parentID === undefined || latest.parentID === watcher.refusedUserMessageId) ? latest : null;
|
|
39422
|
+
const stillRefusedStep = matchingAssistant !== null && (errorContainsReconnectRefusal(matchingAssistant.error) || matchingAssistant.parentID === watcher.refusedUserMessageId && matchingAssistant.error === undefined && matchingAssistant.completedAt === undefined);
|
|
39423
|
+
if (!stillRefusedStep) {
|
|
39424
|
+
cancel(sessionId);
|
|
39425
|
+
sessionLog(sessionId, "rust refusal recovery skipped because persisted history advanced past the refused step");
|
|
39426
|
+
return;
|
|
39427
|
+
}
|
|
39428
|
+
if (watcher.state !== "pending" || watchers.get(sessionId) !== watcher)
|
|
39429
|
+
return;
|
|
39430
|
+
watcher.state = "claimed";
|
|
39431
|
+
const delivered = await deliverSyntheticUserMessage(sessionId, {
|
|
39432
|
+
client: options.client,
|
|
39433
|
+
text: RUST_REFUSAL_RECOVERY_PROMPT,
|
|
39434
|
+
beforeSend: () => watchers.get(sessionId) === watcher && watcher.state === "claimed"
|
|
39435
|
+
}).catch((error) => {
|
|
39436
|
+
sessionLog(sessionId, "rust refusal recovery synthetic delivery failed:", error);
|
|
39437
|
+
return false;
|
|
39438
|
+
});
|
|
39439
|
+
if (!delivered) {
|
|
39440
|
+
if (watchers.get(sessionId) === watcher) {
|
|
39441
|
+
watcher.state = "pending";
|
|
39442
|
+
schedule(sessionId, watcher);
|
|
39443
|
+
}
|
|
39444
|
+
return;
|
|
39445
|
+
}
|
|
39446
|
+
watchers.delete(sessionId);
|
|
39447
|
+
sessionLog(sessionId, "rust refusal recovery synthetic continue delivered");
|
|
39448
|
+
};
|
|
39449
|
+
return {
|
|
39450
|
+
arm(args) {
|
|
39451
|
+
if (args.compactionOff || args.providerProvenEmergency)
|
|
39452
|
+
return;
|
|
39453
|
+
const refusalKey = `${args.sessionId}:${args.refusedUserMessageId}`;
|
|
39454
|
+
if (latestRefusalBySession.get(args.sessionId) === refusalKey)
|
|
39455
|
+
return;
|
|
39456
|
+
latestRefusalBySession.set(args.sessionId, refusalKey);
|
|
39457
|
+
const current = watchers.get(args.sessionId);
|
|
39458
|
+
if (current)
|
|
39459
|
+
cancel(args.sessionId);
|
|
39460
|
+
const watcher = {
|
|
39461
|
+
refusalKey,
|
|
39462
|
+
refusedUserMessageId: args.refusedUserMessageId,
|
|
39463
|
+
projectRoot: args.projectRoot,
|
|
39464
|
+
armedAtMs: Date.now(),
|
|
39465
|
+
state: "pending"
|
|
39466
|
+
};
|
|
39467
|
+
watchers.set(args.sessionId, watcher);
|
|
39468
|
+
schedule(args.sessionId, watcher);
|
|
39469
|
+
sessionLog(args.sessionId, `rust refusal recovery armed refusal=${refusalKey}`);
|
|
39470
|
+
},
|
|
39471
|
+
cancel,
|
|
39472
|
+
forget(sessionId) {
|
|
39473
|
+
cancel(sessionId);
|
|
39474
|
+
latestRefusalBySession.delete(sessionId);
|
|
39475
|
+
},
|
|
39476
|
+
activeCountForTests() {
|
|
39477
|
+
return watchers.size;
|
|
39478
|
+
}
|
|
39479
|
+
};
|
|
39480
|
+
}
|
|
39481
|
+
|
|
38835
39482
|
// src/hooks/magic-context/text-complete.ts
|
|
38836
39483
|
function createTextCompleteHandler() {
|
|
38837
39484
|
return async (_input, output) => {
|
|
@@ -39232,7 +39879,7 @@ function memoryGuidanceBlock(memoryEnabled) {
|
|
|
39232
39879
|
` : "";
|
|
39233
39880
|
}
|
|
39234
39881
|
var BASE_INTRO = (memoryEnabled) => `Messages and tool outputs are tagged with §N§ identifiers (e.g., §1§, §42§).
|
|
39235
|
-
Use \`ctx_reduce\` to mark spent tagged content as discardable and reclaim space. Marking
|
|
39882
|
+
Use \`ctx_reduce\` to mark spent tagged content as discardable and reclaim space. Marking QUEUES content for release. It stays fully visible to you until it is actually released, which may be the next turn or many turns later. Mark a tool output as soon as you're done with it rather than hoarding the call for the end of the turn. The newest token-mass window stays protected until displaced. Syntax: "3-5", "1,2,9", or "1-5,8,12-15".
|
|
39236
39883
|
Do not announce or narrate \`ctx_reduce\` drops — just call the tool silently. Saying "I'll drop these outputs" wastes tokens the user does not care about.
|
|
39237
39884
|
${CTX_NOTE_GUIDANCE}
|
|
39238
39885
|
${memoryGuidanceBlock(memoryEnabled)}Use \`ctx_search\` to search across project memories, indexed git commits, and this session's full conversation history (including compacted parts) from one query.
|
|
@@ -39993,6 +40640,8 @@ function createMagicContextHook(deps) {
|
|
|
39993
40640
|
authoritySeed: (args) => transport.authoritySeed(args),
|
|
39994
40641
|
authorityDrain: (args) => transport.authorityDrain(args),
|
|
39995
40642
|
mirrorPull: (args) => transport.mirrorPull(args),
|
|
40643
|
+
mirrorMemory: (args) => transport.mirrorMemory(args),
|
|
40644
|
+
memoryIdentityAck: (args) => transport.memoryIdentityAck(args),
|
|
39996
40645
|
getCompartmentsAfter: async (sessionId, afterSequence) => {
|
|
39997
40646
|
const response = await transport.call({
|
|
39998
40647
|
sessionId,
|
|
@@ -40023,18 +40672,45 @@ function createMagicContextHook(deps) {
|
|
|
40023
40672
|
return client;
|
|
40024
40673
|
})();
|
|
40025
40674
|
const rustModeModuleClient = deps.config.transform_mode === "rust" ? authorityRecoveryModuleClient : undefined;
|
|
40026
|
-
const
|
|
40675
|
+
const rustRefusalRecovery = rustModeModuleClient ? createRustRefusalRecovery({
|
|
40676
|
+
moduleClient: rustModeModuleClient,
|
|
40677
|
+
client: deps.client
|
|
40678
|
+
}) : undefined;
|
|
40679
|
+
const syncModuleDomain = async (domain, pageBudget) => {
|
|
40027
40680
|
if (!rustModeModuleClient?.mirrorPull)
|
|
40028
40681
|
return;
|
|
40029
40682
|
await drainMirrorPages({
|
|
40030
40683
|
db,
|
|
40031
40684
|
module: rustModeModuleClient,
|
|
40032
40685
|
domain,
|
|
40033
|
-
limit: 1000
|
|
40686
|
+
limit: 1000,
|
|
40687
|
+
pageBudget
|
|
40034
40688
|
});
|
|
40035
40689
|
};
|
|
40036
40690
|
const syncModuleNotes = () => syncModuleDomain("notes");
|
|
40037
|
-
const
|
|
40691
|
+
const syncModuleMemoryIdentity = async (moduleProject, moduleRowId, projectRoot) => {
|
|
40692
|
+
if (!rustModeModuleClient?.mirrorMemory)
|
|
40693
|
+
return;
|
|
40694
|
+
const { row } = await rustModeModuleClient.mirrorMemory({
|
|
40695
|
+
module_row_id: moduleRowId,
|
|
40696
|
+
projectRoot
|
|
40697
|
+
});
|
|
40698
|
+
if (!row)
|
|
40699
|
+
return;
|
|
40700
|
+
const identity = applyTargetedMemoryMirrorRow({ db, row });
|
|
40701
|
+
if (!identity || !rustModeModuleClient.memoryIdentityAck)
|
|
40702
|
+
return;
|
|
40703
|
+
await rustModeModuleClient.memoryIdentityAck({
|
|
40704
|
+
project: moduleProject,
|
|
40705
|
+
projectRoot,
|
|
40706
|
+
rows: [
|
|
40707
|
+
{
|
|
40708
|
+
module_row_id: moduleRowId,
|
|
40709
|
+
context_row_id: identity.contextRowId
|
|
40710
|
+
}
|
|
40711
|
+
]
|
|
40712
|
+
});
|
|
40713
|
+
};
|
|
40038
40714
|
const rustToolBackends = deps.config.transform_mode === "rust" && rustModeModuleClient ? {
|
|
40039
40715
|
authorityState: async ({ projectPath, projectRoot, sessionId, domain }) => {
|
|
40040
40716
|
if (!rustModeModuleClient.authorityStatus)
|
|
@@ -40075,7 +40751,7 @@ function createMagicContextHook(deps) {
|
|
|
40075
40751
|
filter,
|
|
40076
40752
|
limit,
|
|
40077
40753
|
offset,
|
|
40078
|
-
|
|
40754
|
+
noteIds
|
|
40079
40755
|
}) => {
|
|
40080
40756
|
const response = await rustModeModuleClient.call({
|
|
40081
40757
|
sessionId,
|
|
@@ -40096,13 +40772,13 @@ function createMagicContextHook(deps) {
|
|
|
40096
40772
|
filter,
|
|
40097
40773
|
limit,
|
|
40098
40774
|
offset,
|
|
40099
|
-
|
|
40775
|
+
note_ids: noteIds
|
|
40100
40776
|
}
|
|
40101
40777
|
}
|
|
40102
40778
|
});
|
|
40103
40779
|
await syncModuleNotes();
|
|
40104
40780
|
if (compileStatus && !moduleNoteResponseIsError(response)) {
|
|
40105
|
-
const moduleRowId = action === "write" ? moduleNoteRowId(response) :
|
|
40781
|
+
const moduleRowId = action === "write" ? moduleNoteRowId(response) : noteIds?.[0] ?? null;
|
|
40106
40782
|
if (moduleRowId === null || !applyMirroredNoteCompileFields({
|
|
40107
40783
|
db,
|
|
40108
40784
|
moduleProject: memoryProject,
|
|
@@ -40131,6 +40807,11 @@ function createMagicContextHook(deps) {
|
|
|
40131
40807
|
reason,
|
|
40132
40808
|
limit
|
|
40133
40809
|
}) => {
|
|
40810
|
+
const hostIds = ids ?? [];
|
|
40811
|
+
const translatedIds = translateHostMemoryIds(db, hostIds);
|
|
40812
|
+
if ("error" in translatedIds)
|
|
40813
|
+
return translatedIds.error;
|
|
40814
|
+
const moduleIds = translatedIds.moduleIds;
|
|
40134
40815
|
const response = await rustModeModuleClient.call({
|
|
40135
40816
|
sessionId,
|
|
40136
40817
|
projectRoot,
|
|
@@ -40142,14 +40823,24 @@ function createMagicContextHook(deps) {
|
|
|
40142
40823
|
action,
|
|
40143
40824
|
content,
|
|
40144
40825
|
category,
|
|
40145
|
-
ids,
|
|
40826
|
+
ids: moduleIds,
|
|
40827
|
+
host_ids: hostIds,
|
|
40828
|
+
memory_id_lane: "host",
|
|
40146
40829
|
reason,
|
|
40147
40830
|
limit,
|
|
40148
40831
|
memory_project: memoryProject
|
|
40149
40832
|
}
|
|
40150
40833
|
}
|
|
40151
40834
|
});
|
|
40152
|
-
|
|
40835
|
+
const operation = moduleMemoryOperation(response);
|
|
40836
|
+
const newModuleRowId = operation?.action === "write" ? operation.module_id : operation?.action === "merge" ? operation.canonical_module_id : undefined;
|
|
40837
|
+
try {
|
|
40838
|
+
if (newModuleRowId !== undefined) {
|
|
40839
|
+
await syncModuleMemoryIdentity(memoryProject, newModuleRowId, projectRoot);
|
|
40840
|
+
}
|
|
40841
|
+
} catch (error) {
|
|
40842
|
+
log("[magic-context] targeted memory mirror sync failed:", error);
|
|
40843
|
+
}
|
|
40153
40844
|
if (!moduleNoteResponseIsError(response) && (action === "write" || action === "update" || action === "merge")) {
|
|
40154
40845
|
(async () => {
|
|
40155
40846
|
await ensureProjectRegisteredFromOpenCodeDirectory(projectRoot, db);
|
|
@@ -40161,7 +40852,13 @@ function createMagicContextHook(deps) {
|
|
|
40161
40852
|
log("[magic-context] mirrored memory embedding failed:", error);
|
|
40162
40853
|
});
|
|
40163
40854
|
}
|
|
40164
|
-
return
|
|
40855
|
+
return translateModuleMemoryMutationReply({
|
|
40856
|
+
db,
|
|
40857
|
+
moduleProject: memoryProject,
|
|
40858
|
+
response,
|
|
40859
|
+
requestedHostIds: hostIds,
|
|
40860
|
+
requestedCategory: category
|
|
40861
|
+
}) ?? response;
|
|
40165
40862
|
},
|
|
40166
40863
|
noteEvaluationAvailable: (evaluationProjectPath) => getModuleNoteEvaluationBridge(evaluationProjectPath) !== undefined,
|
|
40167
40864
|
memorySync: (sessionId) => {
|
|
@@ -40298,7 +40995,8 @@ function createMagicContextHook(deps) {
|
|
|
40298
40995
|
tsAuthorityRecoveryModuleClient: authorityRecoveryModuleClient,
|
|
40299
40996
|
rustMemorySyncRequestedSessions,
|
|
40300
40997
|
onRustModeParked: notifyRustModeParked,
|
|
40301
|
-
onRustModeProjectPrepared: ensureModuleNoteEvaluationBridge
|
|
40998
|
+
onRustModeProjectPrepared: ensureModuleNoteEvaluationBridge,
|
|
40999
|
+
onRustEngineReconnectRefusal: (args) => rustRefusalRecovery?.arm(args)
|
|
40302
41000
|
});
|
|
40303
41001
|
const eventHandler = createEventHandler2({
|
|
40304
41002
|
contextUsageMap,
|
|
@@ -40323,6 +41021,7 @@ function createMagicContextHook(deps) {
|
|
|
40323
41021
|
},
|
|
40324
41022
|
rustSessionCleanup: rustModeModuleClient !== undefined,
|
|
40325
41023
|
onSessionDeleted: async (sessionId) => {
|
|
41024
|
+
rustRefusalRecovery?.forget(sessionId);
|
|
40326
41025
|
dropSlot(sessionId, "session-deleted");
|
|
40327
41026
|
try {
|
|
40328
41027
|
await transform.clearRustSession(sessionId);
|
|
@@ -40965,6 +41664,46 @@ Two recovery modes for finer detail:
|
|
|
40965
41664
|
- ctx_expand(message=138) — returns the FULL untruncated content of the message at that ordinal: every text part, and every tool call's complete input + output, read from stored history. This is the cheap way to get back a tool output you dropped with ctx_reduce — the original is still in storage even though the wire shows [dropped §N§]. If the message was deleted from history (session prune/revert), it says so.`;
|
|
40966
41665
|
var CTX_EXPAND_TOKEN_BUDGET = 15000;
|
|
40967
41666
|
|
|
41667
|
+
// src/tools/ctx-expand/mode.ts
|
|
41668
|
+
function isInt(value) {
|
|
41669
|
+
return typeof value === "number" && Number.isInteger(value);
|
|
41670
|
+
}
|
|
41671
|
+
function minOrdinal(domain) {
|
|
41672
|
+
return domain === "non-negative" ? 0 : 1;
|
|
41673
|
+
}
|
|
41674
|
+
function messageError(domain) {
|
|
41675
|
+
return domain === "non-negative" ? "Error: message must be a non-negative integer." : "Error: message must be a positive integer.";
|
|
41676
|
+
}
|
|
41677
|
+
function rangeError(domain) {
|
|
41678
|
+
return domain === "non-negative" ? "Error: provide either message=<ordinal>, or start and end (non-negative integers, start <= end)." : "Error: provide either message=<ordinal>, or start and end (positive integers, start <= end).";
|
|
41679
|
+
}
|
|
41680
|
+
function resolveCtxExpandMode(args, domain) {
|
|
41681
|
+
const min = minOrdinal(domain);
|
|
41682
|
+
const messagePresent = args.message !== undefined && args.message !== null;
|
|
41683
|
+
const message = isInt(args.message) ? args.message : undefined;
|
|
41684
|
+
const start = isInt(args.start) ? args.start : undefined;
|
|
41685
|
+
const end = isInt(args.end) ? args.end : undefined;
|
|
41686
|
+
const messageValid = message !== undefined && message >= min;
|
|
41687
|
+
const rangeValid = start !== undefined && end !== undefined && start >= min && end >= start;
|
|
41688
|
+
const fillerPair = start === 0 && end === 0;
|
|
41689
|
+
const rangeNamed = rangeValid && !fillerPair;
|
|
41690
|
+
if (messageValid && !rangeNamed) {
|
|
41691
|
+
return { kind: "message", message };
|
|
41692
|
+
}
|
|
41693
|
+
if (messagePresent && !messageValid && !rangeNamed) {
|
|
41694
|
+
return { kind: "error", message: messageError(domain) };
|
|
41695
|
+
}
|
|
41696
|
+
if (rangeValid) {
|
|
41697
|
+
return {
|
|
41698
|
+
kind: "range",
|
|
41699
|
+
start,
|
|
41700
|
+
end,
|
|
41701
|
+
verbose: args.verbose === true
|
|
41702
|
+
};
|
|
41703
|
+
}
|
|
41704
|
+
return { kind: "error", message: rangeError(domain) };
|
|
41705
|
+
}
|
|
41706
|
+
|
|
40968
41707
|
// src/tools/ctx-expand/render.ts
|
|
40969
41708
|
function isRecord5(value) {
|
|
40970
41709
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
@@ -41158,27 +41897,26 @@ function createCtxExpandTool(deps) {
|
|
|
41158
41897
|
message: "number"
|
|
41159
41898
|
});
|
|
41160
41899
|
const sessionId = toolContext.sessionID;
|
|
41161
|
-
|
|
41162
|
-
|
|
41163
|
-
|
|
41164
|
-
}
|
|
41165
|
-
return renderMessageByOrdinal(sessionId, args.message);
|
|
41900
|
+
const mode = resolveCtxExpandMode(args, "positive");
|
|
41901
|
+
if (mode.kind === "error") {
|
|
41902
|
+
return mode.message;
|
|
41166
41903
|
}
|
|
41167
|
-
if (
|
|
41168
|
-
return
|
|
41904
|
+
if (mode.kind === "message") {
|
|
41905
|
+
return renderMessageByOrdinal(sessionId, mode.message);
|
|
41169
41906
|
}
|
|
41907
|
+
const { start, end, verbose } = mode;
|
|
41170
41908
|
const lastCompartmentEnd = getLastCompartmentEndMessage(deps.db, sessionId);
|
|
41171
|
-
if (lastCompartmentEnd >= 0 &&
|
|
41172
|
-
return `Range ${
|
|
41909
|
+
if (lastCompartmentEnd >= 0 && start > lastCompartmentEnd) {
|
|
41910
|
+
return `Range ${start}-${end} is entirely within the live tail (after the last compacted message ${lastCompartmentEnd}); those messages are already visible in context.`;
|
|
41173
41911
|
}
|
|
41174
|
-
const effectiveEnd = lastCompartmentEnd >= 0 ? Math.min(
|
|
41175
|
-
if (
|
|
41176
|
-
const v = renderVerboseRange(sessionId,
|
|
41912
|
+
const effectiveEnd = lastCompartmentEnd >= 0 ? Math.min(end, lastCompartmentEnd) : end;
|
|
41913
|
+
if (verbose) {
|
|
41914
|
+
const v = renderVerboseRange(sessionId, start, effectiveEnd, CTX_EXPAND_TOKEN_BUDGET);
|
|
41177
41915
|
if (!v.text) {
|
|
41178
|
-
return `No messages found in range ${
|
|
41916
|
+
return `No messages found in range ${start}-${effectiveEnd}. The range may be outside this session's history.`;
|
|
41179
41917
|
}
|
|
41180
41918
|
const out = [
|
|
41181
|
-
`Messages ${
|
|
41919
|
+
`Messages ${start}-${v.lastOrdinal} (verbose). Recover any one in full with ctx_expand(message=<ordinal>):`,
|
|
41182
41920
|
"",
|
|
41183
41921
|
v.text
|
|
41184
41922
|
];
|
|
@@ -41188,9 +41926,9 @@ function createCtxExpandTool(deps) {
|
|
|
41188
41926
|
return out.join(`
|
|
41189
41927
|
`);
|
|
41190
41928
|
}
|
|
41191
|
-
const chunk = readSessionChunk(sessionId, CTX_EXPAND_TOKEN_BUDGET,
|
|
41929
|
+
const chunk = readSessionChunk(sessionId, CTX_EXPAND_TOKEN_BUDGET, start, effectiveEnd + 1);
|
|
41192
41930
|
if (!chunk.text || chunk.messageCount === 0) {
|
|
41193
|
-
return `No messages found in range ${
|
|
41931
|
+
return `No messages found in range ${start}-${end}. The range may be outside this session's history.`;
|
|
41194
41932
|
}
|
|
41195
41933
|
const lines = [];
|
|
41196
41934
|
lines.push(`Messages ${chunk.startIndex}-${chunk.endIndex} (${chunk.messageCount} messages, ~${chunk.tokenEstimate} tokens):`);
|
|
@@ -41253,7 +41991,7 @@ function isMemoryCategory(value) {
|
|
|
41253
41991
|
return MEMORY_CATEGORIES.has(value);
|
|
41254
41992
|
}
|
|
41255
41993
|
function normalizeLimit2(limit) {
|
|
41256
|
-
if (typeof limit !== "number" || !Number.isFinite(limit)) {
|
|
41994
|
+
if (typeof limit !== "number" || !Number.isFinite(limit) || limit === 0) {
|
|
41257
41995
|
return DEFAULT_SEARCH_LIMIT;
|
|
41258
41996
|
}
|
|
41259
41997
|
return Math.max(1, Math.floor(limit));
|
|
@@ -41535,6 +42273,27 @@ function createCtxMemoryTool(deps) {
|
|
|
41535
42273
|
return "Error: Could not resolve project identity for memory action.";
|
|
41536
42274
|
}
|
|
41537
42275
|
await deps.ensureProjectRegistered?.(toolContext.directory, deps.db);
|
|
42276
|
+
const activeCurateCategory = toolContext.agent === DREAMER_AGENT ? getActiveCurateCategory(deps.db, projectPath) : null;
|
|
42277
|
+
if (activeCurateCategory) {
|
|
42278
|
+
const usesCategory = ["write", "update", "merge", "list"].includes(args.action);
|
|
42279
|
+
const usesIds = ["update", "archive", "merge", "get"].includes(args.action);
|
|
42280
|
+
const usesSuccessor = args.action === "update" || args.action === "archive";
|
|
42281
|
+
const scopeRefusal = getCurateCategoryScopeRefusal({
|
|
42282
|
+
scope: activeCurateCategory,
|
|
42283
|
+
action: args.action,
|
|
42284
|
+
requestedCategory: usesCategory ? args.category : undefined,
|
|
42285
|
+
ids: usesIds ? [
|
|
42286
|
+
...args.ids ?? [],
|
|
42287
|
+
...usesSuccessor && Number.isInteger(args.superseded_by) ? [args.superseded_by] : []
|
|
42288
|
+
] : [],
|
|
42289
|
+
categoryForId: (id) => {
|
|
42290
|
+
const category = getMemoryById(deps.db, id)?.category;
|
|
42291
|
+
return category ? curateCategoryForMemoryCategory(category) : null;
|
|
42292
|
+
}
|
|
42293
|
+
});
|
|
42294
|
+
if (scopeRefusal)
|
|
42295
|
+
return scopeRefusal;
|
|
42296
|
+
}
|
|
41538
42297
|
const curatePreflight = toolContext.agent === DREAMER_AGENT ? preflightCurateMutation({
|
|
41539
42298
|
db: deps.db,
|
|
41540
42299
|
params: args,
|
|
@@ -41669,7 +42428,8 @@ function createCtxMemoryTool(deps) {
|
|
|
41669
42428
|
if (args.action === "list") {
|
|
41670
42429
|
const limit = normalizeLimit2(args.limit);
|
|
41671
42430
|
const category = normalizeCategory(args.category);
|
|
41672
|
-
const
|
|
42431
|
+
const allMemories = getMemoriesByProject(deps.db, projectPath);
|
|
42432
|
+
const memories = (activeCurateCategory ? allMemories.filter((memory) => curateCategoryForMemoryCategory(memory.category) === activeCurateCategory) : filterByCategory(allMemories, category)).slice(0, limit);
|
|
41673
42433
|
return formatMemoryList(memories);
|
|
41674
42434
|
}
|
|
41675
42435
|
if (args.action === "get") {
|
|
@@ -41926,7 +42686,7 @@ Use a note when something matters LATER but not in the next few steps: "revisit
|
|
|
41926
42686
|
Actions:
|
|
41927
42687
|
- write: save a note (content). Add surface_condition to make it a smart note (below).
|
|
41928
42688
|
- read: list notes, newest first. Default: latest active session notes + ready smart notes; page older ones with limit/offset, or inspect other states with filter.
|
|
41929
|
-
- update: change
|
|
42689
|
+
- update: change one note (note_ids=[N]). dismiss: retire 1–50 notes (note_ids=[...]).
|
|
41930
42690
|
|
|
41931
42691
|
Smart notes: pass surface_condition and the note stays hidden until a background checker confirms the condition — using ONLY externally verifiable signals (GitHub state via gh, files on disk, git history, web pages). It cannot see this conversation, so the condition must be checkable from outside:
|
|
41932
42692
|
✓ "When PR #42 in cortexkit/magic-context is merged"
|
|
@@ -41939,7 +42699,7 @@ Example: ctx_note(action="write", content="Re-run the perf benchmark once the bo
|
|
|
41939
42699
|
import { tool as tool3 } from "@opencode-ai/plugin";
|
|
41940
42700
|
|
|
41941
42701
|
// src/features/magic-context/smart-notes/condition-compiler.ts
|
|
41942
|
-
import { existsSync as
|
|
42702
|
+
import { existsSync as existsSync13 } from "node:fs";
|
|
41943
42703
|
import { isAbsolute as isAbsolute4 } from "node:path";
|
|
41944
42704
|
|
|
41945
42705
|
// ../retina-local-fs/src/path-fence.ts
|
|
@@ -42196,7 +42956,7 @@ async function compileSurfaceCondition(surfaceCondition, options) {
|
|
|
42196
42956
|
dataDirectory: options.dataDirectory,
|
|
42197
42957
|
cwd: options.projectPath
|
|
42198
42958
|
});
|
|
42199
|
-
return { path: resolved, exists:
|
|
42959
|
+
return { path: resolved, exists: existsSync13(resolved) };
|
|
42200
42960
|
});
|
|
42201
42961
|
let predicates;
|
|
42202
42962
|
try {
|
|
@@ -42451,7 +43211,7 @@ function formatNoteLine(note) {
|
|
|
42451
43211
|
}
|
|
42452
43212
|
var DISMISS_FOOTER = `
|
|
42453
43213
|
|
|
42454
|
-
To dismiss a stale note: ctx_note(action="dismiss",
|
|
43214
|
+
To dismiss a stale note: ctx_note(action="dismiss", note_ids=[N])`;
|
|
42455
43215
|
var DEFAULT_READ_LIMIT = 25;
|
|
42456
43216
|
function paginateNewestFirst(notes, limit, offset) {
|
|
42457
43217
|
const total = notes.length;
|
|
@@ -42566,8 +43326,7 @@ var ctxNoteArgsShape = {
|
|
|
42566
43326
|
filter: tool3.schema.enum(["all", "active", "pending", "ready", "dismissed"]).optional().describe("Optional read filter. Defaults to active session notes + ready smart notes. Use 'all' to inspect every status or 'pending' to inspect unsurfaced smart notes."),
|
|
42567
43327
|
limit: tool3.schema.number().optional().describe("Max notes per section for read, newest first (default: 25)"),
|
|
42568
43328
|
offset: tool3.schema.number().optional().describe("Skip this many newest notes for read — page older ones (default: 0)"),
|
|
42569
|
-
|
|
42570
|
-
note_ids: tool3.schema.array(tool3.schema.number().int().min(1)).min(1).max(50).optional().describe("One to fifty note ids for 'dismiss' only; do not combine with note_id.")
|
|
43329
|
+
note_ids: tool3.schema.array(tool3.schema.number().int().min(1)).min(1).max(50).optional().describe("Note ids: exactly one for 'update', one to fifty for 'dismiss'. Ignored by 'write' and 'read'.")
|
|
42571
43330
|
};
|
|
42572
43331
|
var ctxNoteArgsSchema = tool3.schema.object(ctxNoteArgsShape).passthrough();
|
|
42573
43332
|
function formatDismissResults(results) {
|
|
@@ -42576,9 +43335,10 @@ function formatDismissResults(results) {
|
|
|
42576
43335
|
${results.map((result) => `- Note #${result.noteId}: ${result.outcome}`).join(`
|
|
42577
43336
|
`)}`;
|
|
42578
43337
|
}
|
|
42579
|
-
function
|
|
42580
|
-
|
|
42581
|
-
|
|
43338
|
+
function parseNoteIds(action, value) {
|
|
43339
|
+
const max = action === "update" ? 1 : 50;
|
|
43340
|
+
if (!Array.isArray(value) || value.length < 1 || value.length > max || value.some((id) => typeof id !== "number" || !Number.isInteger(id) || id <= 0)) {
|
|
43341
|
+
return action === "update" ? "Error: 'note_ids' must contain exactly one positive integer id when action is 'update'." : "Error: 'note_ids' must contain 1 to 50 positive integer ids when action is 'dismiss'.";
|
|
42582
43342
|
}
|
|
42583
43343
|
return value;
|
|
42584
43344
|
}
|
|
@@ -42599,22 +43359,13 @@ function createCtxNoteTool(deps) {
|
|
|
42599
43359
|
},
|
|
42600
43360
|
limit: "number",
|
|
42601
43361
|
offset: "number",
|
|
42602
|
-
note_id: "number",
|
|
42603
43362
|
note_ids: { type: "array", items: "number", maxItems: 50 }
|
|
42604
43363
|
});
|
|
42605
43364
|
const sessionId = toolContext.sessionID;
|
|
42606
43365
|
const action = args.action ?? (args.content?.trim() ? "write" : "read");
|
|
42607
|
-
const
|
|
42608
|
-
|
|
42609
|
-
|
|
42610
|
-
return "Error: 'note_id' and 'note_ids' cannot be used together; provide one or the other.";
|
|
42611
|
-
}
|
|
42612
|
-
if (hasNoteIds && action !== "dismiss") {
|
|
42613
|
-
return "Error: 'note_ids' is only valid when action is 'dismiss'.";
|
|
42614
|
-
}
|
|
42615
|
-
const dismissNoteIds = action === "dismiss" && hasNoteIds ? parseDismissNoteIds(args.note_ids) : undefined;
|
|
42616
|
-
if (typeof dismissNoteIds === "string")
|
|
42617
|
-
return dismissNoteIds;
|
|
43366
|
+
const noteIds = action === "dismiss" || action === "update" ? parseNoteIds(action, args.note_ids) : undefined;
|
|
43367
|
+
if (typeof noteIds === "string")
|
|
43368
|
+
return noteIds;
|
|
42618
43369
|
const wakePlaneActive = action === "write" && Boolean(args.surface_condition?.trim()) && await wakePlaneStatus() === "present";
|
|
42619
43370
|
const surfaceCondition = wakePlaneActive ? undefined : args.surface_condition?.trim();
|
|
42620
43371
|
const projectIdentity = deps.resolveProjectPath?.(toolContext.directory);
|
|
@@ -42663,8 +43414,7 @@ function createCtxNoteTool(deps) {
|
|
|
42663
43414
|
filter: args.filter,
|
|
42664
43415
|
limit: args.limit,
|
|
42665
43416
|
offset: args.offset,
|
|
42666
|
-
|
|
42667
|
-
noteIds: dismissNoteIds
|
|
43417
|
+
noteIds: Array.isArray(noteIds) ? noteIds : undefined
|
|
42668
43418
|
};
|
|
42669
43419
|
try {
|
|
42670
43420
|
const text = moduleNoteText(await rustNote(request), args, action);
|
|
@@ -42733,33 +43483,24 @@ wake plane active — create a scheduled wake instead; stored as a plain note.`;
|
|
|
42733
43483
|
return `Saved session note #${note.id}.`;
|
|
42734
43484
|
}
|
|
42735
43485
|
if (action === "dismiss") {
|
|
42736
|
-
if (dismissNoteIds) {
|
|
42737
|
-
if (!projectIdentity) {
|
|
42738
|
-
return "Error: Could not resolve project identity for note dismiss.";
|
|
42739
|
-
}
|
|
42740
|
-
return formatDismissResults(dismissNotes(deps.db, dismissNoteIds, {
|
|
42741
|
-
projectPath: projectIdentity,
|
|
42742
|
-
sessionId
|
|
42743
|
-
}));
|
|
42744
|
-
}
|
|
42745
|
-
const noteId = args.note_id;
|
|
42746
|
-
if (typeof noteId !== "number") {
|
|
42747
|
-
return "Error: 'note_id' is required when action is 'dismiss'.";
|
|
42748
|
-
}
|
|
42749
43486
|
if (!projectIdentity) {
|
|
42750
43487
|
return "Error: Could not resolve project identity for note dismiss.";
|
|
42751
43488
|
}
|
|
42752
|
-
const
|
|
43489
|
+
const ids = noteIds;
|
|
43490
|
+
if (ids.length === 1) {
|
|
43491
|
+
const dismissed = dismissNote(deps.db, ids[0], {
|
|
43492
|
+
projectPath: projectIdentity,
|
|
43493
|
+
sessionId
|
|
43494
|
+
});
|
|
43495
|
+
return dismissed ? `Note #${ids[0]} dismissed.` : `Error: Note #${ids[0]} not found in your session/project or already dismissed.`;
|
|
43496
|
+
}
|
|
43497
|
+
return formatDismissResults(dismissNotes(deps.db, ids, {
|
|
42753
43498
|
projectPath: projectIdentity,
|
|
42754
43499
|
sessionId
|
|
42755
|
-
});
|
|
42756
|
-
return dismissed ? `Note #${noteId} dismissed.` : `Error: Note #${noteId} not found in your session/project or already dismissed.`;
|
|
43500
|
+
}));
|
|
42757
43501
|
}
|
|
42758
43502
|
if (action === "update") {
|
|
42759
|
-
const noteId =
|
|
42760
|
-
if (typeof noteId !== "number") {
|
|
42761
|
-
return "Error: 'note_id' is required when action is 'update'.";
|
|
42762
|
-
}
|
|
43503
|
+
const noteId = noteIds[0];
|
|
42763
43504
|
const updates = {};
|
|
42764
43505
|
if (args.content?.trim())
|
|
42765
43506
|
updates.content = args.content.trim();
|
|
@@ -42831,7 +43572,7 @@ function createCtxNoteTools(deps) {
|
|
|
42831
43572
|
var CTX_REDUCE_DESCRIPTION = `Mark spent tagged content as discardable to reclaim context space. This is NOT an immediate delete. Use §N§ identifiers visible in the conversation. The \`drop\` param accepts ranges: "3-5", "1,2,9", "1-5,8".
|
|
42832
43573
|
|
|
42833
43574
|
How it works:
|
|
42834
|
-
- Marking QUEUES content for release. It stays fully visible to you until
|
|
43575
|
+
- Marking QUEUES content for release. It stays fully visible to you until it is actually released, which may be the next turn or many turns later. Mark spent outputs as soon as you finish with them; don't hoard the call for the end of the turn.
|
|
42835
43576
|
- The newest tags are protected: marking one just queues it until it ages out of the recent window, so marking recent output is harmless.
|
|
42836
43577
|
- When content is finally released it becomes a short placeholder, and re-running the tool is the only way to get it back. So mark only what you are genuinely DONE with — the test is "have I extracted what I need from this?", not "is it safe / do I have time before it drops?".
|
|
42837
43578
|
|
|
@@ -43076,7 +43817,7 @@ var VALID_SOURCES = new Set([
|
|
|
43076
43817
|
"note"
|
|
43077
43818
|
]);
|
|
43078
43819
|
function normalizeLimit3(limit) {
|
|
43079
|
-
if (typeof limit !== "number" || !Number.isFinite(limit)) {
|
|
43820
|
+
if (typeof limit !== "number" || !Number.isFinite(limit) || limit === 0) {
|
|
43080
43821
|
return DEFAULT_CTX_SEARCH_LIMIT;
|
|
43081
43822
|
}
|
|
43082
43823
|
return Math.max(1, Math.floor(limit));
|
|
@@ -43095,7 +43836,7 @@ function normalizeSources(sources) {
|
|
|
43095
43836
|
}
|
|
43096
43837
|
}
|
|
43097
43838
|
}
|
|
43098
|
-
return result;
|
|
43839
|
+
return sources.length === 0 ? undefined : result;
|
|
43099
43840
|
}
|
|
43100
43841
|
var ctxSearchArgsShape = {
|
|
43101
43842
|
query: tool5.schema.string().optional().describe("Search query. Matches against memory content, Primers, git commit messages, and raw user/assistant message text."),
|
|
@@ -43322,7 +44063,7 @@ import {
|
|
|
43322
44063
|
chmodSync as chmodSync2,
|
|
43323
44064
|
mkdirSync as mkdirSync4,
|
|
43324
44065
|
readdirSync,
|
|
43325
|
-
readFileSync as
|
|
44066
|
+
readFileSync as readFileSync7,
|
|
43326
44067
|
renameSync as renameSync5,
|
|
43327
44068
|
rmSync as rmSync4,
|
|
43328
44069
|
unlinkSync as unlinkSync2,
|
|
@@ -43459,7 +44200,7 @@ class MagicContextRpcServer {
|
|
|
43459
44200
|
for (const entry of readdirSync(this.portDir)) {
|
|
43460
44201
|
if (!entry.startsWith("port-") || !entry.endsWith(".json"))
|
|
43461
44202
|
continue;
|
|
43462
|
-
const record = parseRpcPortFile(
|
|
44203
|
+
const record = parseRpcPortFile(readFileSync7(`${this.portDir}/${entry}`, "utf-8"));
|
|
43463
44204
|
if (!record || record.pid === process.pid || !isPidAlive(record.pid))
|
|
43464
44205
|
continue;
|
|
43465
44206
|
log(`[rpc] another Magic Context RPC server is active for this project (pid ${record.pid}, port ${record.port}); starting separate instance on a new port`);
|
|
@@ -43853,7 +44594,240 @@ ${data.output?.output ?? ""}`
|
|
|
43853
44594
|
return [...content.length ? [make("assistant", content)] : [], ...results];
|
|
43854
44595
|
}
|
|
43855
44596
|
|
|
44597
|
+
// src/v2/hooks/hidden-child.ts
|
|
44598
|
+
var HIDDEN_HISTORIAN_AGENT = "historian";
|
|
44599
|
+
var HIDDEN_DREAMER_AGENT = "dreamer-classifier";
|
|
44600
|
+
async function registerHiddenChildAgents(agent) {
|
|
44601
|
+
await agent.transform((editor) => {
|
|
44602
|
+
for (const id of [HIDDEN_HISTORIAN_AGENT, HIDDEN_DREAMER_AGENT]) {
|
|
44603
|
+
editor.update(id, (config) => {
|
|
44604
|
+
config.system = "Magic Context hidden completion carrier.";
|
|
44605
|
+
config.description = "Internal Magic Context hidden completion carrier.";
|
|
44606
|
+
config.mode = "primary";
|
|
44607
|
+
config.hidden = true;
|
|
44608
|
+
config.request.settings = {};
|
|
44609
|
+
config.request.headers = {};
|
|
44610
|
+
config.request.body = {};
|
|
44611
|
+
config.permissions = [{ action: "*", resource: "*", effect: "deny" }];
|
|
44612
|
+
});
|
|
44613
|
+
}
|
|
44614
|
+
});
|
|
44615
|
+
}
|
|
44616
|
+
function newestUserText(draft) {
|
|
44617
|
+
const message = draft.messages.at(-1);
|
|
44618
|
+
if (!message || message.role !== undefined && message.role !== "user")
|
|
44619
|
+
return;
|
|
44620
|
+
const content = message.content;
|
|
44621
|
+
if (typeof content === "string" && content.length > 0)
|
|
44622
|
+
return content;
|
|
44623
|
+
const parts = Array.isArray(content) ? content : Array.isArray(message.parts) ? message.parts : [];
|
|
44624
|
+
for (const part of parts) {
|
|
44625
|
+
if (!part || typeof part !== "object")
|
|
44626
|
+
continue;
|
|
44627
|
+
const record = part;
|
|
44628
|
+
if (typeof record.text !== "string" || record.text.length === 0)
|
|
44629
|
+
continue;
|
|
44630
|
+
if (record.type === undefined || record.type === "text" || record.type === "input_text") {
|
|
44631
|
+
return record.text;
|
|
44632
|
+
}
|
|
44633
|
+
}
|
|
44634
|
+
return;
|
|
44635
|
+
}
|
|
44636
|
+
function calibratedParts(attempt) {
|
|
44637
|
+
const parts = attempt.request.body.parts;
|
|
44638
|
+
if (!Array.isArray(parts) || parts.length === 0 || parts.some((part) => !part || typeof part !== "object" || part.type !== "text" || typeof part.text !== "string")) {
|
|
44639
|
+
throw new HiddenCompletionRefusal("hidden_prompt_unrecognized", "Hidden completion accepts text-only calibrated prompts", true);
|
|
44640
|
+
}
|
|
44641
|
+
return parts.map((part) => ({ type: "text", text: part.text }));
|
|
44642
|
+
}
|
|
44643
|
+
|
|
44644
|
+
class HiddenChildHook {
|
|
44645
|
+
childIDs = new Set;
|
|
44646
|
+
attempts = new Map;
|
|
44647
|
+
registerChild(sessionID) {
|
|
44648
|
+
this.childIDs.add(sessionID);
|
|
44649
|
+
}
|
|
44650
|
+
registerAttempt(marker, attempt) {
|
|
44651
|
+
this.registerChild(attempt.childSessionId);
|
|
44652
|
+
this.attempts.set(marker, attempt);
|
|
44653
|
+
}
|
|
44654
|
+
releaseAttempt(marker) {
|
|
44655
|
+
this.attempts.delete(marker);
|
|
44656
|
+
}
|
|
44657
|
+
owns(sessionID) {
|
|
44658
|
+
return this.childIDs.has(sessionID);
|
|
44659
|
+
}
|
|
44660
|
+
apply(draft) {
|
|
44661
|
+
if (!this.owns(draft.sessionID))
|
|
44662
|
+
return false;
|
|
44663
|
+
const raw = newestUserText(draft);
|
|
44664
|
+
const stripped = raw === undefined ? undefined : stripWellFormedLeadingTagPrefix(raw);
|
|
44665
|
+
const attempt = (raw !== undefined ? this.attempts.get(raw) : undefined) ?? (stripped && stripped !== raw ? this.attempts.get(stripped) : undefined);
|
|
44666
|
+
if (!attempt || attempt.childSessionId !== draft.sessionID) {
|
|
44667
|
+
throw new HiddenCompletionRefusal("hidden_prompt_unrecognized", "Refusing an unregistered prompt on a Magic Context hidden-run session", true);
|
|
44668
|
+
}
|
|
44669
|
+
if (attempt.request.signal?.aborted) {
|
|
44670
|
+
throw new Error("Hidden completion prompt aborted");
|
|
44671
|
+
}
|
|
44672
|
+
const system = typeof attempt.request.body.system === "string" ? attempt.request.body.system : attempt.identity.system;
|
|
44673
|
+
const temperature = attempt.request.body.temperature;
|
|
44674
|
+
draft.system = [{ type: "text", text: system }];
|
|
44675
|
+
draft.messages = [{ role: "user", content: calibratedParts(attempt) }];
|
|
44676
|
+
draft.options = {
|
|
44677
|
+
maxOutputTokens: 32768,
|
|
44678
|
+
maxTokens: 32768,
|
|
44679
|
+
...typeof temperature === "number" && Number.isFinite(temperature) ? { temperature } : {}
|
|
44680
|
+
};
|
|
44681
|
+
draft.tools = {};
|
|
44682
|
+
attempt.shaped = true;
|
|
44683
|
+
return true;
|
|
44684
|
+
}
|
|
44685
|
+
}
|
|
44686
|
+
|
|
43856
44687
|
// src/v2/hidden-completion.ts
|
|
44688
|
+
var META_PREFIX = "opencode2_hidden_children:";
|
|
44689
|
+
var POLL_INTERVAL_MS = 200;
|
|
44690
|
+
function hiddenChildrenMetaKey(projectIdentity) {
|
|
44691
|
+
return `${META_PREFIX}${projectIdentity}`;
|
|
44692
|
+
}
|
|
44693
|
+
function emptyMeta() {
|
|
44694
|
+
return { version: 1, active: {}, retired_children: [] };
|
|
44695
|
+
}
|
|
44696
|
+
function isModel(value) {
|
|
44697
|
+
if (!value || typeof value !== "object")
|
|
44698
|
+
return false;
|
|
44699
|
+
const model = value;
|
|
44700
|
+
return typeof model.providerID === "string" && typeof model.modelID === "string";
|
|
44701
|
+
}
|
|
44702
|
+
function isRole(value) {
|
|
44703
|
+
return value === "historian" || value === "dreamer";
|
|
44704
|
+
}
|
|
44705
|
+
function isPersistedChild(value) {
|
|
44706
|
+
if (!value || typeof value !== "object")
|
|
44707
|
+
return false;
|
|
44708
|
+
const child = value;
|
|
44709
|
+
return typeof child.id === "string" && isRole(child.role) && typeof child.generation === "string" && typeof child.title === "string" && isModel(child.model) && typeof child.created_at === "number" && typeof child.title_reasserted === "boolean";
|
|
44710
|
+
}
|
|
44711
|
+
function parseMeta(value) {
|
|
44712
|
+
if (value === null)
|
|
44713
|
+
return emptyMeta();
|
|
44714
|
+
let parsed;
|
|
44715
|
+
try {
|
|
44716
|
+
parsed = JSON.parse(value);
|
|
44717
|
+
} catch (error) {
|
|
44718
|
+
throw new Error("Invalid OpenCode 2 hidden-child metadata JSON", { cause: error });
|
|
44719
|
+
}
|
|
44720
|
+
if (!parsed || typeof parsed !== "object") {
|
|
44721
|
+
throw new Error("Invalid OpenCode 2 hidden-child metadata");
|
|
44722
|
+
}
|
|
44723
|
+
const candidate = parsed;
|
|
44724
|
+
if (candidate.version !== 1 || !candidate.active || !candidate.retired_children) {
|
|
44725
|
+
throw new Error("Unsupported OpenCode 2 hidden-child metadata version");
|
|
44726
|
+
}
|
|
44727
|
+
const active = {};
|
|
44728
|
+
for (const role of ["historian", "dreamer"]) {
|
|
44729
|
+
const child = candidate.active[role];
|
|
44730
|
+
if (child !== undefined) {
|
|
44731
|
+
if (!isPersistedChild(child) || child.role !== role) {
|
|
44732
|
+
throw new Error(`Invalid OpenCode 2 ${role} child metadata`);
|
|
44733
|
+
}
|
|
44734
|
+
active[role] = child;
|
|
44735
|
+
}
|
|
44736
|
+
}
|
|
44737
|
+
const retired = candidate.retired_children;
|
|
44738
|
+
if (!Array.isArray(retired) || retired.some((child) => !isPersistedChild(child) || typeof child.retired_at !== "number" || typeof child.reason !== "string")) {
|
|
44739
|
+
throw new Error("Invalid OpenCode 2 retired-child metadata");
|
|
44740
|
+
}
|
|
44741
|
+
return { version: 1, active, retired_children: retired };
|
|
44742
|
+
}
|
|
44743
|
+
|
|
44744
|
+
class HiddenChildStateStore {
|
|
44745
|
+
db;
|
|
44746
|
+
key;
|
|
44747
|
+
constructor(db, projectIdentity) {
|
|
44748
|
+
this.db = db;
|
|
44749
|
+
this.key = hiddenChildrenMetaKey(projectIdentity);
|
|
44750
|
+
}
|
|
44751
|
+
read() {
|
|
44752
|
+
const row = this.db.prepare("SELECT value FROM schema_migrations_meta WHERE key = ?").get(this.key);
|
|
44753
|
+
return parseMeta(row?.value ?? null);
|
|
44754
|
+
}
|
|
44755
|
+
mutate(change) {
|
|
44756
|
+
return this.db.transaction(() => {
|
|
44757
|
+
const state = this.read();
|
|
44758
|
+
const result = change(state);
|
|
44759
|
+
this.db.prepare(`INSERT INTO schema_migrations_meta (key, value) VALUES (?, ?)
|
|
44760
|
+
ON CONFLICT(key) DO UPDATE SET value = excluded.value`).run(this.key, JSON.stringify(state));
|
|
44761
|
+
return result;
|
|
44762
|
+
})();
|
|
44763
|
+
}
|
|
44764
|
+
put(child) {
|
|
44765
|
+
this.mutate((state) => {
|
|
44766
|
+
state.active[child.role] = child;
|
|
44767
|
+
});
|
|
44768
|
+
}
|
|
44769
|
+
updateModel(child, model) {
|
|
44770
|
+
return this.mutate((state) => {
|
|
44771
|
+
const active = state.active[child.role];
|
|
44772
|
+
if (!active || active.id !== child.id)
|
|
44773
|
+
return { ...child, model };
|
|
44774
|
+
active.model = model;
|
|
44775
|
+
return { ...active };
|
|
44776
|
+
});
|
|
44777
|
+
}
|
|
44778
|
+
markTitleReasserted(child) {
|
|
44779
|
+
return this.mutate((state) => {
|
|
44780
|
+
const active = state.active[child.role];
|
|
44781
|
+
if (!active || active.id !== child.id)
|
|
44782
|
+
return { ...child, title_reasserted: true };
|
|
44783
|
+
active.title_reasserted = true;
|
|
44784
|
+
return { ...active };
|
|
44785
|
+
});
|
|
44786
|
+
}
|
|
44787
|
+
retire(child, reason) {
|
|
44788
|
+
this.mutate((state) => {
|
|
44789
|
+
const active = state.active[child.role];
|
|
44790
|
+
if (!active || active.id !== child.id)
|
|
44791
|
+
return;
|
|
44792
|
+
state.retired_children.push({
|
|
44793
|
+
...active,
|
|
44794
|
+
retired_at: Date.now(),
|
|
44795
|
+
reason
|
|
44796
|
+
});
|
|
44797
|
+
delete state.active[child.role];
|
|
44798
|
+
});
|
|
44799
|
+
}
|
|
44800
|
+
}
|
|
44801
|
+
function modelKey(model) {
|
|
44802
|
+
return `${model.providerID}/${model.modelID}`;
|
|
44803
|
+
}
|
|
44804
|
+
function sameModel(left, right) {
|
|
44805
|
+
return modelKey(left) === modelKey(right) && left.variant === right.variant;
|
|
44806
|
+
}
|
|
44807
|
+
function configuredHead(identity) {
|
|
44808
|
+
const candidates = [identity.model, ...identity.configuredModels ?? []];
|
|
44809
|
+
for (const candidate of candidates) {
|
|
44810
|
+
const entry = toModelEntry(candidate);
|
|
44811
|
+
const parsed = entry ? parseProviderModel(entry.model) : null;
|
|
44812
|
+
if (parsed)
|
|
44813
|
+
return { ...parsed, ...entry?.qualifier ? { variant: entry.qualifier } : {} };
|
|
44814
|
+
}
|
|
44815
|
+
return;
|
|
44816
|
+
}
|
|
44817
|
+
function roleFor(identity) {
|
|
44818
|
+
return identity.kind === "dreamer-task" ? "dreamer" : "historian";
|
|
44819
|
+
}
|
|
44820
|
+
function roleTitle(role) {
|
|
44821
|
+
return role === "historian" ? "Magic Context historian" : "Magic Context dreamer";
|
|
44822
|
+
}
|
|
44823
|
+
function roleAgent(role) {
|
|
44824
|
+
return role === "historian" ? HIDDEN_HISTORIAN_AGENT : HIDDEN_DREAMER_AGENT;
|
|
44825
|
+
}
|
|
44826
|
+
function promptText(request) {
|
|
44827
|
+
const parts = request.body.parts;
|
|
44828
|
+
return Array.isArray(parts) ? parts.flatMap((part) => part && typeof part === "object" && typeof part.text === "string" ? [part.text] : []).join(`
|
|
44829
|
+
`) : "";
|
|
44830
|
+
}
|
|
43857
44831
|
function meter(system, prompt, text) {
|
|
43858
44832
|
return {
|
|
43859
44833
|
input: estimateTokens(system) + estimateTokens(prompt),
|
|
@@ -43862,115 +44836,294 @@ function meter(system, prompt, text) {
|
|
|
43862
44836
|
cacheWrite: 0
|
|
43863
44837
|
};
|
|
43864
44838
|
}
|
|
43865
|
-
|
|
44839
|
+
function successfulReusableAssistant(row) {
|
|
44840
|
+
return row !== undefined && typeof row.data.finish === "string" && row.data.error === undefined && row.data.tokens !== undefined;
|
|
44841
|
+
}
|
|
44842
|
+
function assistantText(row) {
|
|
44843
|
+
const text = (row.data.content ?? []).flatMap((part) => part.type === "text" && typeof part.text === "string" ? [part.text] : []).join("");
|
|
44844
|
+
return text.length > 0 ? text : null;
|
|
44845
|
+
}
|
|
44846
|
+
function errorText(value) {
|
|
44847
|
+
if (value instanceof Error)
|
|
44848
|
+
return value.message;
|
|
44849
|
+
if (typeof value === "string")
|
|
44850
|
+
return value;
|
|
44851
|
+
try {
|
|
44852
|
+
return JSON.stringify(value);
|
|
44853
|
+
} catch {
|
|
44854
|
+
return String(value);
|
|
44855
|
+
}
|
|
44856
|
+
}
|
|
44857
|
+
function requestModel(request, current) {
|
|
44858
|
+
const requested = request.body.model;
|
|
44859
|
+
if (requested && typeof requested.providerID === "string" && typeof requested.modelID === "string") {
|
|
44860
|
+
return {
|
|
44861
|
+
providerID: requested.providerID,
|
|
44862
|
+
modelID: requested.modelID,
|
|
44863
|
+
...typeof request.body.variant === "string" ? { variant: request.body.variant } : {}
|
|
44864
|
+
};
|
|
44865
|
+
}
|
|
44866
|
+
return current;
|
|
44867
|
+
}
|
|
44868
|
+
function withReader(openReader, read) {
|
|
44869
|
+
const reader = openReader();
|
|
44870
|
+
try {
|
|
44871
|
+
return read(reader);
|
|
44872
|
+
} finally {
|
|
44873
|
+
reader.close?.();
|
|
44874
|
+
}
|
|
44875
|
+
}
|
|
44876
|
+
async function sleepUntilPoll(signal, deadline) {
|
|
44877
|
+
if (signal?.aborted)
|
|
44878
|
+
throw new Error("Hidden completion prompt aborted");
|
|
44879
|
+
const delay = Math.min(POLL_INTERVAL_MS, Math.max(0, deadline - Date.now()));
|
|
44880
|
+
if (delay <= 0)
|
|
44881
|
+
return;
|
|
44882
|
+
await new Promise((resolve, reject) => {
|
|
44883
|
+
const timer = setTimeout(resolve, delay);
|
|
44884
|
+
const abort = () => {
|
|
44885
|
+
clearTimeout(timer);
|
|
44886
|
+
reject(new Error("Hidden completion prompt aborted"));
|
|
44887
|
+
};
|
|
44888
|
+
signal?.addEventListener("abort", abort, { once: true });
|
|
44889
|
+
if (signal?.aborted)
|
|
44890
|
+
abort();
|
|
44891
|
+
else
|
|
44892
|
+
setTimeout(() => {
|
|
44893
|
+
signal?.removeEventListener("abort", abort);
|
|
44894
|
+
}, delay);
|
|
44895
|
+
});
|
|
44896
|
+
}
|
|
44897
|
+
async function awaitAssistantRow(openReader, childID, afterSeq, deadline, signal) {
|
|
44898
|
+
for (;; ) {
|
|
44899
|
+
const row = withReader(openReader, (reader) => reader.latestAssistant(childID));
|
|
44900
|
+
if (row && row.seq > afterSeq) {
|
|
44901
|
+
if (row.data.error !== undefined) {
|
|
44902
|
+
throw new Error(`Hidden completion provider error: ${errorText(row.data.error)}`);
|
|
44903
|
+
}
|
|
44904
|
+
if (typeof row.data.finish === "string")
|
|
44905
|
+
return row;
|
|
44906
|
+
}
|
|
44907
|
+
if (Date.now() >= deadline) {
|
|
44908
|
+
throw new Error("Hidden completion timed out waiting for a persisted assistant row");
|
|
44909
|
+
}
|
|
44910
|
+
await sleepUntilPoll(signal, deadline);
|
|
44911
|
+
}
|
|
44912
|
+
}
|
|
44913
|
+
async function createV2HiddenCompletionExecutor(host, options) {
|
|
43866
44914
|
const runs = new WeakMap;
|
|
43867
|
-
const
|
|
43868
|
-
const
|
|
43869
|
-
const
|
|
43870
|
-
|
|
43871
|
-
|
|
43872
|
-
|
|
43873
|
-
|
|
43874
|
-
}
|
|
43875
|
-
const
|
|
43876
|
-
|
|
43877
|
-
|
|
43878
|
-
|
|
43879
|
-
|
|
43880
|
-
|
|
43881
|
-
|
|
43882
|
-
|
|
43883
|
-
|
|
43884
|
-
|
|
43885
|
-
|
|
43886
|
-
|
|
43887
|
-
|
|
43888
|
-
|
|
43889
|
-
|
|
43890
|
-
|
|
43891
|
-
|
|
43892
|
-
|
|
43893
|
-
|
|
43894
|
-
if (
|
|
43895
|
-
|
|
44915
|
+
const store = new HiddenChildStateStore(options.db, options.projectIdentity);
|
|
44916
|
+
const generation = options.generation ?? "opencode2";
|
|
44917
|
+
const roleTails = new Map;
|
|
44918
|
+
const persisted = store.read();
|
|
44919
|
+
for (const child of [...Object.values(persisted.active), ...persisted.retired_children]) {
|
|
44920
|
+
if (child)
|
|
44921
|
+
options.hook.registerChild(child.id);
|
|
44922
|
+
}
|
|
44923
|
+
const acquireRole = async (role) => {
|
|
44924
|
+
const previous = roleTails.get(role) ?? Promise.resolve();
|
|
44925
|
+
let release;
|
|
44926
|
+
const gate = new Promise((resolve) => {
|
|
44927
|
+
release = resolve;
|
|
44928
|
+
});
|
|
44929
|
+
const tail = previous.then(() => gate);
|
|
44930
|
+
roleTails.set(role, tail);
|
|
44931
|
+
await previous;
|
|
44932
|
+
return () => {
|
|
44933
|
+
release();
|
|
44934
|
+
if (roleTails.get(role) === tail)
|
|
44935
|
+
roleTails.delete(role);
|
|
44936
|
+
};
|
|
44937
|
+
};
|
|
44938
|
+
const resolveHead = async (identity) => {
|
|
44939
|
+
const configured = configuredHead(identity);
|
|
44940
|
+
if (configured)
|
|
44941
|
+
return configured;
|
|
44942
|
+
if (!identity.parentSessionId) {
|
|
44943
|
+
throw new HiddenCompletionRefusal("hidden_model_unsupported", "Hidden completion requires a configured model or an existing parent session model", true);
|
|
43896
44944
|
}
|
|
43897
|
-
const
|
|
43898
|
-
if (!
|
|
43899
|
-
throw new HiddenCompletionRefusal("
|
|
44945
|
+
const parent = await host.get({ sessionID: identity.parentSessionId });
|
|
44946
|
+
if (!parent.model) {
|
|
44947
|
+
throw new HiddenCompletionRefusal("hidden_model_unsupported", "Hidden completion could not resolve the parent session model", true);
|
|
43900
44948
|
}
|
|
43901
|
-
|
|
43902
|
-
|
|
43903
|
-
|
|
43904
|
-
|
|
44949
|
+
return {
|
|
44950
|
+
providerID: parent.model.providerID,
|
|
44951
|
+
modelID: parent.model.id,
|
|
44952
|
+
...parent.model.variant ? { variant: parent.model.variant } : {}
|
|
44953
|
+
};
|
|
44954
|
+
};
|
|
44955
|
+
const switchChildModel = async (run, requested) => {
|
|
44956
|
+
if (sameModel(run.child.model, requested))
|
|
44957
|
+
return;
|
|
44958
|
+
await host.switchModel({
|
|
44959
|
+
sessionID: run.child.id,
|
|
44960
|
+
model: {
|
|
44961
|
+
providerID: requested.providerID,
|
|
44962
|
+
id: requested.modelID,
|
|
44963
|
+
...requested.variant ? { variant: requested.variant } : {}
|
|
43905
44964
|
}
|
|
43906
|
-
|
|
43907
|
-
|
|
43908
|
-
|
|
43909
|
-
|
|
43910
|
-
|
|
43911
|
-
|
|
43912
|
-
|
|
43913
|
-
|
|
43914
|
-
}
|
|
44965
|
+
});
|
|
44966
|
+
run.child = store.updateModel(run.child, requested);
|
|
44967
|
+
};
|
|
44968
|
+
const retire = (run, reason) => {
|
|
44969
|
+
if (run.retired)
|
|
44970
|
+
return;
|
|
44971
|
+
store.retire(run.child, reason);
|
|
44972
|
+
run.retired = true;
|
|
44973
|
+
};
|
|
44974
|
+
const interruptAndRetire = async (run, reason) => {
|
|
44975
|
+
try {
|
|
44976
|
+
await host.interrupt({ sessionID: run.child.id });
|
|
44977
|
+
} finally {
|
|
44978
|
+
retire(run, reason);
|
|
44979
|
+
}
|
|
44980
|
+
};
|
|
43915
44981
|
return {
|
|
43916
44982
|
capabilities: { tools: false, harness: "opencode2" },
|
|
43917
44983
|
async open(identity) {
|
|
43918
|
-
const
|
|
43919
|
-
const
|
|
43920
|
-
|
|
43921
|
-
|
|
43922
|
-
|
|
43923
|
-
|
|
43924
|
-
|
|
43925
|
-
|
|
44984
|
+
const role = roleFor(identity);
|
|
44985
|
+
const releaseRole = await acquireRole(role);
|
|
44986
|
+
let openedChild;
|
|
44987
|
+
try {
|
|
44988
|
+
await options.ensureAgent?.();
|
|
44989
|
+
const head = await resolveHead(identity);
|
|
44990
|
+
let active = store.read().active[role];
|
|
44991
|
+
if (active && active.generation !== generation) {
|
|
44992
|
+
store.retire(active, "host-generation-changed");
|
|
44993
|
+
active = undefined;
|
|
44994
|
+
}
|
|
44995
|
+
if (active) {
|
|
44996
|
+
const activeID = active.id;
|
|
44997
|
+
const latest = withReader(options.openReader, (reader) => reader.latestAssistant(activeID));
|
|
44998
|
+
if (!successfulReusableAssistant(latest)) {
|
|
44999
|
+
store.retire(active, "newest-assistant-not-reusable");
|
|
45000
|
+
active = undefined;
|
|
45001
|
+
}
|
|
45002
|
+
}
|
|
45003
|
+
if (!active) {
|
|
45004
|
+
const title = roleTitle(role);
|
|
45005
|
+
const created = await host.create({
|
|
45006
|
+
title,
|
|
45007
|
+
agent: roleAgent(role),
|
|
45008
|
+
model: {
|
|
45009
|
+
providerID: head.providerID,
|
|
45010
|
+
id: head.modelID,
|
|
45011
|
+
...head.variant ? { variant: head.variant } : {}
|
|
45012
|
+
},
|
|
45013
|
+
location: { directory: identity.directory },
|
|
45014
|
+
metadata: { magic_context: "hidden-run", role }
|
|
45015
|
+
});
|
|
45016
|
+
if (!created.id)
|
|
45017
|
+
throw new Error("OpenCode 2 did not return a child session id");
|
|
45018
|
+
active = {
|
|
45019
|
+
id: created.id,
|
|
45020
|
+
role,
|
|
45021
|
+
generation,
|
|
45022
|
+
title,
|
|
45023
|
+
model: head,
|
|
45024
|
+
created_at: Date.now(),
|
|
45025
|
+
title_reasserted: false
|
|
45026
|
+
};
|
|
45027
|
+
store.put(active);
|
|
45028
|
+
options.hook.registerChild(active.id);
|
|
45029
|
+
}
|
|
45030
|
+
openedChild = active;
|
|
45031
|
+
const handle = { id: active.id, childSessionId: active.id };
|
|
45032
|
+
const run = {
|
|
45033
|
+
identity,
|
|
45034
|
+
role,
|
|
45035
|
+
child: active,
|
|
45036
|
+
releaseRole,
|
|
45037
|
+
failed: false,
|
|
45038
|
+
retired: false
|
|
45039
|
+
};
|
|
45040
|
+
runs.set(handle, run);
|
|
45041
|
+
await switchChildModel(run, head);
|
|
45042
|
+
return handle;
|
|
45043
|
+
} catch (error) {
|
|
45044
|
+
if (openedChild)
|
|
45045
|
+
store.retire(openedChild, "hidden-run-open-failed");
|
|
45046
|
+
releaseRole();
|
|
45047
|
+
throw error;
|
|
45048
|
+
}
|
|
43926
45049
|
},
|
|
43927
45050
|
async attempt(handle, request) {
|
|
43928
45051
|
const run = runs.get(handle);
|
|
43929
45052
|
if (!run)
|
|
43930
45053
|
throw new Error("Unknown hidden completion run");
|
|
43931
|
-
|
|
43932
|
-
|
|
43933
|
-
if (sessionID === undefined)
|
|
43934
|
-
throw new Error("Hidden completion session id missing");
|
|
43935
|
-
const requested = request.body.model ?? actual;
|
|
43936
|
-
if (modelKey(requested) !== modelKey(actual))
|
|
43937
|
-
refuseModel(modelKey(requested), modelKey(actual));
|
|
43938
|
-
if (request.signal?.aborted)
|
|
45054
|
+
if (request.signal?.aborted) {
|
|
45055
|
+
await interruptAndRetire(run, "aborted-before-prompt");
|
|
43939
45056
|
throw new Error("Hidden completion prompt aborted");
|
|
43940
|
-
|
|
43941
|
-
const
|
|
43942
|
-
|
|
45057
|
+
}
|
|
45058
|
+
const requested = requestModel(request, run.child.model);
|
|
45059
|
+
await switchChildModel(run, requested);
|
|
45060
|
+
const baseline = withReader(options.openReader, (reader) => reader.latestSequence(run.child.id));
|
|
45061
|
+
const marker = `mc:hidden:${crypto.randomUUID()}:${crypto.randomUUID()}`;
|
|
45062
|
+
const attempt = {
|
|
45063
|
+
childSessionId: run.child.id,
|
|
45064
|
+
identity: run.identity,
|
|
45065
|
+
request,
|
|
45066
|
+
shaped: false
|
|
45067
|
+
};
|
|
45068
|
+
options.hook.registerAttempt(marker, attempt);
|
|
45069
|
+
const deadline = Date.now() + run.identity.timeoutMs;
|
|
45070
|
+
let abortReject;
|
|
45071
|
+
const aborted = new Promise((_resolve, reject) => {
|
|
45072
|
+
abortReject = reject;
|
|
45073
|
+
});
|
|
45074
|
+
const onAbort = () => {
|
|
45075
|
+
interruptAndRetire(run, "prompt-aborted").finally(() => abortReject(new Error("Hidden completion prompt aborted")));
|
|
45076
|
+
};
|
|
45077
|
+
const deadlineTimer = setTimeout(() => {
|
|
45078
|
+
interruptAndRetire(run, "prompt-timeout").finally(() => abortReject(new Error("Hidden completion prompt timed out")));
|
|
45079
|
+
}, Math.max(0, deadline - Date.now()));
|
|
45080
|
+
request.signal?.addEventListener("abort", onAbort, { once: true });
|
|
43943
45081
|
try {
|
|
43944
|
-
|
|
43945
|
-
|
|
43946
|
-
|
|
43947
|
-
|
|
43948
|
-
|
|
43949
|
-
|
|
43950
|
-
|
|
43951
|
-
|
|
43952
|
-
|
|
43953
|
-
|
|
43954
|
-
|
|
43955
|
-
|
|
43956
|
-
|
|
43957
|
-
|
|
43958
|
-
|
|
45082
|
+
await Promise.race([
|
|
45083
|
+
host.prompt({ sessionID: run.child.id, text: marker }),
|
|
45084
|
+
aborted
|
|
45085
|
+
]);
|
|
45086
|
+
await Promise.race([host.wait({ sessionID: run.child.id }), aborted]);
|
|
45087
|
+
clearTimeout(deadlineTimer);
|
|
45088
|
+
const row = await Promise.race([
|
|
45089
|
+
awaitAssistantRow(options.openReader, run.child.id, baseline, deadline, request.signal),
|
|
45090
|
+
aborted
|
|
45091
|
+
]);
|
|
45092
|
+
if (!attempt.shaped) {
|
|
45093
|
+
throw new HiddenCompletionRefusal("hidden_prompt_unrecognized", "Host did not dispatch the hidden child context hook", true);
|
|
45094
|
+
}
|
|
45095
|
+
if (!run.child.title_reasserted) {
|
|
45096
|
+
await host.update({ sessionID: run.child.id, title: run.child.title });
|
|
45097
|
+
run.child = store.markTitleReasserted(run.child);
|
|
45098
|
+
}
|
|
45099
|
+
const text = assistantText(row);
|
|
43959
45100
|
const system = typeof request.body.system === "string" ? request.body.system : run.identity.system;
|
|
43960
|
-
const
|
|
43961
|
-
usage.input += run.usage?.input ?? 0;
|
|
43962
|
-
usage.output += run.usage?.output ?? 0;
|
|
43963
|
-
run.usage = usage;
|
|
45101
|
+
const tokens = row.data.tokens;
|
|
43964
45102
|
run.completion = {
|
|
43965
|
-
text
|
|
43966
|
-
|
|
43967
|
-
|
|
43968
|
-
|
|
43969
|
-
|
|
45103
|
+
text,
|
|
45104
|
+
reasoning: null,
|
|
45105
|
+
usage: tokens ? {
|
|
45106
|
+
input: tokens.input,
|
|
45107
|
+
output: tokens.output,
|
|
45108
|
+
cacheRead: tokens.cache.read,
|
|
45109
|
+
cacheWrite: tokens.cache.write
|
|
45110
|
+
} : meter(system, promptText(request), text ?? ""),
|
|
45111
|
+
lengthCapped: ["length", "max_tokens"].includes(row.data.finish ?? ""),
|
|
45112
|
+
providerId: row.data.model?.providerID ?? requested.providerID,
|
|
45113
|
+
modelId: row.data.model?.id ?? requested.modelID
|
|
43970
45114
|
};
|
|
45115
|
+
} catch (error) {
|
|
45116
|
+
run.failed = true;
|
|
45117
|
+
if (request.signal?.aborted && !run.retired) {
|
|
45118
|
+
await interruptAndRetire(run, "prompt-aborted");
|
|
45119
|
+
} else if (error instanceof Error && error.message.includes("timed out") && !run.retired) {
|
|
45120
|
+
await interruptAndRetire(run, "prompt-timeout");
|
|
45121
|
+
}
|
|
45122
|
+
throw error;
|
|
43971
45123
|
} finally {
|
|
43972
|
-
|
|
43973
|
-
|
|
45124
|
+
clearTimeout(deadlineTimer);
|
|
45125
|
+
request.signal?.removeEventListener("abort", onAbort);
|
|
45126
|
+
options.hook.releaseAttempt(marker);
|
|
43974
45127
|
}
|
|
43975
45128
|
},
|
|
43976
45129
|
async collect(handle) {
|
|
@@ -43979,18 +45132,27 @@ async function createV2HiddenCompletionExecutor(host, currentModel) {
|
|
|
43979
45132
|
throw new Error("Hidden completion has no settled output");
|
|
43980
45133
|
return completion;
|
|
43981
45134
|
},
|
|
43982
|
-
async close() {
|
|
45135
|
+
async close(handle, settlement) {
|
|
45136
|
+
if (!handle)
|
|
45137
|
+
return;
|
|
45138
|
+
const run = runs.get(handle);
|
|
45139
|
+
if (!run)
|
|
45140
|
+
return;
|
|
45141
|
+
try {
|
|
45142
|
+
if (!run.completion && (run.failed || !settlement.promptSettled)) {
|
|
45143
|
+
retire(run, "hidden-run-failed");
|
|
45144
|
+
}
|
|
45145
|
+
} finally {
|
|
45146
|
+
runs.delete(handle);
|
|
45147
|
+
run.releaseRole();
|
|
45148
|
+
}
|
|
45149
|
+
}
|
|
43983
45150
|
};
|
|
43984
45151
|
}
|
|
43985
45152
|
|
|
43986
45153
|
// src/v2/store-reader.ts
|
|
43987
|
-
import { join as join11 } from "node:path";
|
|
43988
|
-
function sourceDatabaseFilename(channel, env = process.env) {
|
|
43989
|
-
return env.OPENCODE_DB ?? (["latest", "dev", "beta", "next", "prod"].includes(channel) || env.OPENCODE_DISABLE_CHANNEL_DB === "1" || env.OPENCODE_DISABLE_CHANNEL_DB === "true" ? "opencode.db" : `opencode-${channel.replace(/[^a-zA-Z0-9._-]/g, "")}.db`);
|
|
43990
|
-
}
|
|
43991
45154
|
function gaDatabasePath(dataHome, channel = "latest", env = process.env) {
|
|
43992
|
-
|
|
43993
|
-
return filename === ":memory:" ? filename : join11(dataHome, "opencode", filename);
|
|
45155
|
+
return resolveOpenCodeDbPath("v2", { dataHome, channel, env }).path;
|
|
43994
45156
|
}
|
|
43995
45157
|
function decode(row) {
|
|
43996
45158
|
const data = JSON.parse(row.data);
|
|
@@ -44007,6 +45169,12 @@ class V2StoreReader {
|
|
|
44007
45169
|
db;
|
|
44008
45170
|
constructor(path) {
|
|
44009
45171
|
this.db = new Database(path, { readonly: true, fileMustExist: true });
|
|
45172
|
+
try {
|
|
45173
|
+
assertOpenCodeStoreGeneration(this.db, "v2", path);
|
|
45174
|
+
} catch (error) {
|
|
45175
|
+
this.db.close();
|
|
45176
|
+
throw error;
|
|
45177
|
+
}
|
|
44010
45178
|
}
|
|
44011
45179
|
close() {
|
|
44012
45180
|
this.db.close();
|
|
@@ -44032,6 +45200,16 @@ class V2StoreReader {
|
|
|
44032
45200
|
idleRows(sessionID, after = -1) {
|
|
44033
45201
|
return this.all(sessionID, after, "idle");
|
|
44034
45202
|
}
|
|
45203
|
+
latestSequence(sessionID) {
|
|
45204
|
+
const row = this.db.prepare("SELECT MAX(seq) AS seq FROM session_message WHERE session_id = ?").get(sessionID);
|
|
45205
|
+
return typeof row?.seq === "number" ? row.seq : -1;
|
|
45206
|
+
}
|
|
45207
|
+
latestAssistant(sessionID) {
|
|
45208
|
+
const row = this.db.prepare(`SELECT id, session_id, type, seq, data FROM session_message
|
|
45209
|
+
WHERE session_id = ? AND type = 'assistant'
|
|
45210
|
+
ORDER BY seq DESC LIMIT 1`).get(sessionID);
|
|
45211
|
+
return row ? decode(row) : undefined;
|
|
45212
|
+
}
|
|
44035
45213
|
window(sessionID) {
|
|
44036
45214
|
return this.db.transaction(() => {
|
|
44037
45215
|
const cut = this.latestCompaction(sessionID);
|
|
@@ -44281,7 +45459,7 @@ function rawMessages(rows, history = rows) {
|
|
|
44281
45459
|
const ordinals = new Map(history.filter(isRawRow).map((row, index) => [row.id, index + 1]));
|
|
44282
45460
|
return rows.filter(isRawRow).map((row) => ({
|
|
44283
45461
|
id: row.id,
|
|
44284
|
-
ordinal: ordinals.get(row.id),
|
|
45462
|
+
ordinal: ordinals.get(row.id) ?? 0,
|
|
44285
45463
|
role: row.type === "assistant" ? "assistant" : "user",
|
|
44286
45464
|
createdAt: row.data.time?.created,
|
|
44287
45465
|
parts: row.type === "assistant" ? (row.data.content ?? []).map((part) => {
|
|
@@ -44315,20 +45493,96 @@ function createHostSeams(context, read, liveModels) {
|
|
|
44315
45493
|
hostRefuse: (_client, sessionID) => interruptBeforeProvider(context.session, sessionID)
|
|
44316
45494
|
};
|
|
44317
45495
|
}
|
|
45496
|
+
function toolResultText(result) {
|
|
45497
|
+
const content = result?.content ?? result?.output;
|
|
45498
|
+
if (typeof content === "string")
|
|
45499
|
+
return content;
|
|
45500
|
+
if (content && typeof content === "object" && !Array.isArray(content)) {
|
|
45501
|
+
const record = content;
|
|
45502
|
+
if (typeof record.text === "string")
|
|
45503
|
+
return record.text;
|
|
45504
|
+
if (typeof record.value === "string")
|
|
45505
|
+
return record.value;
|
|
45506
|
+
return "";
|
|
45507
|
+
}
|
|
45508
|
+
if (!Array.isArray(content))
|
|
45509
|
+
return "";
|
|
45510
|
+
return content.map((part) => {
|
|
45511
|
+
if (typeof part === "string")
|
|
45512
|
+
return part;
|
|
45513
|
+
if (!part || typeof part !== "object")
|
|
45514
|
+
return "";
|
|
45515
|
+
const record = part;
|
|
45516
|
+
if (typeof record.text === "string")
|
|
45517
|
+
return record.text;
|
|
45518
|
+
if (typeof record.value === "string")
|
|
45519
|
+
return record.value;
|
|
45520
|
+
return "";
|
|
45521
|
+
}).filter(Boolean).join(`
|
|
45522
|
+
`);
|
|
45523
|
+
}
|
|
45524
|
+
function catalogModels(listed) {
|
|
45525
|
+
const rows = Array.isArray(listed) ? listed : listed && typeof listed === "object" && Array.isArray(listed.data) ? listed.data : [];
|
|
45526
|
+
return rows.flatMap((row) => {
|
|
45527
|
+
if (!row || typeof row !== "object")
|
|
45528
|
+
return [];
|
|
45529
|
+
const model = row;
|
|
45530
|
+
if (typeof model.id !== "string" || typeof model.providerID !== "string")
|
|
45531
|
+
return [];
|
|
45532
|
+
const contextLimit = model.limit?.context;
|
|
45533
|
+
if (typeof contextLimit !== "number" || !Number.isFinite(contextLimit))
|
|
45534
|
+
return [];
|
|
45535
|
+
return [{ id: model.id, providerID: model.providerID, limit: { context: contextLimit } }];
|
|
45536
|
+
});
|
|
45537
|
+
}
|
|
45538
|
+
function applyV2PromptSurfaceTools(draft, runtime, config) {
|
|
45539
|
+
if (!draft.tools)
|
|
45540
|
+
return;
|
|
45541
|
+
const modelKey = `${draft.model.providerID}/${draft.model.id}`;
|
|
45542
|
+
const registration = runtime.resolveRegistration(config, modelKey);
|
|
45543
|
+
for (const id of ACTIVE_TOOL_IDS) {
|
|
45544
|
+
const tool = draft.tools[id];
|
|
45545
|
+
if (!tool)
|
|
45546
|
+
continue;
|
|
45547
|
+
tool.description = registration.descriptionFor(id, tool.description);
|
|
45548
|
+
}
|
|
45549
|
+
}
|
|
44318
45550
|
async function registerContext(context) {
|
|
44319
45551
|
const directory = context.location.directory;
|
|
44320
45552
|
const config = loadPluginConfigDetailed(directory).config;
|
|
44321
45553
|
if (!config.enabled || !isCompactionEnabled(config))
|
|
44322
45554
|
return;
|
|
45555
|
+
const conflicts = detectConflicts(directory, {
|
|
45556
|
+
compactionEnabled: true,
|
|
45557
|
+
hostGeneration: "v2"
|
|
45558
|
+
});
|
|
45559
|
+
if (conflicts.hasConflict) {
|
|
45560
|
+
console.warn(`[magic-context] v2 setup disabled by conflicting context hooks: ${conflicts.reasons.join("; ")}`);
|
|
45561
|
+
return;
|
|
45562
|
+
}
|
|
44323
45563
|
const folds = new FoldOwner(context.storage);
|
|
44324
45564
|
const limits = new Map;
|
|
44325
45565
|
const queriedModels = new Set;
|
|
44326
45566
|
const liveModels = new Map;
|
|
44327
|
-
const
|
|
44328
|
-
|
|
44329
|
-
|
|
44330
|
-
|
|
44331
|
-
}
|
|
45567
|
+
const promptSurfaceRuntime = createPromptSurfaceRuntime({
|
|
45568
|
+
harness: "opencode2",
|
|
45569
|
+
directory,
|
|
45570
|
+
warn: (message) => console.warn(`[magic-context] config warning: ${message}`)
|
|
45571
|
+
});
|
|
45572
|
+
let db;
|
|
45573
|
+
try {
|
|
45574
|
+
db = openDatabase() ?? undefined;
|
|
45575
|
+
} catch {}
|
|
45576
|
+
const hiddenChildHook = new HiddenChildHook;
|
|
45577
|
+
await registerHiddenChildAgents(context.agent);
|
|
45578
|
+
let hiddenAgentsReady;
|
|
45579
|
+
const hiddenCompletionExecutor = db && isDatabasePersisted(db) ? await createV2HiddenCompletionExecutor(context.session, {
|
|
45580
|
+
db,
|
|
45581
|
+
projectIdentity: resolveProjectIdentity(directory) ?? directory,
|
|
45582
|
+
hook: hiddenChildHook,
|
|
45583
|
+
ensureAgent: () => hiddenAgentsReady ??= context.agent.reload(),
|
|
45584
|
+
openReader: () => new V2StoreReader(gaDatabasePath(getDataDir(), process.env.OPENCODE_CHANNEL ?? "latest"))
|
|
45585
|
+
}) : undefined;
|
|
44332
45586
|
const dreamTrigger = hiddenCompletionExecutor && config.dreamer && !config.dreamer.disable ? startDreamTrigger(context, {
|
|
44333
45587
|
config: config.dreamer,
|
|
44334
45588
|
executor: hiddenCompletionExecutor,
|
|
@@ -44349,16 +45603,17 @@ async function registerContext(context) {
|
|
|
44349
45603
|
let toolDuties;
|
|
44350
45604
|
await context.tool.hook("execute.before", (draft) => assertExecutableToolInput(draft.input));
|
|
44351
45605
|
await context.tool.hook("execute.after", async (draft) => {
|
|
44352
|
-
if (!db
|
|
45606
|
+
if (!db)
|
|
45607
|
+
return;
|
|
45608
|
+
if (draft.status && draft.status !== "completed")
|
|
44353
45609
|
return;
|
|
44354
45610
|
try {
|
|
44355
45611
|
toolDuties ??= createToolExecuteAfterHook({ db, channel1StateBySession: channel1 });
|
|
44356
|
-
const
|
|
44357
|
-
const text = typeof content === "string" ? content : Array.isArray(content) ? content.filter((part) => part.type === "text").map((part) => part.text).join(`
|
|
44358
|
-
`) : "";
|
|
45612
|
+
const text = toolResultText(draft.result);
|
|
44359
45613
|
const output = { output: text };
|
|
44360
45614
|
await toolDuties({ ...draft, args: draft.input }, output);
|
|
44361
45615
|
if (draft.result && output.output !== text) {
|
|
45616
|
+
const content = draft.result.content;
|
|
44362
45617
|
if (typeof content === "string")
|
|
44363
45618
|
draft.result.content = output.output;
|
|
44364
45619
|
else if (Array.isArray(content) && output.output.startsWith(text))
|
|
@@ -44383,7 +45638,6 @@ async function registerContext(context) {
|
|
|
44383
45638
|
getCount: (sessionID) => read(sessionID).length
|
|
44384
45639
|
});
|
|
44385
45640
|
let transform;
|
|
44386
|
-
let db;
|
|
44387
45641
|
const refuseIfUnsafe = async (draft) => {
|
|
44388
45642
|
let unsafe = false;
|
|
44389
45643
|
try {
|
|
@@ -44397,10 +45651,8 @@ async function registerContext(context) {
|
|
|
44397
45651
|
const tokens = latest?.data.tokens;
|
|
44398
45652
|
const modelKey = `${draft.model.providerID}/${draft.model.id}`;
|
|
44399
45653
|
if (!queriedModels.has(modelKey)) {
|
|
44400
|
-
const catalog = await context.
|
|
44401
|
-
|
|
44402
|
-
});
|
|
44403
|
-
for (const model of catalog.data)
|
|
45654
|
+
const catalog = await Promise.resolve(context.model.list());
|
|
45655
|
+
for (const model of catalogModels(catalog))
|
|
44404
45656
|
limits.set(`${model.providerID}/${model.id}`, model.limit.context);
|
|
44405
45657
|
queriedModels.add(modelKey);
|
|
44406
45658
|
}
|
|
@@ -44420,7 +45672,8 @@ async function registerContext(context) {
|
|
|
44420
45672
|
} finally {
|
|
44421
45673
|
reader.close();
|
|
44422
45674
|
}
|
|
44423
|
-
} catch {
|
|
45675
|
+
} catch (error) {
|
|
45676
|
+
console.warn("[magic-context] v2 refuseIfUnsafe", error);
|
|
44424
45677
|
unsafe = true;
|
|
44425
45678
|
}
|
|
44426
45679
|
if (unsafe)
|
|
@@ -44473,6 +45726,26 @@ async function registerContext(context) {
|
|
|
44473
45726
|
}
|
|
44474
45727
|
});
|
|
44475
45728
|
await context.session.hook("context", async (draft) => {
|
|
45729
|
+
if (hiddenChildHook.apply(draft))
|
|
45730
|
+
return;
|
|
45731
|
+
liveModels.set(draft.sessionID, {
|
|
45732
|
+
providerID: draft.model.providerID,
|
|
45733
|
+
modelID: draft.model.id
|
|
45734
|
+
});
|
|
45735
|
+
variants.set(draft.sessionID, draft.model.variant);
|
|
45736
|
+
agents.set(draft.sessionID, draft.agent);
|
|
45737
|
+
applyV2PromptSurfaceTools(draft, promptSurfaceRuntime, config.prompt_surface);
|
|
45738
|
+
if (context.tool.transform) {
|
|
45739
|
+
const modelKey = `${draft.model.providerID}/${draft.model.id}`;
|
|
45740
|
+
const registration = promptSurfaceRuntime.resolveRegistration(config.prompt_surface, modelKey);
|
|
45741
|
+
await context.tool.transform((editor) => {
|
|
45742
|
+
for (const id of ACTIVE_TOOL_IDS) {
|
|
45743
|
+
editor.update(id, (tool) => {
|
|
45744
|
+
tool.description = registration.descriptionFor(id, tool.description);
|
|
45745
|
+
});
|
|
45746
|
+
}
|
|
45747
|
+
});
|
|
45748
|
+
}
|
|
44476
45749
|
let postFold = false;
|
|
44477
45750
|
try {
|
|
44478
45751
|
if (await refuseIfUnsafe(draft))
|
|
@@ -44589,6 +45862,9 @@ async function registerContext(context) {
|
|
|
44589
45862
|
const mapped = adaptPayload(draft, admitted);
|
|
44590
45863
|
await transform({}, mapped);
|
|
44591
45864
|
mapped.commit();
|
|
45865
|
+
if (db) {
|
|
45866
|
+
await deliverPendingChannel2(context, db, draft.sessionID, channel1.get(draft.sessionID));
|
|
45867
|
+
}
|
|
44592
45868
|
if (checkpoint && submitted !== undefined) {
|
|
44593
45869
|
const head = draft.messages.find((message) => message.id === HEAD_IDS[0]);
|
|
44594
45870
|
const baseline = head?.content.find((part) => part.type === "text")?.text;
|
|
@@ -44628,18 +45904,18 @@ ${baseline}
|
|
|
44628
45904
|
}
|
|
44629
45905
|
|
|
44630
45906
|
// src/v2/hooks/update-check.ts
|
|
44631
|
-
import { existsSync as
|
|
44632
|
-
import { dirname as dirname8, join as
|
|
45907
|
+
import { existsSync as existsSync14, readFileSync as readFileSync8 } from "node:fs";
|
|
45908
|
+
import { dirname as dirname8, join as join11 } from "node:path";
|
|
44633
45909
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
44634
45910
|
function packageInfo() {
|
|
44635
45911
|
let directory = dirname8(fileURLToPath3(import.meta.url));
|
|
44636
45912
|
for (;; ) {
|
|
44637
45913
|
try {
|
|
44638
|
-
const pkg = JSON.parse(
|
|
45914
|
+
const pkg = JSON.parse(readFileSync8(join11(directory, "package.json"), "utf8"));
|
|
44639
45915
|
if (pkg.name === "@cortexkit/opencode-magic-context" && typeof pkg.version === "string") {
|
|
44640
45916
|
return {
|
|
44641
45917
|
version: pkg.version,
|
|
44642
|
-
development:
|
|
45918
|
+
development: existsSync14(join11(directory, "src/v2/server.ts"))
|
|
44643
45919
|
};
|
|
44644
45920
|
}
|
|
44645
45921
|
} catch {}
|
|
@@ -44686,7 +45962,17 @@ function startUpdateChecks(context, check = (signal) => {
|
|
|
44686
45962
|
}
|
|
44687
45963
|
|
|
44688
45964
|
// src/v2/server.ts
|
|
45965
|
+
function isOpenCode2HostContext(context) {
|
|
45966
|
+
if (typeof context !== "object" || context === null)
|
|
45967
|
+
return false;
|
|
45968
|
+
const session = context.session;
|
|
45969
|
+
return typeof session === "object" && session !== null && typeof session.hook === "function";
|
|
45970
|
+
}
|
|
44689
45971
|
async function setup(context) {
|
|
45972
|
+
if (!isOpenCode2HostContext(context)) {
|
|
45973
|
+
log("v2 setup() called on a host without session.hook; v1 server lane owns this host, v2 lane inert");
|
|
45974
|
+
return async () => {};
|
|
45975
|
+
}
|
|
44690
45976
|
setHarness("opencode2");
|
|
44691
45977
|
const duties = await registerContext(context);
|
|
44692
45978
|
const checks = loadPluginConfigDetailed(context.location.directory).config.auto_update === false ? undefined : startUpdateChecks(context);
|
|
@@ -44710,6 +45996,7 @@ var server = async (ctx) => {
|
|
|
44710
45996
|
let hooksDeadlineReason = null;
|
|
44711
45997
|
let deadlinePhase = null;
|
|
44712
45998
|
emitBootEnteringBreadcrumb(process.pid, ctx.directory, log, flushLogger);
|
|
45999
|
+
setHarness("opencode");
|
|
44713
46000
|
const configStartedAt = performance.now();
|
|
44714
46001
|
beginBootQuietPeriod();
|
|
44715
46002
|
const configMigrationWarnings = migrateMagicContextConfigLocations(ctx.directory, {
|
|
@@ -44749,7 +46036,7 @@ var server = async (ctx) => {
|
|
|
44749
46036
|
if (hasBannerEntries)
|
|
44750
46037
|
setTimeout(async () => {
|
|
44751
46038
|
try {
|
|
44752
|
-
const { sendStatusNotification } = await import("./send-session-notification-
|
|
46039
|
+
const { sendStatusNotification } = await import("./send-session-notification-jbxknvar.js");
|
|
44753
46040
|
const clientWithSessions = ctx.client;
|
|
44754
46041
|
const sessions = await Promise.resolve(clientWithSessions.session?.list?.()).catch(() => null);
|
|
44755
46042
|
const sessionList = Array.isArray(sessions) ? sessions : sessions?.data;
|
|
@@ -44766,7 +46053,7 @@ var server = async (ctx) => {
|
|
|
44766
46053
|
log(`[magic-context] opencode_db_missing path=${openCodeDbResolution.path} source=${openCodeDbResolution.source}`);
|
|
44767
46054
|
setTimeout(async () => {
|
|
44768
46055
|
try {
|
|
44769
|
-
const { sendStatusNotification } = await import("./send-session-notification-
|
|
46056
|
+
const { sendStatusNotification } = await import("./send-session-notification-jbxknvar.js");
|
|
44770
46057
|
const clientWithSessions = ctx.client;
|
|
44771
46058
|
const sessions = await Promise.resolve(clientWithSessions.session?.list?.()).catch(() => null);
|
|
44772
46059
|
const sessionList = Array.isArray(sessions) ? sessions : sessions?.data;
|
|
@@ -45012,12 +46299,12 @@ var server = async (ctx) => {
|
|
|
45012
46299
|
{
|
|
45013
46300
|
const fence = getSchemaFenceRejection();
|
|
45014
46301
|
if (fence) {
|
|
45015
|
-
import("./conflict-warning-hook-
|
|
46302
|
+
import("./conflict-warning-hook-aktepwpz.js").then(({ sendSchemaFenceWarning }) => sendSchemaFenceWarning(ctx.client, ctx.directory, fence));
|
|
45016
46303
|
}
|
|
45017
46304
|
}
|
|
45018
46305
|
const serverUrl = ctx.serverUrl;
|
|
45019
46306
|
const serverUrlStr = serverUrl instanceof URL ? serverUrl.toString().replace(/\/$/, "") : typeof serverUrl === "string" ? serverUrl.replace(/\/$/, "") : undefined;
|
|
45020
|
-
import("./send-session-notification-
|
|
46307
|
+
import("./send-session-notification-jbxknvar.js").then(({ setNotificationServerUrl }) => {
|
|
45021
46308
|
setNotificationServerUrl(serverUrlStr);
|
|
45022
46309
|
});
|
|
45023
46310
|
if (conflictResult?.hasConflict) {
|
|
@@ -45040,7 +46327,7 @@ var server = async (ctx) => {
|
|
|
45040
46327
|
}) => {
|
|
45041
46328
|
if (!shouldShowAnnouncement())
|
|
45042
46329
|
return;
|
|
45043
|
-
return import("./conflict-warning-hook-
|
|
46330
|
+
return import("./conflict-warning-hook-aktepwpz.js").then(({ sendStartupAnnouncement }) => sendStartupAnnouncement(ctx.client, ctx.directory, ANNOUNCEMENT_VERSION, ANNOUNCEMENT_FEATURES, ANNOUNCEMENT_FOOTER, markAnnouncementSeen));
|
|
45044
46331
|
}).catch(() => {});
|
|
45045
46332
|
}, 8000);
|
|
45046
46333
|
}
|