@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: '1970-01-01', anchor: mapping.targetId, revision: retainedHistory.get(mapping.targetId)?.revision ?? 1, reviewAfter: null }));
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: '1970-01-01', anchor: id, revision: 1, reviewAfter: null, ...knownMetadata.get(mapping.sourceFile) });
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')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nowcrew/daemon",
3
- "version": "0.6.93-beta.8",
3
+ "version": "0.6.93-beta.9",
4
4
  "type": "module",
5
5
  "description": "crew daemon — 运行在用户机器:拉起/管理 agent 进程,注入 crew CLI,归一化 runtime 事件",
6
6
  "license": "Apache-2.0",