@nowcrew/daemon 0.6.101-beta.6 → 0.6.101-beta.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cloud-report-upload.js +10 -1
- package/dist/execution-journal.js +1 -3
- package/dist/execution-protocol.js +1 -1
- package/dist/execution-runner.js +1 -4
- package/dist/local-execution-prompt.js +3 -8
- package/dist/local-executor.js +55 -78
- package/dist/local-memory/index-budget.js +3 -9
- package/dist/local-memory/inventory-cli.js +8 -52
- package/dist/local-memory/inventory-source.js +8 -15
- package/dist/local-memory/pending-query.js +2 -5
- package/dist/local-memory/pending-schema.js +1 -1
- package/dist/local-memory/pending.js +2 -16
- package/dist/local-memory/prompt.js +5 -21
- package/dist/local-memory/read-cli.js +76 -98
- package/dist/local-memory/rollout.js +11 -79
- package/dist/local-memory/runtime.js +17 -191
- package/dist/local-memory/write.js +21 -190
- package/dist/local-memory-diagnostics.js +15 -96
- package/dist/local-memory-telemetry.js +3 -31
- package/dist/machine-info.js +0 -3
- package/dist/marketplace-protocol.js +1 -1
- package/dist/marketplace-remote.js +1 -1
- package/dist/marketplace-runner.js +1 -1
- package/dist/memory-prune-diagnostics.js +4 -74
- package/dist/message-file-preview.js +1 -11
- package/dist/prompt.js +17 -9
- package/dist/runner.js +1 -1
- package/dist/runtimes/claude-thread-runner.js +4 -25
- package/dist/serve.js +3 -38
- package/dist/token.js +0 -1
- package/dist/workspace-control-handler.js +3 -16
- package/dist/workspace.js +4 -23
- package/package.json +1 -1
- package/dist/local-memory/commit-telemetry.js +0 -30
- package/dist/local-memory/execution-workspace.js +0 -117
- package/dist/local-memory/full-index-search.js +0 -47
- package/dist/local-memory/initialization-identity.js +0 -36
- package/dist/local-memory/inventory-v2.js +0 -362
- package/dist/local-memory/legacy-adapter.js +0 -233
- package/dist/local-memory/migration-access.js +0 -242
- package/dist/local-memory/migration-cli.js +0 -54
- package/dist/local-memory/migration-io.js +0 -199
- package/dist/local-memory/migration-pending.js +0 -9
- package/dist/local-memory/migration-plan.js +0 -432
- package/dist/local-memory/migration-schema.js +0 -58
- package/dist/local-memory/migration-state-invariants.js +0 -65
- package/dist/local-memory/migration-store.js +0 -414
- package/dist/local-memory/migration-tool-entry.js +0 -21
- package/dist/local-memory/release-artifact-guard.js +0 -55
- package/dist/local-memory/source-path.js +0 -13
- package/dist/local-memory/storage-format.js +0 -249
- package/dist/local-memory/writer-mode.js +0 -13
- package/dist/memory-migration-controller.js +0 -89
- package/dist/memory-migration-inspect.js +0 -116
- package/dist/memory-migration-journal.js +0 -14
- package/dist/memory-migration-protocol.js +0 -14
- package/dist/memory-migration-runtime.js +0 -367
|
@@ -6,8 +6,6 @@ import { dslog } from "../slog.js";
|
|
|
6
6
|
import { LocalMemoryChangeSchema, LocalMemorySingleLineText, validateLocalMemoryChange, } from "./candidate.js";
|
|
7
7
|
import { LOCAL_MEMORY_INDEX_CODE_POINT_CAP, LOCAL_MEMORY_INDEX_ENTRY_CAP, LOCAL_MEMORY_TOTAL_CODE_POINT_CAP, renderGeneratedIndex, selectLocalMemoryIndexEntries, } from "./index-budget.js";
|
|
8
8
|
import { persistPendingMemoryCandidate, readPendingMemoryCandidates, removePendingMemoryCandidate, } from "./pending.js";
|
|
9
|
-
import { assertLocalMemoryStorageSize, detectLocalMemoryStorageVersion, LOCAL_MEMORY_GENERATED_INDEX_PATTERN, LOCAL_MEMORY_NOTE_BYTE_CAP, LOCAL_MEMORY_READ_BYTE_CAP, parseFullMemoryIndex, replaceFullMemoryIndex, selectLocalMemoryPreview, } from "./storage-format.js";
|
|
10
|
-
import { assertMemoryInventoryHealth, assertMemoryWriterAllowed, withMemoryAccess } from "./migration-access.js";
|
|
11
9
|
const StatusChangeSchema = z.object({
|
|
12
10
|
memoryId: LocalMemorySingleLineText,
|
|
13
11
|
expectedRevision: z.number().int().positive(),
|
|
@@ -22,7 +20,6 @@ const ResultSchema = z.object({
|
|
|
22
20
|
outcome: z.enum(["no_change", "proposed", "conflict", "failed"]),
|
|
23
21
|
changes: z.array(LocalMemoryChangeSchema).max(50),
|
|
24
22
|
statusChanges: z.array(StatusChangeSchema).max(50),
|
|
25
|
-
workLogDisposition: z.enum(["clear", "preserve"]).optional(),
|
|
26
23
|
}).strict();
|
|
27
24
|
const GENERATED_INDEX_PATTERN = /<!--\s*NOWWORK:MEMORY_INDEX:BEGIN\s+schema=1\s*-->[\s\S]*?<!--\s*NOWWORK:MEMORY_INDEX:END\s*-->/u;
|
|
28
25
|
const INDEX_HEADING = /^##\s+Knowledge Index\s*$/mu;
|
|
@@ -93,14 +90,12 @@ function parseCards(section) {
|
|
|
93
90
|
});
|
|
94
91
|
}
|
|
95
92
|
export function parseLocalMemoryIndex(memory) {
|
|
96
|
-
if (detectLocalMemoryStorageVersion(memory) === 2)
|
|
97
|
-
return parseFullMemoryIndex(memory);
|
|
98
93
|
const section = indexSection(memory);
|
|
99
94
|
const generated = GENERATED_INDEX_PATTERN.exec(section)?.[0];
|
|
100
95
|
return parseCards(generated ?? section);
|
|
101
96
|
}
|
|
102
97
|
function parseUnmarkedMemoryIndex(memory) {
|
|
103
|
-
const section = indexSection(memory).replace(
|
|
98
|
+
const section = indexSection(memory).replace(GENERATED_INDEX_PATTERN, "");
|
|
104
99
|
return parseCards(section);
|
|
105
100
|
}
|
|
106
101
|
function replaceGeneratedIndex(memory, entries) {
|
|
@@ -127,36 +122,11 @@ function noteSection(id, revision, title, body) {
|
|
|
127
122
|
}
|
|
128
123
|
function notePattern(id) {
|
|
129
124
|
const escaped = id.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
|
|
130
|
-
return new RegExp(`<!--\\s*NOWWORK:MEMORY_ENTRY:BEGIN\\s+id=${escaped}
|
|
131
|
-
}
|
|
132
|
-
function uniqueNoteSection(content, id) {
|
|
133
|
-
const escaped = id.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
|
|
134
|
-
const begins = [...content.matchAll(new RegExp(`<!--\\s*NOWWORK:MEMORY_ENTRY:BEGIN\\s+id=${escaped}(?=\\s|-->)`, "gu"))];
|
|
135
|
-
const ends = [...content.matchAll(new RegExp(`<!--\\s*NOWWORK:MEMORY_ENTRY:END\\s+id=${escaped}\\s*-->`, "gu"))];
|
|
136
|
-
if (begins.length === 0 && ends.length === 0)
|
|
137
|
-
return null;
|
|
138
|
-
const section = notePattern(id).exec(content)?.[0];
|
|
139
|
-
if (begins.length !== 1 || ends.length !== 1 || section === undefined
|
|
140
|
-
|| (section.match(/NOWWORK:MEMORY_ENTRY:(?:BEGIN|END)/gu) ?? []).length !== 2) {
|
|
141
|
-
throw new Error("local_memory_note_anchor_invalid");
|
|
142
|
-
}
|
|
143
|
-
return section;
|
|
125
|
+
return new RegExp(`<!--\\s*NOWWORK:MEMORY_ENTRY:BEGIN\\s+id=${escaped}[^>]*-->[\\s\\S]*?<!--\\s*NOWWORK:MEMORY_ENTRY:END\\s+id=${escaped}\\s*-->\\s*`, "u");
|
|
144
126
|
}
|
|
145
127
|
function replaceNote(content, id, replacement) {
|
|
146
128
|
const pattern = notePattern(id);
|
|
147
|
-
return
|
|
148
|
-
}
|
|
149
|
-
function updateNoteRevision(content, id, revision) {
|
|
150
|
-
const section = uniqueNoteSection(content, id);
|
|
151
|
-
const beginning = `<!-- NOWWORK:MEMORY_ENTRY:BEGIN id=${id} `;
|
|
152
|
-
const ending = `<!-- NOWWORK:MEMORY_ENTRY:END id=${id} -->`;
|
|
153
|
-
if (section === null || content.split(beginning).length !== 2 || content.split(ending).length !== 2) {
|
|
154
|
-
throw new Error("local_memory_note_anchor_missing");
|
|
155
|
-
}
|
|
156
|
-
const updated = section.replace(/^(<!--\s*NOWWORK:MEMORY_ENTRY:BEGIN\s+id=[A-Za-z0-9_-]+\s+revision=)[1-9][0-9]*(\s*-->)/u, (_match, prefix, suffix) => `${prefix}${revision}${suffix}`);
|
|
157
|
-
if (!updated.startsWith(`${beginning}revision=${revision} -->`))
|
|
158
|
-
throw new Error("local_memory_note_anchor_missing");
|
|
159
|
-
return content.replace(notePattern(id), () => updated);
|
|
129
|
+
return pattern.test(content) ? content.replace(pattern, replacement) : null;
|
|
160
130
|
}
|
|
161
131
|
function validateCandidate(result) {
|
|
162
132
|
if (result.outcome === "no_change" && (result.changes.length > 0 || result.statusChanges.length > 0)) {
|
|
@@ -210,25 +180,6 @@ function stableId(executionId, index, change) {
|
|
|
210
180
|
const input = [executionId, String(index), change.operation, change.title, change.summary, change.detailBody].join("\0");
|
|
211
181
|
return `mem_${createHash("sha256").update(input, "utf8").digest("hex").slice(0, 12)}`;
|
|
212
182
|
}
|
|
213
|
-
function migrationPendingId(change) {
|
|
214
|
-
// Keep the digest independent of object insertion order for callers that
|
|
215
|
-
// reach applyLocalMemoryResult directly instead of the JSON/Zod boundary.
|
|
216
|
-
const canonicalChange = {
|
|
217
|
-
operation: change.operation,
|
|
218
|
-
memoryId: change.memoryId,
|
|
219
|
-
baseRevision: change.baseRevision,
|
|
220
|
-
supersedesMemoryId: change.supersedesMemoryId,
|
|
221
|
-
title: change.title,
|
|
222
|
-
kind: change.kind,
|
|
223
|
-
summary: change.summary,
|
|
224
|
-
triggers: change.triggers,
|
|
225
|
-
priority: change.priority,
|
|
226
|
-
detailCategory: change.detailCategory,
|
|
227
|
-
detailBody: change.detailBody,
|
|
228
|
-
reviewAfter: change.reviewAfter,
|
|
229
|
-
};
|
|
230
|
-
return `pending-migration-${createHash("sha256").update(JSON.stringify(canonicalChange), "utf8").digest("hex").slice(0, 12)}`;
|
|
231
|
-
}
|
|
232
183
|
function normalize(value) {
|
|
233
184
|
return value.normalize("NFKC").toLocaleLowerCase().replace(/\s+/gu, " ").trim();
|
|
234
185
|
}
|
|
@@ -248,14 +199,14 @@ function detailCategoryFromFile(file) {
|
|
|
248
199
|
return DETAIL_CATEGORIES.has(category) ? category : null;
|
|
249
200
|
}
|
|
250
201
|
function readNoteBody(content, id) {
|
|
251
|
-
const
|
|
252
|
-
if (
|
|
202
|
+
const begin = content.indexOf(`<!-- NOWWORK:MEMORY_ENTRY:BEGIN id=${id}`);
|
|
203
|
+
if (begin < 0)
|
|
253
204
|
return null;
|
|
254
|
-
const bodyStart =
|
|
255
|
-
const bodyEnd =
|
|
205
|
+
const bodyStart = content.indexOf("\n\n", begin);
|
|
206
|
+
const bodyEnd = content.indexOf(`\n<!-- NOWWORK:MEMORY_ENTRY:END id=${id}`, bodyStart + 2);
|
|
256
207
|
if (bodyStart < 0 || bodyEnd < 0)
|
|
257
208
|
return null;
|
|
258
|
-
return
|
|
209
|
+
return content.slice(bodyStart + 2, bodyEnd).trim();
|
|
259
210
|
}
|
|
260
211
|
function archivedChange(entry, detailBody) {
|
|
261
212
|
const detailCategory = detailCategoryFromFile(entry.file);
|
|
@@ -279,34 +230,6 @@ function archivedChange(entry, detailBody) {
|
|
|
279
230
|
function emptyResult() {
|
|
280
231
|
return { createdIds: [], updatedIds: [], statusChangedIds: [], deferredIds: [], pendingIds: [] };
|
|
281
232
|
}
|
|
282
|
-
async function stageMigrationDeferredPending(input) {
|
|
283
|
-
if (input.result.outcome !== "proposed")
|
|
284
|
-
return emptyResult();
|
|
285
|
-
if (input.result.statusChanges.length > 0 || input.result.changes.some((change) => change.operation !== "create")) {
|
|
286
|
-
throw new Error("local_memory_migration_pending_create_only");
|
|
287
|
-
}
|
|
288
|
-
const executionId = input.executionId ?? "unknown";
|
|
289
|
-
const pending = input.result.changes.map((change) => ({
|
|
290
|
-
schemaVersion: 1,
|
|
291
|
-
pendingId: migrationPendingId(change),
|
|
292
|
-
createdAt: new Date().toISOString(),
|
|
293
|
-
reason: "legacy_requires_migration",
|
|
294
|
-
source: { executionId, pruneTraceId: input.pruneTraceId ?? null },
|
|
295
|
-
candidate: change,
|
|
296
|
-
}));
|
|
297
|
-
await assertMemoryAccessDirectory(input.agentDir);
|
|
298
|
-
await withMemoryAccess(input.agentDir, async () => {
|
|
299
|
-
const memory = await readFile(join(input.agentDir, "MEMORY.md"), "utf8").catch(() => null);
|
|
300
|
-
if (memory === null || detectLocalMemoryStorageVersion(memory) !== 1) {
|
|
301
|
-
throw new Error("local_memory_migration_pending_storage_invalid");
|
|
302
|
-
}
|
|
303
|
-
for (const candidate of pending) {
|
|
304
|
-
await persistPendingMemoryCandidate({ agentDir: input.agentDir, candidate });
|
|
305
|
-
}
|
|
306
|
-
}, { pendingOnly: true });
|
|
307
|
-
const pendingIds = [...new Set(pending.map((candidate) => candidate.pendingId))];
|
|
308
|
-
return { createdIds: [], updatedIds: [], statusChangedIds: [], deferredIds: pendingIds, pendingIds };
|
|
309
|
-
}
|
|
310
233
|
function isWithin(root, candidate) {
|
|
311
234
|
const path = relative(root, candidate);
|
|
312
235
|
return path === "" || (path !== ".." && !path.startsWith(`..${sep}`));
|
|
@@ -321,29 +244,12 @@ async function assertWritablePaths(agentDir, memoryPath) {
|
|
|
321
244
|
if (!memoryStat.isFile() || memoryStat.isSymbolicLink())
|
|
322
245
|
throw new Error("local_memory_memory_path_invalid");
|
|
323
246
|
}
|
|
324
|
-
async function assertMemoryAccessDirectory(agentDir) {
|
|
325
|
-
try {
|
|
326
|
-
const stat = await lstat(join(agentDir, ".crew/memory"));
|
|
327
|
-
if (!stat.isDirectory() || stat.isSymbolicLink())
|
|
328
|
-
throw new Error("local_memory_pending_path_invalid");
|
|
329
|
-
}
|
|
330
|
-
catch (error) {
|
|
331
|
-
if (error.code === "ENOENT")
|
|
332
|
-
return;
|
|
333
|
-
throw error;
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
247
|
async function readNote(path) {
|
|
337
248
|
try {
|
|
338
249
|
const stat = await lstat(path);
|
|
339
250
|
if (!stat.isFile() || stat.isSymbolicLink())
|
|
340
251
|
throw new Error("local_memory_note_path_invalid");
|
|
341
|
-
|
|
342
|
-
throw new Error("local_memory_note_byte_limit");
|
|
343
|
-
const content = await readFile(path, "utf8");
|
|
344
|
-
if (Buffer.byteLength(content, "utf8") > LOCAL_MEMORY_NOTE_BYTE_CAP)
|
|
345
|
-
throw new Error("local_memory_note_byte_limit");
|
|
346
|
-
return content;
|
|
252
|
+
return await readFile(path, "utf8");
|
|
347
253
|
}
|
|
348
254
|
catch (error) {
|
|
349
255
|
if (error.code === "ENOENT")
|
|
@@ -363,11 +269,6 @@ async function atomicWrite(path, content) {
|
|
|
363
269
|
}
|
|
364
270
|
}
|
|
365
271
|
function projectIndex(memory, entries, protectedIds) {
|
|
366
|
-
if (detectLocalMemoryStorageVersion(memory) === 2) {
|
|
367
|
-
const updated = replaceFullMemoryIndex(memory, entries);
|
|
368
|
-
selectLocalMemoryPreview(updated);
|
|
369
|
-
return { memory: updated, omittedIds: [], reason: null };
|
|
370
|
-
}
|
|
371
272
|
const empty = replaceGeneratedIndex(memory, []);
|
|
372
273
|
if (codePointLength(empty) > LOCAL_MEMORY_TOTAL_CODE_POINT_CAP)
|
|
373
274
|
throw new Error("local_memory_memory_over_budget");
|
|
@@ -405,29 +306,12 @@ async function withApplyLease(agentDir, operation) {
|
|
|
405
306
|
}
|
|
406
307
|
export async function applyLocalMemoryResult(input) {
|
|
407
308
|
validateCandidate(input.result);
|
|
408
|
-
if (input.
|
|
409
|
-
return stageMigrationDeferredPending(input);
|
|
410
|
-
if (input.result.outcome !== "proposed" && input.requiredStorageVersion !== 2)
|
|
309
|
+
if (input.result.outcome !== "proposed")
|
|
411
310
|
return emptyResult();
|
|
412
311
|
const memoryPath = join(input.agentDir, "MEMORY.md");
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
await assertMemoryAccessDirectory(input.agentDir);
|
|
416
|
-
return withApplyLease(input.agentDir, async () => withMemoryAccess(input.agentDir, async () => {
|
|
417
|
-
await assertMemoryWriterAllowed(input.agentDir, input.writerCapabilities ?? []);
|
|
418
|
-
const memoryStat = await lstat(memoryPath);
|
|
419
|
-
if (memoryStat.size > 16 * 1024 * 1024)
|
|
420
|
-
throw new Error("local_memory_storage_byte_limit");
|
|
312
|
+
await assertWritablePaths(input.agentDir, memoryPath);
|
|
313
|
+
return withApplyLease(input.agentDir, async () => {
|
|
421
314
|
const memory = await readFile(memoryPath, "utf8");
|
|
422
|
-
assertLocalMemoryStorageSize(memory);
|
|
423
|
-
const fullStorage = detectLocalMemoryStorageVersion(memory) === 2;
|
|
424
|
-
if (input.requiredStorageVersion === 2 && !fullStorage) {
|
|
425
|
-
throw new Error("local_memory_v2_state_invalid_before_commit");
|
|
426
|
-
}
|
|
427
|
-
// A V2 no-op is still a commit decision. Return only after the access
|
|
428
|
-
// lock and committed-state writer gate have validated the same snapshot.
|
|
429
|
-
if (input.result.outcome !== "proposed")
|
|
430
|
-
return emptyResult();
|
|
431
315
|
if (parseUnmarkedMemoryIndex(memory).length > 0)
|
|
432
316
|
throw new Error("local_memory_legacy_index_requires_migration");
|
|
433
317
|
let entries = [...parseLocalMemoryIndex(memory)];
|
|
@@ -458,26 +342,6 @@ export async function applyLocalMemoryResult(input) {
|
|
|
458
342
|
const pendingCandidates = [];
|
|
459
343
|
const resolvedPendingIds = new Set();
|
|
460
344
|
const noteUpdates = new Map();
|
|
461
|
-
const noteCache = new Map();
|
|
462
|
-
let totalReadBytes = Buffer.byteLength(memory, "utf8");
|
|
463
|
-
const readStoredNote = async (path) => {
|
|
464
|
-
const cached = noteUpdates.get(path) ?? noteCache.get(path);
|
|
465
|
-
if (cached !== undefined)
|
|
466
|
-
return cached;
|
|
467
|
-
const stat = await lstat(path).catch((error) => {
|
|
468
|
-
if (error.code === "ENOENT")
|
|
469
|
-
return null;
|
|
470
|
-
throw error;
|
|
471
|
-
});
|
|
472
|
-
if (stat !== null && totalReadBytes + stat.size > LOCAL_MEMORY_READ_BYTE_CAP)
|
|
473
|
-
throw new Error("local_memory_read_byte_limit");
|
|
474
|
-
const content = await readNote(path);
|
|
475
|
-
totalReadBytes += Buffer.byteLength(content, "utf8");
|
|
476
|
-
if (totalReadBytes > LOCAL_MEMORY_READ_BYTE_CAP)
|
|
477
|
-
throw new Error("local_memory_read_byte_limit");
|
|
478
|
-
noteCache.set(path, content);
|
|
479
|
-
return content;
|
|
480
|
-
};
|
|
481
345
|
let allowActiveEviction = false;
|
|
482
346
|
const randomId = input.randomId ?? randomUUID;
|
|
483
347
|
const executionId = input.executionId ?? "unknown";
|
|
@@ -519,21 +383,10 @@ export async function applyLocalMemoryResult(input) {
|
|
|
519
383
|
if (existingCreate !== undefined && !matchesCreateCandidate(existingCreate, change)) {
|
|
520
384
|
throw new Error("local_memory_duplicate_candidate");
|
|
521
385
|
}
|
|
522
|
-
if (existingCreate === undefined && entries.some((entry) => (
|
|
523
|
-
|
|
386
|
+
if (existingCreate === undefined && entries.some((entry) => normalize(entry.title) === normalize(change.title)
|
|
387
|
+
|| normalize(entry.summary) === normalize(change.summary))) {
|
|
524
388
|
throw new Error("local_memory_duplicate_candidate");
|
|
525
389
|
}
|
|
526
|
-
if (existingCreate !== undefined) {
|
|
527
|
-
if (existingCreate.revision !== 1 || existingCreate.status !== "active") {
|
|
528
|
-
throw new Error("local_memory_create_replay_conflict");
|
|
529
|
-
}
|
|
530
|
-
const stored = await readStoredNote(resolve(input.agentDir, existingCreate.file));
|
|
531
|
-
if (uniqueNoteSection(stored, id)?.trimEnd() !== noteSection(id, 1, change.title, change.detailBody).trimEnd()) {
|
|
532
|
-
throw new Error("local_memory_create_replay_conflict");
|
|
533
|
-
}
|
|
534
|
-
// A proven duplicate is a no-op; it must never rewrite a newer body or status.
|
|
535
|
-
continue;
|
|
536
|
-
}
|
|
537
390
|
}
|
|
538
391
|
const revision = existingCreate?.revision ?? (current === undefined ? 1 : current.revision + 1);
|
|
539
392
|
const entry = existingCreate ?? entryFromChange(change, id, revision, current?.status ?? "active");
|
|
@@ -547,7 +400,7 @@ export async function applyLocalMemoryResult(input) {
|
|
|
547
400
|
: item),
|
|
548
401
|
entry,
|
|
549
402
|
];
|
|
550
|
-
const allowEvictionForChange =
|
|
403
|
+
const allowEvictionForChange = change.operation === "create" && change.priority === "high";
|
|
551
404
|
const protectedIds = new Set(allowEvictionForChange ? pinnedIds(entries) : activeOrPinnedIds(entries));
|
|
552
405
|
if (allowEvictionForChange)
|
|
553
406
|
allowActiveEviction = true;
|
|
@@ -564,7 +417,7 @@ export async function applyLocalMemoryResult(input) {
|
|
|
564
417
|
const notePath = resolve(input.agentDir, entry.file);
|
|
565
418
|
if (!isWithin(resolve(input.agentDir, "notes"), notePath))
|
|
566
419
|
throw new Error("local_memory_note_path_invalid");
|
|
567
|
-
const previous = await
|
|
420
|
+
const previous = noteUpdates.get(notePath) ?? await readNote(notePath);
|
|
568
421
|
const replacement = noteSection(id, revision, change.title, change.detailBody);
|
|
569
422
|
const existingSection = replaceNote(previous, id, replacement);
|
|
570
423
|
const next = existingSection ?? (current === undefined
|
|
@@ -582,7 +435,7 @@ export async function applyLocalMemoryResult(input) {
|
|
|
582
435
|
// Pending create candidates are durable overflow, not dead ends. Promote only
|
|
583
436
|
// when the current catalog has room; supersede/update candidates stay pending
|
|
584
437
|
// until a fresh revision-aware decision can safely replay them.
|
|
585
|
-
const pendingCandidatesOnDisk =
|
|
438
|
+
const pendingCandidatesOnDisk = await readPendingMemoryCandidates({ agentDir: input.agentDir }).catch((error) => {
|
|
586
439
|
if (!(error instanceof Error) || error.message !== "memory_pending_directory_over_budget")
|
|
587
440
|
throw error;
|
|
588
441
|
// 自动提升是可选工作,目录查询预算不应阻断本轮已验证的更新或腾位操作。
|
|
@@ -593,10 +446,6 @@ export async function applyLocalMemoryResult(input) {
|
|
|
593
446
|
return [];
|
|
594
447
|
});
|
|
595
448
|
for (const pending of pendingCandidatesOnDisk) {
|
|
596
|
-
// Migration-deferred candidates require reviewed import; only capacity
|
|
597
|
-
// overflow is eligible for the existing automatic promotion path.
|
|
598
|
-
if (pending.reason !== "index_over_budget")
|
|
599
|
-
continue;
|
|
600
449
|
const change = pending.candidate;
|
|
601
450
|
if (change.operation !== "create")
|
|
602
451
|
continue;
|
|
@@ -611,7 +460,7 @@ export async function applyLocalMemoryResult(input) {
|
|
|
611
460
|
|| normalize(entry.summary) === normalize(change.summary)));
|
|
612
461
|
if (duplicate !== undefined) {
|
|
613
462
|
const duplicatePath = resolve(input.agentDir, duplicate.file);
|
|
614
|
-
const duplicateBody = readNoteBody(await
|
|
463
|
+
const duplicateBody = readNoteBody(noteUpdates.get(duplicatePath) ?? await readNote(duplicatePath), duplicate.id);
|
|
615
464
|
if (duplicateBody === change.detailBody
|
|
616
465
|
|| duplicateBody === unwrappedNoteBody(change.title, change.detailBody).trim()) {
|
|
617
466
|
resolvedPendingIds.add(pending.pendingId);
|
|
@@ -629,7 +478,7 @@ export async function applyLocalMemoryResult(input) {
|
|
|
629
478
|
const notePath = resolve(input.agentDir, entry.file);
|
|
630
479
|
if (!isWithin(resolve(input.agentDir, "notes"), notePath))
|
|
631
480
|
throw new Error("local_memory_note_path_invalid");
|
|
632
|
-
const previous = await
|
|
481
|
+
const previous = noteUpdates.get(notePath) ?? await readNote(notePath);
|
|
633
482
|
const replacement = noteSection(id, 1, change.title, change.detailBody);
|
|
634
483
|
const existingSection = replaceNote(previous, id, replacement);
|
|
635
484
|
const next = existingSection ?? `${previous.trimEnd()}${previous.trimEnd() ? "\n\n" : ""}${replacement}`;
|
|
@@ -638,17 +487,6 @@ export async function applyLocalMemoryResult(input) {
|
|
|
638
487
|
createdIds.push(id);
|
|
639
488
|
resolvedPendingIds.add(pending.pendingId);
|
|
640
489
|
}
|
|
641
|
-
if (fullStorage) {
|
|
642
|
-
const changedMetadataIds = new Set([
|
|
643
|
-
...statusChangedIds,
|
|
644
|
-
...input.result.changes.flatMap(change => change.supersedesMemoryId === null ? [] : [change.supersedesMemoryId]),
|
|
645
|
-
]);
|
|
646
|
-
for (const id of changedMetadataIds) {
|
|
647
|
-
const entry = entries.find(item => item.id === id);
|
|
648
|
-
const notePath = resolve(input.agentDir, entry.file);
|
|
649
|
-
noteUpdates.set(notePath, updateNoteRevision(await readStoredNote(notePath), id, entry.revision));
|
|
650
|
-
}
|
|
651
|
-
}
|
|
652
490
|
let finalProjection = projectIndex(memory, entries, allowActiveEviction ? pinnedIds(entries) : activeOrPinnedIds(entries));
|
|
653
491
|
if (finalProjection.reason !== null
|
|
654
492
|
&& (!allowActiveEviction || finalProjection.reason === "index_over_budget_pinned")) {
|
|
@@ -660,7 +498,7 @@ export async function applyLocalMemoryResult(input) {
|
|
|
660
498
|
.filter((entry) => entry?.status === "active");
|
|
661
499
|
for (const entry of omittedActiveEntries) {
|
|
662
500
|
const notePath = resolve(input.agentDir, entry.file);
|
|
663
|
-
const content = await
|
|
501
|
+
const content = noteUpdates.get(notePath) ?? await readNote(notePath);
|
|
664
502
|
const detailBody = readNoteBody(content, entry.id);
|
|
665
503
|
const change = detailBody === null ? null : archivedChange(entry, detailBody);
|
|
666
504
|
if (change === null)
|
|
@@ -681,13 +519,6 @@ export async function applyLocalMemoryResult(input) {
|
|
|
681
519
|
if (finalProjection.reason !== null)
|
|
682
520
|
throw new Error(finalProjection.reason);
|
|
683
521
|
}
|
|
684
|
-
// Complete every resource check before the first persistent write.
|
|
685
|
-
assertLocalMemoryStorageSize(finalProjection.memory);
|
|
686
|
-
for (const content of noteUpdates.values()) {
|
|
687
|
-
if (Buffer.byteLength(content, "utf8") > LOCAL_MEMORY_NOTE_BYTE_CAP)
|
|
688
|
-
throw new Error("local_memory_note_byte_limit");
|
|
689
|
-
}
|
|
690
|
-
await assertMemoryInventoryHealth(input.agentDir);
|
|
691
522
|
for (const candidate of pendingCandidates)
|
|
692
523
|
await persistPendingMemoryCandidate({ agentDir: input.agentDir, candidate });
|
|
693
524
|
for (const [path, content] of noteUpdates)
|
|
@@ -704,5 +535,5 @@ export async function applyLocalMemoryResult(input) {
|
|
|
704
535
|
deferredIds,
|
|
705
536
|
pendingIds: deferredIds,
|
|
706
537
|
};
|
|
707
|
-
})
|
|
538
|
+
});
|
|
708
539
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
|
-
import {
|
|
2
|
+
import { readFile, stat } from "node:fs/promises";
|
|
3
3
|
import { isAbsolute, join, normalize, relative, resolve } from "node:path";
|
|
4
4
|
import { parseArgs } from "node:util";
|
|
5
5
|
import { capMemoryForInject, MEMORY_INJECT_CAP } from "./prompt.js";
|
|
@@ -8,7 +8,6 @@ const INJECTION_MARKERS = [
|
|
|
8
8
|
"## [注入] 你的 MEMORY.md(索引,只读参考)\n",
|
|
9
9
|
];
|
|
10
10
|
const LOCAL_MEMORY_HASH_CAP_BYTES = 10 * 1024 * 1024;
|
|
11
|
-
export const LOCAL_MEMORY_DIAGNOSTICS_TIMEOUT_MS = 2_000;
|
|
12
11
|
function errorCode(error) {
|
|
13
12
|
const code = error?.code;
|
|
14
13
|
return typeof code === "string" ? code : error instanceof Error ? error.name : "unknown";
|
|
@@ -40,75 +39,30 @@ async function inspectFile(path, signal) {
|
|
|
40
39
|
return { ...base, error_code: errorCode(error) };
|
|
41
40
|
}
|
|
42
41
|
}
|
|
43
|
-
async function
|
|
44
|
-
let metadata;
|
|
45
|
-
try {
|
|
46
|
-
metadata = await lstat(path);
|
|
47
|
-
}
|
|
48
|
-
catch (error) {
|
|
49
|
-
const code = errorCode(error);
|
|
50
|
-
return code === "ENOENT" ? { exists: false, entry_count: 0 } : { exists: false, error_code: code };
|
|
51
|
-
}
|
|
52
|
-
const base = { exists: true, mtime_ms: metadata.mtimeMs };
|
|
53
|
-
if (metadata.isSymbolicLink() || !metadata.isDirectory())
|
|
54
|
-
return { ...base, hash_skipped_reason: "not_regular_file" };
|
|
55
|
-
try {
|
|
56
|
-
const names = (await readdir(path, { withFileTypes: true }))
|
|
57
|
-
.filter(entry => entry.name.endsWith(".json"))
|
|
58
|
-
.sort((left, right) => left.name < right.name ? -1 : left.name > right.name ? 1 : 0);
|
|
59
|
-
if (names.length > 128)
|
|
60
|
-
return { ...base, entry_count: names.length, error_code: "entry_limit" };
|
|
61
|
-
const hash = createHash("sha256");
|
|
62
|
-
let size = 0;
|
|
63
|
-
for (const entry of names) {
|
|
64
|
-
if (signal.aborted)
|
|
65
|
-
throw signal.reason;
|
|
66
|
-
if (!entry.isFile() || entry.isSymbolicLink())
|
|
67
|
-
return { ...base, entry_count: names.length, error_code: "invalid_entry" };
|
|
68
|
-
const fact = await inspectFile(join(path, entry.name), signal);
|
|
69
|
-
if (!fact.exists || fact.sha256 === undefined || fact.error_code !== undefined
|
|
70
|
-
|| fact.hash_skipped_reason !== undefined)
|
|
71
|
-
return { ...base, entry_count: names.length, error_code: "incomplete_entry" };
|
|
72
|
-
size += fact.size_bytes ?? 0;
|
|
73
|
-
hash.update(entry.name).update("\0").update(fact.sha256).update("\0");
|
|
74
|
-
}
|
|
75
|
-
return { ...base, size_bytes: size, entry_count: names.length, sha256: hash.digest("hex") };
|
|
76
|
-
}
|
|
77
|
-
catch (error) {
|
|
78
|
-
return { ...base, error_code: errorCode(error) };
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
export async function withinLocalMemoryDiagnosticsDeadline(operation, timeoutMs) {
|
|
42
|
+
export async function inspectLocalMemoryFilesWithinDeadline(homeDir, timeoutMs) {
|
|
82
43
|
const controller = new AbortController();
|
|
83
44
|
let timer;
|
|
45
|
+
const inspection = Promise.all([
|
|
46
|
+
inspectFile(join(homeDir, "MEMORY.md"), controller.signal),
|
|
47
|
+
inspectFile(join(homeDir, "notes", "lessons.md"), controller.signal),
|
|
48
|
+
]).then(([memory, lessons]) => ({ memory, lessons }));
|
|
84
49
|
const timeout = new Promise((_resolve, reject) => {
|
|
85
50
|
timer = setTimeout(() => {
|
|
86
|
-
|
|
51
|
+
controller.abort();
|
|
52
|
+
reject(Object.assign(new Error("local memory diagnostics timed out"), {
|
|
87
53
|
code: "diagnostics_timeout",
|
|
88
|
-
});
|
|
89
|
-
controller.abort(error);
|
|
90
|
-
reject(error);
|
|
54
|
+
}));
|
|
91
55
|
}, Math.max(1, timeoutMs));
|
|
92
56
|
timer.unref?.();
|
|
93
57
|
});
|
|
94
58
|
try {
|
|
95
|
-
return await Promise.race([
|
|
59
|
+
return await Promise.race([inspection, timeout]);
|
|
96
60
|
}
|
|
97
61
|
finally {
|
|
98
62
|
if (timer !== undefined)
|
|
99
63
|
clearTimeout(timer);
|
|
100
64
|
}
|
|
101
65
|
}
|
|
102
|
-
export async function inspectLocalMemoryFilesWithinDeadline(homeDir, timeoutMs) {
|
|
103
|
-
return withinLocalMemoryDiagnosticsDeadline(async (signal) => {
|
|
104
|
-
const [memory, lessons, pending] = await Promise.all([
|
|
105
|
-
inspectFile(join(homeDir, "MEMORY.md"), signal),
|
|
106
|
-
inspectFile(join(homeDir, "notes", "lessons.md"), signal),
|
|
107
|
-
inspectPendingDirectory(join(homeDir, ".crew", "memory", "pending"), signal),
|
|
108
|
-
]);
|
|
109
|
-
return { memory, lessons, pending };
|
|
110
|
-
}, timeoutMs);
|
|
111
|
-
}
|
|
112
66
|
export function localMemoryContentFacts(content, maxScanBytes = LOCAL_MEMORY_HASH_CAP_BYTES) {
|
|
113
67
|
const sizeBytes = Buffer.byteLength(content, "utf8");
|
|
114
68
|
if (sizeBytes > Math.max(0, maxScanBytes)) {
|
|
@@ -122,12 +76,12 @@ export function localMemoryContentFacts(content, maxScanBytes = LOCAL_MEMORY_HAS
|
|
|
122
76
|
lessons_reference_count: content.match(/\bnotes[\\/]lessons\.md\b/gi)?.length ?? 0,
|
|
123
77
|
};
|
|
124
78
|
}
|
|
125
|
-
export function analyzeLocalMemoryInjection(systemPrompt, sourceMemory
|
|
79
|
+
export function analyzeLocalMemoryInjection(systemPrompt, sourceMemory) {
|
|
126
80
|
const sourceBytes = Buffer.byteLength(sourceMemory, "utf8");
|
|
127
81
|
if (sourceMemory.length === 0) {
|
|
128
82
|
return { state: "empty_source", source_bytes: 0, bounded_bytes: 0, injected_bytes: 0 };
|
|
129
83
|
}
|
|
130
|
-
const bounded = capMemoryForInject(sourceMemory
|
|
84
|
+
const bounded = capMemoryForInject(sourceMemory);
|
|
131
85
|
const marker = INJECTION_MARKERS.find((candidate) => systemPrompt.includes(candidate));
|
|
132
86
|
if (marker === undefined) {
|
|
133
87
|
return {
|
|
@@ -263,50 +217,15 @@ function crewMemoryReadAccess(command, paths) {
|
|
|
263
217
|
return null;
|
|
264
218
|
}
|
|
265
219
|
}
|
|
266
|
-
/**
|
|
267
|
-
* Decode only the shell wrapper shape emitted by supported runtimes. The body must be one complete
|
|
268
|
-
* quoted argument. Double-quoted bodies may escape only a quote or backslash; shell expansion and
|
|
269
|
-
* concatenated quoting stay unknown so telemetry never guesses what the shell actually executed.
|
|
270
|
-
*/
|
|
271
|
-
function unwrapLiteralShellCommand(command) {
|
|
272
|
-
const trimmed = command.trim();
|
|
273
|
-
const wrapper = /^\/bin\/(?:(?:zsh|bash)\s+-lc|sh\s+-c)\s+([\s\S]+)$/u.exec(trimmed);
|
|
274
|
-
if (wrapper === null)
|
|
275
|
-
return trimmed;
|
|
276
|
-
const quoted = wrapper[1];
|
|
277
|
-
const quote = quoted[0];
|
|
278
|
-
if ((quote !== "'" && quote !== '"') || quoted.at(-1) !== quote || quoted.length < 2)
|
|
279
|
-
return null;
|
|
280
|
-
const body = quoted.slice(1, -1);
|
|
281
|
-
if (quote === "'")
|
|
282
|
-
return body.includes("'") ? null : body;
|
|
283
|
-
let decoded = "";
|
|
284
|
-
for (let index = 0; index < body.length; index += 1) {
|
|
285
|
-
const character = body[index];
|
|
286
|
-
if (character === '"' || character === "$" || character === "`")
|
|
287
|
-
return null;
|
|
288
|
-
if (character !== "\\") {
|
|
289
|
-
decoded += character;
|
|
290
|
-
continue;
|
|
291
|
-
}
|
|
292
|
-
const escaped = body[index + 1];
|
|
293
|
-
if (escaped !== '"' && escaped !== "\\")
|
|
294
|
-
return null;
|
|
295
|
-
decoded += escaped;
|
|
296
|
-
index += 1;
|
|
297
|
-
}
|
|
298
|
-
return decoded;
|
|
299
|
-
}
|
|
300
220
|
function commandAccesses(command, paths) {
|
|
301
|
-
|
|
302
|
-
if (unwrapped === null || /[;|&\n]/.test(unwrapped))
|
|
221
|
+
if (/[;|&\n]/.test(command))
|
|
303
222
|
return [];
|
|
304
223
|
const accesses = new Map();
|
|
305
|
-
const memoryRead = crewMemoryReadAccess(
|
|
224
|
+
const memoryRead = crewMemoryReadAccess(command, paths);
|
|
306
225
|
if (memoryRead !== null) {
|
|
307
226
|
accesses.set(`${memoryRead.target}:${memoryRead.relative_path ?? ""}:read`, memoryRead);
|
|
308
227
|
}
|
|
309
|
-
const expanded =
|
|
228
|
+
const expanded = command
|
|
310
229
|
.replaceAll("${CREW_HOME}", paths.homeDir)
|
|
311
230
|
.replaceAll("$CREW_HOME", paths.homeDir)
|
|
312
231
|
.replace(/["']/g, "");
|
|
@@ -25,17 +25,6 @@ export function logLocalMemoryContextPrepareFailure(identity, phase, error) {
|
|
|
25
25
|
...errorFields(error),
|
|
26
26
|
});
|
|
27
27
|
}
|
|
28
|
-
export function logLocalMemoryContextDegraded(identity, error) {
|
|
29
|
-
safeLog("local_memory.context_degraded", "本地记忆准备失败,已安全降级为无记忆执行", {
|
|
30
|
-
level: "WARN",
|
|
31
|
-
execution_id: identity.executionId,
|
|
32
|
-
agent_handle: identity.agentHandle,
|
|
33
|
-
task_key: identity.taskKey,
|
|
34
|
-
memory_read_enabled: false,
|
|
35
|
-
memory_write_enabled: false,
|
|
36
|
-
...errorFields(error),
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
28
|
export function logLocalMemoryDiagnosticsFailure(identity, phase, error) {
|
|
40
29
|
safeLog("local_memory.diagnostics_failed", "本地记忆诊断失败并已放行", {
|
|
41
30
|
level: "WARN",
|
|
@@ -49,7 +38,6 @@ export function logLocalMemoryDiagnosticsFailure(identity, phase, error) {
|
|
|
49
38
|
function snapshotFields(snapshot) {
|
|
50
39
|
if (snapshot === null)
|
|
51
40
|
return {};
|
|
52
|
-
const pending = snapshot.pending ?? { exists: false, entry_count: 0 };
|
|
53
41
|
return {
|
|
54
42
|
memory_exists: snapshot.memory.exists,
|
|
55
43
|
memory_size_bytes: snapshot.memory.size_bytes,
|
|
@@ -66,12 +54,6 @@ function snapshotFields(snapshot) {
|
|
|
66
54
|
lessons_hash_skipped_reason: snapshot.lessons.hash_skipped_reason,
|
|
67
55
|
lessons_error_code: snapshot.lessons.error_code,
|
|
68
56
|
lessons_markdown_heading_count: snapshot.lessons.markdown_heading_count,
|
|
69
|
-
pending_exists: pending.exists,
|
|
70
|
-
pending_size_bytes: pending.size_bytes,
|
|
71
|
-
pending_mtime_ms: pending.mtime_ms,
|
|
72
|
-
pending_sha256: pending.sha256,
|
|
73
|
-
pending_error_code: pending.error_code,
|
|
74
|
-
pending_entry_count: pending.entry_count,
|
|
75
57
|
};
|
|
76
58
|
}
|
|
77
59
|
function promptDelivery(runtime, stableProtocolRuntime) {
|
|
@@ -121,7 +103,7 @@ export function createLocalMemoryTelemetry(options) {
|
|
|
121
103
|
contextPrepared(context) {
|
|
122
104
|
try {
|
|
123
105
|
const sourceFacts = localMemoryContentFacts(context.memory);
|
|
124
|
-
const injectionFacts = analyzeLocalMemoryInjection(context.systemPrompt, context.memory
|
|
106
|
+
const injectionFacts = analyzeLocalMemoryInjection(context.systemPrompt, context.memory);
|
|
125
107
|
safeLog("local_memory.context_prepared", "本地记忆上下文已准备", {
|
|
126
108
|
execution_id: options.executionId,
|
|
127
109
|
agent_handle: options.agentHandle,
|
|
@@ -201,13 +183,10 @@ export function createLocalMemoryTelemetry(options) {
|
|
|
201
183
|
const lessonsChanged = beforeSnapshot !== null && afterSnapshot !== null
|
|
202
184
|
? localMemoryFileChanged(beforeSnapshot.lessons, afterSnapshot.lessons)
|
|
203
185
|
: undefined;
|
|
204
|
-
const pendingChanged = beforeSnapshot !== null && afterSnapshot !== null
|
|
205
|
-
? localMemoryFileChanged(beforeSnapshot.pending ?? { exists: false }, afterSnapshot.pending ?? { exists: false })
|
|
206
|
-
: undefined;
|
|
207
186
|
const accessSummary = accessObserver.summary();
|
|
208
|
-
const sharedFilesChanged = memoryChanged === undefined || lessonsChanged === undefined
|
|
187
|
+
const sharedFilesChanged = memoryChanged === undefined || lessonsChanged === undefined
|
|
209
188
|
? undefined
|
|
210
|
-
: memoryChanged || lessonsChanged
|
|
189
|
+
: memoryChanged || lessonsChanged;
|
|
211
190
|
safeLog("local_memory.execution_observed", "本地记忆执行观察已完成", {
|
|
212
191
|
execution_id: options.executionId,
|
|
213
192
|
agent_handle: options.agentHandle,
|
|
@@ -221,7 +200,6 @@ export function createLocalMemoryTelemetry(options) {
|
|
|
221
200
|
executor_outcome: executorCompleted ? "succeeded" : "failed",
|
|
222
201
|
memory_changed: memoryChanged,
|
|
223
202
|
lessons_changed: lessonsChanged,
|
|
224
|
-
pending_changed: pendingChanged,
|
|
225
203
|
shared_files_changed_during_execution: sharedFilesChanged,
|
|
226
204
|
unexpected_shared_write: options.isMemoryPrune
|
|
227
205
|
? undefined
|
|
@@ -246,12 +224,6 @@ export function createLocalMemoryTelemetry(options) {
|
|
|
246
224
|
lessons_after_hash_skipped_reason: afterSnapshot.lessons.hash_skipped_reason,
|
|
247
225
|
lessons_after_error_code: afterSnapshot.lessons.error_code,
|
|
248
226
|
lessons_after_markdown_heading_count: afterSnapshot.lessons.markdown_heading_count,
|
|
249
|
-
pending_after_exists: afterSnapshot.pending?.exists ?? false,
|
|
250
|
-
pending_after_size_bytes: afterSnapshot.pending?.size_bytes,
|
|
251
|
-
pending_after_mtime_ms: afterSnapshot.pending?.mtime_ms,
|
|
252
|
-
pending_after_sha256: afterSnapshot.pending?.sha256,
|
|
253
|
-
pending_after_error_code: afterSnapshot.pending?.error_code,
|
|
254
|
-
pending_after_entry_count: afterSnapshot.pending?.entry_count ?? 0,
|
|
255
227
|
}),
|
|
256
228
|
});
|
|
257
229
|
},
|
package/dist/machine-info.js
CHANGED
|
@@ -27,7 +27,6 @@ import { RUNTIME_HEALTH_PROBE_CAPABILITY } from "./runtime-health.js";
|
|
|
27
27
|
import { probeDeepSeekHarnessAcp, deepSeekHarnessLauncher } from "./runtimes/deepseek-harness.js";
|
|
28
28
|
import { daemonHome } from "./computer-profile.js";
|
|
29
29
|
import { daemonReleaseProvenance } from "./release-provenance.js";
|
|
30
|
-
import { MEMORY_MIGRATION_CAPABILITY, MEMORY_STORAGE_V2_CAPABILITY, MEMORY_STATE_GUARD_CAPABILITY } from "./memory-migration-protocol.js";
|
|
31
30
|
export { executableRuntimes } from "./runtime-capabilities.js";
|
|
32
31
|
const execFileP = promisify(execFile);
|
|
33
32
|
export const PROJECT_WORKSPACES_CAPABILITY = "project_workspaces_v1";
|
|
@@ -44,7 +43,6 @@ export const NATIVE_PROJECT_WORKSPACE_READINESS = Object.freeze({
|
|
|
44
43
|
export const DAEMON_CAPABILITIES = Object.freeze([
|
|
45
44
|
RUNTIME_TOOL_UPDATES_CAPABILITY,
|
|
46
45
|
MARKETPLACE_CAPABILITY,
|
|
47
|
-
MEMORY_MIGRATION_CAPABILITY, MEMORY_STORAGE_V2_CAPABILITY, MEMORY_STATE_GUARD_CAPABILITY,
|
|
48
46
|
MAINTENANCE_CAPABILITY,
|
|
49
47
|
"scheduled_job_v1",
|
|
50
48
|
"reply_origin_v1",
|
|
@@ -81,7 +79,6 @@ export const daemonCapabilities = (runtimePlatform = process.platform, readiness
|
|
|
81
79
|
return Object.freeze(DAEMON_CAPABILITIES.filter((capability) => (((capability !== MARKETPLACE_CAPABILITY && capability !== MAINTENANCE_CAPABILITY && capability !== RUNTIME_TOOL_UPDATES_CAPABILITY) || nativeWorkspacePlatform)
|
|
82
80
|
&& (capability !== PROJECT_WORKSPACES_CAPABILITY || nativeWorkspaceReady)
|
|
83
81
|
&& (capability !== "message_file_preview_v1" || nativeWorkspacePlatform)
|
|
84
|
-
&& (nativeWorkspacePlatform || ![MEMORY_MIGRATION_CAPABILITY, MEMORY_STORAGE_V2_CAPABILITY, MEMORY_STATE_GUARD_CAPABILITY].includes(capability))
|
|
85
82
|
&& (nativeWorkspacePlatform
|
|
86
83
|
|| (capability !== "project_skills_v1"
|
|
87
84
|
&& capability !== "project_skill_projection_v2"
|
|
@@ -2,7 +2,7 @@ import { z } from "zod";
|
|
|
2
2
|
// 与另一个进程中的 marketplace-protocol.ts 保持一致;跨进程契约测试校验摘要。
|
|
3
3
|
export const MARKETPLACE_CAPABILITY = "marketplace_update_v1";
|
|
4
4
|
export const MARKETPLACE = "nowwork-pm";
|
|
5
|
-
export const PLUGIN = "
|
|
5
|
+
export const PLUGIN = "AIinterview-plugin";
|
|
6
6
|
export const MarketplaceModeSchema = z.enum(["inspect", "refresh", "update"]);
|
|
7
7
|
export const MarketplaceStatusSchema = z.enum(["queued", "running", "completed", "partial", "failed", "unknown"]);
|
|
8
8
|
export const MarketplaceTargetSchema = z.object({
|