@magic-markdown/cli 0.3.12 → 0.3.13
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/dist/index.js +206 -48
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -918,7 +918,8 @@ function selectorFromRange(markdown, range) {
|
|
|
918
918
|
function remapAnchor(markdown, anchor) {
|
|
919
919
|
const lines = getLines(markdown);
|
|
920
920
|
const quoteLines = anchor.selector.quote.split(/\r?\n/);
|
|
921
|
-
const
|
|
921
|
+
const candidates = findQuoteCandidates(lines, quoteLines);
|
|
922
|
+
const best = bestCandidate(lines, candidates, anchor.selector);
|
|
922
923
|
if (!best) {
|
|
923
924
|
return {
|
|
924
925
|
...anchor,
|
|
@@ -939,30 +940,44 @@ function remapAnchor(markdown, anchor) {
|
|
|
939
940
|
function remapAnchors(markdown, anchors) {
|
|
940
941
|
return anchors.map((anchor) => remapAnchor(markdown, anchor));
|
|
941
942
|
}
|
|
942
|
-
function
|
|
943
|
-
if (quoteLines.length === 0) return
|
|
943
|
+
function findQuoteCandidates(lines, quoteLines) {
|
|
944
|
+
if (quoteLines.length === 0) return [];
|
|
945
|
+
const ranges = [];
|
|
946
|
+
const quoteText = quoteLines.join("\n");
|
|
944
947
|
for (let index = 0; index <= lines.length - quoteLines.length; index += 1) {
|
|
945
948
|
const candidate = lines.slice(index, index + quoteLines.length);
|
|
946
|
-
if (candidate.join("\n") === quoteLines.
|
|
947
|
-
return { startLine: index + 1, endLine: index + quoteLines.length };
|
|
948
|
-
}
|
|
949
|
+
if (candidate.join("\n") === quoteText) ranges.push({ startLine: index + 1, endLine: index + quoteLines.length });
|
|
949
950
|
}
|
|
950
|
-
return
|
|
951
|
+
return ranges;
|
|
952
|
+
}
|
|
953
|
+
function bestCandidate(lines, candidates, selector) {
|
|
954
|
+
if (candidates.length <= 1) return candidates[0];
|
|
955
|
+
const scored = candidates.map((range) => ({ range, score: scoreContext(lines, range.startLine, range.endLine, selector) })).sort((left, right) => right.score - left.score);
|
|
956
|
+
const best = scored[0];
|
|
957
|
+
if (!best) return void 0;
|
|
958
|
+
const tied = scored.filter((candidate) => candidate.score === best.score);
|
|
959
|
+
return tied.length === 1 ? best.range : void 0;
|
|
951
960
|
}
|
|
952
961
|
function scoreContext(lines, startLine, endLine, selector) {
|
|
953
962
|
let score = 0.7;
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
const actualPrefix = lines.slice(Math.max(0, startLine - 4), startLine - 1).join("\n");
|
|
963
|
+
const expectedPrefix = contextPrefix(selector.prefix);
|
|
964
|
+
if (expectedPrefix) {
|
|
965
|
+
const actualPrefix = contextPrefix(lines.slice(Math.max(0, startLine - 4), startLine - 1).join("\n"));
|
|
957
966
|
if (expectedPrefix && actualPrefix.endsWith(expectedPrefix)) score += 0.15;
|
|
958
967
|
}
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
const actualSuffix = lines.slice(endLine, endLine + 3).join("\n");
|
|
968
|
+
const expectedSuffix = contextSuffix(selector.suffix);
|
|
969
|
+
if (expectedSuffix) {
|
|
970
|
+
const actualSuffix = contextSuffix(lines.slice(endLine, endLine + 3).join("\n"));
|
|
962
971
|
if (expectedSuffix && actualSuffix.startsWith(expectedSuffix)) score += 0.15;
|
|
963
972
|
}
|
|
964
973
|
return Math.min(1, score);
|
|
965
974
|
}
|
|
975
|
+
function contextPrefix(value) {
|
|
976
|
+
return value?.split(/\r?\n/).filter(Boolean).slice(-3).join("\n") ?? "";
|
|
977
|
+
}
|
|
978
|
+
function contextSuffix(value) {
|
|
979
|
+
return value?.split(/\r?\n/).filter(Boolean).slice(0, 3).join("\n") ?? "";
|
|
980
|
+
}
|
|
966
981
|
|
|
967
982
|
// ../core/src/text-merge.ts
|
|
968
983
|
var MAX_DIFF_CELLS = 25e6;
|
|
@@ -1163,6 +1178,9 @@ function regionTouchesSuggestionRange(region, baseStart, baseEnd) {
|
|
|
1163
1178
|
return region.baseStart < baseEnd && regionEnd > baseStart;
|
|
1164
1179
|
}
|
|
1165
1180
|
function currentSuggestionRange(markdown, suggestion, anchor) {
|
|
1181
|
+
const anchoredRange = currentAnchorRange(markdown, suggestion, anchor);
|
|
1182
|
+
if (anchoredRange) return anchoredRange;
|
|
1183
|
+
if (anchor && !anchorIsReliable(anchor)) return void 0;
|
|
1166
1184
|
const hintedRange = suggestion.patch.range;
|
|
1167
1185
|
if (rangeIsWithin(markdown, hintedRange) && extractLineRange(markdown, hintedRange) === suggestion.patch.before) return hintedRange;
|
|
1168
1186
|
const candidates = findBeforeCandidates(markdown, suggestion.patch.before);
|
|
@@ -1177,6 +1195,14 @@ function currentSuggestionRange(markdown, suggestion, anchor) {
|
|
|
1177
1195
|
if (best.score < 0.7) return void 0;
|
|
1178
1196
|
return best.range;
|
|
1179
1197
|
}
|
|
1198
|
+
function currentAnchorRange(markdown, suggestion, anchor) {
|
|
1199
|
+
if (!anchor || !anchorIsReliable(anchor) || !anchor.range) return void 0;
|
|
1200
|
+
if (!rangeIsWithin(markdown, anchor.range)) return void 0;
|
|
1201
|
+
return extractLineRange(markdown, anchor.range) === suggestion.patch.before ? anchor.range : void 0;
|
|
1202
|
+
}
|
|
1203
|
+
function anchorIsReliable(anchor) {
|
|
1204
|
+
return anchor.status === "mapped" && anchor.confidence >= 0.65;
|
|
1205
|
+
}
|
|
1180
1206
|
function findBeforeCandidates(markdown, before) {
|
|
1181
1207
|
const lines = getLines(markdown);
|
|
1182
1208
|
const beforeLines = linePattern(before);
|
|
@@ -1200,22 +1226,22 @@ function linePattern(value) {
|
|
|
1200
1226
|
function scoreContext2(markdown, range, anchor) {
|
|
1201
1227
|
const lines = getLines(markdown);
|
|
1202
1228
|
let score = anchor.selector.quote === extractLineRange(markdown, range) ? 0.7 : 0.65;
|
|
1203
|
-
const expectedPrefix =
|
|
1229
|
+
const expectedPrefix = contextPrefix2(anchor.selector.prefix);
|
|
1204
1230
|
if (expectedPrefix) {
|
|
1205
|
-
const actualPrefix =
|
|
1231
|
+
const actualPrefix = contextPrefix2(lines.slice(Math.max(0, range.startLine - 4), range.startLine - 1).join("\n"));
|
|
1206
1232
|
if (actualPrefix?.endsWith(expectedPrefix)) score += 0.15;
|
|
1207
1233
|
}
|
|
1208
|
-
const expectedSuffix =
|
|
1234
|
+
const expectedSuffix = contextSuffix2(anchor.selector.suffix);
|
|
1209
1235
|
if (expectedSuffix) {
|
|
1210
|
-
const actualSuffix =
|
|
1236
|
+
const actualSuffix = contextSuffix2(lines.slice(range.endLine, range.endLine + 3).join("\n"));
|
|
1211
1237
|
if (actualSuffix?.startsWith(expectedSuffix)) score += 0.15;
|
|
1212
1238
|
}
|
|
1213
1239
|
return Math.min(1, score);
|
|
1214
1240
|
}
|
|
1215
|
-
function
|
|
1241
|
+
function contextPrefix2(value) {
|
|
1216
1242
|
return value?.split(/\r?\n/).filter(Boolean).slice(-3).join("\n") || void 0;
|
|
1217
1243
|
}
|
|
1218
|
-
function
|
|
1244
|
+
function contextSuffix2(value) {
|
|
1219
1245
|
return value?.split(/\r?\n/).filter(Boolean).slice(0, 3).join("\n") || void 0;
|
|
1220
1246
|
}
|
|
1221
1247
|
|
|
@@ -4606,44 +4632,46 @@ function gatherMarks(schema2, marks) {
|
|
|
4606
4632
|
}
|
|
4607
4633
|
|
|
4608
4634
|
// ../core/src/pm-schema.ts
|
|
4635
|
+
var blockAttrs = { blockId: { default: null } };
|
|
4609
4636
|
var canonicalSchema = new Schema({
|
|
4610
4637
|
nodes: {
|
|
4611
4638
|
// The doc allows suggestion marks on its block children so pending
|
|
4612
4639
|
// block-level suggestions (node marks) survive fromJSON and can be
|
|
4613
4640
|
// structurally reverted before serialization.
|
|
4614
4641
|
doc: { content: "block+", marks: "insertion deletion modification" },
|
|
4615
|
-
paragraph: { group: "block", content: "inline*" },
|
|
4642
|
+
paragraph: { group: "block", content: "inline*", attrs: blockAttrs },
|
|
4616
4643
|
heading: {
|
|
4617
4644
|
group: "block",
|
|
4618
4645
|
content: "inline*",
|
|
4619
|
-
attrs: { level: { default: 1 } }
|
|
4646
|
+
attrs: { ...blockAttrs, level: { default: 1 } }
|
|
4620
4647
|
},
|
|
4621
|
-
blockquote: { group: "block", content: "block+" },
|
|
4648
|
+
blockquote: { group: "block", content: "block+", attrs: blockAttrs },
|
|
4622
4649
|
codeBlock: {
|
|
4623
4650
|
group: "block",
|
|
4624
4651
|
content: "text*",
|
|
4625
4652
|
marks: "",
|
|
4626
4653
|
code: true,
|
|
4627
|
-
attrs: { language: { default: null } }
|
|
4654
|
+
attrs: { ...blockAttrs, language: { default: null } }
|
|
4628
4655
|
},
|
|
4629
|
-
horizontalRule: { group: "block" },
|
|
4630
|
-
bulletList: { group: "block", content: "listItem+" },
|
|
4656
|
+
horizontalRule: { group: "block", attrs: blockAttrs },
|
|
4657
|
+
bulletList: { group: "block", content: "listItem+", attrs: blockAttrs },
|
|
4631
4658
|
orderedList: {
|
|
4632
4659
|
group: "block",
|
|
4633
4660
|
content: "listItem+",
|
|
4634
|
-
attrs: { start: { default: 1 } }
|
|
4661
|
+
attrs: { ...blockAttrs, start: { default: 1 } }
|
|
4635
4662
|
},
|
|
4636
|
-
listItem: { content: "paragraph block*" },
|
|
4637
|
-
taskList: { group: "block", content: "taskItem+" },
|
|
4663
|
+
listItem: { content: "paragraph block*", attrs: blockAttrs },
|
|
4664
|
+
taskList: { group: "block", content: "taskItem+", attrs: blockAttrs },
|
|
4638
4665
|
taskItem: {
|
|
4639
4666
|
content: "paragraph block*",
|
|
4640
|
-
attrs: { checked: { default: false } }
|
|
4667
|
+
attrs: { ...blockAttrs, checked: { default: false } }
|
|
4641
4668
|
},
|
|
4642
|
-
table: { group: "block", content: "tableRow+" },
|
|
4643
|
-
tableRow: { content: "(tableCell | tableHeader)+" },
|
|
4669
|
+
table: { group: "block", content: "tableRow+", attrs: blockAttrs },
|
|
4670
|
+
tableRow: { content: "(tableCell | tableHeader)+", attrs: blockAttrs },
|
|
4644
4671
|
tableHeader: {
|
|
4645
4672
|
content: "block+",
|
|
4646
4673
|
attrs: {
|
|
4674
|
+
...blockAttrs,
|
|
4647
4675
|
colspan: { default: 1 },
|
|
4648
4676
|
rowspan: { default: 1 },
|
|
4649
4677
|
colwidth: { default: null }
|
|
@@ -4652,6 +4680,7 @@ var canonicalSchema = new Schema({
|
|
|
4652
4680
|
tableCell: {
|
|
4653
4681
|
content: "block+",
|
|
4654
4682
|
attrs: {
|
|
4683
|
+
...blockAttrs,
|
|
4655
4684
|
colspan: { default: 1 },
|
|
4656
4685
|
rowspan: { default: 1 },
|
|
4657
4686
|
colwidth: { default: null }
|
|
@@ -10950,6 +10979,36 @@ function backticksFor2(node, side) {
|
|
|
10950
10979
|
return result;
|
|
10951
10980
|
}
|
|
10952
10981
|
|
|
10982
|
+
// ../core/src/pm-parse.ts
|
|
10983
|
+
var parser = new MarkdownParser(canonicalSchema, new lib_default(), {
|
|
10984
|
+
blockquote: { block: "blockquote" },
|
|
10985
|
+
paragraph: { block: "paragraph" },
|
|
10986
|
+
list_item: { block: "listItem" },
|
|
10987
|
+
bullet_list: { block: "bulletList" },
|
|
10988
|
+
ordered_list: {
|
|
10989
|
+
block: "orderedList",
|
|
10990
|
+
getAttrs: (tok) => ({ start: Number(tok.attrGet("start")) || 1 })
|
|
10991
|
+
},
|
|
10992
|
+
heading: { block: "heading", getAttrs: (tok) => ({ level: Number(tok.tag.slice(1)) || 1 }) },
|
|
10993
|
+
code_block: { block: "codeBlock", noCloseToken: true },
|
|
10994
|
+
fence: { block: "codeBlock", getAttrs: (tok) => ({ language: tok.info || null }), noCloseToken: true },
|
|
10995
|
+
hr: { node: "horizontalRule" },
|
|
10996
|
+
hardbreak: { node: "hardBreak" },
|
|
10997
|
+
em: { mark: "italic" },
|
|
10998
|
+
strong: { mark: "bold" },
|
|
10999
|
+
s: { mark: "strike" },
|
|
11000
|
+
link: { mark: "link", getAttrs: (tok) => ({ href: tok.attrGet("href") }) },
|
|
11001
|
+
code_inline: { mark: "code", noCloseToken: true },
|
|
11002
|
+
image: {
|
|
11003
|
+
node: "image",
|
|
11004
|
+
getAttrs: (tok) => ({
|
|
11005
|
+
alt: tok.content,
|
|
11006
|
+
src: tok.attrGet("src"),
|
|
11007
|
+
title: tok.attrGet("title")
|
|
11008
|
+
})
|
|
11009
|
+
}
|
|
11010
|
+
});
|
|
11011
|
+
|
|
10953
11012
|
// ../core/src/remote-document-io.ts
|
|
10954
11013
|
var RemoteDocumentIO = class {
|
|
10955
11014
|
constructor(document) {
|
|
@@ -10997,7 +11056,7 @@ var RemoteDocumentIO = class {
|
|
|
10997
11056
|
};
|
|
10998
11057
|
|
|
10999
11058
|
// src/agent.ts
|
|
11000
|
-
var CLI_VERSION = "0.3.
|
|
11059
|
+
var CLI_VERSION = "0.3.13";
|
|
11001
11060
|
var CLI_PACKAGE_NAME = "@magic-markdown/cli";
|
|
11002
11061
|
var AGENT_COMMANDS = [
|
|
11003
11062
|
{
|
|
@@ -11058,10 +11117,11 @@ var AGENT_COMMANDS = [
|
|
|
11058
11117
|
{
|
|
11059
11118
|
name: "remote",
|
|
11060
11119
|
summary: "Read, organize, comment on, suggest edits to, monitor, and restore the active Magic Markdown remote join.",
|
|
11061
|
-
usage: "mdocs remote map|graph|context|review|create-file|move-file|comment|suggest|reject|events|history|restore|library|create-folder|update-folder|move-root|invite-folder --json",
|
|
11120
|
+
usage: "mdocs remote status|map|graph|context|review|create-file|move-file|comment|suggest|reject|events|history|restore|library|create-folder|update-folder|move-root|invite-folder --json",
|
|
11062
11121
|
output: "json",
|
|
11063
11122
|
mutates: true,
|
|
11064
11123
|
examples: [
|
|
11124
|
+
"mdocs remote status --expect-scope file --expect-root root_abc --expect-doc doc_abc --json",
|
|
11065
11125
|
"mdocs remote context --summary --json",
|
|
11066
11126
|
"mdocs remote context --start-line 1 --end-line 100 --no-review --json",
|
|
11067
11127
|
"mdocs remote context --start-line 101 --end-line 200 --no-review --json",
|
|
@@ -11081,6 +11141,7 @@ var AGENT_COMMANDS = [
|
|
|
11081
11141
|
"mdocs remote invite-folder fold_abc123 --email person@example.com --role edit --json"
|
|
11082
11142
|
],
|
|
11083
11143
|
notes: [
|
|
11144
|
+
"Use remote status --json immediately after joining when the handoff includes expected scope/root/doc values. If it reports wrong_binding, stop and ask for the correct share or connector.",
|
|
11084
11145
|
"Use remote context --summary --json first on file-scoped joins and before reading large documents. It returns metadata, heading line numbers, current head, review counts, and suggested next commands without dumping Markdown.",
|
|
11085
11146
|
"remote context accepts --start-line and --end-line (1-based, inclusive) to page through large documents. The response always includes totalLines, startLine, and endLine \u2014 if totalLines > endLine, request the next page with --start-line <endLine+1>.",
|
|
11086
11147
|
"Use remote context --no-review when reading document content only; use remote review to list open comments, open suggestions, and anchors separately.",
|
|
@@ -11358,11 +11419,12 @@ Run \`mdocs help <command>\` (or \`mdocs <command> --help\`) for usage, examples
|
|
|
11358
11419
|
## Start Here
|
|
11359
11420
|
|
|
11360
11421
|
1. If given a Magic Markdown share URL, run \`mdocs join <share-url> --json\` first, and always include \`--name "<your agent name>"\` (for example \`--name "Claude Code"\`) so collaborators can see which agent is connected. Use \`mdocs remote ...\` commands after joining.
|
|
11361
|
-
2. If
|
|
11362
|
-
3.
|
|
11363
|
-
4. Run \`mdocs
|
|
11364
|
-
5.
|
|
11365
|
-
6.
|
|
11422
|
+
2. If the handoff includes expected binding values, run \`mdocs remote status --expect-scope <file|project> --expect-root <rootId> --expect-doc <docId> --json\` after joining. If it reports \`wrong_binding\`, stop and ask for the correct share or connector.
|
|
11423
|
+
3. If working in a local workspace, run \`mdocs doctor --json\` to validate the workspace and learn recommended next commands.
|
|
11424
|
+
4. Run \`mdocs map --json\` or \`mdocs remote map --json\` to list documents, paths, docIds, open comments, open suggestions, anchor review counts, and link counts. File-scoped joins (most share links) cover a single document, so \`mdocs remote map\` is unavailable for them \u2014 use \`mdocs remote context --summary --json\` instead. Project-scoped joins cover one root; workspace-scoped joins cover Home and can target duplicate paths as \`<rootId>:<path-or-docId>\`.
|
|
11425
|
+
5. Run \`mdocs graph --json\` or project-scoped \`mdocs remote graph --json\` before broad edits to inspect the Obsidian-style document graph built from Markdown links and wikilinks.
|
|
11426
|
+
6. For a document, run \`mdocs context <path|docId> --summary --json\` locally or \`mdocs remote context <path|docId> --summary --json\` for a joined share before reading full content. Then page Markdown with \`--start-line\` / \`--end-line\` and \`--no-review\` when you only need document text.
|
|
11427
|
+
7. Pull review state separately with \`mdocs review <path|docId> --json\` locally or \`mdocs remote review <path|docId> --json\` for a joined share. Use \`mdocs comment\` / \`mdocs remote comment\` for review notes and \`mdocs suggest\` / \`mdocs remote suggest\` for proposed replacements. Do not insert comments, CriticMarkup, directives, or Magic markers into Markdown files.
|
|
11366
11428
|
|
|
11367
11429
|
## Filesystem Bridge / Resume
|
|
11368
11430
|
|
|
@@ -11407,7 +11469,7 @@ If Magic and the local root both changed the same document while you were offlin
|
|
|
11407
11469
|
## Errors, Conflicts, and Exit Codes
|
|
11408
11470
|
|
|
11409
11471
|
- Errors go to stderr. With \`--json\` they are structured: \`{ "ok": false, "error": { "code", "message", "hint" }, "cliVersion" }\`. Follow the \`hint\`.
|
|
11410
|
-
- Exit codes: 0 ok, 1 internal, 2 usage/invalid range, 3 conflict, 4 not found, 5 network, 6 unauthorized (share link revoked or expired).
|
|
11472
|
+
- Exit codes: 0 ok, 1 internal, 2 usage/invalid range, 3 conflict, 4 not found or wrong binding, 5 network, 6 unauthorized (share link revoked or expired).
|
|
11411
11473
|
- \`remote comment\` and \`remote suggest\` are concurrency-safe: the server merges review additions without clobbering concurrent edits, and the CLI rebases and retries automatically. A surviving \`conflict\` error means the document is changing rapidly \u2014 refetch context and retry.
|
|
11412
11474
|
- \`remote events --json\` may return \`"truncated": true\` when older events were dropped from the bounded event log. Do not assume nothing happened; refetch with \`mdocs remote context --summary --json\`, then read needed pages and review state.
|
|
11413
11475
|
- Retries are safe: remote writes carry a changeId and the server deduplicates replays.
|
|
@@ -11431,7 +11493,7 @@ Start the local stdio MCP server with:
|
|
|
11431
11493
|
mdocs serve-mcp --cwd /path/to/workspace
|
|
11432
11494
|
\`\`\`
|
|
11433
11495
|
|
|
11434
|
-
The MCP server exposes document resources, image resources, workspace map and graph resources, an agent guide resource, typed tools for comments and suggestions, and the \`magic_markdown_agent_workflow\` prompt. Use \`mdocs_context\` / \`magic_context\` with \`summary: true\` before dumping Markdown; use \`includeReview: false\` for content-only reads and \`mdocs_review\` / \`magic_review\` for review state.
|
|
11496
|
+
The MCP server exposes document resources, image resources, workspace map and graph resources, an agent guide resource, typed tools for comments and suggestions, and the \`magic_markdown_agent_workflow\` prompt. Use \`magic_status\` first when expected binding values are available; stop if it returns \`wrong_binding\`. Then use \`mdocs_context\` / \`magic_context\` with \`summary: true\` before dumping Markdown; use \`includeReview: false\` for content-only reads and \`mdocs_review\` / \`magic_review\` for review state.
|
|
11435
11497
|
`;
|
|
11436
11498
|
}
|
|
11437
11499
|
function formatCommandReference() {
|
|
@@ -11459,6 +11521,7 @@ var CLI_EXIT_CODES = {
|
|
|
11459
11521
|
invalid_range: 2,
|
|
11460
11522
|
conflict: 3,
|
|
11461
11523
|
not_found: 4,
|
|
11524
|
+
wrong_binding: 4,
|
|
11462
11525
|
network_error: 5,
|
|
11463
11526
|
unauthorized: 6
|
|
11464
11527
|
};
|
|
@@ -12511,6 +12574,16 @@ async function postReview(record, docId, additions, actor) {
|
|
|
12511
12574
|
);
|
|
12512
12575
|
return response.document;
|
|
12513
12576
|
}
|
|
12577
|
+
async function postReviewOperation(record, docId, operation, actor) {
|
|
12578
|
+
return fetchJson(
|
|
12579
|
+
`${record.origin}/api/workspaces/${encodeURIComponent(record.workspaceId)}/roots/${encodeURIComponent(record.rootId)}/documents/${encodeURIComponent(docId)}/review-ops`,
|
|
12580
|
+
{
|
|
12581
|
+
method: "POST",
|
|
12582
|
+
headers: { ...shareHeaders(record.shareUrl), "Content-Type": "application/json" },
|
|
12583
|
+
body: JSON.stringify({ actor, operation })
|
|
12584
|
+
}
|
|
12585
|
+
);
|
|
12586
|
+
}
|
|
12514
12587
|
async function pushDocument(record, baseDocument, markdown, sidecar) {
|
|
12515
12588
|
const createdAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
12516
12589
|
const payload = {
|
|
@@ -12808,6 +12881,8 @@ async function runJoinsCommand(root) {
|
|
|
12808
12881
|
async function runRemoteCommand(root, subcommand, parsed) {
|
|
12809
12882
|
const record = await normalizedSelectedJoin(root, parsed.flags);
|
|
12810
12883
|
switch (subcommand) {
|
|
12884
|
+
case "status":
|
|
12885
|
+
return remoteStatus(record, parsed.flags);
|
|
12811
12886
|
case "map":
|
|
12812
12887
|
case void 0: {
|
|
12813
12888
|
if (record.scope === "file") {
|
|
@@ -12861,10 +12936,53 @@ async function runRemoteCommand(root, subcommand, parsed) {
|
|
|
12861
12936
|
return rejoin(root, record.joinId, parsed.flags);
|
|
12862
12937
|
default:
|
|
12863
12938
|
throw new CliError("usage_error", `Unknown remote subcommand: ${subcommand}`, {
|
|
12864
|
-
hint: "Use mdocs remote map|graph|context|review|create-file|move-file|comment|suggest|reject|events|history|restore|library|create-folder|update-folder|move-root|invite-folder|rejoin."
|
|
12939
|
+
hint: "Use mdocs remote status|map|graph|context|review|create-file|move-file|comment|suggest|reject|events|history|restore|library|create-folder|update-folder|move-root|invite-folder|rejoin."
|
|
12865
12940
|
});
|
|
12866
12941
|
}
|
|
12867
12942
|
}
|
|
12943
|
+
async function remoteStatus(record, flags) {
|
|
12944
|
+
const document = record.rootId && record.docId ? (await fetchState(record)).document : void 0;
|
|
12945
|
+
const expected = expectedBinding(flags);
|
|
12946
|
+
const actual = {
|
|
12947
|
+
joinId: record.joinId,
|
|
12948
|
+
scope: record.scope,
|
|
12949
|
+
workspaceId: record.workspaceId,
|
|
12950
|
+
rootId: record.rootId,
|
|
12951
|
+
docId: document?.docId ?? record.docId,
|
|
12952
|
+
path: document?.path,
|
|
12953
|
+
currentHead: document?.currentSha ?? record.currentHead,
|
|
12954
|
+
agent: { id: record.agentId, name: record.agentName },
|
|
12955
|
+
currentDocument: document ? {
|
|
12956
|
+
docId: document.docId,
|
|
12957
|
+
path: document.path,
|
|
12958
|
+
title: document.title,
|
|
12959
|
+
currentSha: document.currentSha
|
|
12960
|
+
} : void 0
|
|
12961
|
+
};
|
|
12962
|
+
const mismatches = bindingMismatches(expected, actual);
|
|
12963
|
+
if (mismatches.length > 0) {
|
|
12964
|
+
throw new CliError("wrong_binding", "This Magic binding is for a different document or scope.", {
|
|
12965
|
+
hint: "Use the connector URL or CLI join command from the handoff copy.",
|
|
12966
|
+
details: {
|
|
12967
|
+
expected,
|
|
12968
|
+
actual,
|
|
12969
|
+
verification: { matches: false, mismatches }
|
|
12970
|
+
}
|
|
12971
|
+
});
|
|
12972
|
+
}
|
|
12973
|
+
return {
|
|
12974
|
+
ok: true,
|
|
12975
|
+
connected: true,
|
|
12976
|
+
...actual,
|
|
12977
|
+
expected,
|
|
12978
|
+
verification: { matches: true, mismatches: [] },
|
|
12979
|
+
nextCommands: [
|
|
12980
|
+
record.scope === "workspace" ? "mdocs remote map --json" : void 0,
|
|
12981
|
+
record.scope === "project" ? "mdocs remote map --json" : void 0,
|
|
12982
|
+
record.scope === "workspace" ? void 0 : "mdocs remote context --summary --json"
|
|
12983
|
+
].filter(Boolean)
|
|
12984
|
+
};
|
|
12985
|
+
}
|
|
12868
12986
|
async function remoteGraph(record) {
|
|
12869
12987
|
assertProjectScope(record, "graph");
|
|
12870
12988
|
const rootRecord = assertRootScoped(record, "graph");
|
|
@@ -13108,13 +13226,24 @@ async function remoteSuggest(root, record, parsed) {
|
|
|
13108
13226
|
const replacement = await readRequiredTextFlag(parsed.flags, root, ["with", "replacement"]);
|
|
13109
13227
|
const message = await readOptionalTextFlag(parsed.flags, root, ["message"]) ?? "Suggested edit";
|
|
13110
13228
|
const range = parseRange(requiredFlag(parsed.flags, "range"));
|
|
13111
|
-
const
|
|
13112
|
-
|
|
13113
|
-
|
|
13114
|
-
|
|
13115
|
-
|
|
13229
|
+
const pathOrDocId = parsed.command[2] ?? record.docId;
|
|
13230
|
+
if (!pathOrDocId) {
|
|
13231
|
+
throw new CliError("usage_error", "Missing document path or docId.", {
|
|
13232
|
+
hint: "Pass a document path or docId, or join with --doc <docId>."
|
|
13233
|
+
});
|
|
13234
|
+
}
|
|
13235
|
+
const document = await fetchDocument(record, pathOrDocId);
|
|
13236
|
+
const documentRecord = rootScopedRecordFor(record, document.rootId);
|
|
13237
|
+
await refreshPresence(documentRecord, document.docId);
|
|
13238
|
+
const result = await postReviewOperation(
|
|
13239
|
+
documentRecord,
|
|
13240
|
+
document.docId,
|
|
13241
|
+
{ kind: "create_suggestion", payload: { ...range, replacement, message } },
|
|
13242
|
+
actorForRecord(record)
|
|
13116
13243
|
);
|
|
13117
|
-
|
|
13244
|
+
if (result.document) await recordHead(root, record, result.document);
|
|
13245
|
+
const placementStatus = result.reviewRecord?.placement?.status;
|
|
13246
|
+
return { suggestion: result.suggestion, reviewRecord: result.reviewRecord, placementStatus, projectionStatus: result.projectionStatus, document: result.document };
|
|
13118
13247
|
}
|
|
13119
13248
|
async function remoteCreateFolder(record, parsed) {
|
|
13120
13249
|
assertProjectScope(record, "create-folder");
|
|
@@ -13379,6 +13508,33 @@ function joinSummary(record, document) {
|
|
|
13379
13508
|
].filter(Boolean)
|
|
13380
13509
|
};
|
|
13381
13510
|
}
|
|
13511
|
+
function expectedBinding(flags) {
|
|
13512
|
+
const scope = stringFlag(flags, "expect-scope", "expected-scope");
|
|
13513
|
+
const rootId = stringFlag(flags, "expect-root", "expected-root");
|
|
13514
|
+
const docId = stringFlag(flags, "expect-doc", "expected-doc");
|
|
13515
|
+
const path = stringFlag(flags, "expect-path", "expected-path");
|
|
13516
|
+
return {
|
|
13517
|
+
...scope ? { scope } : {},
|
|
13518
|
+
...rootId ? { rootId } : {},
|
|
13519
|
+
...docId ? { docId } : {},
|
|
13520
|
+
...path ? { path } : {}
|
|
13521
|
+
};
|
|
13522
|
+
}
|
|
13523
|
+
function stringFlag(flags, primary, alias) {
|
|
13524
|
+
const value = flags[primary] ?? flags[alias];
|
|
13525
|
+
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
13526
|
+
}
|
|
13527
|
+
function bindingMismatches(expected, actual) {
|
|
13528
|
+
const checks = [
|
|
13529
|
+
["scope", expected.scope, actual.scope],
|
|
13530
|
+
["rootId", expected.rootId, actual.rootId],
|
|
13531
|
+
["docId", expected.docId, actual.docId],
|
|
13532
|
+
["path", expected.path, actual.path]
|
|
13533
|
+
];
|
|
13534
|
+
return checks.flatMap(
|
|
13535
|
+
([field, expectedValue, actualValue]) => expectedValue && expectedValue !== actualValue ? [{ field, expected: expectedValue, actual: actualValue }] : []
|
|
13536
|
+
);
|
|
13537
|
+
}
|
|
13382
13538
|
function assertProjectScope(record, command) {
|
|
13383
13539
|
if (record.scope === "project") return;
|
|
13384
13540
|
throw new CliError("usage_error", `remote ${command} requires a project-scoped join.`, {
|
|
@@ -14575,6 +14731,7 @@ Commands:
|
|
|
14575
14731
|
checkpoint create|list|restore Manage local reversible checkpoints
|
|
14576
14732
|
join <share-url> --json Join a Magic Markdown share through the CLI
|
|
14577
14733
|
joins --json List saved Magic Markdown remote joins
|
|
14734
|
+
remote status --json Verify the active remote join binding
|
|
14578
14735
|
remote map|graph|context|review|create-file|move-file
|
|
14579
14736
|
Work with documents in the active remote join
|
|
14580
14737
|
remote comment|suggest Add remote review comments and suggestions
|
|
@@ -14643,7 +14800,8 @@ main().catch((error) => {
|
|
|
14643
14800
|
code: cliError.code,
|
|
14644
14801
|
message: cliError.message,
|
|
14645
14802
|
...hint ? { hint } : {},
|
|
14646
|
-
...usage && cliError.hint ? { usage } : {}
|
|
14803
|
+
...usage && cliError.hint ? { usage } : {},
|
|
14804
|
+
...cliError.details !== void 0 ? { details: cliError.details } : {}
|
|
14647
14805
|
},
|
|
14648
14806
|
cliVersion: CLI_VERSION
|
|
14649
14807
|
};
|
package/package.json
CHANGED