emdash-emit 0.1.10 → 0.1.12

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.
Files changed (68) hide show
  1. package/CHANGELOG.md +135 -0
  2. package/README.md +24 -4
  3. package/dist/cli/commands/conflicts.d.ts.map +1 -1
  4. package/dist/cli/commands/conflicts.js +45 -1
  5. package/dist/cli/commands/conflicts.js.map +1 -1
  6. package/dist/cli/commands/pull.d.ts.map +1 -1
  7. package/dist/cli/commands/pull.js +5 -4
  8. package/dist/cli/commands/pull.js.map +1 -1
  9. package/dist/cli/commands/push.d.ts.map +1 -1
  10. package/dist/cli/commands/push.js +46 -3
  11. package/dist/cli/commands/push.js.map +1 -1
  12. package/dist/cli/commands/status.d.ts.map +1 -1
  13. package/dist/cli/commands/status.js +18 -4
  14. package/dist/cli/commands/status.js.map +1 -1
  15. package/dist/client/api.d.ts +6 -0
  16. package/dist/client/api.d.ts.map +1 -1
  17. package/dist/client/api.js +36 -0
  18. package/dist/client/api.js.map +1 -1
  19. package/dist/db/cache.d.ts +11 -0
  20. package/dist/db/cache.d.ts.map +1 -1
  21. package/dist/db/cache.js +136 -7
  22. package/dist/db/cache.js.map +1 -1
  23. package/dist/mcp/heartbeat.d.ts +29 -0
  24. package/dist/mcp/heartbeat.d.ts.map +1 -0
  25. package/dist/mcp/heartbeat.js +132 -0
  26. package/dist/mcp/heartbeat.js.map +1 -0
  27. package/dist/mcp/server.d.ts.map +1 -1
  28. package/dist/mcp/server.js +2 -0
  29. package/dist/mcp/server.js.map +1 -1
  30. package/dist/mcp/tools/sync-push.d.ts.map +1 -1
  31. package/dist/mcp/tools/sync-push.js +38 -5
  32. package/dist/mcp/tools/sync-push.js.map +1 -1
  33. package/dist/sync/conflicts.d.ts +24 -0
  34. package/dist/sync/conflicts.d.ts.map +1 -1
  35. package/dist/sync/conflicts.js +111 -0
  36. package/dist/sync/conflicts.js.map +1 -1
  37. package/dist/sync/delete.d.ts.map +1 -1
  38. package/dist/sync/delete.js +66 -3
  39. package/dist/sync/delete.js.map +1 -1
  40. package/dist/sync/doctor.d.ts +10 -0
  41. package/dist/sync/doctor.d.ts.map +1 -1
  42. package/dist/sync/doctor.js +197 -6
  43. package/dist/sync/doctor.js.map +1 -1
  44. package/dist/sync/merge.d.ts +59 -3
  45. package/dist/sync/merge.d.ts.map +1 -1
  46. package/dist/sync/merge.js +177 -5
  47. package/dist/sync/merge.js.map +1 -1
  48. package/dist/sync/orchestrator.d.ts +6 -1
  49. package/dist/sync/orchestrator.d.ts.map +1 -1
  50. package/dist/sync/orchestrator.js +15 -2
  51. package/dist/sync/orchestrator.js.map +1 -1
  52. package/dist/sync/pull.d.ts +5 -1
  53. package/dist/sync/pull.d.ts.map +1 -1
  54. package/dist/sync/pull.js +174 -148
  55. package/dist/sync/pull.js.map +1 -1
  56. package/dist/sync/push.d.ts +6 -0
  57. package/dist/sync/push.d.ts.map +1 -1
  58. package/dist/sync/push.js +155 -5
  59. package/dist/sync/push.js.map +1 -1
  60. package/dist/sync/status.d.ts +9 -0
  61. package/dist/sync/status.d.ts.map +1 -1
  62. package/dist/sync/status.js +10 -1
  63. package/dist/sync/status.js.map +1 -1
  64. package/dist/sync/terms.d.ts +32 -0
  65. package/dist/sync/terms.d.ts.map +1 -0
  66. package/dist/sync/terms.js +62 -0
  67. package/dist/sync/terms.js.map +1 -0
  68. package/package.json +2 -1
