emdash-emit 0.1.8 → 0.1.10
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/README.md +132 -28
- 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/profile.d.ts.map +1 -1
- package/dist/cli/commands/profile.js +67 -13
- package/dist/cli/commands/profile.js.map +1 -1
- package/dist/cli/commands/pull.d.ts +5 -0
- package/dist/cli/commands/pull.d.ts.map +1 -1
- package/dist/cli/commands/pull.js +119 -39
- 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 +38 -1
- package/dist/cli/commands/push.js.map +1 -1
- package/dist/cli/commands/status.d.ts +19 -0
- package/dist/cli/commands/status.d.ts.map +1 -1
- package/dist/cli/commands/status.js +87 -5
- package/dist/cli/commands/status.js.map +1 -1
- package/dist/cli/context.d.ts +38 -1
- package/dist/cli/context.d.ts.map +1 -1
- package/dist/cli/context.js +129 -16
- package/dist/cli/context.js.map +1 -1
- package/dist/client/auth.d.ts +1 -0
- package/dist/client/auth.d.ts.map +1 -1
- package/dist/client/auth.js +1 -0
- package/dist/client/auth.js.map +1 -1
- package/dist/client/http.d.ts.map +1 -1
- package/dist/client/http.js +27 -10
- package/dist/client/http.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 +8 -0
- package/dist/mcp/context.d.ts.map +1 -1
- package/dist/mcp/server.d.ts +8 -0
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +91 -15
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/tool-errors.d.ts +16 -0
- package/dist/mcp/tool-errors.d.ts.map +1 -0
- package/dist/mcp/tool-errors.js +137 -0
- package/dist/mcp/tool-errors.js.map +1 -0
- package/dist/mcp/tools/profile.d.ts +9 -2
- package/dist/mcp/tools/profile.d.ts.map +1 -1
- package/dist/mcp/tools/profile.js +53 -36
- 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 +22 -8
- 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 +49 -23
- 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 +132 -73
- 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 +39 -33
- 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 +103 -11
- 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 +224 -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/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 +6 -0
- package/dist/sync/orchestrator.d.ts.map +1 -1
- package/dist/sync/orchestrator.js +54 -27
- 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 +51 -0
- package/dist/sync/pull.d.ts.map +1 -1
- package/dist/sync/pull.js +289 -58
- package/dist/sync/pull.js.map +1 -1
- package/dist/sync/push.d.ts +12 -0
- package/dist/sync/push.d.ts.map +1 -1
- package/dist/sync/push.js +69 -24
- package/dist/sync/push.js.map +1 -1
- package/dist/sync/status.d.ts +21 -1
- package/dist/sync/status.d.ts.map +1 -1
- package/dist/sync/status.js +66 -6
- 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 +142 -9
- package/dist/sync/taxonomies.js.map +1 -1
- package/dist/utils/config.d.ts +23 -0
- package/dist/utils/config.d.ts.map +1 -1
- package/dist/utils/config.js +41 -4
- package/dist/utils/config.js.map +1 -1
- package/dist/utils/frontmatter.d.ts +51 -2
- package/dist/utils/frontmatter.d.ts.map +1 -1
- package/dist/utils/frontmatter.js +234 -9
- package/dist/utils/frontmatter.js.map +1 -1
- package/dist/utils/profile.d.ts +3 -3
- package/dist/utils/profile.d.ts.map +1 -1
- package/dist/utils/profile.js +105 -8
- package/dist/utils/profile.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync-conflicts.js","sourceRoot":"","sources":["../../../src/mcp/tools/sync-conflicts.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import type { ContextResolver } from '../context.js';
|
|
3
|
+
export declare function registerSyncDeleteTool(server: McpServer, resolveContext: ContextResolver): void;
|
|
4
|
+
//# sourceMappingURL=sync-delete.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync-delete.d.ts","sourceRoot":"","sources":["../../../src/mcp/tools/sync-delete.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,eAAe,EAAiB,MAAM,eAAe,CAAC;AAIpE,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,SAAS,EAAE,cAAc,EAAE,eAAe,GAAG,IAAI,CA6D/F"}
|
|
@@ -0,0 +1,77 @@
|
|
|
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 { z } from 'zod';
|
|
23
|
+
import { deleteArticle } from '../../sync/delete.js';
|
|
24
|
+
import { formatToolError, formatToolSuccess } from '../tool-errors.js';
|
|
25
|
+
export function registerSyncDeleteTool(server, resolveContext) {
|
|
26
|
+
server.tool('sync_delete', 'Safely delete an article from both the local workspace and remote EmDash server. Enforces strict safety guards: rejects deletion if unpushed local modifications exist, requires "allowDeletePublished: true" to delete published articles, saves an automatic rescue backup to posts/conflicts/<file>.deleted.md, and preserves referenced media files in media/.', {
|
|
27
|
+
filePath: z
|
|
28
|
+
.string()
|
|
29
|
+
.optional()
|
|
30
|
+
.describe('Workspace-relative file path to delete (e.g. posts/draft/20261108_01M6...-my-slug.md)'),
|
|
31
|
+
id: z.string().optional().describe('Article ULID to delete'),
|
|
32
|
+
allowDeletePublished: z
|
|
33
|
+
.boolean()
|
|
34
|
+
.optional()
|
|
35
|
+
.describe('Explicit confirmation required to delete a published live article'),
|
|
36
|
+
dryRun: z
|
|
37
|
+
.boolean()
|
|
38
|
+
.optional()
|
|
39
|
+
.describe('Preview deletion metadata, line count, and referenced media without deleting'),
|
|
40
|
+
collection: z
|
|
41
|
+
.string()
|
|
42
|
+
.optional()
|
|
43
|
+
.describe('Collection name containing the article (defaults to "posts")'),
|
|
44
|
+
profile: z.string().optional().describe('Target profile name for multi-site setups'),
|
|
45
|
+
}, async (args) => {
|
|
46
|
+
let ctx;
|
|
47
|
+
try {
|
|
48
|
+
ctx = resolveContext(args.profile);
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
return formatToolError(error);
|
|
52
|
+
}
|
|
53
|
+
if (!args.filePath && !args.id) {
|
|
54
|
+
return formatToolError(new Error('Please specify either "filePath" or "id" of the article to delete.'));
|
|
55
|
+
}
|
|
56
|
+
try {
|
|
57
|
+
const collection = args.collection || ctx.config.defaultCollection;
|
|
58
|
+
const result = await deleteArticle({
|
|
59
|
+
workspaceRoot: ctx.root,
|
|
60
|
+
cache: ctx.cache,
|
|
61
|
+
filePath: args.filePath,
|
|
62
|
+
id: args.id,
|
|
63
|
+
collection,
|
|
64
|
+
allowDeletePublished: args.allowDeletePublished,
|
|
65
|
+
dryRun: args.dryRun,
|
|
66
|
+
origin: ctx.origin,
|
|
67
|
+
token: ctx.auth?.token,
|
|
68
|
+
refreshToken: ctx.auth?.refreshToken,
|
|
69
|
+
});
|
|
70
|
+
return formatToolSuccess(result, ctx.meta);
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
return formatToolError(error, ctx.meta);
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=sync-delete.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync-delete.js","sourceRoot":"","sources":["../../../src/mcp/tools/sync-delete.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAEvE,MAAM,UAAU,sBAAsB,CAAC,MAAiB,EAAE,cAA+B;IACvF,MAAM,CAAC,IAAI,CACT,aAAa,EACb,oWAAoW,EACpW;QACE,QAAQ,EAAE,CAAC;aACR,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CACP,uFAAuF,CACxF;QACH,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,wBAAwB,CAAC;QAC5D,oBAAoB,EAAE,CAAC;aACpB,OAAO,EAAE;aACT,QAAQ,EAAE;aACV,QAAQ,CAAC,mEAAmE,CAAC;QAChF,MAAM,EAAE,CAAC;aACN,OAAO,EAAE;aACT,QAAQ,EAAE;aACV,QAAQ,CAAC,8EAA8E,CAAC;QAC3F,UAAU,EAAE,CAAC;aACV,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CAAC,8DAA8D,CAAC;QAC3E,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,2CAA2C,CAAC;KACrF,EACD,KAAK,EAAE,IAAI,EAAE,EAAE;QACb,IAAI,GAAkB,CAAC;QACvB,IAAI,CAAC;YACH,GAAG,GAAG,cAAc,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACrC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,eAAe,CAAC,KAAK,CAAC,CAAC;QAChC,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,QAAQ,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;YAC/B,OAAO,eAAe,CACpB,IAAI,KAAK,CAAC,oEAAoE,CAAC,CAChF,CAAC;QACJ,CAAC;QAED,IAAI,CAAC;YACH,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,IAAI,GAAG,CAAC,MAAM,CAAC,iBAAiB,CAAC;YACnE,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC;gBACjC,aAAa,EAAE,GAAG,CAAC,IAAI;gBACvB,KAAK,EAAE,GAAG,CAAC,KAAK;gBAChB,QAAQ,EAAE,IAAI,CAAC,QAAQ;gBACvB,EAAE,EAAE,IAAI,CAAC,EAAE;gBACX,UAAU;gBACV,oBAAoB,EAAE,IAAI,CAAC,oBAAoB;gBAC/C,MAAM,EAAE,IAAI,CAAC,MAAM;gBACnB,MAAM,EAAE,GAAG,CAAC,MAAM;gBAClB,KAAK,EAAE,GAAG,CAAC,IAAI,EAAE,KAAK;gBACtB,YAAY,EAAE,GAAG,CAAC,IAAI,EAAE,YAAY;aACrC,CAAC,CAAC;YAEH,OAAO,iBAAiB,CAAC,MAA4C,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;QACnF,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,eAAe,CAAC,KAAK,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;QAC1C,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sync-diff.d.ts","sourceRoot":"","sources":["../../../src/mcp/tools/sync-diff.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,eAAe,
|
|
1
|
+
{"version":3,"file":"sync-diff.d.ts","sourceRoot":"","sources":["../../../src/mcp/tools/sync-diff.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,eAAe,EAAiB,MAAM,eAAe,CAAC;AAIpE,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,EAAE,cAAc,EAAE,eAAe,GAAG,IAAI,CA6C7F"}
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
*/
|
|
22
22
|
import { z } from 'zod';
|
|
23
23
|
import { inspectArticleDiff } from '../../sync/diff.js';
|
|
24
|
+
import { formatToolError } from '../tool-errors.js';
|
|
24
25
|
export function registerSyncDiffTool(server, resolveContext) {
|
|
25
26
|
server.tool('sync_diff', 'Display line-by-line differences between local article edits and the baseline snapshot/remote version before pushing. Useful for reviewing changes or diagnosing unpushed modifications.', {
|
|
26
27
|
filePath: z
|
|
@@ -30,18 +31,31 @@ export function registerSyncDiffTool(server, resolveContext) {
|
|
|
30
31
|
id: z.string().optional().describe('Article ID (ULID) to inspect'),
|
|
31
32
|
profile: z.string().optional().describe('Target profile name for multi-site setups'),
|
|
32
33
|
}, async (args) => {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
}
|
|
34
|
+
let ctx;
|
|
35
|
+
try {
|
|
36
|
+
ctx = resolveContext(args.profile);
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
return formatToolError(error);
|
|
40
|
+
}
|
|
41
|
+
let inspection;
|
|
42
|
+
try {
|
|
43
|
+
inspection = inspectArticleDiff({
|
|
44
|
+
workspaceRoot: ctx.root,
|
|
45
|
+
cache: ctx.cache,
|
|
46
|
+
filePath: args.filePath,
|
|
47
|
+
id: args.id,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
return formatToolError(error, ctx.meta);
|
|
52
|
+
}
|
|
53
|
+
const metaSuffix = `\n\n_meta: ${JSON.stringify(ctx.meta)}`;
|
|
40
54
|
return {
|
|
41
55
|
content: [
|
|
42
56
|
{
|
|
43
57
|
type: 'text',
|
|
44
|
-
text: inspection.formattedOutput
|
|
58
|
+
text: `${inspection.formattedOutput}${metaSuffix}`,
|
|
45
59
|
},
|
|
46
60
|
],
|
|
47
61
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sync-diff.js","sourceRoot":"","sources":["../../../src/mcp/tools/sync-diff.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAE,kBAAkB,
|
|
1
|
+
{"version":3,"file":"sync-diff.js","sourceRoot":"","sources":["../../../src/mcp/tools/sync-diff.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAE,kBAAkB,EAA8B,MAAM,oBAAoB,CAAC;AACpF,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD,MAAM,UAAU,oBAAoB,CAAC,MAAiB,EAAE,cAA+B;IACrF,MAAM,CAAC,IAAI,CACT,WAAW,EACX,0LAA0L,EAC1L;QACE,QAAQ,EAAE,CAAC;aACR,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CACP,iGAAiG,CAClG;QACH,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,8BAA8B,CAAC;QAClE,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,2CAA2C,CAAC;KACrF,EACD,KAAK,EAAE,IAAI,EAAE,EAAE;QACb,IAAI,GAAkB,CAAC;QACvB,IAAI,CAAC;YACH,GAAG,GAAG,cAAc,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACrC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,eAAe,CAAC,KAAK,CAAC,CAAC;QAChC,CAAC;QACD,IAAI,UAAiC,CAAC;QACtC,IAAI,CAAC;YACH,UAAU,GAAG,kBAAkB,CAAC;gBAC9B,aAAa,EAAE,GAAG,CAAC,IAAI;gBACvB,KAAK,EAAE,GAAG,CAAC,KAAK;gBAChB,QAAQ,EAAE,IAAI,CAAC,QAAQ;gBACvB,EAAE,EAAE,IAAI,CAAC,EAAE;aACZ,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,eAAe,CAAC,KAAK,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;QAC1C,CAAC;QAED,MAAM,UAAU,GAAG,cAAc,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;QAE5D,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAM;oBACZ,IAAI,EAAE,GAAG,UAAU,CAAC,eAAe,GAAG,UAAU,EAAE;iBACnD;aACF;SACF,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import type { ContextResolver } from '../context.js';
|
|
3
|
+
export declare function registerSyncDoctorTool(server: McpServer, resolveContext: ContextResolver): void;
|
|
4
|
+
//# sourceMappingURL=sync-doctor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync-doctor.d.ts","sourceRoot":"","sources":["../../../src/mcp/tools/sync-doctor.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,eAAe,EAAiB,MAAM,eAAe,CAAC;AAIpE,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,SAAS,EAAE,cAAc,EAAE,eAAe,GAAG,IAAI,CAoC/F"}
|
|
@@ -0,0 +1,57 @@
|
|
|
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 { z } from 'zod';
|
|
23
|
+
import { runWorkspaceDoctor } from '../../sync/doctor.js';
|
|
24
|
+
import { formatToolError, formatToolSuccess } from '../tool-errors.js';
|
|
25
|
+
export function registerSyncDoctorTool(server, resolveContext) {
|
|
26
|
+
server.tool('sync_doctor', 'Run comprehensive workspace diagnostics: verifies version compatibility, profile/config origin consistency, frontmatter syntax integrity across all articles, quarantined conflict copies, unpushed modifications, and referenced media existence.', {
|
|
27
|
+
collection: z
|
|
28
|
+
.string()
|
|
29
|
+
.optional()
|
|
30
|
+
.describe('Collection to diagnose (defaults to defaultCollection or "posts")'),
|
|
31
|
+
profile: z.string().optional().describe('Target profile name for multi-site setups'),
|
|
32
|
+
}, async (args) => {
|
|
33
|
+
let ctx;
|
|
34
|
+
try {
|
|
35
|
+
ctx = resolveContext(args.profile);
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
return formatToolError(error);
|
|
39
|
+
}
|
|
40
|
+
try {
|
|
41
|
+
const collection = args.collection || ctx.config.defaultCollection || 'posts';
|
|
42
|
+
const report = await runWorkspaceDoctor({
|
|
43
|
+
workspaceRoot: ctx.root,
|
|
44
|
+
cache: ctx.cache,
|
|
45
|
+
config: ctx.config,
|
|
46
|
+
profileName: ctx.auth.profileName,
|
|
47
|
+
profileOrigin: ctx.auth.origin,
|
|
48
|
+
collection,
|
|
49
|
+
});
|
|
50
|
+
return formatToolSuccess(report, ctx.meta);
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
return formatToolError(err, ctx.meta);
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=sync-doctor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync-doctor.js","sourceRoot":"","sources":["../../../src/mcp/tools/sync-doctor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAEvE,MAAM,UAAU,sBAAsB,CAAC,MAAiB,EAAE,cAA+B;IACvF,MAAM,CAAC,IAAI,CACT,aAAa,EACb,oPAAoP,EACpP;QACE,UAAU,EAAE,CAAC;aACV,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CAAC,mEAAmE,CAAC;QAChF,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,2CAA2C,CAAC;KACrF,EACD,KAAK,EAAE,IAAI,EAAE,EAAE;QACb,IAAI,GAAkB,CAAC;QACvB,IAAI,CAAC;YACH,GAAG,GAAG,cAAc,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACrC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,eAAe,CAAC,KAAK,CAAC,CAAC;QAChC,CAAC;QAED,IAAI,CAAC;YACH,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,IAAI,GAAG,CAAC,MAAM,CAAC,iBAAiB,IAAI,OAAO,CAAC;YAC9E,MAAM,MAAM,GAAG,MAAM,kBAAkB,CAAC;gBACtC,aAAa,EAAE,GAAG,CAAC,IAAI;gBACvB,KAAK,EAAE,GAAG,CAAC,KAAK;gBAChB,MAAM,EAAE,GAAG,CAAC,MAAM;gBAClB,WAAW,EAAE,GAAG,CAAC,IAAI,CAAC,WAAW;gBACjC,aAAa,EAAE,GAAG,CAAC,IAAI,CAAC,MAAM;gBAC9B,UAAU;aACX,CAAC,CAAC;YAEH,OAAO,iBAAiB,CAAC,MAA4C,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;QACnF,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,eAAe,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;QACxC,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sync-new.d.ts","sourceRoot":"","sources":["../../../src/mcp/tools/sync-new.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,eAAe,
|
|
1
|
+
{"version":3,"file":"sync-new.d.ts","sourceRoot":"","sources":["../../../src/mcp/tools/sync-new.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,eAAe,EAAiB,MAAM,eAAe,CAAC;AASpE,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,SAAS,EAAE,cAAc,EAAE,eAAe,GAAG,IAAI,CAwE5F"}
|
|
@@ -20,8 +20,9 @@
|
|
|
20
20
|
* SOFTWARE.
|
|
21
21
|
*/
|
|
22
22
|
import { z } from 'zod';
|
|
23
|
-
import { createArticleScaffold } from '../../sync/new.js';
|
|
23
|
+
import { createArticleScaffold, checkRemoteDuplicateSlug, DuplicateSlugError, } from '../../sync/new.js';
|
|
24
24
|
import { getLocalTaxonomiesSummary, formatTaxonomiesHint } from '../../sync/taxonomies.js';
|
|
25
|
+
import { formatToolError } from '../tool-errors.js';
|
|
25
26
|
export function registerSyncNewTool(server, resolveContext) {
|
|
26
27
|
server.tool('sync_new', 'Create a new article draft scaffold in posts/draft/ with standardized frontmatter (ULID, slug, title, default bylines). Returns the created relative file path and available categories/tags hints (sorted by usage) so you can edit the Markdown file directly before pushing.', {
|
|
27
28
|
slug: z.string().describe('URL slug for the new article'),
|
|
@@ -37,28 +38,53 @@ export function registerSyncNewTool(server, resolveContext) {
|
|
|
37
38
|
.describe('Author byline slug (defaults to first cached non-guest author by slug)'),
|
|
38
39
|
profile: z.string().optional().describe('Target profile name for multi-site setups'),
|
|
39
40
|
}, async (args) => {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
|
|
41
|
+
let ctx;
|
|
42
|
+
try {
|
|
43
|
+
ctx = resolveContext(args.profile);
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
return formatToolError(error);
|
|
47
|
+
}
|
|
48
|
+
try {
|
|
49
|
+
const collection = args.collection || ctx.config.defaultCollection;
|
|
50
|
+
// Best-effort remote duplicate check if connected
|
|
51
|
+
if (ctx.origin && ctx.auth?.token) {
|
|
52
|
+
const remoteDup = await checkRemoteDuplicateSlug({
|
|
53
|
+
origin: ctx.origin,
|
|
54
|
+
token: ctx.auth.token,
|
|
55
|
+
collection,
|
|
56
|
+
slug: args.slug,
|
|
57
|
+
}).catch(() => null);
|
|
58
|
+
if (remoteDup) {
|
|
59
|
+
throw new DuplicateSlugError(remoteDup);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
const res = createArticleScaffold({
|
|
63
|
+
slug: args.slug,
|
|
64
|
+
workspaceRoot: ctx.root,
|
|
65
|
+
collection,
|
|
66
|
+
title: args.title,
|
|
67
|
+
locale: args.locale || ctx.config.defaultLocale,
|
|
68
|
+
byline: args.byline,
|
|
69
|
+
cache: ctx.cache,
|
|
70
|
+
});
|
|
71
|
+
const taxSummary = getLocalTaxonomiesSummary(ctx.root);
|
|
72
|
+
const taxHint = formatTaxonomiesHint(taxSummary, { maxTags: 60 });
|
|
73
|
+
const hintBlock = taxHint ? `\n\n${taxHint}` : '';
|
|
74
|
+
const metaSuffix = `\n\n_meta: ${JSON.stringify(ctx.meta)}`;
|
|
75
|
+
return {
|
|
76
|
+
content: [
|
|
77
|
+
{
|
|
78
|
+
type: 'text',
|
|
79
|
+
text: `✅ Created new draft article '${args.slug}' (ID: ${res.id}) at ${res.filePath}.${hintBlock}\n\nYou can now edit the file directly and sync it with sync_push.${metaSuffix}`,
|
|
80
|
+
},
|
|
81
|
+
],
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
// Slug validation, byline resolution, and taxonomy hint reads all fail here.
|
|
86
|
+
return formatToolError(error, ctx?.meta);
|
|
87
|
+
}
|
|
62
88
|
});
|
|
63
89
|
}
|
|
64
90
|
//# sourceMappingURL=sync-new.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sync-new.js","sourceRoot":"","sources":["../../../src/mcp/tools/sync-new.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,
|
|
1
|
+
{"version":3,"file":"sync-new.js","sourceRoot":"","sources":["../../../src/mcp/tools/sync-new.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sync-pull.d.ts","sourceRoot":"","sources":["../../../src/mcp/tools/sync-pull.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,eAAe,
|
|
1
|
+
{"version":3,"file":"sync-pull.d.ts","sourceRoot":"","sources":["../../../src/mcp/tools/sync-pull.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,eAAe,EAAiB,MAAM,eAAe,CAAC;AAapE,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,EAAE,cAAc,EAAE,eAAe,GAAG,IAAI,CA6T9F"}
|
|
@@ -20,12 +20,13 @@
|
|
|
20
20
|
* SOFTWARE.
|
|
21
21
|
*/
|
|
22
22
|
import { z } from 'zod';
|
|
23
|
-
import { pullArticle } from '../../sync/pull.js';
|
|
24
|
-
import { pullBatch
|
|
23
|
+
import { pullArticle, formatQuarantineNotice } from '../../sync/pull.js';
|
|
24
|
+
import { pullBatch } from '../../sync/orchestrator.js';
|
|
25
25
|
import { pullTaxonomies, getLocalTaxonomiesSummary, formatTaxonomiesHint, } from '../../sync/taxonomies.js';
|
|
26
26
|
import { pullMedia } from '../../sync/media.js';
|
|
27
27
|
import { resolveArticleTarget } from '../../sync/diff.js';
|
|
28
28
|
import { compareArticleFilenameDesc } from '../../utils/naming.js';
|
|
29
|
+
import { formatToolError } from '../tool-errors.js';
|
|
29
30
|
export function registerSyncPullTools(server, resolveContext) {
|
|
30
31
|
// sync_pull: Pull remote article(s) and taxonomies
|
|
31
32
|
server.tool('sync_pull', 'Pull remote articles and taxonomies from EmDash into local Markdown files (posts/published/ and posts/draft/) and YAML taxonomy definitions (categories/ and tags/). Batch mode automatically syncs categories and tags alongside articles and returns available taxonomy hints (also shown with postsOnly:true). Use postsOnly:true to skip taxonomies. Use includeMedia:true to also pull media assets. Supports pulling a single article by id/filePath. After pulling, ALWAYS read and edit the local Markdown files directly with standard file tools.', {
|
|
@@ -65,7 +66,13 @@ export function registerSyncPullTools(server, resolveContext) {
|
|
|
65
66
|
.describe('With includeMedia: download only metadata YAML, skip binary file downloads.'),
|
|
66
67
|
profile: z.string().optional().describe('Target profile name for multi-site setups'),
|
|
67
68
|
}, async (args) => {
|
|
68
|
-
|
|
69
|
+
let ctx;
|
|
70
|
+
try {
|
|
71
|
+
ctx = resolveContext(args.profile);
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
return formatToolError(error);
|
|
75
|
+
}
|
|
69
76
|
const collection = args.collection || ctx.config.defaultCollection;
|
|
70
77
|
const origin = ctx.origin;
|
|
71
78
|
const { id: targetId } = resolveArticleTarget({
|
|
@@ -74,23 +81,41 @@ export function registerSyncPullTools(server, resolveContext) {
|
|
|
74
81
|
id: args.id,
|
|
75
82
|
});
|
|
76
83
|
if (targetId) {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
84
|
+
let res;
|
|
85
|
+
try {
|
|
86
|
+
res = await pullArticle(collection, targetId, {
|
|
87
|
+
workspaceRoot: ctx.root,
|
|
88
|
+
cache: ctx.cache,
|
|
89
|
+
origin,
|
|
90
|
+
token: ctx.auth.token,
|
|
91
|
+
refreshToken: ctx.auth.refreshToken,
|
|
92
|
+
force: args.force,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
return formatToolError(error);
|
|
97
|
+
}
|
|
98
|
+
const actionText = res.healed
|
|
99
|
+
? '🛠️ Repaired frontmatter syntax (unpushed local body was strictly preserved)'
|
|
100
|
+
: res.localEditsPreserved
|
|
101
|
+
? 'ℹ️ Local edits preserved (remote changes were NOT applied)'
|
|
102
|
+
: res.skipped
|
|
103
|
+
? 'ℹ️ Article is already up-to-date'
|
|
104
|
+
: '✅ Successfully pulled article';
|
|
88
105
|
const titleText = res.title ? ` "${res.title}"` : '';
|
|
106
|
+
const warnLine = ctx.originWarning ? `\n\n${ctx.originWarning}` : '';
|
|
107
|
+
const quarantineNotice = formatQuarantineNotice(res.quarantined);
|
|
108
|
+
const quarantineLine = quarantineNotice ? `\n\n${quarantineNotice}` : '';
|
|
109
|
+
const nextStep = res.localEditsPreserved
|
|
110
|
+
? '\n\nYour local version is intact. Push it with sync_push to publish your edits, ' +
|
|
111
|
+
'or re-run sync_pull with force: true to accept the remote version instead.'
|
|
112
|
+
: '\n\nYou can now read or edit this local Markdown file directly.';
|
|
113
|
+
const metaSuffix = `\n\n_meta: ${JSON.stringify(ctx.meta)}`;
|
|
89
114
|
return {
|
|
90
115
|
content: [
|
|
91
116
|
{
|
|
92
117
|
type: 'text',
|
|
93
|
-
text: `${actionText}${titleText} (${res.slug})\nFile path: ${res.filePath}\nStatus: ${res.status}
|
|
118
|
+
text: `${actionText}${titleText} (${res.slug})\nFile path: ${res.filePath}\nStatus: ${res.status}${quarantineLine}${warnLine}${nextStep}${metaSuffix}`,
|
|
94
119
|
},
|
|
95
120
|
],
|
|
96
121
|
};
|
|
@@ -148,6 +173,13 @@ export function registerSyncPullTools(server, resolveContext) {
|
|
|
148
173
|
const listLines = sampleItems.map((item) => ` - [${item.status}] ${item.filePath}${item.title ? ` (${item.title})` : ''}`);
|
|
149
174
|
const headerLabel = updatedItems.length > 0 ? 'Updated Articles' : 'Recent Articles in Workspace';
|
|
150
175
|
const detailBlock = listLines.length > 0 ? `\n\n${headerLabel}:\n${listLines.join('\n')}` : '';
|
|
176
|
+
const preservedMsg = batchResult.preserved && batchResult.preserved > 0
|
|
177
|
+
? `\n🛡️ ${batchResult.preserved} article(s) had unpushed local edits; Emit kept your local version (remote changes were NOT applied). Push them with sync_push, or re-run with force: true to accept the remote version instead.`
|
|
178
|
+
: '';
|
|
179
|
+
const quarantineNotices = sortedItems
|
|
180
|
+
.map((item) => formatQuarantineNotice(item.quarantined))
|
|
181
|
+
.filter((notice) => notice.length > 0);
|
|
182
|
+
const quarantineMsg = quarantineNotices.length > 0 ? `\n\n${quarantineNotices.join('\n\n')}` : '';
|
|
151
183
|
// 3. Pull media if includeMedia
|
|
152
184
|
let mediaMsg = '';
|
|
153
185
|
if (includeMedia) {
|
|
@@ -162,63 +194,68 @@ export function registerSyncPullTools(server, resolveContext) {
|
|
|
162
194
|
});
|
|
163
195
|
mediaMsg = `\nMedia: ${mediaResult.total} items (${mediaResult.downloaded} downloaded, ${mediaResult.skipped} up-to-date).`;
|
|
164
196
|
}
|
|
197
|
+
const warnLine = ctx.originWarning ? `\n\n${ctx.originWarning}` : '';
|
|
198
|
+
const metaSuffix = `\n\n_meta: ${JSON.stringify(ctx.meta)}`;
|
|
165
199
|
return {
|
|
166
200
|
content: [
|
|
167
201
|
{
|
|
168
202
|
type: 'text',
|
|
169
|
-
text: `✅ Synced ${batchResult.total} articles (${batchResult.updated} updated, ${batchResult.skipped} up-to-date/skipped${deletedMsg}).${taxonomiesMsg}${mediaMsg}${detailBlock}\n\nYou can now read or edit these local Markdown files directly.`,
|
|
203
|
+
text: `✅ Synced ${batchResult.total} articles (${batchResult.updated} updated, ${batchResult.skipped} up-to-date/skipped${deletedMsg}).${taxonomiesMsg}${mediaMsg}${preservedMsg}${quarantineMsg}${detailBlock}${warnLine}${metaSuffix}\n\nYou can now read or edit these local Markdown files directly.`,
|
|
170
204
|
},
|
|
171
205
|
],
|
|
172
206
|
};
|
|
173
207
|
}
|
|
174
208
|
catch (error) {
|
|
175
|
-
|
|
176
|
-
return {
|
|
177
|
-
isError: true,
|
|
178
|
-
content: [
|
|
179
|
-
{
|
|
180
|
-
type: 'text',
|
|
181
|
-
text: `❌ ${error.message}`,
|
|
182
|
-
},
|
|
183
|
-
],
|
|
184
|
-
};
|
|
185
|
-
}
|
|
186
|
-
throw error;
|
|
209
|
+
return formatToolError(error, ctx?.meta);
|
|
187
210
|
}
|
|
188
211
|
});
|
|
189
212
|
// sync_pull_taxonomies
|
|
190
213
|
server.tool('sync_pull_taxonomies', 'Pull remote categories and tags into local YAML definitions (categories/<id>-<name>.yaml and tags/<id>-<name>.yaml) and return formatted available categories/tags hints (up to 200 tags). Use before writing articles to inspect valid category and tag IDs/slugs.', {
|
|
191
214
|
profile: z.string().optional().describe('Target profile name for multi-site setups'),
|
|
192
215
|
}, async (args) => {
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
216
|
+
try {
|
|
217
|
+
const ctx = resolveContext(args.profile);
|
|
218
|
+
const res = await pullTaxonomies({
|
|
219
|
+
workspaceRoot: ctx.root,
|
|
220
|
+
origin: ctx.origin,
|
|
221
|
+
token: ctx.auth.token,
|
|
222
|
+
refreshToken: ctx.auth.refreshToken,
|
|
223
|
+
});
|
|
224
|
+
const taxSummary = getLocalTaxonomiesSummary(ctx.root);
|
|
225
|
+
const taxHint = formatTaxonomiesHint(taxSummary, { maxTags: 200 });
|
|
226
|
+
const hintBlock = taxHint ? `\n\n${taxHint}` : '';
|
|
227
|
+
const failNotes = [];
|
|
228
|
+
if (res.categoriesFailed)
|
|
229
|
+
failNotes.push('categories');
|
|
230
|
+
if (res.tagsFailed)
|
|
231
|
+
failNotes.push('tags');
|
|
232
|
+
const statusLine = failNotes.length > 0
|
|
233
|
+
? `⚠️ Warning: Failed to fetch remote ${failNotes.join(' and ')} (preserved existing local definitions in categories/ and tags/).`
|
|
234
|
+
: `✅ Successfully pulled taxonomies (${res.categoriesCount} categories, ${res.tagsCount} tags) into categories/ and tags/.`;
|
|
235
|
+
const metaSuffix = `\n\n_meta: ${JSON.stringify(ctx.meta)}`;
|
|
236
|
+
return {
|
|
237
|
+
content: [
|
|
238
|
+
{
|
|
239
|
+
type: 'text',
|
|
240
|
+
text: `${statusLine}${hintBlock}${metaSuffix}`,
|
|
241
|
+
},
|
|
242
|
+
],
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
catch (error) {
|
|
246
|
+
return formatToolError(error);
|
|
247
|
+
}
|
|
219
248
|
});
|
|
220
249
|
// sync_pull_media
|
|
221
|
-
server.tool('sync_pull_media', 'Download remote media assets and companion YAML metadata into the local media/ directory (media/<yyyyMMdd>_<id>-<name>.<ext> and .yaml).
|
|
250
|
+
server.tool('sync_pull_media', 'Download remote media assets and companion YAML metadata into the local media/ directory (media/<yyyyMMdd>_<id>-<name>.<ext> and .yaml). Can pull all media, a limited batch, or targeted media referenced by a specific article.', {
|
|
251
|
+
article: z
|
|
252
|
+
.string()
|
|
253
|
+
.optional()
|
|
254
|
+
.describe('Target article ULID or Markdown file path to pull only media referenced by that article'),
|
|
255
|
+
collection: z
|
|
256
|
+
.string()
|
|
257
|
+
.optional()
|
|
258
|
+
.describe('Collection name when using article (defaults to "posts")'),
|
|
222
259
|
limit: z
|
|
223
260
|
.number()
|
|
224
261
|
.optional()
|
|
@@ -227,24 +264,46 @@ export function registerSyncPullTools(server, resolveContext) {
|
|
|
227
264
|
downloadFiles: z.boolean().optional().describe('Download binary files (defaults to true)'),
|
|
228
265
|
profile: z.string().optional().describe('Target profile name for multi-site setups'),
|
|
229
266
|
}, async (args) => {
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
|
|
267
|
+
try {
|
|
268
|
+
const ctx = resolveContext(args.profile);
|
|
269
|
+
const res = await pullMedia({
|
|
270
|
+
workspaceRoot: ctx.root,
|
|
271
|
+
origin: ctx.origin,
|
|
272
|
+
token: ctx.auth.token,
|
|
273
|
+
refreshToken: ctx.auth.refreshToken,
|
|
274
|
+
article: args.article,
|
|
275
|
+
collection: args.collection || ctx.config.defaultCollection,
|
|
276
|
+
limit: args.limit || ctx.config.mediaSyncLimit || 300,
|
|
277
|
+
all: args.all,
|
|
278
|
+
downloadFiles: args.downloadFiles,
|
|
279
|
+
});
|
|
280
|
+
const metaSuffix = `\n\n_meta: ${JSON.stringify(ctx.meta)}`;
|
|
281
|
+
if (args.article) {
|
|
282
|
+
const failedMsg = res.failed ? `, ${res.failed} failed` : '';
|
|
283
|
+
const idsList = res.mediaIds && res.mediaIds.length > 0
|
|
284
|
+
? `\nMedia IDs: ${res.mediaIds.join(', ')}`
|
|
285
|
+
: '';
|
|
286
|
+
return {
|
|
287
|
+
content: [
|
|
288
|
+
{
|
|
289
|
+
type: 'text',
|
|
290
|
+
text: `✅ Successfully pulled media for article '${res.articleId || args.article}': ${res.total} referenced item(s) (${res.downloaded} downloaded, ${res.skipped} skipped/up-to-date${failedMsg}).${idsList}${metaSuffix}`,
|
|
291
|
+
},
|
|
292
|
+
],
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
return {
|
|
296
|
+
content: [
|
|
297
|
+
{
|
|
298
|
+
type: 'text',
|
|
299
|
+
text: `✅ Successfully pulled media: ${res.total} items (${res.downloaded} downloaded, ${res.skipped} skipped/up-to-date).${metaSuffix}`,
|
|
300
|
+
},
|
|
301
|
+
],
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
catch (error) {
|
|
305
|
+
return formatToolError(error);
|
|
306
|
+
}
|
|
248
307
|
});
|
|
249
308
|
}
|
|
250
309
|
//# sourceMappingURL=sync-pull.js.map
|