@cortexkit/pi-magic-context 0.49.33 → 0.49.35
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/auto-search-worker.js +11 -6
- package/dist/chunk-embedding-write-worker.js +16 -13
- package/dist/{compaction-marker-candidates-p1kqkqhq.js → compaction-marker-candidates-hk2frhac.js} +3 -2
- package/dist/compaction-marker-candidates-worker.js +1 -1
- package/dist/{compartment-chunk-embedding-8c85ebce.js → compartment-chunk-embedding-5j1d1e3v.js} +8 -7
- package/dist/embedding-backfill-jt459ady.js +26 -0
- package/dist/embedding-worker-process.js +2 -1
- package/dist/embedding-worker.js +5 -4
- package/dist/expand-attachments-8sxeyj26.js +21 -0
- package/dist/historian-calibration-extension.js +2 -1
- package/dist/{index-drmr22ac.js → index-0rvn6vhq.js} +3 -3
- package/dist/{index-hqw0rt9k.js → index-0wtm7g7f.js} +1 -1
- package/dist/{index-r9y6tbbm.js → index-11knwv2h.js} +20 -240
- package/dist/{index-0gymvr5j.js → index-2p691ayw.js} +19 -8
- package/dist/{index-wqpjhx1p.js → index-2qqsnh1b.js} +2 -2
- package/dist/index-3bb24eb6.js +229 -0
- package/dist/{index-48twbev2.js → index-6pk49fc3.js} +37 -51
- package/dist/index-6y6v2wvn.js +194 -0
- package/dist/{index-wpazxe9x.js → index-8m82cez2.js} +4 -4
- package/dist/{index-xn5yh0pn.js → index-a11nmw5t.js} +29 -128
- package/dist/index-by1bzjcd.js +24 -0
- package/dist/index-c6wbq66z.js +168 -0
- package/dist/{index-jn44h81p.js → index-cq71g4dk.js} +1 -1
- package/dist/{index-6wdwv3a6.js → index-d0w84hy5.js} +1 -1
- package/dist/{index-pb3ea2tq.js → index-d107f484.js} +5 -5
- package/dist/index-d21rhpbd.js +4171 -0
- package/dist/index-dnp1jjar.js +222 -0
- package/dist/index-ea37qn4x.js +777 -0
- package/dist/{index-k5ya5k8r.js → index-fzm8fm4z.js} +469 -4976
- package/dist/{index-fgs78jyd.js → index-gymgz20n.js} +5 -222
- package/dist/index-hgd00nas.js +113 -0
- package/dist/{index-d5q1q700.js → index-m68qfjte.js} +2 -2
- package/dist/{index-6981g1xv.js → index-mkh1cm5k.js} +1 -1
- package/dist/{index-4zemngt7.js → index-mp0gh04g.js} +2 -2
- package/dist/{index-23t8ryqw.js → index-n0zjvs3h.js} +1 -168
- package/dist/{index-bvpar0bg.js → index-rgvqh5x7.js} +2 -2
- package/dist/{index-gwxaz0z5.js → index-rzfr7wdv.js} +2 -2
- package/dist/{index-87xkw8xm.js → index-svqk0701.js} +70 -35
- package/dist/{index-9xd7qveg.js → index-vgfk2xa5.js} +4 -4
- package/dist/index-w26zvs1q.js +528 -0
- package/dist/index-wrr9rp9a.js +16 -0
- package/dist/{index-my0dn413.js → index-wt7vmyj4.js} +1 -1
- package/dist/{index-c474g0gj.js → index-yacs388s.js} +1 -1
- package/dist/{index-e59j3yq5.js → index-yg42q9bc.js} +95 -550
- package/dist/{index-eqw9t2ty.js → index-yhsmjvqa.js} +3 -3
- package/dist/index.js +523 -236
- package/dist/{logger-shetp43v.js → logger-2j70hhz4.js} +2 -1
- package/dist/{message-fts-rowid-map-3mbvdgn9.js → message-fts-rowid-map-aw4xa05a.js} +5 -4
- package/dist/{message-index-bounded-n30vk21s.js → message-index-bounded-da34vhs4.js} +12 -10
- package/dist/{message-time-backfill-e3r8ddh1.js → message-time-backfill-x45573rs.js} +3 -2
- package/dist/migration-worker.js +13 -10
- package/dist/{project-embedding-registry-acqb6be4.js → project-embedding-registry-davzvsz9.js} +13 -11
- package/dist/raw-ordinal-warmup-worker.js +12 -7
- package/dist/{read-session-chunk-ka6dhc77.js → read-session-chunk-nbcznexm.js} +14 -8
- package/dist/{read-session-raw-g9b1zdn5.js → read-session-raw-zb8kpa2y.js} +3 -2
- package/dist/render-d931g2vv.js +41 -0
- package/dist/{safe-notification-target-zcpchea6.js → safe-notification-target-jk69jxwp.js} +3 -2
- package/dist/search-archive-a76pp30g.js +24 -0
- package/dist/{search-qbxrnnjb.js → search-atp7g95j.js} +24 -20
- package/dist/{storage-tags-6409qq18.js → storage-tags-jy8b0xsy.js} +5 -4
- package/dist/store-kabezr25.js +453 -0
- package/dist/store-reader-2m80zs5z.js +14 -0
- package/dist/subagent-entry.js +31 -23
- package/dist/tag-snapshot-worker-pi.js +15 -12
- package/dist/v2-archive-reader-wcjcfdzq.js +11 -0
- package/package.json +1 -1
- package/dist/embedding-backfill-rwfmyvze.js +0 -24
- package/dist/search-archive-msy2bczx.js +0 -21
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import {
|
|
2
|
+
sanitizeDiagnosticText
|
|
3
|
+
} from "./index-dnp1jjar.js";
|
|
4
|
+
|
|
5
|
+
// ../plugin/src/features/magic-context/fail-closed-block.ts
|
|
6
|
+
var FAIL_CLOSED_DOCTOR_COMMAND = "npx @cortexkit/magic-context@latest doctor";
|
|
7
|
+
var FAIL_CLOSED_REPROBE_EVERY_N = 5;
|
|
8
|
+
function attachFailClosedBlockingProcessEvidence(process, evidence) {
|
|
9
|
+
Object.defineProperties(process, {
|
|
10
|
+
startTime: { configurable: true, value: evidence.startTime },
|
|
11
|
+
commandLine: { configurable: true, value: evidence.commandLine }
|
|
12
|
+
});
|
|
13
|
+
return process;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
class FailClosedBlockingError extends Error {
|
|
17
|
+
code = "FAIL_CLOSED_BLOCKING";
|
|
18
|
+
reason;
|
|
19
|
+
constructor(message, reason, options) {
|
|
20
|
+
super(message, options);
|
|
21
|
+
this.name = "FailClosedBlockingError";
|
|
22
|
+
this.reason = reason;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
var OPENCODE_INTERNAL_AGENT_NAMES = new Set(["title", "summary", "compaction"]);
|
|
26
|
+
function isMagicContextHiddenAgentName(agent) {
|
|
27
|
+
if (agent === "smart-note-compiler" || agent.startsWith("smart-note-")) {
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
if (agent === "historian" || agent.startsWith("historian-"))
|
|
31
|
+
return true;
|
|
32
|
+
if (agent === "dreamer" || agent.startsWith("dreamer-"))
|
|
33
|
+
return true;
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
var MAX_FORMATTED_BLOCKING_PROCESSES = 8;
|
|
37
|
+
var MAX_FORMATTED_COMMAND_LINE_LENGTH = 80;
|
|
38
|
+
function normalizeFailClosedProcessKind(process) {
|
|
39
|
+
switch (process.kind) {
|
|
40
|
+
case "OpenCode server":
|
|
41
|
+
case "OpenCode instance (TUI/CLI)":
|
|
42
|
+
case "Pi":
|
|
43
|
+
case "process":
|
|
44
|
+
return process.kind;
|
|
45
|
+
}
|
|
46
|
+
switch (process.harness?.trim().toLowerCase()) {
|
|
47
|
+
case "opencode server":
|
|
48
|
+
return "OpenCode server";
|
|
49
|
+
case "opencode instance (tui/cli)":
|
|
50
|
+
case "opencode instance":
|
|
51
|
+
return "OpenCode instance (TUI/CLI)";
|
|
52
|
+
case "pi":
|
|
53
|
+
case "pi harness":
|
|
54
|
+
case "omp":
|
|
55
|
+
return "Pi";
|
|
56
|
+
default:
|
|
57
|
+
return "process";
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
function formatFailClosedProcessStartTime(startTime) {
|
|
61
|
+
if (!Number.isFinite(startTime) || startTime <= 0)
|
|
62
|
+
return "unverified";
|
|
63
|
+
try {
|
|
64
|
+
const parts = new Intl.DateTimeFormat("en-US", {
|
|
65
|
+
day: "numeric",
|
|
66
|
+
hour: "2-digit",
|
|
67
|
+
minute: "2-digit",
|
|
68
|
+
month: "short",
|
|
69
|
+
hour12: false
|
|
70
|
+
}).formatToParts(new Date(startTime));
|
|
71
|
+
const values = Object.fromEntries(parts.map(({ type, value }) => [type, value]));
|
|
72
|
+
if (!values.month || !values.day || !values.hour || !values.minute)
|
|
73
|
+
return "unverified";
|
|
74
|
+
return `${values.month} ${values.day} ${values.hour}:${values.minute}`;
|
|
75
|
+
} catch {
|
|
76
|
+
return "unverified";
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
function formatFailClosedCommandLine(commandLine) {
|
|
80
|
+
if (typeof commandLine !== "string" || commandLine.trim().length === 0)
|
|
81
|
+
return "unverified";
|
|
82
|
+
try {
|
|
83
|
+
const normalized = commandLine.replaceAll("\x00", " ").replace(/\s+/g, " ").trim();
|
|
84
|
+
if (normalized.length === 0)
|
|
85
|
+
return "unverified";
|
|
86
|
+
const sanitized = sanitizeDiagnosticText(normalized).trim();
|
|
87
|
+
if (sanitized.length === 0)
|
|
88
|
+
return "unverified";
|
|
89
|
+
return sanitized.length > MAX_FORMATTED_COMMAND_LINE_LENGTH ? `${sanitized.slice(0, MAX_FORMATTED_COMMAND_LINE_LENGTH - 3)}...` : sanitized;
|
|
90
|
+
} catch {
|
|
91
|
+
return "unverified";
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
function formatFailClosedBlockingProcesses(processes) {
|
|
95
|
+
const uniqueProcesses = new Map;
|
|
96
|
+
for (const process of processes) {
|
|
97
|
+
if (!Number.isInteger(process.pid) || process.pid <= 0)
|
|
98
|
+
continue;
|
|
99
|
+
const candidate = {
|
|
100
|
+
kind: normalizeFailClosedProcessKind(process),
|
|
101
|
+
pid: process.pid,
|
|
102
|
+
startTime: process.startTime,
|
|
103
|
+
commandLine: process.commandLine
|
|
104
|
+
};
|
|
105
|
+
const previous = uniqueProcesses.get(process.pid);
|
|
106
|
+
if (!previous || previous.kind === "process" && candidate.kind !== "process") {
|
|
107
|
+
uniqueProcesses.set(process.pid, candidate);
|
|
108
|
+
} else {
|
|
109
|
+
uniqueProcesses.set(process.pid, {
|
|
110
|
+
...previous,
|
|
111
|
+
startTime: previous.startTime ?? candidate.startTime,
|
|
112
|
+
commandLine: previous.commandLine ?? candidate.commandLine
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
const entries = [...uniqueProcesses.values()];
|
|
117
|
+
const visible = entries.slice(0, MAX_FORMATTED_BLOCKING_PROCESSES);
|
|
118
|
+
const rendered = visible.map(({ kind, pid }) => `${kind} (PID ${pid})`);
|
|
119
|
+
const omitted = entries.length - visible.length;
|
|
120
|
+
if (omitted > 0)
|
|
121
|
+
rendered.push(`${omitted} more blocking process(es)`);
|
|
122
|
+
if (rendered.length === 0)
|
|
123
|
+
return "a live process";
|
|
124
|
+
const summary = rendered.length === 1 ? rendered[0] : `${rendered.slice(0, -1).join(", ")}, and ${rendered.at(-1)}`;
|
|
125
|
+
const evidence = entries.map(({ kind, pid, startTime, commandLine }) => `- PID ${pid}: ${kind}, started ${formatFailClosedProcessStartTime(startTime)}, cmd: ${formatFailClosedCommandLine(commandLine)}`).join(`
|
|
126
|
+
`);
|
|
127
|
+
return `${summary}
|
|
128
|
+
Blocking process evidence:
|
|
129
|
+
${evidence}`;
|
|
130
|
+
}
|
|
131
|
+
function formatFailClosedBlockingMessage(reason) {
|
|
132
|
+
if (reason.kind === "migration_guard") {
|
|
133
|
+
if (reason.unreadableFile) {
|
|
134
|
+
const arm = reason.unreadableArm ?? "io";
|
|
135
|
+
const recovery = arm === "io" ? `If none of these processes are running, it is safe to delete ${reason.unreadableFile} and retry.` : `The file may be a recent incomplete write; retry after the file is older than the ten-minute grace window, or stop the relevant process before deleting it.`;
|
|
136
|
+
return [
|
|
137
|
+
`Magic Context cannot migrate the shared database because RPC discovery file ${reason.unreadableFile} is uncertain (${arm} arm), so the absence of a live process cannot be proven.`,
|
|
138
|
+
recovery,
|
|
139
|
+
`Recovery: ${FAIL_CLOSED_DOCTOR_COMMAND}`
|
|
140
|
+
].join(" ");
|
|
141
|
+
}
|
|
142
|
+
return [
|
|
143
|
+
`Magic Context cannot migrate the shared database (one database serves every project on this machine) because ${formatFailClosedBlockingProcesses(reason.blockingProcesses)} may be running an older Magic Context build that would fail against the migrated database.`,
|
|
144
|
+
`The database is at upstream migration v${reason.persistedVersion}; this build needs v${reason.supportedVersion}.`,
|
|
145
|
+
"Restart the blocking process — even one from a different project — and it will pick up the new build and migrate on start; or shut it down and retry.",
|
|
146
|
+
"If that host loads a pinned or cached older Magic Context build, a restart alone is not enough: stop it or update its Magic Context build, then start this host once so it migrates the database with nothing older attached.",
|
|
147
|
+
`Recovery: ${FAIL_CLOSED_DOCTOR_COMMAND}`
|
|
148
|
+
].join(" ");
|
|
149
|
+
}
|
|
150
|
+
if (reason.kind === "schema_fence") {
|
|
151
|
+
return [
|
|
152
|
+
`Magic Context cannot operate: this Magic Context build is older than the database; upgrade/restart this harness (upstream migration lane v${reason.persistedVersion}, build supports through v${reason.supportedVersion}).`,
|
|
153
|
+
`Recovery: ${FAIL_CLOSED_DOCTOR_COMMAND}`
|
|
154
|
+
].join(" ");
|
|
155
|
+
}
|
|
156
|
+
const cause = reason.cause.trim().length > 0 ? reason.cause.trim() : "unknown storage error";
|
|
157
|
+
return [
|
|
158
|
+
`Magic Context cannot operate: persistent storage failed (${cause}).`,
|
|
159
|
+
"The plugin will not silently degrade to native compaction while enabled.",
|
|
160
|
+
`Recovery: ${FAIL_CLOSED_DOCTOR_COMMAND}`
|
|
161
|
+
].join(" ");
|
|
162
|
+
}
|
|
163
|
+
function createFailClosedBlockingError(reason, options) {
|
|
164
|
+
return new FailClosedBlockingError(formatFailClosedBlockingMessage(reason), reason, options);
|
|
165
|
+
}
|
|
166
|
+
function isFailClosedBlockingError(error) {
|
|
167
|
+
return error instanceof FailClosedBlockingError || typeof error === "object" && error !== null && error.name === "FailClosedBlockingError" && error.code === "FAIL_CLOSED_BLOCKING";
|
|
168
|
+
}
|
|
169
|
+
function shouldBypassFailClosedBlock(input) {
|
|
170
|
+
if (input.isPiSubagentEnv === true)
|
|
171
|
+
return true;
|
|
172
|
+
if (input.isInternalChildSession === true)
|
|
173
|
+
return true;
|
|
174
|
+
const agent = typeof input.agent === "string" ? input.agent.trim() : "";
|
|
175
|
+
if (agent.length === 0)
|
|
176
|
+
return false;
|
|
177
|
+
if (OPENCODE_INTERNAL_AGENT_NAMES.has(agent))
|
|
178
|
+
return true;
|
|
179
|
+
if (isMagicContextHiddenAgentName(agent))
|
|
180
|
+
return true;
|
|
181
|
+
return false;
|
|
182
|
+
}
|
|
183
|
+
function createFailClosedController(options) {
|
|
184
|
+
const reprobeEveryN = Math.max(1, options?.reprobeEveryN ?? FAIL_CLOSED_REPROBE_EVERY_N);
|
|
185
|
+
let reason = null;
|
|
186
|
+
let blockedPassCount = 0;
|
|
187
|
+
return {
|
|
188
|
+
arm(next) {
|
|
189
|
+
reason = next;
|
|
190
|
+
blockedPassCount = 0;
|
|
191
|
+
},
|
|
192
|
+
clear() {
|
|
193
|
+
reason = null;
|
|
194
|
+
blockedPassCount = 0;
|
|
195
|
+
},
|
|
196
|
+
isArmed() {
|
|
197
|
+
return reason !== null;
|
|
198
|
+
},
|
|
199
|
+
getReason() {
|
|
200
|
+
return reason;
|
|
201
|
+
},
|
|
202
|
+
async enforce(input) {
|
|
203
|
+
if (!reason)
|
|
204
|
+
return;
|
|
205
|
+
if (!input.blockingEnabled)
|
|
206
|
+
return;
|
|
207
|
+
if (input.exempt)
|
|
208
|
+
return;
|
|
209
|
+
blockedPassCount += 1;
|
|
210
|
+
const shouldReprobe = typeof input.tryReopen === "function" && (blockedPassCount === 1 || blockedPassCount % reprobeEveryN === 0);
|
|
211
|
+
if (shouldReprobe) {
|
|
212
|
+
try {
|
|
213
|
+
const healed = await input.tryReopen?.();
|
|
214
|
+
if (healed) {
|
|
215
|
+
reason = null;
|
|
216
|
+
blockedPassCount = 0;
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
} catch {}
|
|
220
|
+
}
|
|
221
|
+
const blockedReason = reason;
|
|
222
|
+
if (!blockedReason)
|
|
223
|
+
return;
|
|
224
|
+
throw createFailClosedBlockingError(blockedReason);
|
|
225
|
+
}
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
export { FAIL_CLOSED_DOCTOR_COMMAND, attachFailClosedBlockingProcessEvidence, formatFailClosedBlockingMessage, createFailClosedBlockingError, isFailClosedBlockingError, shouldBypassFailClosedBlock, createFailClosedController };
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getMagicContextStorageDir,
|
|
3
3
|
log2
|
|
4
|
-
} from "./index-
|
|
4
|
+
} from "./index-gymgz20n.js";
|
|
5
5
|
import {
|
|
6
6
|
inRootAsyncContext2
|
|
7
7
|
} from "./index-2qtx0q6h.js";
|
|
8
|
+
import {
|
|
9
|
+
projectDirectoryKey
|
|
10
|
+
} from "./index-wrr9rp9a.js";
|
|
8
11
|
import {
|
|
9
12
|
writeStorageFileAtomicSync
|
|
10
13
|
} from "./index-81nthk8j.js";
|
|
@@ -14,32 +17,15 @@ import { execFileSync } from "node:child_process";
|
|
|
14
17
|
import { createHash as createHash2 } from "node:crypto";
|
|
15
18
|
import { existsSync, realpathSync as realpathSync2, statSync as statSync2 } from "node:fs";
|
|
16
19
|
import { homedir } from "node:os";
|
|
17
|
-
import
|
|
20
|
+
import path3 from "node:path";
|
|
18
21
|
|
|
19
22
|
// ../plugin/src/features/magic-context/memory/project-identity-cache.ts
|
|
20
23
|
import { createHash } from "node:crypto";
|
|
21
24
|
import { promises as fs, readFileSync } from "node:fs";
|
|
22
|
-
import path2 from "node:path";
|
|
23
|
-
|
|
24
|
-
// ../plugin/src/shared/project-directory-key.ts
|
|
25
25
|
import path from "node:path";
|
|
26
|
-
function projectDirectoryKey(directory) {
|
|
27
|
-
const slashed = directory.replaceAll("\\", "/").replace(/^\/\/\?\/UNC\//i, "//").replace(/^\/\/\?\//, "");
|
|
28
|
-
if (/^[a-z]:\//i.test(slashed) || slashed.startsWith("//")) {
|
|
29
|
-
return path.win32.normalize(slashed).replaceAll("\\", "/").replace(/\/$/, "").toLowerCase();
|
|
30
|
-
}
|
|
31
|
-
return path.resolve(directory);
|
|
32
|
-
}
|
|
33
|
-
function sameProjectDirectory(a, b) {
|
|
34
|
-
if (a.length === 0 || b.length === 0)
|
|
35
|
-
return false;
|
|
36
|
-
return projectDirectoryKey(a) === projectDirectoryKey(b);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// ../plugin/src/features/magic-context/memory/project-identity-cache.ts
|
|
40
26
|
function cachePath(directory, storageDir = getMagicContextStorageDir()) {
|
|
41
27
|
const hash = createHash("sha256").update(projectDirectoryKey(directory)).digest("hex");
|
|
42
|
-
return
|
|
28
|
+
return path.join(storageDir, "project-identities", `${hash}.json`);
|
|
43
29
|
}
|
|
44
30
|
function rememberGitIdentity(directory, identity) {
|
|
45
31
|
try {
|
|
@@ -56,7 +42,7 @@ function readRememberedGitIdentity(directory, storageDir) {
|
|
|
56
42
|
return;
|
|
57
43
|
}
|
|
58
44
|
async function pruneMissingProjectIdentities(storageDir = getMagicContextStorageDir()) {
|
|
59
|
-
const directory =
|
|
45
|
+
const directory = path.join(storageDir, "project-identities");
|
|
60
46
|
let removed = 0;
|
|
61
47
|
let entries;
|
|
62
48
|
try {
|
|
@@ -67,10 +53,10 @@ async function pruneMissingProjectIdentities(storageDir = getMagicContextStorage
|
|
|
67
53
|
for (const entry of entries) {
|
|
68
54
|
if (!/^[0-9a-f]{64}\.json$/.test(entry))
|
|
69
55
|
continue;
|
|
70
|
-
const file =
|
|
56
|
+
const file = path.join(directory, entry);
|
|
71
57
|
try {
|
|
72
58
|
const record = JSON.parse(await fs.readFile(file, "utf8"));
|
|
73
|
-
if (typeof record.directory !== "string" || !
|
|
59
|
+
if (typeof record.directory !== "string" || !path.isAbsolute(record.directory) || cachePath(record.directory, storageDir) !== file || !/^git:[0-9a-f]{7,64}$/.test(record.identity))
|
|
74
60
|
continue;
|
|
75
61
|
try {
|
|
76
62
|
await fs.stat(record.directory);
|
|
@@ -87,7 +73,7 @@ async function pruneMissingProjectIdentities(storageDir = getMagicContextStorage
|
|
|
87
73
|
|
|
88
74
|
// ../plugin/src/features/magic-context/memory/unborn-head.ts
|
|
89
75
|
import { readFileSync as readFileSync2, realpathSync, statSync } from "node:fs";
|
|
90
|
-
import
|
|
76
|
+
import path2 from "node:path";
|
|
91
77
|
var GIT_LOCATION_ENV_VARS = [
|
|
92
78
|
"GIT_DIR",
|
|
93
79
|
"GIT_COMMON_DIR",
|
|
@@ -123,7 +109,7 @@ function stripLineEnding(text) {
|
|
|
123
109
|
return text.replace(/\r?\n$/u, "");
|
|
124
110
|
}
|
|
125
111
|
function resolveMetadataPath(baseDirectory, value) {
|
|
126
|
-
return
|
|
112
|
+
return path2.resolve(baseDirectory, value);
|
|
127
113
|
}
|
|
128
114
|
function isPlainBranchName(name) {
|
|
129
115
|
if (name.length === 0 || name.endsWith("/") || name.endsWith("."))
|
|
@@ -140,7 +126,7 @@ function isPlainBranchName(name) {
|
|
|
140
126
|
function findGitDirectory(start) {
|
|
141
127
|
let current = start;
|
|
142
128
|
while (true) {
|
|
143
|
-
const dotGit =
|
|
129
|
+
const dotGit = path2.join(current, ".git");
|
|
144
130
|
const kind = entryKind(dotGit);
|
|
145
131
|
if (kind === "directory")
|
|
146
132
|
return dotGit;
|
|
@@ -156,7 +142,7 @@ function findGitDirectory(start) {
|
|
|
156
142
|
}
|
|
157
143
|
if (kind !== "missing")
|
|
158
144
|
return;
|
|
159
|
-
const parent =
|
|
145
|
+
const parent = path2.dirname(current);
|
|
160
146
|
if (parent === current)
|
|
161
147
|
return;
|
|
162
148
|
current = parent;
|
|
@@ -181,7 +167,7 @@ function isUnbornHeadInLayout(directory) {
|
|
|
181
167
|
if (gitDirectory === undefined)
|
|
182
168
|
return false;
|
|
183
169
|
let commonDirectory = gitDirectory;
|
|
184
|
-
const commondir = readText(
|
|
170
|
+
const commondir = readText(path2.join(gitDirectory, "commondir"));
|
|
185
171
|
if (commondir.ok) {
|
|
186
172
|
const value = stripLineEnding(commondir.text);
|
|
187
173
|
if (value === "" || value.includes(`
|
|
@@ -191,22 +177,22 @@ function isUnbornHeadInLayout(directory) {
|
|
|
191
177
|
} else if (!commondir.missing) {
|
|
192
178
|
return false;
|
|
193
179
|
}
|
|
194
|
-
if (entryKind(
|
|
180
|
+
if (entryKind(path2.join(gitDirectory, "HEAD")) !== "file")
|
|
195
181
|
return false;
|
|
196
|
-
if (entryKind(
|
|
182
|
+
if (entryKind(path2.join(commonDirectory, "objects")) !== "directory")
|
|
197
183
|
return false;
|
|
198
|
-
if (entryKind(
|
|
184
|
+
if (entryKind(path2.join(commonDirectory, "refs")) !== "directory")
|
|
199
185
|
return false;
|
|
200
|
-
if (entryKind(
|
|
186
|
+
if (entryKind(path2.join(commonDirectory, "reftable")) !== "missing")
|
|
201
187
|
return false;
|
|
202
|
-
const config = readText(
|
|
188
|
+
const config = readText(path2.join(commonDirectory, "config"));
|
|
203
189
|
if (config.ok) {
|
|
204
190
|
if (/refstorage/iu.test(config.text))
|
|
205
191
|
return false;
|
|
206
192
|
} else if (!config.missing) {
|
|
207
193
|
return false;
|
|
208
194
|
}
|
|
209
|
-
const head = readText(
|
|
195
|
+
const head = readText(path2.join(gitDirectory, "HEAD"));
|
|
210
196
|
if (!head.ok)
|
|
211
197
|
return false;
|
|
212
198
|
const headMatch = /^ref: (refs\/heads\/(.+))$/u.exec(head.text.replace(/\s+$/u, ""));
|
|
@@ -216,10 +202,10 @@ function isUnbornHeadInLayout(directory) {
|
|
|
216
202
|
return false;
|
|
217
203
|
const refSegments = ref.split("/");
|
|
218
204
|
for (const base of new Set([commonDirectory, gitDirectory])) {
|
|
219
|
-
if (entryKind(
|
|
205
|
+
if (entryKind(path2.join(base, ...refSegments)) !== "missing")
|
|
220
206
|
return false;
|
|
221
207
|
}
|
|
222
|
-
const packed = readText(
|
|
208
|
+
const packed = readText(path2.join(commonDirectory, "packed-refs"));
|
|
223
209
|
if (packed.ok) {
|
|
224
210
|
if (packedRefsList(packed.text, ref) !== false)
|
|
225
211
|
return false;
|
|
@@ -234,7 +220,7 @@ function isUnbornHeadOnDisk(directory, env = process.env) {
|
|
|
234
220
|
}
|
|
235
221
|
let realDirectory;
|
|
236
222
|
try {
|
|
237
|
-
realDirectory = realpathSync.native(
|
|
223
|
+
realDirectory = realpathSync.native(path2.resolve(directory));
|
|
238
224
|
} catch {
|
|
239
225
|
return false;
|
|
240
226
|
}
|
|
@@ -316,7 +302,7 @@ function getErrorStderr(error) {
|
|
|
316
302
|
return "";
|
|
317
303
|
}
|
|
318
304
|
function directoryFallback(directory) {
|
|
319
|
-
const canonical =
|
|
305
|
+
const canonical = path3.resolve(directory);
|
|
320
306
|
const hash = createHash2("md5").update(canonical, "utf8").digest("hex").slice(0, 12);
|
|
321
307
|
return `dir:${hash}`;
|
|
322
308
|
}
|
|
@@ -388,7 +374,7 @@ function classifyGitError(error, rawDirectory) {
|
|
|
388
374
|
}
|
|
389
375
|
function resolveProjectIdentityStrict(directory, allowHomeProject = homeProjectPermission, options = {}) {
|
|
390
376
|
assertProjectAllowed(directory, allowHomeProject);
|
|
391
|
-
const canonical =
|
|
377
|
+
const canonical = path3.resolve(directory);
|
|
392
378
|
const cached = options.cache === false ? undefined : identityCache.get(canonical);
|
|
393
379
|
if (cached !== undefined) {
|
|
394
380
|
return cached;
|
|
@@ -460,9 +446,9 @@ function nearestLastKnownGitIdentity(canonical) {
|
|
|
460
446
|
const cached = lastKnownGitIdentity(current);
|
|
461
447
|
if (cached !== undefined)
|
|
462
448
|
return { identity: cached, source: current };
|
|
463
|
-
if (existsSync(
|
|
449
|
+
if (existsSync(path3.join(current, ".git")))
|
|
464
450
|
break;
|
|
465
|
-
const parent =
|
|
451
|
+
const parent = path3.dirname(current);
|
|
466
452
|
if (parent === current)
|
|
467
453
|
break;
|
|
468
454
|
current = parent;
|
|
@@ -512,20 +498,20 @@ function isUserHomeDirectory(directory) {
|
|
|
512
498
|
if (projectDirectoryKey(directory) === projectDirectoryKey(userHomeDirectoryForIdentity()))
|
|
513
499
|
return true;
|
|
514
500
|
try {
|
|
515
|
-
return projectDirectoryKey(realpathSync2.native(
|
|
501
|
+
return projectDirectoryKey(realpathSync2.native(path3.resolve(directory))) === projectDirectoryKey(canonicalUserHomeDirectory());
|
|
516
502
|
} catch {
|
|
517
503
|
return false;
|
|
518
504
|
}
|
|
519
505
|
}
|
|
520
506
|
function assertProjectAllowed(directory, allowHomeProject) {
|
|
521
|
-
const canonical =
|
|
507
|
+
const canonical = path3.resolve(directory);
|
|
522
508
|
if (!allowHomeProject && (isUserHomeDirectory(directory) || isUserHomeDirectory(gitRootDirectory(canonical) ?? canonical))) {
|
|
523
509
|
throw new ProjectIdentityError("home_project_disabled", directory, "Home project memory is disabled; set allow_home_project to opt in");
|
|
524
510
|
}
|
|
525
511
|
}
|
|
526
512
|
function resolveProjectIdentity(directory, allowHomeProject = homeProjectPermission) {
|
|
527
513
|
assertProjectAllowed(directory, allowHomeProject);
|
|
528
|
-
const canonical =
|
|
514
|
+
const canonical = path3.resolve(directory);
|
|
529
515
|
const cachedFallback = directoryFallbackCache.get(canonical);
|
|
530
516
|
if (cachedFallback !== undefined) {
|
|
531
517
|
if (!hasGitDir(canonical)) {
|
|
@@ -573,7 +559,7 @@ function resolveProjectIdentityOrFallback(directory, allowHomeProject = homeProj
|
|
|
573
559
|
try {
|
|
574
560
|
return resolveProjectIdentity(directory, allowHomeProject);
|
|
575
561
|
} catch (error) {
|
|
576
|
-
const canonical =
|
|
562
|
+
const canonical = path3.resolve(directory);
|
|
577
563
|
if (hasGitDir(canonical) || error instanceof ProjectIdentityError && error.errorClass === "home_project_disabled")
|
|
578
564
|
throw error;
|
|
579
565
|
const fallback = rememberedIdentityOrDirectoryFallback(canonical);
|
|
@@ -596,14 +582,14 @@ function hasGitDir(canonical) {
|
|
|
596
582
|
function gitRootInAncestorChain(startDirectory) {
|
|
597
583
|
let current = startDirectory;
|
|
598
584
|
while (true) {
|
|
599
|
-
if (existsSync(
|
|
585
|
+
if (existsSync(path3.join(current, ".git"))) {
|
|
600
586
|
try {
|
|
601
587
|
return realpathSync2.native(current);
|
|
602
588
|
} catch {
|
|
603
|
-
return
|
|
589
|
+
return path3.resolve(current);
|
|
604
590
|
}
|
|
605
591
|
}
|
|
606
|
-
const parent =
|
|
592
|
+
const parent = path3.dirname(current);
|
|
607
593
|
if (parent === current) {
|
|
608
594
|
return null;
|
|
609
595
|
}
|
|
@@ -625,13 +611,13 @@ function gitRootDirectory(canonical) {
|
|
|
625
611
|
}
|
|
626
612
|
}
|
|
627
613
|
function directoryHasGitMetadata(directory) {
|
|
628
|
-
return gitRootDirectory(
|
|
614
|
+
return gitRootDirectory(path3.resolve(directory)) !== null;
|
|
629
615
|
}
|
|
630
616
|
function isUsableProjectIdentity(identity) {
|
|
631
617
|
return typeof identity === "string" && identity.trim().length > 0;
|
|
632
618
|
}
|
|
633
619
|
function resolveProjectIdentityForSession(directory, allowHomeProject = homeProjectPermission) {
|
|
634
|
-
const resolvedDirectory =
|
|
620
|
+
const resolvedDirectory = path3.resolve(directory);
|
|
635
621
|
const cacheKey = `${allowHomeProject ? "1" : "0"}\x00${resolvedDirectory}`;
|
|
636
622
|
const cached = sessionIdentityCache.get(cacheKey);
|
|
637
623
|
if (cached && (cached.revalidateAt === null || nowMs() < cached.revalidateAt) && !(cached.identity?.startsWith("dir:") && hasGitDir(resolvedDirectory))) {
|
|
@@ -710,4 +696,4 @@ function setBootQuietPeriodForTests(startAtMs) {
|
|
|
710
696
|
bootQuietUntilMs = startAtMs === null ? 0 : startAtMs + BOOT_QUIET_MS;
|
|
711
697
|
}
|
|
712
698
|
|
|
713
|
-
export {
|
|
699
|
+
export { pruneMissingProjectIdentities, setHomeProjectPermission, ProjectIdentityError, resolveProjectIdentityStrict, isUserHomeDirectory, resolveProjectIdentity, directoryHasGitMetadata, isUsableProjectIdentity, resolveProjectIdentityForSession, normalizeStoredProjectPath, storedPathBelongsToIdentity, beginBootQuietPeriod, scheduleAfterBootQuiet, setBootQuietPeriodForTests };
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import {
|
|
2
|
+
registerExitAbort
|
|
3
|
+
} from "./index-399p688g.js";
|
|
4
|
+
import {
|
|
5
|
+
inRootAsyncContext2
|
|
6
|
+
} from "./index-2qtx0q6h.js";
|
|
7
|
+
import {
|
|
8
|
+
createWorkerShutdown
|
|
9
|
+
} from "./index-54wmg4rj.js";
|
|
10
|
+
|
|
11
|
+
// ../plugin/src/tools/ctx-expand/v2-archive-reader.ts
|
|
12
|
+
import { Worker } from "node:worker_threads";
|
|
13
|
+
var worker;
|
|
14
|
+
var shutdown;
|
|
15
|
+
var ready;
|
|
16
|
+
var idle;
|
|
17
|
+
var startingTimer;
|
|
18
|
+
var rejectStart;
|
|
19
|
+
var nextId = 0;
|
|
20
|
+
var exitRegistered = false;
|
|
21
|
+
var pending = new Map;
|
|
22
|
+
async function stopV2ArchiveReader() {
|
|
23
|
+
const closing = shutdown;
|
|
24
|
+
worker = undefined;
|
|
25
|
+
shutdown = undefined;
|
|
26
|
+
ready = undefined;
|
|
27
|
+
clearTimeout(idle);
|
|
28
|
+
clearTimeout(startingTimer);
|
|
29
|
+
rejectStart?.(new Error("Search archive worker unavailable: reader stopped"));
|
|
30
|
+
rejectStart = undefined;
|
|
31
|
+
for (const item of pending.values()) {
|
|
32
|
+
clearTimeout(item.timer);
|
|
33
|
+
item.reject(new Error("Search archive worker unavailable: reader stopped"));
|
|
34
|
+
}
|
|
35
|
+
pending.clear();
|
|
36
|
+
await closing?.close();
|
|
37
|
+
}
|
|
38
|
+
function start() {
|
|
39
|
+
if (ready)
|
|
40
|
+
return ready;
|
|
41
|
+
if (!exitRegistered) {
|
|
42
|
+
exitRegistered = true;
|
|
43
|
+
const controller = new AbortController;
|
|
44
|
+
controller.signal.addEventListener("abort", () => {
|
|
45
|
+
stopV2ArchiveReader();
|
|
46
|
+
}, { once: true });
|
|
47
|
+
registerExitAbort(controller);
|
|
48
|
+
}
|
|
49
|
+
ready = new Promise((resolve, reject) => {
|
|
50
|
+
rejectStart = reject;
|
|
51
|
+
const entry = new URL(import.meta.url.endsWith(".ts") ? "../../hooks/magic-context/raw-ordinal-warmup-worker.ts" : "./raw-ordinal-warmup-worker.js", import.meta.url);
|
|
52
|
+
const current = inRootAsyncContext2(() => new Worker(entry, { workerData: { v2ArchiveReader: true } }));
|
|
53
|
+
worker = current;
|
|
54
|
+
shutdown = createWorkerShutdown(current, "v2-archive-reader", 2000);
|
|
55
|
+
current.unref();
|
|
56
|
+
const fail = (detail) => {
|
|
57
|
+
if (worker !== current)
|
|
58
|
+
return;
|
|
59
|
+
clearTimeout(startingTimer);
|
|
60
|
+
reject(new Error(`Search archive worker unavailable: ${detail}`));
|
|
61
|
+
stopV2ArchiveReader();
|
|
62
|
+
};
|
|
63
|
+
startingTimer = setTimeout(() => fail("reader did not start"), 1e4);
|
|
64
|
+
startingTimer.unref?.();
|
|
65
|
+
current.on("error", (error) => fail(String(error)));
|
|
66
|
+
current.on("exit", (code) => fail(`exit code ${code}`));
|
|
67
|
+
current.on("message", (reply) => {
|
|
68
|
+
if (worker !== current)
|
|
69
|
+
return;
|
|
70
|
+
if (reply.kind === "v2-archive-ready") {
|
|
71
|
+
clearTimeout(startingTimer);
|
|
72
|
+
rejectStart = undefined;
|
|
73
|
+
resolve();
|
|
74
|
+
} else if (reply.kind === "v2-archive-result") {
|
|
75
|
+
const item = pending.get(reply.id);
|
|
76
|
+
if (!item)
|
|
77
|
+
return;
|
|
78
|
+
pending.delete(reply.id);
|
|
79
|
+
clearTimeout(item.timer);
|
|
80
|
+
if (reply.error)
|
|
81
|
+
item.reject(new Error(`Search archive worker unavailable: ${reply.error}`));
|
|
82
|
+
else
|
|
83
|
+
item.resolve(reply.text);
|
|
84
|
+
if (pending.size === 0) {
|
|
85
|
+
idle = setTimeout(() => {
|
|
86
|
+
stopV2ArchiveReader();
|
|
87
|
+
}, 60000);
|
|
88
|
+
idle.unref?.();
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
return ready;
|
|
94
|
+
}
|
|
95
|
+
async function readV2ArchiveOffThread2(path, rawPath, sessionId, read) {
|
|
96
|
+
try {
|
|
97
|
+
clearTimeout(idle);
|
|
98
|
+
await start();
|
|
99
|
+
const current = worker;
|
|
100
|
+
if (!current)
|
|
101
|
+
throw new Error("Search archive worker unavailable: reader stopped");
|
|
102
|
+
return await new Promise((resolve, reject) => {
|
|
103
|
+
const id = ++nextId;
|
|
104
|
+
const timer = setTimeout(() => {
|
|
105
|
+
stopV2ArchiveReader();
|
|
106
|
+
}, 10 * 60000);
|
|
107
|
+
timer.unref?.();
|
|
108
|
+
pending.set(id, { resolve, reject, timer });
|
|
109
|
+
try {
|
|
110
|
+
current.postMessage({
|
|
111
|
+
kind: "v2-archive-read",
|
|
112
|
+
id,
|
|
113
|
+
path,
|
|
114
|
+
rawPath,
|
|
115
|
+
sessionId,
|
|
116
|
+
read
|
|
117
|
+
});
|
|
118
|
+
} catch {
|
|
119
|
+
stopV2ArchiveReader();
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
} catch (error) {
|
|
123
|
+
await stopV2ArchiveReader();
|
|
124
|
+
if (error instanceof Error && error.message.startsWith("Search archive worker unavailable:"))
|
|
125
|
+
throw error;
|
|
126
|
+
throw new Error(`Search archive worker unavailable: ${String(error)}`);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
async function serveV2ArchiveReads2(port, openConnections) {
|
|
130
|
+
const [
|
|
131
|
+
{ Database },
|
|
132
|
+
{ V2StoreReaderPool },
|
|
133
|
+
{ createV2RawMessageReader, createV2RawMessageProvider },
|
|
134
|
+
{ setBoundedRawMessageProvider },
|
|
135
|
+
{ renderItemByTag, renderMessageByOrdinal, renderVerboseRangeForTool },
|
|
136
|
+
{ renderSearchArchive },
|
|
137
|
+
{ createV2RecoveryAttachments }
|
|
138
|
+
] = await Promise.all([
|
|
139
|
+
import("./sqlite-v89bj0yy.js"),
|
|
140
|
+
import("./store-reader-2m80zs5z.js"),
|
|
141
|
+
import("./store-kabezr25.js"),
|
|
142
|
+
import("./read-session-chunk-nbcznexm.js"),
|
|
143
|
+
import("./render-d931g2vv.js"),
|
|
144
|
+
import("./search-archive-a76pp30g.js"),
|
|
145
|
+
import("./expand-attachments-8sxeyj26.js")
|
|
146
|
+
]);
|
|
147
|
+
const pool = new V2StoreReaderPool;
|
|
148
|
+
openConnections.add(pool);
|
|
149
|
+
port.on("message", (request) => {
|
|
150
|
+
if (request.kind !== "v2-archive-read")
|
|
151
|
+
return;
|
|
152
|
+
let db;
|
|
153
|
+
let unregister;
|
|
154
|
+
let rawReader;
|
|
155
|
+
let reply;
|
|
156
|
+
try {
|
|
157
|
+
db = new Database(request.path, { readonly: true, fileMustExist: true });
|
|
158
|
+
openConnections.add(db);
|
|
159
|
+
db.exec("PRAGMA busy_timeout = 250");
|
|
160
|
+
const raw = pool.open(request.rawPath);
|
|
161
|
+
rawReader = raw;
|
|
162
|
+
const reader = createV2RawMessageReader(() => raw, undefined, () => {});
|
|
163
|
+
const attachments = createV2RecoveryAttachments(raw);
|
|
164
|
+
unregister = setBoundedRawMessageProvider(request.sessionId, createV2RawMessageProvider(reader, request.sessionId));
|
|
165
|
+
const read = request.read;
|
|
166
|
+
let text;
|
|
167
|
+
if (read.kind === "tag") {
|
|
168
|
+
text = renderItemByTag(db, request.sessionId, read.tag, "part", attachments);
|
|
169
|
+
} else {
|
|
170
|
+
const start = read.kind === "message" ? read.message : read.start;
|
|
171
|
+
const end = read.kind === "message" ? read.message : read.end;
|
|
172
|
+
text = renderSearchArchive(db, request.sessionId, start, end, read.tokenBudget, read.kind === "archive" && read.archiveOnly, () => reader.ordinalMapForRange(request.sessionId, start, end));
|
|
173
|
+
if (text === null && read.kind === "message") {
|
|
174
|
+
text = renderMessageByOrdinal(request.sessionId, read.message, attachments);
|
|
175
|
+
} else if (text === null && read.kind === "verbose") {
|
|
176
|
+
text = renderVerboseRangeForTool(request.sessionId, start, end, read.tokenBudget, read.expandTools, attachments);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
reply = { kind: "v2-archive-result", id: request.id, text };
|
|
180
|
+
} catch (error) {
|
|
181
|
+
reply = { kind: "v2-archive-result", id: request.id, text: null, error: String(error) };
|
|
182
|
+
} finally {
|
|
183
|
+
unregister?.();
|
|
184
|
+
rawReader?.close();
|
|
185
|
+
if (db)
|
|
186
|
+
openConnections.delete(db);
|
|
187
|
+
db?.close();
|
|
188
|
+
}
|
|
189
|
+
port.postMessage(reply);
|
|
190
|
+
});
|
|
191
|
+
port.postMessage({ kind: "v2-archive-ready" });
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
export { readV2ArchiveOffThread2, serveV2ArchiveReads2 };
|