emdash-emit 0.1.9 → 0.1.11
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/CHANGELOG.md +101 -0
- package/README.md +102 -13
- package/dist/bin/emit.d.ts.map +1 -1
- package/dist/bin/emit.js +6 -0
- package/dist/bin/emit.js.map +1 -1
- package/dist/cli/commands/conflicts.d.ts +4 -0
- package/dist/cli/commands/conflicts.d.ts.map +1 -0
- package/dist/cli/commands/conflicts.js +153 -0
- package/dist/cli/commands/conflicts.js.map +1 -0
- package/dist/cli/commands/delete.d.ts +4 -0
- package/dist/cli/commands/delete.d.ts.map +1 -0
- package/dist/cli/commands/delete.js +89 -0
- package/dist/cli/commands/delete.js.map +1 -0
- package/dist/cli/commands/doctor.d.ts +4 -0
- package/dist/cli/commands/doctor.d.ts.map +1 -0
- package/dist/cli/commands/doctor.js +82 -0
- package/dist/cli/commands/doctor.js.map +1 -0
- package/dist/cli/commands/new.d.ts.map +1 -1
- package/dist/cli/commands/new.js +52 -22
- package/dist/cli/commands/new.js.map +1 -1
- package/dist/cli/commands/pull.d.ts.map +1 -1
- package/dist/cli/commands/pull.js +23 -0
- package/dist/cli/commands/pull.js.map +1 -1
- package/dist/cli/commands/push.d.ts.map +1 -1
- package/dist/cli/commands/push.js +36 -1
- package/dist/cli/commands/push.js.map +1 -1
- package/dist/cli/commands/status.d.ts.map +1 -1
- package/dist/cli/commands/status.js +27 -7
- package/dist/cli/commands/status.js.map +1 -1
- package/dist/cli/context.d.ts +3 -1
- package/dist/cli/context.d.ts.map +1 -1
- package/dist/cli/context.js +17 -6
- package/dist/cli/context.js.map +1 -1
- package/dist/db/cache.d.ts +3 -0
- package/dist/db/cache.d.ts.map +1 -1
- package/dist/db/cache.js +39 -0
- package/dist/db/cache.js.map +1 -1
- package/dist/mcp/context.d.ts +7 -0
- package/dist/mcp/context.d.ts.map +1 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +39 -2
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/tool-errors.d.ts +7 -2
- package/dist/mcp/tool-errors.d.ts.map +1 -1
- package/dist/mcp/tool-errors.js +80 -5
- package/dist/mcp/tool-errors.js.map +1 -1
- package/dist/mcp/tools/profile.d.ts.map +1 -1
- package/dist/mcp/tools/profile.js +4 -0
- package/dist/mcp/tools/profile.js.map +1 -1
- package/dist/mcp/tools/sync-conflicts.d.ts +4 -0
- package/dist/mcp/tools/sync-conflicts.d.ts.map +1 -0
- package/dist/mcp/tools/sync-conflicts.js +100 -0
- package/dist/mcp/tools/sync-conflicts.js.map +1 -0
- package/dist/mcp/tools/sync-delete.d.ts +4 -0
- package/dist/mcp/tools/sync-delete.d.ts.map +1 -0
- package/dist/mcp/tools/sync-delete.js +77 -0
- package/dist/mcp/tools/sync-delete.js.map +1 -0
- package/dist/mcp/tools/sync-diff.d.ts.map +1 -1
- package/dist/mcp/tools/sync-diff.js +3 -2
- package/dist/mcp/tools/sync-diff.js.map +1 -1
- package/dist/mcp/tools/sync-doctor.d.ts +4 -0
- package/dist/mcp/tools/sync-doctor.d.ts.map +1 -0
- package/dist/mcp/tools/sync-doctor.js +57 -0
- package/dist/mcp/tools/sync-doctor.js.map +1 -0
- package/dist/mcp/tools/sync-new.d.ts.map +1 -1
- package/dist/mcp/tools/sync-new.js +16 -3
- package/dist/mcp/tools/sync-new.js.map +1 -1
- package/dist/mcp/tools/sync-pull.d.ts.map +1 -1
- package/dist/mcp/tools/sync-pull.js +41 -11
- package/dist/mcp/tools/sync-pull.js.map +1 -1
- package/dist/mcp/tools/sync-push.d.ts.map +1 -1
- package/dist/mcp/tools/sync-push.js +16 -2
- package/dist/mcp/tools/sync-push.js.map +1 -1
- package/dist/mcp/tools/sync-status.d.ts.map +1 -1
- package/dist/mcp/tools/sync-status.js +63 -22
- package/dist/mcp/tools/sync-status.js.map +1 -1
- package/dist/sync/conflicts.d.ts +89 -0
- package/dist/sync/conflicts.d.ts.map +1 -0
- package/dist/sync/conflicts.js +374 -0
- package/dist/sync/conflicts.js.map +1 -0
- package/dist/sync/delete.d.ts +58 -0
- package/dist/sync/delete.d.ts.map +1 -0
- package/dist/sync/delete.js +221 -0
- package/dist/sync/delete.js.map +1 -0
- package/dist/sync/diff.d.ts.map +1 -1
- package/dist/sync/diff.js +6 -3
- package/dist/sync/diff.js.map +1 -1
- package/dist/sync/doctor.d.ts +31 -0
- package/dist/sync/doctor.d.ts.map +1 -0
- package/dist/sync/doctor.js +273 -0
- package/dist/sync/doctor.js.map +1 -0
- package/dist/sync/media.d.ts +22 -0
- package/dist/sync/media.d.ts.map +1 -1
- package/dist/sync/media.js +342 -94
- package/dist/sync/media.js.map +1 -1
- package/dist/sync/merge.d.ts +17 -1
- package/dist/sync/merge.d.ts.map +1 -1
- package/dist/sync/merge.js +110 -3
- package/dist/sync/merge.js.map +1 -1
- package/dist/sync/new.d.ts +31 -0
- package/dist/sync/new.d.ts.map +1 -1
- package/dist/sync/new.js +139 -2
- package/dist/sync/new.js.map +1 -1
- package/dist/sync/orchestrator.d.ts.map +1 -1
- package/dist/sync/orchestrator.js +2 -0
- package/dist/sync/orchestrator.js.map +1 -1
- package/dist/sync/preflight.d.ts.map +1 -1
- package/dist/sync/preflight.js +29 -3
- package/dist/sync/preflight.js.map +1 -1
- package/dist/sync/pull.d.ts +4 -0
- package/dist/sync/pull.d.ts.map +1 -1
- package/dist/sync/pull.js +159 -80
- package/dist/sync/pull.js.map +1 -1
- package/dist/sync/push.d.ts +10 -0
- package/dist/sync/push.d.ts.map +1 -1
- package/dist/sync/push.js +84 -31
- package/dist/sync/push.js.map +1 -1
- package/dist/sync/status.d.ts +10 -0
- package/dist/sync/status.d.ts.map +1 -1
- package/dist/sync/status.js +26 -0
- package/dist/sync/status.js.map +1 -1
- package/dist/sync/taxonomies.d.ts +14 -5
- package/dist/sync/taxonomies.d.ts.map +1 -1
- package/dist/sync/taxonomies.js +104 -6
- package/dist/sync/taxonomies.js.map +1 -1
- package/dist/sync/terms.d.ts +32 -0
- package/dist/sync/terms.d.ts.map +1 -0
- package/dist/sync/terms.js +62 -0
- package/dist/sync/terms.js.map +1 -0
- package/dist/utils/config.d.ts +12 -0
- package/dist/utils/config.d.ts.map +1 -1
- package/dist/utils/config.js +27 -0
- package/dist/utils/config.js.map +1 -1
- package/dist/utils/frontmatter.d.ts +40 -3
- package/dist/utils/frontmatter.d.ts.map +1 -1
- package/dist/utils/frontmatter.js +188 -5
- package/dist/utils/frontmatter.js.map +1 -1
- package/package.json +2 -1
|
@@ -20,15 +20,29 @@
|
|
|
20
20
|
* SOFTWARE.
|
|
21
21
|
*/
|
|
22
22
|
import { z } from 'zod';
|
|
23
|
-
import { getWorkspaceStatus } from '../../sync/status.js';
|
|
24
|
-
import { formatToolError } from '../tool-errors.js';
|
|
25
|
-
const
|
|
23
|
+
import { getWorkspaceStatus, filterStatusItems, } from '../../sync/status.js';
|
|
24
|
+
import { formatToolError, formatToolSuccess } from '../tool-errors.js';
|
|
25
|
+
const MAX_ACTION_REQUIRED = 30;
|
|
26
|
+
const MAX_RECENT_SYNCED = 5;
|
|
26
27
|
export function registerSyncStatusTool(server, resolveContext) {
|
|
27
|
-
server.tool('sync_status', 'Inspect local workspace sync status
|
|
28
|
+
server.tool('sync_status', 'Inspect local workspace sync status with articles sorted newest-first. Returns a summary-first payload (concise summary, up to 30 action-required articles, and 5 recent synced articles) to conserve LLM context. Use "search" or "slugFilter" to find specific articles across the full workspace.', {
|
|
28
29
|
collection: z
|
|
29
30
|
.string()
|
|
30
31
|
.optional()
|
|
31
32
|
.describe('Collection name to inspect (defaults to "posts")'),
|
|
33
|
+
search: z
|
|
34
|
+
.string()
|
|
35
|
+
.optional()
|
|
36
|
+
.describe('Search query matching article title, slug, ID, or file path'),
|
|
37
|
+
slugFilter: z.string().optional().describe('Filter articles by exact or partial slug'),
|
|
38
|
+
status: z
|
|
39
|
+
.enum(['draft', 'published'])
|
|
40
|
+
.optional()
|
|
41
|
+
.describe('Filter by article publication status (draft or published)'),
|
|
42
|
+
syncStatus: z
|
|
43
|
+
.enum(['synced', 'modified', 'untracked', 'invalid'])
|
|
44
|
+
.optional()
|
|
45
|
+
.describe('Filter by synchronization state'),
|
|
32
46
|
profile: z.string().optional().describe('Target profile name for multi-site setups'),
|
|
33
47
|
}, async (args) => {
|
|
34
48
|
// Resolve context inside the guard too: workspace/profile resolution can throw
|
|
@@ -49,20 +63,49 @@ export function registerSyncStatusTool(server, resolveContext) {
|
|
|
49
63
|
catch (error) {
|
|
50
64
|
return formatToolError(error);
|
|
51
65
|
}
|
|
52
|
-
|
|
66
|
+
const isFiltered = Boolean(args.search || args.slugFilter || args.status || args.syncStatus);
|
|
67
|
+
const filteredList = isFiltered
|
|
68
|
+
? filterStatusItems(status.items, {
|
|
69
|
+
search: args.search,
|
|
70
|
+
slugFilter: args.slugFilter,
|
|
71
|
+
status: args.status,
|
|
72
|
+
syncStatus: args.syncStatus,
|
|
73
|
+
})
|
|
74
|
+
: null;
|
|
75
|
+
// Extract action-required items (modified, invalid, untracked)
|
|
76
|
+
// Cap invalid items at 10 to prevent verbose error stack traces from blowing the token budget
|
|
77
|
+
const MAX_INVALID_MCP_ITEMS = 10;
|
|
53
78
|
let invalidSeen = 0;
|
|
54
|
-
const
|
|
55
|
-
if (item.syncStatus
|
|
56
|
-
return
|
|
57
|
-
|
|
58
|
-
|
|
79
|
+
const cappedActionItems = status.items.filter((item) => {
|
|
80
|
+
if (item.syncStatus === 'synced')
|
|
81
|
+
return false;
|
|
82
|
+
if (item.syncStatus === 'invalid') {
|
|
83
|
+
invalidSeen++;
|
|
84
|
+
return invalidSeen <= MAX_INVALID_MCP_ITEMS;
|
|
85
|
+
}
|
|
86
|
+
return true;
|
|
59
87
|
});
|
|
60
88
|
const invalidTruncated = Math.max(0, status.summary.invalid - MAX_INVALID_MCP_ITEMS);
|
|
89
|
+
const actionRequired = cappedActionItems.slice(0, MAX_ACTION_REQUIRED);
|
|
90
|
+
const rawActionRequiredCount = status.items.filter((i) => i.syncStatus !== 'synced').length;
|
|
91
|
+
const actionRequiredTruncated = rawActionRequiredCount > MAX_ACTION_REQUIRED || invalidTruncated > 0;
|
|
92
|
+
// Extract recent synced articles
|
|
93
|
+
const allSynced = status.items.filter((item) => item.syncStatus === 'synced');
|
|
94
|
+
const recentArticles = allSynced.slice(0, MAX_RECENT_SYNCED);
|
|
95
|
+
const recentArticlesTruncated = allSynced.length > MAX_RECENT_SYNCED;
|
|
61
96
|
const uncachedInvalid = status.items.filter((item) => item.syncStatus === 'invalid' && item.cached === false);
|
|
62
97
|
const exampleUncachedId = uncachedInvalid.find((i) => i.id && i.id !== 'unknown')?.id || '<ULID>';
|
|
63
98
|
const responsePayload = {
|
|
64
|
-
items: filteredItems,
|
|
65
99
|
summary: status.summary,
|
|
100
|
+
actionRequired,
|
|
101
|
+
actionRequiredTruncated,
|
|
102
|
+
recentArticles,
|
|
103
|
+
recentArticlesTruncated,
|
|
104
|
+
total: status.summary.total,
|
|
105
|
+
searchQuery: args.search || args.slugFilter || null,
|
|
106
|
+
...(isFiltered ? { filteredArticles: filteredList } : {}),
|
|
107
|
+
// Fallback for callers expecting .items:
|
|
108
|
+
items: isFiltered ? filteredList : [...actionRequired, ...recentArticles],
|
|
66
109
|
...(ctx.originWarning ? { warnings: [ctx.originWarning] } : {}),
|
|
67
110
|
...(invalidTruncated > 0
|
|
68
111
|
? {
|
|
@@ -70,27 +113,25 @@ export function registerSyncStatusTool(server, resolveContext) {
|
|
|
70
113
|
invalidNote: `...and ${invalidTruncated} more invalid frontmatter file(s) omitted to conserve context.`,
|
|
71
114
|
}
|
|
72
115
|
: {}),
|
|
116
|
+
...(actionRequiredTruncated && invalidTruncated === 0
|
|
117
|
+
? {
|
|
118
|
+
actionRequiredNote: `...and ${rawActionRequiredCount - MAX_ACTION_REQUIRED} more action-required item(s) omitted. Use search or slugFilter to narrow down.`,
|
|
119
|
+
}
|
|
120
|
+
: {}),
|
|
73
121
|
...(status.summary.invalid > 0
|
|
74
122
|
? {
|
|
75
123
|
repairHint: uncachedInvalid.length > 0
|
|
76
|
-
? `Run sync_pull to automatically repair cached invalid frontmatter
|
|
77
|
-
: 'Run sync_pull (or "emit pull" in CLI) to automatically re-serialize and repair
|
|
124
|
+
? `Run sync_pull to automatically repair cached invalid frontmatter (local body is strictly preserved). For ${uncachedInvalid.length} uncached file(s) outside the sliding window, run sync_pull with id: "${exampleUncachedId}" (or "emit pull ${exampleUncachedId}" in CLI).`
|
|
125
|
+
: 'Run sync_pull (or "emit pull" in CLI) to automatically re-serialize and repair frontmatter syntax (local body is strictly preserved).',
|
|
78
126
|
}
|
|
79
127
|
: {}),
|
|
80
128
|
...(status.summary.conflicts > 0
|
|
81
129
|
? {
|
|
82
|
-
conflictsNote: `${status.summary.conflicts} preserved local copy(ies) exist in ${collection}/conflicts/
|
|
130
|
+
conflictsNote: `${status.summary.conflicts} preserved local copy(ies) exist in ${collection}/conflicts/ (sync conflicts and deletion rescue backups are both preserved here). Review each copy, merge valuable content manually, or use sync_conflicts (action: 'list' | 'diff' | 'resolve'). Preserved copies are never pushed or pruned automatically, and sync_push refuses a posts/conflicts/ path with QUARANTINED_COPY_NOT_PUSHABLE.`,
|
|
83
131
|
}
|
|
84
132
|
: {}),
|
|
85
133
|
};
|
|
86
|
-
return
|
|
87
|
-
content: [
|
|
88
|
-
{
|
|
89
|
-
type: 'text',
|
|
90
|
-
text: JSON.stringify(responsePayload, null, 2),
|
|
91
|
-
},
|
|
92
|
-
],
|
|
93
|
-
};
|
|
134
|
+
return formatToolSuccess(responsePayload, ctx.meta);
|
|
94
135
|
});
|
|
95
136
|
}
|
|
96
137
|
//# sourceMappingURL=sync-status.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sync-status.js","sourceRoot":"","sources":["../../../src/mcp/tools/sync-status.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,
|
|
1
|
+
{"version":3,"file":"sync-status.js","sourceRoot":"","sources":["../../../src/mcp/tools/sync-status.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import type { CacheDatabase } from '../db/cache.js';
|
|
2
|
+
export type ConflictFileType = 'conflict' | 'deleted' | 'unknown';
|
|
3
|
+
export interface ConflictItem {
|
|
4
|
+
filePath: string;
|
|
5
|
+
fileName: string;
|
|
6
|
+
type: ConflictFileType;
|
|
7
|
+
id?: string;
|
|
8
|
+
slug?: string;
|
|
9
|
+
title?: string;
|
|
10
|
+
status?: string;
|
|
11
|
+
canonicalPath?: string | null;
|
|
12
|
+
sizeBytes: number;
|
|
13
|
+
createdAt: string;
|
|
14
|
+
}
|
|
15
|
+
export interface ConflictDiffResult {
|
|
16
|
+
conflictFilePath: string;
|
|
17
|
+
canonicalFilePath: string | null;
|
|
18
|
+
type: ConflictFileType;
|
|
19
|
+
id?: string;
|
|
20
|
+
slug?: string;
|
|
21
|
+
hasDifferences: boolean;
|
|
22
|
+
additions: number;
|
|
23
|
+
deletions: number;
|
|
24
|
+
diffText: string;
|
|
25
|
+
}
|
|
26
|
+
export interface ConflictResolutionResult {
|
|
27
|
+
success: boolean;
|
|
28
|
+
strategy: 'accept-local' | 'accept-canonical';
|
|
29
|
+
conflictFilePath: string;
|
|
30
|
+
canonicalFilePath?: string | null;
|
|
31
|
+
message: string;
|
|
32
|
+
warnings?: string[];
|
|
33
|
+
}
|
|
34
|
+
export declare class CanonicalHasUnpushedEditsError extends Error {
|
|
35
|
+
code: string;
|
|
36
|
+
canonicalFilePath: string;
|
|
37
|
+
conflictFilePath: string;
|
|
38
|
+
id: string;
|
|
39
|
+
suggestion: string;
|
|
40
|
+
constructor(details: {
|
|
41
|
+
canonicalFilePath: string;
|
|
42
|
+
conflictFilePath: string;
|
|
43
|
+
id: string;
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
export declare class QuarantinedPathRequiredError extends Error {
|
|
47
|
+
code: string;
|
|
48
|
+
filePath: string;
|
|
49
|
+
collection: string;
|
|
50
|
+
suggestion: string;
|
|
51
|
+
constructor(details: {
|
|
52
|
+
filePath: string;
|
|
53
|
+
collection: string;
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Strips the conflict/deletion suffix to recover the original article filename base.
|
|
58
|
+
* e.g. "20261108_01M6...-my-slug.conflict.md" -> "20261108_01M6...-my-slug"
|
|
59
|
+
* "20261108_01M6...-my-slug.deleted.md" -> "20261108_01M6...-my-slug"
|
|
60
|
+
*/
|
|
61
|
+
export declare function extractBaseArticleName(fileName: string): string;
|
|
62
|
+
/**
|
|
63
|
+
* Resolves the canonical live file corresponding to a quarantined conflict or deleted backup.
|
|
64
|
+
*/
|
|
65
|
+
export declare function findCanonicalArticlePath(workspaceRoot: string, baseName: string, articleId?: string, collection?: string): string | null;
|
|
66
|
+
/**
|
|
67
|
+
* Lists all quarantined conflict files and deleted rescue copies in posts/conflicts/.
|
|
68
|
+
*/
|
|
69
|
+
export declare function listConflicts(workspaceRoot: string, collection?: string): ConflictItem[];
|
|
70
|
+
/**
|
|
71
|
+
* Computes a diff between the quarantined conflict/deleted copy and the canonical article.
|
|
72
|
+
*/
|
|
73
|
+
export declare function diffConflict(options: {
|
|
74
|
+
workspaceRoot: string;
|
|
75
|
+
filePath: string;
|
|
76
|
+
collection?: string;
|
|
77
|
+
}): ConflictDiffResult;
|
|
78
|
+
/**
|
|
79
|
+
* Resolves a quarantined conflict file with either accept-local or accept-canonical strategy.
|
|
80
|
+
*/
|
|
81
|
+
export declare function resolveConflict(options: {
|
|
82
|
+
workspaceRoot: string;
|
|
83
|
+
cache: CacheDatabase;
|
|
84
|
+
filePath: string;
|
|
85
|
+
strategy: 'accept-local' | 'accept-canonical';
|
|
86
|
+
force?: boolean;
|
|
87
|
+
collection?: string;
|
|
88
|
+
}): ConflictResolutionResult;
|
|
89
|
+
//# sourceMappingURL=conflicts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conflicts.d.ts","sourceRoot":"","sources":["../../src/sync/conflicts.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (C) 2026 SPORT-SERVICE RS★R
|
|
3
|
+
*
|
|
4
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
5
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
6
|
+
* in the Software without restriction, including without limitation the rights
|
|
7
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
8
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
9
|
+
* furnished to do so, subject to the following conditions:
|
|
10
|
+
*
|
|
11
|
+
* The above copyright notice and this permission notice shall be included in all
|
|
12
|
+
* copies or substantial portions of the Software.
|
|
13
|
+
*
|
|
14
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
15
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
16
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
17
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
18
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
19
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
20
|
+
* SOFTWARE.
|
|
21
|
+
*/
|
|
22
|
+
import fs from 'node:fs';
|
|
23
|
+
import path from 'node:path';
|
|
24
|
+
import { parseMarkdown, lenientRepairMarkdownFrontmatter } from '../utils/frontmatter.js';
|
|
25
|
+
import { computeContextDiff } from './diff.js';
|
|
26
|
+
import { calculateHash } from './pull.js';
|
|
27
|
+
export class CanonicalHasUnpushedEditsError extends Error {
|
|
28
|
+
code = 'CANONICAL_HAS_UNPUSHED_EDITS';
|
|
29
|
+
canonicalFilePath;
|
|
30
|
+
conflictFilePath;
|
|
31
|
+
id;
|
|
32
|
+
suggestion;
|
|
33
|
+
constructor(details) {
|
|
34
|
+
super(`ABORT: Canonical article "${details.canonicalFilePath}" contains unpushed local modifications. Overwriting it with quarantined copy "${details.conflictFilePath}" would lose those edits.`);
|
|
35
|
+
this.name = 'CanonicalHasUnpushedEditsError';
|
|
36
|
+
this.canonicalFilePath = details.canonicalFilePath;
|
|
37
|
+
this.conflictFilePath = details.conflictFilePath;
|
|
38
|
+
this.id = details.id;
|
|
39
|
+
this.suggestion = `Inspect differences first with "emit conflicts diff ${details.conflictFilePath}" or "emit diff ${details.canonicalFilePath}". If you explicitly intend to discard canonical edits and overwrite, pass --force (or MCP force: true).`;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
export class QuarantinedPathRequiredError extends Error {
|
|
43
|
+
code = 'QUARANTINED_PATH_REQUIRED';
|
|
44
|
+
filePath;
|
|
45
|
+
collection;
|
|
46
|
+
suggestion;
|
|
47
|
+
constructor(details) {
|
|
48
|
+
super(`Target file must be located inside ${details.collection}/conflicts/: ${details.filePath}`);
|
|
49
|
+
this.name = 'QuarantinedPathRequiredError';
|
|
50
|
+
this.filePath = details.filePath;
|
|
51
|
+
this.collection = details.collection;
|
|
52
|
+
this.suggestion = `Specify a quarantined conflict file path located inside ${details.collection}/conflicts/. Run "emit conflicts list" (or MCP sync_conflicts action: "list") to inspect valid targets.`;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Strips the conflict/deletion suffix to recover the original article filename base.
|
|
57
|
+
* e.g. "20261108_01M6...-my-slug.conflict.md" -> "20261108_01M6...-my-slug"
|
|
58
|
+
* "20261108_01M6...-my-slug.deleted.md" -> "20261108_01M6...-my-slug"
|
|
59
|
+
*/
|
|
60
|
+
export function extractBaseArticleName(fileName) {
|
|
61
|
+
if (fileName.endsWith('.conflict.md')) {
|
|
62
|
+
return fileName.slice(0, -'.conflict.md'.length);
|
|
63
|
+
}
|
|
64
|
+
if (fileName.endsWith('.deleted.md')) {
|
|
65
|
+
return fileName.slice(0, -'.deleted.md'.length);
|
|
66
|
+
}
|
|
67
|
+
if (fileName.endsWith('.md')) {
|
|
68
|
+
return fileName.slice(0, -'.md'.length);
|
|
69
|
+
}
|
|
70
|
+
return fileName;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Resolves the canonical live file corresponding to a quarantined conflict or deleted backup.
|
|
74
|
+
*/
|
|
75
|
+
export function findCanonicalArticlePath(workspaceRoot, baseName, articleId, collection = 'posts') {
|
|
76
|
+
const candidateDraft = path.join(collection, 'draft', `${baseName}.md`);
|
|
77
|
+
if (fs.existsSync(path.join(workspaceRoot, candidateDraft))) {
|
|
78
|
+
return candidateDraft;
|
|
79
|
+
}
|
|
80
|
+
const candidatePublished = path.join(collection, 'published', `${baseName}.md`);
|
|
81
|
+
if (fs.existsSync(path.join(workspaceRoot, candidatePublished))) {
|
|
82
|
+
return candidatePublished;
|
|
83
|
+
}
|
|
84
|
+
// If exact baseName doesn't match, attempt search by ULID in draft and published dirs
|
|
85
|
+
if (articleId && articleId.length === 26) {
|
|
86
|
+
for (const sub of ['draft', 'published']) {
|
|
87
|
+
const dir = path.join(workspaceRoot, collection, sub);
|
|
88
|
+
if (fs.existsSync(dir)) {
|
|
89
|
+
const files = fs.readdirSync(dir);
|
|
90
|
+
const match = files.find((f) => f.includes(articleId) && f.endsWith('.md'));
|
|
91
|
+
if (match) {
|
|
92
|
+
return path.join(collection, sub, match);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Lists all quarantined conflict files and deleted rescue copies in posts/conflicts/.
|
|
101
|
+
*/
|
|
102
|
+
export function listConflicts(workspaceRoot, collection = 'posts') {
|
|
103
|
+
const conflictsDir = path.join(workspaceRoot, collection, 'conflicts');
|
|
104
|
+
if (!fs.existsSync(conflictsDir)) {
|
|
105
|
+
return [];
|
|
106
|
+
}
|
|
107
|
+
const entries = fs.readdirSync(conflictsDir, { withFileTypes: true });
|
|
108
|
+
const items = [];
|
|
109
|
+
for (const entry of entries) {
|
|
110
|
+
if (!entry.isFile() || !entry.name.endsWith('.md')) {
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
const fileName = entry.name;
|
|
114
|
+
const relPath = path.join(collection, 'conflicts', fileName);
|
|
115
|
+
const fullPath = path.join(conflictsDir, fileName);
|
|
116
|
+
let type = 'unknown';
|
|
117
|
+
if (fileName.endsWith('.deleted.md')) {
|
|
118
|
+
type = 'deleted';
|
|
119
|
+
}
|
|
120
|
+
else if (fileName.endsWith('.conflict.md')) {
|
|
121
|
+
type = 'conflict';
|
|
122
|
+
}
|
|
123
|
+
let id;
|
|
124
|
+
let slug;
|
|
125
|
+
let title;
|
|
126
|
+
let status;
|
|
127
|
+
let sizeBytes = 0;
|
|
128
|
+
let createdAt = new Date().toISOString();
|
|
129
|
+
try {
|
|
130
|
+
const stats = fs.statSync(fullPath);
|
|
131
|
+
sizeBytes = stats.size;
|
|
132
|
+
createdAt = stats.mtime.toISOString();
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
// Ignore stat error
|
|
136
|
+
}
|
|
137
|
+
try {
|
|
138
|
+
const content = fs.readFileSync(fullPath, 'utf8');
|
|
139
|
+
const parsed = parseMarkdown(content);
|
|
140
|
+
id = parsed.frontmatter.id;
|
|
141
|
+
slug = parsed.frontmatter.slug;
|
|
142
|
+
title = parsed.frontmatter.title;
|
|
143
|
+
status = parsed.frontmatter.status;
|
|
144
|
+
}
|
|
145
|
+
catch {
|
|
146
|
+
// Lenient fallback
|
|
147
|
+
try {
|
|
148
|
+
const content = fs.readFileSync(fullPath, 'utf8');
|
|
149
|
+
const healed = lenientRepairMarkdownFrontmatter(content);
|
|
150
|
+
if (healed) {
|
|
151
|
+
const parsed = parseMarkdown(healed);
|
|
152
|
+
id = parsed.frontmatter.id;
|
|
153
|
+
slug = parsed.frontmatter.slug;
|
|
154
|
+
title = parsed.frontmatter.title;
|
|
155
|
+
status = parsed.frontmatter.status;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
catch {
|
|
159
|
+
// Unparseable frontmatter
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
const baseName = extractBaseArticleName(fileName);
|
|
163
|
+
const canonicalPath = findCanonicalArticlePath(workspaceRoot, baseName, id, collection);
|
|
164
|
+
items.push({
|
|
165
|
+
filePath: relPath,
|
|
166
|
+
fileName,
|
|
167
|
+
type,
|
|
168
|
+
id,
|
|
169
|
+
slug,
|
|
170
|
+
title,
|
|
171
|
+
status,
|
|
172
|
+
canonicalPath,
|
|
173
|
+
sizeBytes,
|
|
174
|
+
createdAt,
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
// Sort newest first
|
|
178
|
+
items.sort((a, b) => b.createdAt.localeCompare(a.createdAt));
|
|
179
|
+
return items;
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Resolves a user-provided file query (path or basename) to an existing conflict file.
|
|
183
|
+
*/
|
|
184
|
+
function resolveConflictFile(workspaceRoot, filePathOrName, collection = 'posts') {
|
|
185
|
+
const norm = filePathOrName.trim();
|
|
186
|
+
const conflictsDir = path.resolve(workspaceRoot, collection, 'conflicts');
|
|
187
|
+
const checkInside = (p) => {
|
|
188
|
+
const rel = path.relative(conflictsDir, p);
|
|
189
|
+
return !rel.startsWith('..') && !path.isAbsolute(rel);
|
|
190
|
+
};
|
|
191
|
+
const directFull = path.isAbsolute(norm) ? norm : path.resolve(workspaceRoot, norm);
|
|
192
|
+
if (fs.existsSync(directFull) && fs.statSync(directFull).isFile()) {
|
|
193
|
+
if (!checkInside(directFull)) {
|
|
194
|
+
throw new QuarantinedPathRequiredError({
|
|
195
|
+
filePath: filePathOrName,
|
|
196
|
+
collection,
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
const relPath = path.relative(workspaceRoot, directFull);
|
|
200
|
+
return { relPath, fullPath: directFull, fileName: path.basename(directFull) };
|
|
201
|
+
}
|
|
202
|
+
// Check inside collection/conflicts
|
|
203
|
+
const insideFull = path.join(conflictsDir, path.basename(norm));
|
|
204
|
+
if (fs.existsSync(insideFull) && fs.statSync(insideFull).isFile()) {
|
|
205
|
+
const relPath = path.relative(workspaceRoot, insideFull);
|
|
206
|
+
return { relPath, fullPath: insideFull, fileName: path.basename(insideFull) };
|
|
207
|
+
}
|
|
208
|
+
throw new Error(`Conflict file not found: ${filePathOrName}`);
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Computes a diff between the quarantined conflict/deleted copy and the canonical article.
|
|
212
|
+
*/
|
|
213
|
+
export function diffConflict(options) {
|
|
214
|
+
const collection = options.collection || 'posts';
|
|
215
|
+
const { relPath, fullPath, fileName } = resolveConflictFile(options.workspaceRoot, options.filePath, collection);
|
|
216
|
+
const conflictContent = fs.readFileSync(fullPath, 'utf8');
|
|
217
|
+
let type = 'unknown';
|
|
218
|
+
if (fileName.endsWith('.deleted.md')) {
|
|
219
|
+
type = 'deleted';
|
|
220
|
+
}
|
|
221
|
+
else if (fileName.endsWith('.conflict.md')) {
|
|
222
|
+
type = 'conflict';
|
|
223
|
+
}
|
|
224
|
+
let id;
|
|
225
|
+
let slug;
|
|
226
|
+
try {
|
|
227
|
+
const parsed = parseMarkdown(conflictContent);
|
|
228
|
+
id = parsed.frontmatter.id;
|
|
229
|
+
slug = parsed.frontmatter.slug;
|
|
230
|
+
}
|
|
231
|
+
catch {
|
|
232
|
+
// Lenient
|
|
233
|
+
}
|
|
234
|
+
const baseName = extractBaseArticleName(fileName);
|
|
235
|
+
const canonicalRel = findCanonicalArticlePath(options.workspaceRoot, baseName, id, collection);
|
|
236
|
+
if (!canonicalRel) {
|
|
237
|
+
// Canonical file is absent (e.g. deleted copy)
|
|
238
|
+
const lineCount = conflictContent.split('\n').length;
|
|
239
|
+
return {
|
|
240
|
+
conflictFilePath: relPath,
|
|
241
|
+
canonicalFilePath: null,
|
|
242
|
+
type,
|
|
243
|
+
id,
|
|
244
|
+
slug,
|
|
245
|
+
hasDifferences: true,
|
|
246
|
+
additions: lineCount,
|
|
247
|
+
deletions: 0,
|
|
248
|
+
diffText: `Canonical article is absent (deleted or not found).\nQuarantined copy (${type}): ${lineCount} lines.`,
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
const canonicalFull = path.join(options.workspaceRoot, canonicalRel);
|
|
252
|
+
const canonicalContent = fs.readFileSync(canonicalFull, 'utf8');
|
|
253
|
+
const diffResult = computeContextDiff(canonicalContent, conflictContent, {
|
|
254
|
+
baseLabel: `canonical: ${canonicalRel}`,
|
|
255
|
+
localLabel: `quarantined: ${relPath}`,
|
|
256
|
+
});
|
|
257
|
+
return {
|
|
258
|
+
conflictFilePath: relPath,
|
|
259
|
+
canonicalFilePath: canonicalRel,
|
|
260
|
+
type,
|
|
261
|
+
id,
|
|
262
|
+
slug,
|
|
263
|
+
hasDifferences: diffResult.hasChanges,
|
|
264
|
+
additions: diffResult.additions,
|
|
265
|
+
deletions: diffResult.deletions,
|
|
266
|
+
diffText: diffResult.unifiedDiff,
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Resolves a quarantined conflict file with either accept-local or accept-canonical strategy.
|
|
271
|
+
*/
|
|
272
|
+
export function resolveConflict(options) {
|
|
273
|
+
const collection = options.collection || 'posts';
|
|
274
|
+
const { relPath, fullPath, fileName } = resolveConflictFile(options.workspaceRoot, options.filePath, collection);
|
|
275
|
+
if (options.strategy === 'accept-canonical') {
|
|
276
|
+
// Discard the quarantined copy
|
|
277
|
+
fs.unlinkSync(fullPath);
|
|
278
|
+
return {
|
|
279
|
+
success: true,
|
|
280
|
+
strategy: 'accept-canonical',
|
|
281
|
+
conflictFilePath: relPath,
|
|
282
|
+
message: `Quarantined file ${relPath} was safely discarded.`,
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
// accept-local: Restore quarantined content to canonical location
|
|
286
|
+
const conflictContent = fs.readFileSync(fullPath, 'utf8');
|
|
287
|
+
let id = 'unknown';
|
|
288
|
+
let slug = 'restored';
|
|
289
|
+
let status = 'draft';
|
|
290
|
+
try {
|
|
291
|
+
const parsed = parseMarkdown(conflictContent);
|
|
292
|
+
id = parsed.frontmatter.id;
|
|
293
|
+
slug = parsed.frontmatter.slug;
|
|
294
|
+
status = parsed.frontmatter.status;
|
|
295
|
+
}
|
|
296
|
+
catch {
|
|
297
|
+
// If invalid, try lenient
|
|
298
|
+
try {
|
|
299
|
+
const healed = lenientRepairMarkdownFrontmatter(conflictContent);
|
|
300
|
+
if (healed) {
|
|
301
|
+
const parsed = parseMarkdown(healed);
|
|
302
|
+
id = parsed.frontmatter.id;
|
|
303
|
+
slug = parsed.frontmatter.slug;
|
|
304
|
+
status = parsed.frontmatter.status;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
catch {
|
|
308
|
+
// Keep defaults
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
const baseName = extractBaseArticleName(fileName);
|
|
312
|
+
let canonicalRel = findCanonicalArticlePath(options.workspaceRoot, baseName, id, collection);
|
|
313
|
+
if (canonicalRel) {
|
|
314
|
+
const canonicalFull = path.join(options.workspaceRoot, canonicalRel);
|
|
315
|
+
// Major 1 Guard: Check if canonical file has unpushed modifications
|
|
316
|
+
if (!options.force && fs.existsSync(canonicalFull)) {
|
|
317
|
+
const canonicalContent = fs.readFileSync(canonicalFull, 'utf8');
|
|
318
|
+
const canonicalHash = calculateHash(canonicalContent);
|
|
319
|
+
let canonicalId = id;
|
|
320
|
+
try {
|
|
321
|
+
const parsedCan = parseMarkdown(canonicalContent);
|
|
322
|
+
canonicalId = parsedCan.frontmatter.id;
|
|
323
|
+
}
|
|
324
|
+
catch {
|
|
325
|
+
// fallback
|
|
326
|
+
}
|
|
327
|
+
const syncState = options.cache.getSyncState(canonicalId);
|
|
328
|
+
if (syncState && syncState.localHash !== canonicalHash) {
|
|
329
|
+
throw new CanonicalHasUnpushedEditsError({
|
|
330
|
+
canonicalFilePath: canonicalRel,
|
|
331
|
+
conflictFilePath: relPath,
|
|
332
|
+
id: canonicalId,
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
else {
|
|
338
|
+
// Recreate target file in collection/status/baseName.md
|
|
339
|
+
canonicalRel = path.join(collection, status, `${baseName}.md`);
|
|
340
|
+
}
|
|
341
|
+
const canonicalFull = path.join(options.workspaceRoot, canonicalRel);
|
|
342
|
+
fs.mkdirSync(path.dirname(canonicalFull), { recursive: true });
|
|
343
|
+
fs.writeFileSync(canonicalFull, conflictContent, 'utf8');
|
|
344
|
+
// Minor B: check if restored article is missing valid ULID
|
|
345
|
+
const warnings = [];
|
|
346
|
+
if (!id || id === 'unknown') {
|
|
347
|
+
warnings.push(`Restored article has no valid ULID (id: ${id}). Re-fetch the canonical copy using "emit pull", or rename the file to follow canonical naming ("<yyyyMMdd>_<ulid>-<title>.md") with a matching frontmatter ID before pushing.`);
|
|
348
|
+
}
|
|
349
|
+
// Update cache sync state if id is valid
|
|
350
|
+
if (id && id !== 'unknown') {
|
|
351
|
+
const newHash = calculateHash(conflictContent);
|
|
352
|
+
const existingSync = options.cache.getSyncState(id);
|
|
353
|
+
options.cache.saveSyncState({
|
|
354
|
+
id,
|
|
355
|
+
localFilePath: canonicalRel,
|
|
356
|
+
localHash: newHash,
|
|
357
|
+
remoteRev: existingSync?.remoteRev || 'local-restored',
|
|
358
|
+
status,
|
|
359
|
+
slug,
|
|
360
|
+
lastSyncedAt: existingSync?.lastSyncedAt || Math.floor(Date.now() / 1000),
|
|
361
|
+
});
|
|
362
|
+
}
|
|
363
|
+
// Safe deletion of conflict file now that canonical is written
|
|
364
|
+
fs.unlinkSync(fullPath);
|
|
365
|
+
return {
|
|
366
|
+
success: true,
|
|
367
|
+
strategy: 'accept-local',
|
|
368
|
+
conflictFilePath: relPath,
|
|
369
|
+
canonicalFilePath: canonicalRel,
|
|
370
|
+
message: `Restored quarantined content to ${canonicalRel} and removed ${relPath}.`,
|
|
371
|
+
warnings: warnings.length > 0 ? warnings : undefined,
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
//# sourceMappingURL=conflicts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conflicts.js","sourceRoot":"","sources":["../../src/sync/conflicts.ts"],"names":[],"mappings":"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"}
|