@@ -1 +1 @@
1
- {"version":3,"file":"orchestrator.d.ts","sourceRoot":"","sources":["../../src/sync/orchestrator.ts"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAAE,aAAa,EAAa,MAAM,gBAAgB,CAAC;AAC/D,OAAO,EAKL,KAAK,UAAU,EACf,KAAK,yBAAyB,EAC/B,MAAM,WAAW,CAAC;AACnB,OAAO,EAAe,KAAK,UAAU,EAAE,KAAK,WAAW,EAAE,MAAM,WAAW,CAAC;AAK3E,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,qBAAa,sBAAuB,SAAQ,KAAK;IACxC,aAAa,EAAE,oBAAoB,EAAE,CAAC;IACtC,KAAK,CAAC,EAAE,MAAM,CAAC;IAEtB,YAAY,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,oBAAoB,EAAE,EAAE,KAAK,CAAC,EAAE,MAAM,EAKjF;CACF;AAED,MAAM,WAAW,gBAAiB,SAAQ,yBAAyB;IACjE,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,aAAa,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,UAAU,CAAA;KAAE,KAAK,IAAI,CAAC;CACvF;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,wFAAwF;IACxF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wFAAwF;IACxF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,UAAU,EAAE,CAAC;CACrB;AAED;;;GAGG;AACH,wBAAsB,SAAS,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,eAAe,CAAC,CA8LnF;AAED,MAAM,WAAW,cAAe,SAAQ,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC;IAClE,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,aAAa,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,UAAU,EAAE,CAAC;CACvB;AAED;;;;GAIG;AACH,wBAAsB,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC,CA8B7E"}
1
+ {"version":3,"file":"orchestrator.d.ts","sourceRoot":"","sources":["../../src/sync/orchestrator.ts"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAAE,aAAa,EAAa,MAAM,gBAAgB,CAAC;AAC/D,OAAO,EAKL,KAAK,UAAU,EACf,KAAK,yBAAyB,EAC/B,MAAM,WAAW,CAAC;AACnB,OAAO,EAAe,KAAK,UAAU,EAAE,KAAK,WAAW,EAAE,MAAM,WAAW,CAAC;AAK3E,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,qBAAa,sBAAuB,SAAQ,KAAK;IACxC,aAAa,EAAE,oBAAoB,EAAE,CAAC;IACtC,KAAK,CAAC,EAAE,MAAM,CAAC;IAEtB,YAAY,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,oBAAoB,EAAE,EAAE,KAAK,CAAC,EAAE,MAAM,EAKjF;CACF;AAED,MAAM,WAAW,gBAAiB,SAAQ,yBAAyB;IACjE,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,aAAa,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,UAAU,CAAA;KAAE,KAAK,IAAI,CAAC;CACvF;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,wFAAwF;IACxF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wFAAwF;IACxF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,UAAU,EAAE,CAAC;CACrB;AAED;;;GAGG;AACH,wBAAsB,SAAS,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,eAAe,CAAC,CA8LnF;AAED,MAAM,WAAW,cAAe,SAAQ,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC;IAClE,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,aAAa,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,YAAY,CAAC,EAAE,KAAK,CAAC;QACnB,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,MAAM,CAAC;QACjB,MAAM,EAAE,kBAAkB,GAAG,gBAAgB,CAAC;KAC/C,CAAC,CAAC;CACJ;AAED;;;;GAIG;AACH,wBAAsB,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC,CAgD7E"}
@@ -217,12 +217,24 @@ export async function pullBatch(options) {
217
217
  }
218
218
  /**
219
219
  * Orchestrates pushing all modified/untracked files in the workspace.
220
- * Excludes synced and invalid (YAML parse error) files so invalid files do not crash batch push.
220
+ * Excludes synced, conflict_pending, delete_pending, and invalid (YAML parse error) files.
221
221
  * Reusable across CLI and MCP servers.
222
222
  */
223
223
  export async function pushAll(options) {
224
224
  const status = getWorkspaceStatus(options.workspaceRoot, options.cache, options.collection);
225
- const toPush = status.items.filter((i) => i.syncStatus === 'modified' || i.syncStatus === 'untracked');
225
+ const eligibleItems = status.items.filter((i) => i.syncStatus === 'modified' || i.syncStatus === 'untracked');
226
+ const skippedItems = [];
227
+ const toPush = eligibleItems.filter((i) => {
228
+ if (i.deletePending) {
229
+ skippedItems.push({ slug: i.slug, filePath: i.filePath, reason: 'delete_pending' });
230
+ return false;
231
+ }
232
+ if (i.conflictPending) {
233
+ skippedItems.push({ slug: i.slug, filePath: i.filePath, reason: 'conflict_pending' });
234
+ return false;
235
+ }
236
+ return true;
237
+ });
226
238
  const results = [];
227
239
  let pushed = 0;
228
240
  for (const item of toPush) {
@@ -244,6 +256,7 @@ export async function pushAll(options) {
244
256
  skipped: status.items.length - toPush.length,
245
257
  invalid: status.summary.invalid,
246
258
  results,
259
+ ...(skippedItems.length > 0 ? { skippedItems } : {}),
247
260
  };
248
261
  }
249
262
  //# sourceMappingURL=orchestrator.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"orchestrator.js","sourceRoot":"","sources":["../../src/sync/orchestrator.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"orchestrator.js","sourceRoot":"","sources":["../../src/sync/orchestrator.ts"],"names":[],"mappings":"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"}
@@ -20,6 +20,7 @@ export interface PullResult {
20
20
  updated: boolean;
21
21
  skipped?: boolean;
22
22
  deleted?: boolean;
23
+ orphan?: boolean;
23
24
  title?: string;
24
25
  /** True when the local file has unpushed edits and Emit kept them instead of applying remote changes. */
25
26
  localEditsPreserved?: boolean;
@@ -94,7 +95,10 @@ export declare function findLocalFilesByUlid(workspaceRoot: string, collection:
94
95
  * silently discarded during a pull.
95
96
  * Returns the relative path of the preserved copy, or null when preservation failed.
96
97
  */
97
- export declare function quarantineLocalCopy(workspaceRoot: string, collection: string, sourceRelPath: string, content: string): string | null;
98
+ export declare function quarantineLocalCopy(workspaceRoot: string, collection: string, sourceRelPath: string, content: string, options?: {
99
+ isForce?: boolean;
100
+ existingCopyHash?: string | null;
101
+ }): string | null;
98
102
  /**
99
103
  * Discovers the server's maximum allowed limit for content list queries from /_emdash/api/openapi.json.
100
104
  * Defaults to 100 if openapi.json cannot be fetched or parsed.
@@ -1 +1 @@
1
- {"version":3,"file":"pull.d.ts","sourceRoot":"","sources":["../../src/sync/pull.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"pull.d.ts","sourceRoot":"","sources":["../../src/sync/pull.ts"],"names":[],"mappings":"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"}
package/dist/sync/pull.js CHANGED
@@ -25,12 +25,13 @@ import crypto from 'node:crypto';
25
25
  import { apiResponseToLocal } from '../client/mapper.js';
26
26
  import { ApiError } from '../client/error.js';
27
27
  import { createAuthedFetch } from '../client/http.js';
28
- import { unwrapEnvelope, extractRev } from '../client/api.js';
28
+ import { unwrapEnvelope, extractRev, normalizeRev } from '../client/api.js';
29
29
  import { computeArticleRelativePath, extractDatePrefixFromPath, parseMarkdown, serializeMarkdown, lenientRepairMarkdownFrontmatter, } from '../utils/frontmatter.js';
30
30
  import { extractUlidFromFilename } from '../utils/naming.js';
31
31
  import { loadLocalTaxonomyCandidates } from './taxonomies.js';
32
32
  import { syncRemoteBylines } from './bylines.js';
33
33
  import { updateConfigSyncedVersion } from '../utils/config.js';
34
+ import { fetchAssignedTerms as fetchAssignedTermsShared } from './terms.js';
34
35
  /** Subdirectory (under a collection) reserved for preserved divergent local copies. */
35
36
  export const CONFLICTS_SUBDIR = 'conflicts';
36
37
  /**
@@ -103,15 +104,28 @@ export function findLocalFilesByUlid(workspaceRoot, collection, id) {
103
104
  * silently discarded during a pull.
104
105
  * Returns the relative path of the preserved copy, or null when preservation failed.
105
106
  */
106
- export function quarantineLocalCopy(workspaceRoot, collection, sourceRelPath, content) {
107
+ export function quarantineLocalCopy(workspaceRoot, collection, sourceRelPath, content, options) {
107
108
  const conflictsDir = path.join(workspaceRoot, collection, CONFLICTS_SUBDIR);
108
109
  const baseName = path.basename(sourceRelPath).replace(/\.md$/i, '');
109
- let quarantineRel = path.join(collection, CONFLICTS_SUBDIR, `${baseName}.conflict.md`);
110
+ const suffixExt = options?.isForce ? '.local-dropped.md' : '.conflict.md';
111
+ let quarantineRel = path.join(collection, CONFLICTS_SUBDIR, `${baseName}${suffixExt}`);
112
+ const quarantineFull = path.join(workspaceRoot, quarantineRel);
110
113
  try {
111
114
  fs.mkdirSync(conflictsDir, { recursive: true });
115
+ // Deduplication check: if canonical conflict file exists and is unedited, overwrite without incrementing
116
+ if (!options?.isForce && fs.existsSync(quarantineFull)) {
117
+ const existingDiskHash = calculateHash(fs.readFileSync(quarantineFull, 'utf8'));
118
+ if ((options?.existingCopyHash && existingDiskHash === options.existingCopyHash) ||
119
+ existingDiskHash === calculateHash(content)) {
120
+ fs.writeFileSync(quarantineFull, content, 'utf8');
121
+ return quarantineRel;
122
+ }
123
+ }
112
124
  let suffix = 2;
113
125
  while (fs.existsSync(path.join(workspaceRoot, quarantineRel))) {
114
- quarantineRel = path.join(collection, CONFLICTS_SUBDIR, `${baseName}.conflict-${suffix}.md`);
126
+ quarantineRel = path.join(collection, CONFLICTS_SUBDIR, options?.isForce
127
+ ? `${baseName}.local-dropped-${suffix}.md`
128
+ : `${baseName}.conflict-${suffix}.md`);
115
129
  suffix += 1;
116
130
  if (suffix > 100)
117
131
  return null;
@@ -128,7 +142,7 @@ export function quarantineLocalCopy(workspaceRoot, collection, sourceRelPath, co
128
142
  * preserves every copy whose content does not match the last synced baseline hash or the
129
143
  * content Emit is about to write.
130
144
  */
131
- function quarantineDivergentLocalCopies(options, collection, localRelPaths, baselineHash, canonicalContent) {
145
+ function quarantineDivergentLocalCopies(options, collection, localRelPaths, baselineHash, canonicalContent, existingCopyHash) {
132
146
  const quarantined = [];
133
147
  for (const localRel of localRelPaths) {
134
148
  const localFull = path.resolve(options.workspaceRoot, localRel);
@@ -147,7 +161,10 @@ function quarantineDivergentLocalCopies(options, collection, localRelPaths, base
147
161
  // Identical to the last synced state: carries no information worth preserving.
148
162
  if (baselineHash && calculateHash(localContent) === baselineHash)
149
163
  continue;
150
- const quarantineRel = quarantineLocalCopy(options.workspaceRoot, collection, localRel, localContent);
164
+ const quarantineRel = quarantineLocalCopy(options.workspaceRoot, collection, localRel, localContent, {
165
+ isForce: Boolean(options.force),
166
+ existingCopyHash,
167
+ });
151
168
  if (quarantineRel) {
152
169
  quarantined.push({
153
170
  sourceFilePath: localRel,
@@ -301,26 +318,14 @@ export async function pullArticle(collection, id, options) {
301
318
  const fetchFn = createAuthedFetch(options);
302
319
  let rawItem = options.rawItem;
303
320
  // Helper to fetch assigned terms for a taxonomy ('category' | 'tag')
304
- const fetchAssignedTerms = async (taxonomy) => {
305
- try {
306
- const termsUrl = new URL(`/_emdash/api/content/${collection}/${id}/terms/${taxonomy}`, options.origin).toString();
307
- const termsRes = await fetchFn(termsUrl, {
308
- method: 'GET',
309
- headers: {
310
- Authorization: `Bearer ${options.token}`,
311
- Accept: 'application/json',
312
- },
313
- });
314
- if (!termsRes.ok)
315
- return null;
316
- const termsJson = (await termsRes.json());
317
- const assigned = termsJson.data?.terms || [];
318
- return assigned.map((t) => t.slug || t.id).filter((s) => Boolean(s));
319
- }
320
- catch {
321
- return null;
322
- }
323
- };
321
+ const fetchAssignedTerms = (taxonomy) => fetchAssignedTermsShared({
322
+ origin: options.origin,
323
+ token: options.token,
324
+ collection,
325
+ id,
326
+ taxonomy,
327
+ fetchFn,
328
+ });
324
329
  // Helper to resolve byline ID-to-slug mapping
325
330
  let bylineIdToSlug = options.bylineIdToSlug;
326
331
  const getBylineIdToSlug = async () => {
@@ -349,134 +354,138 @@ export async function pullArticle(collection, id, options) {
349
354
  candidates = loadLocalTaxonomyCandidates(options.workspaceRoot);
350
355
  return candidates;
351
356
  };
352
- // 1. Fast-path check: If rawItem is provided and not forced, check rev & local hash
353
- if (rawItem && !options.force) {
357
+ // Helper to test fast-path (unmodified skip or non-destructive frontmatter heal)
358
+ const tryFastPathOrHeal = async (item) => {
359
+ if (options.force)
360
+ return null;
354
361
  const existingSync = options.cache.getSyncState(id);
355
- const remoteRev = String(rawItem._rev || rawItem.rev || rawItem.version || '1');
356
- if (existingSync && existingSync.remoteRev === remoteRev) {
357
- const fullExistingPath = path.join(options.workspaceRoot, existingSync.localFilePath);
358
- if (fs.existsSync(fullExistingPath)) {
362
+ const rawObj = (item.rawItem || item);
363
+ const rawRevCandidate = String(item._rev || item.rev || item.version || rawObj._rev || '');
364
+ const remoteRev = extractRev(rawObj, rawRevCandidate);
365
+ if (!existingSync ||
366
+ !remoteRev ||
367
+ normalizeRev(existingSync.remoteRev) !== normalizeRev(remoteRev)) {
368
+ return null;
369
+ }
370
+ const fullExistingPath = path.join(options.workspaceRoot, existingSync.localFilePath);
371
+ if (!fs.existsSync(fullExistingPath)) {
372
+ return null;
373
+ }
374
+ try {
375
+ const currentDiskContent = fs.readFileSync(fullExistingPath, 'utf8');
376
+ const currentDiskHash = calculateHash(currentDiskContent);
377
+ // Check if file path matches current naming standard
378
+ const existingPrefix = extractDatePrefixFromPath(existingSync.localFilePath);
379
+ const rawData = (rawObj.data || rawObj.item || {}) || {};
380
+ const rawTitle = String(rawData.title || rawObj.title || item.title || rawObj.slug || item.slug || '');
381
+ const articleDate = rawObj.publishedAt ||
382
+ item.publishedAt ||
383
+ existingPrefix ||
384
+ rawObj.createdAt ||
385
+ item.createdAt ||
386
+ null;
387
+ const expectedRelPath = computeArticleRelativePath(collection, String(rawObj.status || item.status || 'draft'), id, rawTitle, articleDate);
388
+ // If path matches and contents are unchanged, safely skip (only if local frontmatter is valid YAML)
389
+ if (existingSync.localFilePath === expectedRelPath) {
390
+ if (currentDiskHash === existingSync.localHash) {
391
+ parseMarkdown(currentDiskContent);
392
+ return {
393
+ id,
394
+ slug: existingSync.slug,
395
+ status: existingSync.status,
396
+ filePath: existingSync.localFilePath,
397
+ updated: false,
398
+ skipped: true,
399
+ title: rawTitle,
400
+ };
401
+ }
402
+ // Local file has unpushed edits. Check if frontmatter parses cleanly.
359
403
  try {
360
- const currentDiskContent = fs.readFileSync(fullExistingPath, 'utf8');
361
- const currentDiskHash = calculateHash(currentDiskContent);
362
- // Check if file path matches current naming standard
363
- const existingPrefix = extractDatePrefixFromPath(existingSync.localFilePath);
364
- const rawData = (rawItem.data || {});
365
- const rawTitle = String(rawData.title || rawItem.title || rawItem.slug || '');
366
- const articleDate = rawItem.publishedAt ||
367
- existingPrefix ||
368
- rawItem.createdAt ||
369
- null;
370
- const expectedRelPath = computeArticleRelativePath(collection, String(rawItem.status || 'draft'), id, rawTitle, articleDate);
371
- // If path matches and contents are unchanged, safely skip (only if local frontmatter is valid YAML;
372
- // if an older serializer wrote unquoted %-prefixed slugs that fail parseMarkdown, fall through to self-heal)
373
- if (existingSync.localFilePath === expectedRelPath) {
374
- if (currentDiskHash === existingSync.localHash) {
375
- parseMarkdown(currentDiskContent);
376
- return {
377
- id,
378
- slug: existingSync.slug,
379
- status: existingSync.status,
380
- filePath: existingSync.localFilePath,
381
- updated: false,
382
- skipped: true,
383
- title: rawTitle,
384
- };
404
+ parseMarkdown(currentDiskContent);
405
+ return {
406
+ id,
407
+ slug: existingSync.slug,
408
+ status: existingSync.status,
409
+ filePath: existingSync.localFilePath,
410
+ updated: false,
411
+ skipped: true,
412
+ localEditsPreserved: true,
413
+ title: rawTitle,
414
+ };
415
+ }
416
+ catch {
417
+ // Local frontmatter is invalid. Attempt non-destructive lenient frontmatter repair.
418
+ const repaired = lenientRepairMarkdownFrontmatter(currentDiskContent);
419
+ if (repaired !== null) {
420
+ fs.writeFileSync(fullExistingPath, repaired, 'utf8');
421
+ const parsedRepaired = parseMarkdown(repaired);
422
+ const resolvedBylineMap = await getBylineIdToSlug();
423
+ const effectiveOptions = {
424
+ ...options,
425
+ bylineIdToSlug: resolvedBylineMap,
426
+ };
427
+ const remoteLocal = apiResponseToLocal(rawObj, effectiveOptions);
428
+ const [categoriesTerms, tagsTerms] = await Promise.all([
429
+ fetchAssignedTerms('category'),
430
+ fetchAssignedTerms('tag'),
431
+ ]);
432
+ if (categoriesTerms !== null || tagsTerms !== null) {
433
+ if (!remoteLocal.frontmatter.taxonomies) {
434
+ remoteLocal.frontmatter.taxonomies = {};
435
+ }
436
+ if (categoriesTerms !== null) {
437
+ remoteLocal.frontmatter.taxonomies.categories = categoriesTerms;
438
+ }
439
+ if (tagsTerms !== null) {
440
+ remoteLocal.frontmatter.taxonomies.tags = tagsTerms;
441
+ }
385
442
  }
386
- // Local file has unpushed edits. Check if frontmatter parses cleanly.
387
- // If it parses cleanly, strictly protect local edits without touching the file.
388
- try {
389
- parseMarkdown(currentDiskContent);
390
- return {
443
+ const remoteCanonMarkdown = serializeMarkdown(remoteLocal.frontmatter, remoteLocal.body, getTaxonomyCandidates());
444
+ const remoteCanonHash = calculateHash(remoteCanonMarkdown);
445
+ const existingBase = options.cache.getBaseSnapshot(id);
446
+ if (!(categoriesTerms === null && tagsTerms === null && existingBase)) {
447
+ options.cache.saveBaseSnapshot({
391
448
  id,
392
- slug: existingSync.slug,
393
- status: existingSync.status,
394
- filePath: existingSync.localFilePath,
395
- updated: false,
396
- skipped: true,
397
- localEditsPreserved: true,
398
- title: rawTitle,
399
- };
400
- }
401
- catch {
402
- // Local frontmatter is invalid (e.g. older unquoted % slug or minor indent).
403
- // Attempt non-destructive lenient frontmatter repair (body is 100% untouched).
404
- const repaired = lenientRepairMarkdownFrontmatter(currentDiskContent);
405
- if (repaired !== null) {
406
- // Syntax-only repair succeeded! Overwrite disk with repaired frontmatter (keeping local body).
407
- fs.writeFileSync(fullExistingPath, repaired, 'utf8');
408
- const repairedHash = calculateHash(repaired);
409
- const parsedRepaired = parseMarkdown(repaired);
410
- // Update baseline snapshot using the remote rev and remote payload's canonical representation,
411
- // so subsequent 3-way merges compare against the remote baseline rather than claiming
412
- // local edits are in sync.
413
- // Fetch assigned taxonomy terms so base snapshot reflects remote state rather than empty taxonomies (NEW-1).
414
- const resolvedBylineMap = await getBylineIdToSlug();
415
- const effectiveOptions = {
416
- ...options,
417
- bylineIdToSlug: resolvedBylineMap,
418
- };
419
- const remoteLocal = apiResponseToLocal(rawItem, effectiveOptions);
420
- const [categoriesTerms, tagsTerms] = await Promise.all([
421
- fetchAssignedTerms('category'),
422
- fetchAssignedTerms('tag'),
423
- ]);
424
- if (categoriesTerms !== null || tagsTerms !== null) {
425
- if (!remoteLocal.frontmatter.taxonomies) {
426
- remoteLocal.frontmatter.taxonomies = {};
427
- }
428
- if (categoriesTerms !== null) {
429
- remoteLocal.frontmatter.taxonomies.categories = categoriesTerms;
430
- }
431
- if (tagsTerms !== null) {
432
- remoteLocal.frontmatter.taxonomies.tags = tagsTerms;
433
- }
434
- }
435
- const remoteCanonMarkdown = serializeMarkdown(remoteLocal.frontmatter, remoteLocal.body, getTaxonomyCandidates());
436
- const remoteCanonHash = calculateHash(remoteCanonMarkdown);
437
- // If term requests both failed over network, preserve existing base snapshot if available
438
- // to avoid wiping out taxonomy baselines with an empty assignment (R-2).
439
- const existingBase = options.cache.getBaseSnapshot(id);
440
- if (!(categoriesTerms === null && tagsTerms === null && existingBase)) {
441
- options.cache.saveBaseSnapshot({
442
- id,
443
- rev: remoteRev,
444
- bodyMarkdown: remoteLocal.body,
445
- frontmatterYaml: JSON.stringify(remoteLocal.frontmatter),
446
- hash: remoteCanonHash,
447
- savedAt: Math.floor(Date.now() / 1000),
448
- });
449
- }
450
- // Update syncState keeping remoteCanonHash so local edits (repairedHash) are correctly identified as modified
451
- options.cache.saveSyncState({
452
- id,
453
- localFilePath: existingSync.localFilePath,
454
- localHash: remoteCanonHash,
455
- remoteRev,
456
- status: parsedRepaired.frontmatter.status,
457
- slug: parsedRepaired.frontmatter.slug,
458
- lastSyncedAt: Math.floor(Date.now() / 1000),
459
- });
460
- return {
461
- id,
462
- slug: parsedRepaired.frontmatter.slug,
463
- status: parsedRepaired.frontmatter.status,
464
- filePath: existingSync.localFilePath,
465
- updated: true,
466
- healed: true,
467
- meaningChanged: false,
468
- title: rawTitle,
469
- };
470
- }
471
- // If lenient repair was impossible without altering meaning, fall through to full pull & quarantine.
449
+ rev: remoteRev,
450
+ bodyMarkdown: remoteLocal.body,
451
+ frontmatterYaml: JSON.stringify(remoteLocal.frontmatter),
452
+ hash: remoteCanonHash,
453
+ savedAt: Math.floor(Date.now() / 1000),
454
+ });
472
455
  }
456
+ options.cache.saveSyncState({
457
+ id,
458
+ localFilePath: existingSync.localFilePath,
459
+ localHash: remoteCanonHash,
460
+ remoteRev,
461
+ status: parsedRepaired.frontmatter.status,
462
+ slug: parsedRepaired.frontmatter.slug,
463
+ lastSyncedAt: Math.floor(Date.now() / 1000),
464
+ });
465
+ return {
466
+ id,
467
+ slug: parsedRepaired.frontmatter.slug,
468
+ status: parsedRepaired.frontmatter.status,
469
+ filePath: existingSync.localFilePath,
470
+ updated: true,
471
+ healed: true,
472
+ meaningChanged: false,
473
+ title: rawTitle,
474
+ };
473
475
  }
474
476
  }
475
- catch {
476
- // If read fails, proceed to normal write
477
- }
478
477
  }
479
478
  }
479
+ catch {
480
+ // If error, fall through to full pull
481
+ }
482
+ return null;
483
+ };
484
+ // 1. Fast-path check: If rawItem is provided in options, test fast-path / heal
485
+ if (rawItem) {
486
+ const fastResult = await tryFastPathOrHeal(rawItem);
487
+ if (fastResult)
488
+ return fastResult;
480
489
  }
481
490
  // 2. Fetch raw item if not passed in options
482
491
  if (!rawItem) {
@@ -489,8 +498,8 @@ export async function pullArticle(collection, id, options) {
489
498
  },
490
499
  });
491
500
  if (!res.ok) {
492
- if (res.status === 404) {
493
- // Remote article was deleted (404)
501
+ if (res.status === 404 || res.status === 410) {
502
+ // Remote article was deleted (404/410)
494
503
  const existingSync = options.cache.getSyncState(id);
495
504
  if (existingSync) {
496
505
  const fullPath = path.join(options.workspaceRoot, existingSync.localFilePath);
@@ -515,6 +524,18 @@ export async function pullArticle(collection, id, options) {
515
524
  deleted: true,
516
525
  };
517
526
  }
527
+ else {
528
+ // Local file has unpushed edits: preserve as orphan!
529
+ return {
530
+ id,
531
+ slug: existingSync.slug,
532
+ status: existingSync.status,
533
+ filePath: existingSync.localFilePath,
534
+ updated: false,
535
+ orphan: true,
536
+ localEditsPreserved: true,
537
+ };
538
+ }
518
539
  }
519
540
  }
520
541
  }
@@ -527,6 +548,10 @@ export async function pullArticle(collection, id, options) {
527
548
  });
528
549
  }
529
550
  rawItem = (await res.json());
551
+ // Step 2b (D5): Test fast-path / non-destructive heal for single-article pull as well!
552
+ const singleHealResult = await tryFastPathOrHeal(rawItem);
553
+ if (singleHealResult)
554
+ return singleHealResult;
530
555
  }
531
556
  // Ensure byline ID-to-slug mapping is loaded
532
557
  const resolvedBylineMap = await getBylineIdToSlug();
@@ -579,7 +604,7 @@ export async function pullArticle(collection, id, options) {
579
604
  const canonicalResolved = path.resolve(fullFilePath);
580
605
  // Data safety: preserve every local copy whose content diverges from the last synced
581
606
  // baseline (or has no cache baseline at all) before it is overwritten or unlinked.
582
- const quarantined = quarantineDivergentLocalCopies(options, frontmatter.collection, staleRelPaths, existingSync?.localHash, markdownContent);
607
+ const quarantined = quarantineDivergentLocalCopies(options, frontmatter.collection, staleRelPaths, existingSync?.localHash, markdownContent, existingSync?.conflictCopyHash);
583
608
  for (const staleRel of staleRelPaths) {
584
609
  const staleFull = path.resolve(options.workspaceRoot, staleRel);
585
610
  if (staleFull !== canonicalResolved && fs.existsSync(staleFull)) {
@@ -612,6 +637,7 @@ export async function pullArticle(collection, id, options) {
612
637
  status: frontmatter.status,
613
638
  slug: frontmatter.slug,
614
639
  lastSyncedAt: Math.floor(Date.now() / 1000),
640
+ ...(options.force ? { conflictPending: 0, conflictCopyHash: null } : {}),
615
641
  });
616
642
  // Update entries cache
617
643
  options.cache.saveEntry({