@nowcrew/daemon 0.6.93-beta.8 → 0.6.93-beta.9
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.
|
@@ -31,6 +31,29 @@ function migrationSummary(body, title) {
|
|
|
31
31
|
.replace(/[\u0000-\u001f\u007f]+/gu, ' ').replace(/\s+/gu, ' ').trim().slice(0, 180);
|
|
32
32
|
return clean(body) || clean(title) || 'Migrated memory';
|
|
33
33
|
}
|
|
34
|
+
const MIGRATION_EPOCH_DATE = '1970-01-01';
|
|
35
|
+
function parseLegacyCardMetadata(card) {
|
|
36
|
+
const fieldMatches = [...card.matchAll(/^- ([a-z_]+):[^\S\r\n]*(.*)$/gmu)];
|
|
37
|
+
const fields = Object.fromEntries(fieldMatches.map(match => [match[1], match[2].trim()]));
|
|
38
|
+
const allowedFields = new Set(['file', 'scope', 'type', 'status', 'summary', 'priority', 'updated', 'triggers', 'review_after', 'id', 'anchor', 'revision']);
|
|
39
|
+
const category = /^notes\/(.+)\.md$/u.exec(fields.file ?? '')?.[1] ?? '';
|
|
40
|
+
const valid = !card.replace(/^- ([a-z_]+):[^\S\r\n]*(.*)$/gmu, '').replace(/^### .+\r?\n/u, '').trim()
|
|
41
|
+
&& fieldMatches.length === Object.keys(fields).length
|
|
42
|
+
&& Object.keys(fields).every(key => allowedFields.has(key))
|
|
43
|
+
&& Boolean(categories.test(category) && fields.summary
|
|
44
|
+
&& ['procedural', 'semantic', 'episodic', 'preference'].includes(fields.type ?? '')
|
|
45
|
+
&& ['candidate', 'active', 'pinned', 'stale', 'superseded', 'archived'].includes(fields.status ?? '')
|
|
46
|
+
&& ['high', 'medium', 'low'].includes(fields.priority ?? '') && fields.updated);
|
|
47
|
+
if (!valid)
|
|
48
|
+
return null;
|
|
49
|
+
return {
|
|
50
|
+
type: fields.type, summary: fields.summary,
|
|
51
|
+
priority: fields.priority, updated: fields.updated,
|
|
52
|
+
triggers: (fields.triggers ?? '').split(/[,,、]/u).map(item => item.trim()).filter(Boolean),
|
|
53
|
+
reviewAfter: fields.review_after ?? null,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
const migrationDate = () => new Date().toISOString().slice(0, 10);
|
|
34
57
|
export function validateMigrationTarget(files) {
|
|
35
58
|
let totalBytes = 0;
|
|
36
59
|
for (const [path, bytes] of files) {
|
|
@@ -64,6 +87,7 @@ export function planMemoryMigration(identity, files, supplied = []) {
|
|
|
64
87
|
if (detectLocalMemoryStorageVersion(memory) !== identity.sourceStorageVersion)
|
|
65
88
|
throw new MigrationError('migration_source_version_mismatch');
|
|
66
89
|
const confirmedMappings = supplied.map(value => MigrationRecordMappingSchema.parse(value));
|
|
90
|
+
const fallbackUpdated = migrationDate();
|
|
67
91
|
const mappingSourceDigests = new Map();
|
|
68
92
|
for (const mapping of confirmedMappings) {
|
|
69
93
|
if (mapping.sourceSha256 === undefined)
|
|
@@ -139,7 +163,7 @@ export function planMemoryMigration(identity, files, supplied = []) {
|
|
|
139
163
|
const newEntries = additions.map(mapping => ({ id: mapping.targetId, title: mapping.title,
|
|
140
164
|
file: `notes/${mapping.category}.md`, type: 'semantic', status: mapping.status,
|
|
141
165
|
summary: migrationSummary(retainedHistory.get(mapping.targetId)?.body ?? files.get(mapping.sourceFile).toString('utf8').slice(mapping.start, mapping.end), mapping.title),
|
|
142
|
-
triggers: [], priority: 'medium', updated:
|
|
166
|
+
triggers: [], priority: 'medium', updated: fallbackUpdated, anchor: mapping.targetId, revision: retainedHistory.get(mapping.targetId)?.revision ?? 1, reviewAfter: null }));
|
|
143
167
|
for (const mapping of additions) {
|
|
144
168
|
if (retainedHistory.has(mapping.targetId))
|
|
145
169
|
continue;
|
|
@@ -232,8 +256,15 @@ export function planMemoryMigration(identity, files, supplied = []) {
|
|
|
232
256
|
continue;
|
|
233
257
|
}
|
|
234
258
|
const id = mapping.targetId ?? `mem_${digest(`${identity.migrationId}:${mapping.sourceFile}:${mapping.start}:${mapping.end}`).slice(0, 24)}`;
|
|
259
|
+
const confirmedMetadata = mapping.sourceFile === 'MEMORY.md' ? parseLegacyCardMetadata(body.slice(mapping.start, mapping.end)) : null;
|
|
235
260
|
entries.push({ id, title: mapping.title, file: `notes/${mapping.category}.md`, type: 'semantic', status: mapping.status, summary: migrationSummary(body.slice(mapping.start, mapping.end), mapping.title),
|
|
236
|
-
triggers: [], priority: 'medium', updated:
|
|
261
|
+
triggers: [], priority: 'medium', updated: fallbackUpdated, anchor: id, revision: 1, reviewAfter: null,
|
|
262
|
+
...knownMetadata.get(mapping.sourceFile),
|
|
263
|
+
...(confirmedMetadata ? (() => {
|
|
264
|
+
const source = confirmedMetadata;
|
|
265
|
+
return { type: source.type, summary: source.summary, triggers: source.triggers, priority: source.priority,
|
|
266
|
+
updated: source.updated === MIGRATION_EPOCH_DATE ? fallbackUpdated : source.updated, reviewAfter: source.reviewAfter };
|
|
267
|
+
})() : {}) });
|
|
237
268
|
}
|
|
238
269
|
for (const [path, bytes] of files) {
|
|
239
270
|
if (!path.startsWith('notes/') && path !== 'MEMORY.md')
|