@commentray/core 0.0.2 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (109) hide show
  1. package/dist/anchors.d.ts +6 -0
  2. package/dist/anchors.d.ts.map +1 -1
  3. package/dist/anchors.js +11 -0
  4. package/dist/anchors.js.map +1 -1
  5. package/dist/angles-toml.d.ts +14 -0
  6. package/dist/angles-toml.d.ts.map +1 -1
  7. package/dist/angles-toml.js +51 -0
  8. package/dist/angles-toml.js.map +1 -1
  9. package/dist/block-scroll-pickers.d.ts +22 -0
  10. package/dist/block-scroll-pickers.d.ts.map +1 -0
  11. package/dist/block-scroll-pickers.js +41 -0
  12. package/dist/block-scroll-pickers.js.map +1 -0
  13. package/dist/block-snippet.d.ts +13 -0
  14. package/dist/block-snippet.d.ts.map +1 -0
  15. package/dist/block-snippet.js +30 -0
  16. package/dist/block-snippet.js.map +1 -0
  17. package/dist/blocks.d.ts.map +1 -1
  18. package/dist/blocks.js +13 -13
  19. package/dist/blocks.js.map +1 -1
  20. package/dist/commentray-disk-pairs.d.ts +14 -0
  21. package/dist/commentray-disk-pairs.d.ts.map +1 -0
  22. package/dist/commentray-disk-pairs.js +51 -0
  23. package/dist/commentray-disk-pairs.js.map +1 -0
  24. package/dist/commentray-index-renames.d.ts +21 -0
  25. package/dist/commentray-index-renames.d.ts.map +1 -0
  26. package/dist/commentray-index-renames.js +85 -0
  27. package/dist/commentray-index-renames.js.map +1 -0
  28. package/dist/commentray-path-resolution.js +1 -1
  29. package/dist/commentray-path-resolution.js.map +1 -1
  30. package/dist/config.d.ts.map +1 -1
  31. package/dist/config.js +6 -4
  32. package/dist/config.js.map +1 -1
  33. package/dist/git-relocation-scan.d.ts +9 -0
  34. package/dist/git-relocation-scan.d.ts.map +1 -0
  35. package/dist/git-relocation-scan.js +96 -0
  36. package/dist/git-relocation-scan.js.map +1 -0
  37. package/dist/index-normalize.d.ts +10 -0
  38. package/dist/index-normalize.d.ts.map +1 -0
  39. package/dist/index-normalize.js +60 -0
  40. package/dist/index-normalize.js.map +1 -0
  41. package/dist/index-schema-messages.d.ts +6 -0
  42. package/dist/index-schema-messages.d.ts.map +1 -0
  43. package/dist/index-schema-messages.js +26 -0
  44. package/dist/index-schema-messages.js.map +1 -0
  45. package/dist/index.d.ts +23 -8
  46. package/dist/index.d.ts.map +1 -1
  47. package/dist/index.js +14 -5
  48. package/dist/index.js.map +1 -1
  49. package/dist/marker-ids.d.ts +19 -0
  50. package/dist/marker-ids.d.ts.map +1 -0
  51. package/dist/marker-ids.js +38 -0
  52. package/dist/marker-ids.js.map +1 -0
  53. package/dist/marker-validation.d.ts +22 -0
  54. package/dist/marker-validation.d.ts.map +1 -0
  55. package/dist/marker-validation.js +138 -0
  56. package/dist/marker-validation.js.map +1 -0
  57. package/dist/metadata.d.ts.map +1 -1
  58. package/dist/metadata.js +54 -25
  59. package/dist/metadata.js.map +1 -1
  60. package/dist/migrate-angles-layout.d.ts +27 -0
  61. package/dist/migrate-angles-layout.d.ts.map +1 -0
  62. package/dist/migrate-angles-layout.js +72 -0
  63. package/dist/migrate-angles-layout.js.map +1 -0
  64. package/dist/migrate.d.ts.map +1 -1
  65. package/dist/migrate.js +20 -4
  66. package/dist/migrate.js.map +1 -1
  67. package/dist/model.d.ts +13 -26
  68. package/dist/model.d.ts.map +1 -1
  69. package/dist/model.js +16 -0
  70. package/dist/model.js.map +1 -1
  71. package/dist/paths.d.ts +7 -1
  72. package/dist/paths.d.ts.map +1 -1
  73. package/dist/paths.js +18 -2
  74. package/dist/paths.js.map +1 -1
  75. package/dist/region-marker-convert.d.ts +27 -0
  76. package/dist/region-marker-convert.d.ts.map +1 -0
  77. package/dist/region-marker-convert.js +78 -0
  78. package/dist/region-marker-convert.js.map +1 -0
  79. package/dist/relocation-hints.d.ts +18 -0
  80. package/dist/relocation-hints.d.ts.map +1 -0
  81. package/dist/relocation-hints.js +170 -0
  82. package/dist/relocation-hints.js.map +1 -0
  83. package/dist/scm/git-scm-provider.d.ts +7 -1
  84. package/dist/scm/git-scm-provider.d.ts.map +1 -1
  85. package/dist/scm/git-scm-provider.js +42 -20
  86. package/dist/scm/git-scm-provider.js.map +1 -1
  87. package/dist/scm/git-spawn.d.ts +10 -0
  88. package/dist/scm/git-spawn.d.ts.map +1 -0
  89. package/dist/scm/git-spawn.js +26 -0
  90. package/dist/scm/git-spawn.js.map +1 -0
  91. package/dist/scm/scm-provider.d.ts +10 -0
  92. package/dist/scm/scm-provider.d.ts.map +1 -1
  93. package/dist/scroll-sync.d.ts +8 -23
  94. package/dist/scroll-sync.d.ts.map +1 -1
  95. package/dist/scroll-sync.js +31 -52
  96. package/dist/scroll-sync.js.map +1 -1
  97. package/dist/source-markers.d.ts +28 -0
  98. package/dist/source-markers.d.ts.map +1 -0
  99. package/dist/source-markers.js +241 -0
  100. package/dist/source-markers.js.map +1 -0
  101. package/dist/validate-project.d.ts +9 -1
  102. package/dist/validate-project.d.ts.map +1 -1
  103. package/dist/validate-project.js +107 -16
  104. package/dist/validate-project.js.map +1 -1
  105. package/dist/walk-commentray-source-md.d.ts +5 -0
  106. package/dist/walk-commentray-source-md.d.ts.map +1 -0
  107. package/dist/walk-commentray-source-md.js +33 -0
  108. package/dist/walk-commentray-source-md.js.map +1 -0
  109. package/package.json +6 -2
@@ -0,0 +1,138 @@
1
+ import { parseAnchor } from "./anchors.js";
2
+ import { assertValidMarkerId } from "./marker-ids.js";
3
+ import { parseCommentrayRegionBoundary } from "./source-markers.js";
4
+ /**
5
+ * Scans a single source file for Commentray region / marker boundaries and reports:
6
+ * - invalid ids (syntax that matched but fails `assertValidMarkerId` — rare),
7
+ * - duplicate **start** for the same id before its `end`,
8
+ * - orphan **end** lines,
9
+ * - **start** without a matching **end** (unclosed region).
10
+ */
11
+ export function validateMarkerBoundariesInSource(sourceText, sourcePath) {
12
+ const issues = [];
13
+ const lines = sourceText.replaceAll("\r\n", "\n").split("\n");
14
+ const pendingStartLine = new Map();
15
+ for (let line0 = 0; line0 < lines.length; line0++) {
16
+ const hit = parseCommentrayRegionBoundary(lines[line0] ?? "");
17
+ if (!hit)
18
+ continue;
19
+ try {
20
+ assertValidMarkerId(hit.id);
21
+ }
22
+ catch (e) {
23
+ issues.push({
24
+ level: "error",
25
+ message: `${sourcePath}:${line0 + 1}: ${e instanceof Error ? e.message : String(e)}`,
26
+ });
27
+ continue;
28
+ }
29
+ const loc = `${sourcePath}:${line0 + 1}`;
30
+ if (hit.kind === "start") {
31
+ const priorStart = pendingStartLine.get(hit.id);
32
+ if (priorStart !== undefined) {
33
+ const prev = priorStart + 1;
34
+ issues.push({
35
+ level: "error",
36
+ message: `${loc}: duplicate commentray start for id "${hit.id}" (also opened at line ${prev}). Close the previous region first, or use a unique id per region.`,
37
+ });
38
+ continue;
39
+ }
40
+ pendingStartLine.set(hit.id, line0);
41
+ continue;
42
+ }
43
+ const start0 = pendingStartLine.get(hit.id);
44
+ if (start0 === undefined) {
45
+ issues.push({
46
+ level: "error",
47
+ message: `${loc}: commentray end for id "${hit.id}" has no matching start in this file.`,
48
+ });
49
+ continue;
50
+ }
51
+ pendingStartLine.delete(hit.id);
52
+ }
53
+ for (const [id, line0] of pendingStartLine) {
54
+ issues.push({
55
+ level: "error",
56
+ message: `${sourcePath}:${line0 + 1}: commentray start for id "${id}" has no matching end in this file.`,
57
+ });
58
+ }
59
+ return issues;
60
+ }
61
+ function markerIdFromBlock(block) {
62
+ try {
63
+ const a = parseAnchor(block.anchor);
64
+ if (a.kind === "marker")
65
+ return a.id;
66
+ }
67
+ catch {
68
+ return null;
69
+ }
70
+ if (typeof block.markerId === "string" && block.markerId.trim() !== "") {
71
+ try {
72
+ return assertValidMarkerId(block.markerId);
73
+ }
74
+ catch {
75
+ return null;
76
+ }
77
+ }
78
+ return null;
79
+ }
80
+ /**
81
+ * Index-level rules for stable cross-references:
82
+ * - **Error** if the same `(sourcePath, marker id)` is claimed by **different** block `id`s
83
+ * (e.g. two Angle files disagree).
84
+ * - **Warn** if the same marker id string is reused across **different** source files
85
+ * (repo-wide ambiguity for links and search — allowed, but noisy).
86
+ */
87
+ export function validateIndexMarkerSemantics(index) {
88
+ const issues = [];
89
+ const bySourceAndMarker = new Map();
90
+ const byMarkerRepoWide = new Map();
91
+ for (const [commentrayPath, entry] of Object.entries(index.byCommentrayPath)) {
92
+ for (const block of entry.blocks) {
93
+ const mid = markerIdFromBlock(block);
94
+ if (mid === null)
95
+ continue;
96
+ const key = `${entry.sourcePath}\0${mid}`;
97
+ const loc = {
98
+ sourcePath: entry.sourcePath,
99
+ commentrayPath,
100
+ blockId: block.id,
101
+ };
102
+ const list = bySourceAndMarker.get(key) ?? [];
103
+ list.push(loc);
104
+ bySourceAndMarker.set(key, list);
105
+ const sources = byMarkerRepoWide.get(mid) ?? new Set();
106
+ sources.add(entry.sourcePath);
107
+ byMarkerRepoWide.set(mid, sources);
108
+ }
109
+ }
110
+ for (const [composite, locs] of bySourceAndMarker) {
111
+ if (locs.length < 2)
112
+ continue;
113
+ const sep = composite.indexOf("\0");
114
+ const sourcePath = composite.slice(0, sep);
115
+ const mid = composite.slice(sep + 1);
116
+ const blockIds = new Set(locs.map((l) => l.blockId));
117
+ if (blockIds.size > 1) {
118
+ const detail = locs.map((l) => `${l.blockId} (${l.commentrayPath})`).join(", ");
119
+ issues.push({
120
+ level: "error",
121
+ message: `Marker id "${mid}" for source "${sourcePath}" is indexed with different block ids: ${detail}. ` +
122
+ `One physical region should map to one block id (e.g. align Angle files or deduplicate).`,
123
+ });
124
+ }
125
+ }
126
+ for (const [mid, sources] of byMarkerRepoWide) {
127
+ if (sources.size <= 1)
128
+ continue;
129
+ const paths = [...sources].sort((a, b) => a.localeCompare(b)).join(", ");
130
+ issues.push({
131
+ level: "warn",
132
+ message: `Marker id "${mid}" is reused across different source files (${paths}). ` +
133
+ `That is valid for independent regions, but ambiguous for repo-wide links — consider namespaced ids (e.g. "${mid}--dashboard", "${mid}--api").`,
134
+ });
135
+ }
136
+ return issues;
137
+ }
138
+ //# sourceMappingURL=marker-validation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"marker-validation.js","sourceRoot":"","sources":["../src/marker-validation.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"metadata.d.ts","sourceRoot":"","sources":["../src/metadata.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,eAAe,EAA0B,MAAM,YAAY,CAAC;AAE1E,wBAAgB,UAAU,IAAI,eAAe,CAE5C;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,eAAe,CAiBhE"}
1
+ {"version":3,"file":"metadata.d.ts","sourceRoot":"","sources":["../src/metadata.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,eAAe,EAAoD,MAAM,YAAY,CAAC;AAEpG,wBAAgB,UAAU,IAAI,eAAe,CAE5C;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,eAAe,CAwBhE"}
package/dist/metadata.js CHANGED
@@ -1,4 +1,7 @@
1
- import { CURRENT_SCHEMA_VERSION } from "./model.js";
1
+ import { parseAnchor } from "./anchors.js";
2
+ import { describeIndexSchemaRemediation } from "./index-schema-messages.js";
3
+ import { assertValidMarkerId } from "./marker-ids.js";
4
+ import { coerceIndexSchemaVersion, CURRENT_SCHEMA_VERSION } from "./model.js";
2
5
  export function emptyIndex() {
3
6
  return { schemaVersion: CURRENT_SCHEMA_VERSION, byCommentrayPath: {} };
4
7
  }
@@ -7,9 +10,12 @@ export function assertValidIndex(value) {
7
10
  throw new TypeError("index.json must be a JSON object");
8
11
  }
9
12
  const obj = value;
10
- const schemaVersion = obj.schemaVersion;
13
+ const schemaVersion = coerceIndexSchemaVersion(obj.schemaVersion);
14
+ if (schemaVersion === null) {
15
+ throw new TypeError(`index.json schemaVersion must be an integer (got ${String(obj.schemaVersion)})`);
16
+ }
11
17
  if (schemaVersion !== CURRENT_SCHEMA_VERSION) {
12
- throw new Error(`Unsupported schemaVersion: ${String(schemaVersion)}`);
18
+ throw new Error(`index.json schemaVersion mismatch. ${describeIndexSchemaRemediation(obj.schemaVersion)}`);
13
19
  }
14
20
  const byCommentrayPath = obj.byCommentrayPath;
15
21
  if (typeof byCommentrayPath !== "object" || byCommentrayPath === null) {
@@ -18,7 +24,7 @@ export function assertValidIndex(value) {
18
24
  for (const [key, entry] of Object.entries(byCommentrayPath)) {
19
25
  validateCommentrayEntry(key, entry);
20
26
  }
21
- return obj;
27
+ return { ...obj, schemaVersion: CURRENT_SCHEMA_VERSION };
22
28
  }
23
29
  function validateCommentrayEntry(commentrayPathKey, entry) {
24
30
  if (typeof entry !== "object" || entry === null) {
@@ -40,17 +46,35 @@ function validateCommentrayEntry(commentrayPathKey, entry) {
40
46
  for (const block of e.blocks)
41
47
  validateBlock(commentrayPathKey, block);
42
48
  }
43
- function validateBlock(commentrayPathKey, block) {
44
- if (typeof block !== "object" || block === null) {
45
- throw new TypeError(`Invalid block under ${commentrayPathKey}`);
49
+ function parseValidatedMarkerId(commentrayPathKey, raw) {
50
+ try {
51
+ return assertValidMarkerId(raw);
46
52
  }
47
- const b = block;
48
- if (typeof b.id !== "string") {
49
- throw new TypeError(`block.id must be a string under ${commentrayPathKey}`);
53
+ catch (e) {
54
+ throw new TypeError(`block.id invalid under ${commentrayPathKey}: ${e instanceof Error ? e.message : String(e)}`, { cause: e });
50
55
  }
51
- if (typeof b.anchor !== "string") {
52
- throw new TypeError(`block.anchor must be a string under ${commentrayPathKey}`);
56
+ }
57
+ function parseValidatedAnchor(commentrayPathKey, raw) {
58
+ try {
59
+ return parseAnchor(raw);
60
+ }
61
+ catch (e) {
62
+ throw new TypeError(`Invalid block.anchor under ${commentrayPathKey}: ${e instanceof Error ? e.message : String(e)}`, { cause: e });
63
+ }
64
+ }
65
+ function assertBlockMarkerAnchorConsistency(commentrayPathKey, b, bid, parsedAnchor) {
66
+ if (parsedAnchor.kind === "marker" && parsedAnchor.id !== bid) {
67
+ throw new TypeError(`block.id must match marker anchor id (got id=${b.id}, anchor=${b.anchor}) under ${commentrayPathKey}`);
53
68
  }
69
+ if (parsedAnchor.kind === "marker" &&
70
+ b.markerId !== undefined &&
71
+ typeof b.markerId === "string" &&
72
+ b.markerId.trim() !== "" &&
73
+ assertValidMarkerId(b.markerId) !== parsedAnchor.id) {
74
+ throw new TypeError(`block.markerId must match marker anchor id under ${commentrayPathKey} (block ${b.id})`);
75
+ }
76
+ }
77
+ function validateBlockOptionalFields(commentrayPathKey, b) {
54
78
  if (b.lastVerifiedCommit !== undefined && typeof b.lastVerifiedCommit !== "string") {
55
79
  throw new TypeError(`block.lastVerifiedCommit must be a string when present under ${commentrayPathKey}`);
56
80
  }
@@ -60,22 +84,27 @@ function validateBlock(commentrayPathKey, block) {
60
84
  if (b.markerId !== undefined && typeof b.markerId !== "string") {
61
85
  throw new TypeError(`block.markerId must be a string when present under ${commentrayPathKey}`);
62
86
  }
63
- if (b.fingerprint !== undefined)
64
- validateFingerprint(commentrayPathKey, b.fingerprint);
65
- }
66
- function validateFingerprint(commentrayPathKey, fp) {
67
- if (typeof fp !== "object" || fp === null) {
68
- throw new TypeError(`block.fingerprint must be an object under ${commentrayPathKey}`);
87
+ if (b.snippet !== undefined && typeof b.snippet !== "string") {
88
+ throw new TypeError(`block.snippet must be a string when present under ${commentrayPathKey}`);
69
89
  }
70
- const f = fp;
71
- if (typeof f.startLine !== "string") {
72
- throw new TypeError(`block.fingerprint.startLine must be a string under ${commentrayPathKey}`);
90
+ if (b.fingerprint !== undefined) {
91
+ throw new TypeError(`block.fingerprint is no longer supported under ${commentrayPathKey}; re-open the repo to migrate index.json`);
73
92
  }
74
- if (typeof f.endLine !== "string") {
75
- throw new TypeError(`block.fingerprint.endLine must be a string under ${commentrayPathKey}`);
93
+ }
94
+ function validateBlock(commentrayPathKey, block) {
95
+ if (typeof block !== "object" || block === null) {
96
+ throw new TypeError(`Invalid block under ${commentrayPathKey}`);
76
97
  }
77
- if (typeof f.lineCount !== "number" || !Number.isInteger(f.lineCount) || f.lineCount < 1) {
78
- throw new TypeError(`block.fingerprint.lineCount must be a positive integer under ${commentrayPathKey}`);
98
+ const b = block;
99
+ if (typeof b.id !== "string") {
100
+ throw new TypeError(`block.id must be a string under ${commentrayPathKey}`);
101
+ }
102
+ const bid = parseValidatedMarkerId(commentrayPathKey, b.id);
103
+ if (typeof b.anchor !== "string") {
104
+ throw new TypeError(`block.anchor must be a string under ${commentrayPathKey}`);
79
105
  }
106
+ const parsedAnchor = parseValidatedAnchor(commentrayPathKey, b.anchor);
107
+ assertBlockMarkerAnchorConsistency(commentrayPathKey, b, bid, parsedAnchor);
108
+ validateBlockOptionalFields(commentrayPathKey, b);
80
109
  }
81
110
  //# sourceMappingURL=metadata.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"metadata.js","sourceRoot":"","sources":["../src/metadata.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"metadata.js","sourceRoot":"","sources":["../src/metadata.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import type { CommentrayIndex } from "./model.js";
2
+ export type FlatCompanionEntry = {
3
+ /** Repo-relative path, e.g. `.commentray/source/README.md.md`. */
4
+ flatCommentrayPath: string;
5
+ /** Repo-relative primary source path, e.g. `README.md`. */
6
+ sourcePath: string;
7
+ };
8
+ export type AnglesMigrationMove = {
9
+ fromRepoRel: string;
10
+ toRepoRel: string;
11
+ sourcePath: string;
12
+ };
13
+ export type AnglesMigrationPlan = {
14
+ moves: AnglesMigrationMove[];
15
+ /** Old flat companion path → new angle Markdown path (repo-relative). */
16
+ flatToAnglePath: Map<string, string>;
17
+ };
18
+ /**
19
+ * Lists every flat-layout companion Markdown file under `{storage}/source/`.
20
+ * Returns an empty list when Angles layout is already enabled (sentinel present).
21
+ */
22
+ export declare function discoverFlatCompanionMarkdownFiles(repoRoot: string, storageDir?: string): Promise<FlatCompanionEntry[]>;
23
+ /** `rel` is relative to `{storage}/source/` using `/` separators. */
24
+ export declare function flatRelToSourcePath(relFromSourceDir: string): string;
25
+ export declare function planAnglesMigrationFromCompanions(companions: FlatCompanionEntry[], angleId: string, storageDir: string): AnglesMigrationPlan;
26
+ export declare function rewriteIndexKeysForAnglesMigration(index: CommentrayIndex, flatToAnglePath: Map<string, string>): CommentrayIndex;
27
+ //# sourceMappingURL=migrate-angles-layout.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migrate-angles-layout.d.ts","sourceRoot":"","sources":["../src/migrate-angles-layout.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,eAAe,EAAwB,MAAM,YAAY,CAAC;AAQxE,MAAM,MAAM,kBAAkB,GAAG;IAC/B,kEAAkE;IAClE,kBAAkB,EAAE,MAAM,CAAC;IAC3B,2DAA2D;IAC3D,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,KAAK,EAAE,mBAAmB,EAAE,CAAC;IAC7B,yEAAyE;IACzE,eAAe,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACtC,CAAC;AAEF;;;GAGG;AACH,wBAAsB,kCAAkC,CACtD,QAAQ,EAAE,MAAM,EAChB,UAAU,SAAgB,GACzB,OAAO,CAAC,kBAAkB,EAAE,CAAC,CA2B/B;AAED,qEAAqE;AACrE,wBAAgB,mBAAmB,CAAC,gBAAgB,EAAE,MAAM,GAAG,MAAM,CAKpE;AAED,wBAAgB,iCAAiC,CAC/C,UAAU,EAAE,kBAAkB,EAAE,EAChC,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,GACjB,mBAAmB,CAerB;AAED,wBAAgB,kCAAkC,CAChD,KAAK,EAAE,eAAe,EACtB,eAAe,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GACnC,eAAe,CAOjB"}
@@ -0,0 +1,72 @@
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { assertValidAngleId } from "./angles.js";
4
+ import { commentrayAnglesLayoutEnabled, commentrayMarkdownPathForAngle, normalizeRepoRelativePath, } from "./paths.js";
5
+ import { collectMdRelPathsUnderSourceAbs } from "./walk-commentray-source-md.js";
6
+ /**
7
+ * Lists every flat-layout companion Markdown file under `{storage}/source/`.
8
+ * Returns an empty list when Angles layout is already enabled (sentinel present).
9
+ */
10
+ export async function discoverFlatCompanionMarkdownFiles(repoRoot, storageDir = ".commentray") {
11
+ if (commentrayAnglesLayoutEnabled(repoRoot, storageDir)) {
12
+ return [];
13
+ }
14
+ const storageNorm = normalizeRepoRelativePath(storageDir.replaceAll("\\", "/"));
15
+ const sourceAbs = path.join(repoRoot, ...storageNorm.split("/"), "source");
16
+ let stat;
17
+ try {
18
+ stat = await fs.stat(sourceAbs);
19
+ }
20
+ catch {
21
+ return [];
22
+ }
23
+ if (!stat.isDirectory()) {
24
+ return [];
25
+ }
26
+ const rels = await collectMdRelPathsUnderSourceAbs(sourceAbs);
27
+ const out = [];
28
+ for (const rel of rels) {
29
+ if (rel === ".default" || rel.startsWith(".default/"))
30
+ continue;
31
+ if (!rel.endsWith(".md"))
32
+ continue;
33
+ const sourcePath = flatRelToSourcePath(rel);
34
+ const flatCommentrayPath = path.posix.join(storageNorm, "source", rel);
35
+ out.push({ flatCommentrayPath, sourcePath });
36
+ }
37
+ out.sort((a, b) => a.flatCommentrayPath.localeCompare(b.flatCommentrayPath));
38
+ return out;
39
+ }
40
+ /** `rel` is relative to `{storage}/source/` using `/` separators. */
41
+ export function flatRelToSourcePath(relFromSourceDir) {
42
+ if (!relFromSourceDir.endsWith(".md")) {
43
+ throw new Error(`Expected *.md under source, got: ${relFromSourceDir}`);
44
+ }
45
+ return relFromSourceDir.slice(0, Math.max(0, relFromSourceDir.length - 3));
46
+ }
47
+ export function planAnglesMigrationFromCompanions(companions, angleId, storageDir) {
48
+ const id = assertValidAngleId(angleId);
49
+ const moves = [];
50
+ const flatToAnglePath = new Map();
51
+ for (const c of companions) {
52
+ const toRepoRel = commentrayMarkdownPathForAngle(c.sourcePath, id, storageDir);
53
+ if (c.flatCommentrayPath === toRepoRel)
54
+ continue;
55
+ moves.push({
56
+ fromRepoRel: c.flatCommentrayPath,
57
+ toRepoRel: toRepoRel,
58
+ sourcePath: c.sourcePath,
59
+ });
60
+ flatToAnglePath.set(c.flatCommentrayPath, toRepoRel);
61
+ }
62
+ return { moves, flatToAnglePath };
63
+ }
64
+ export function rewriteIndexKeysForAnglesMigration(index, flatToAnglePath) {
65
+ const next = {};
66
+ for (const [k, entry] of Object.entries(index.byCommentrayPath)) {
67
+ const newKey = flatToAnglePath.get(k) ?? k;
68
+ next[newKey] = { ...entry, commentrayPath: newKey };
69
+ }
70
+ return { ...index, byCommentrayPath: next };
71
+ }
72
+ //# sourceMappingURL=migrate-angles-layout.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migrate-angles-layout.js","sourceRoot":"","sources":["../src/migrate-angles-layout.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"migrate.d.ts","sourceRoot":"","sources":["../src/migrate.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,eAAe,EAGrB,MAAM,YAAY,CAAC;AAIpB,uEAAuE;AACvE,wBAAgB,YAAY,CAAC,GAAG,EAAE,OAAO,GAAG;IAAE,KAAK,EAAE,eAAe,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAqCvF"}
1
+ {"version":3,"file":"migrate.d.ts","sourceRoot":"","sources":["../src/migrate.ts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,eAAe,EAIrB,MAAM,YAAY,CAAC;AAIpB,uEAAuE;AACvE,wBAAgB,YAAY,CAAC,GAAG,EAAE,OAAO,GAAG;IAAE,KAAK,EAAE,eAAe,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAuDvF"}
package/dist/migrate.js CHANGED
@@ -1,4 +1,5 @@
1
- import { CURRENT_SCHEMA_VERSION, } from "./model.js";
1
+ import { describeIndexSchemaRemediation } from "./index-schema-messages.js";
2
+ import { coerceIndexSchemaVersion, CURRENT_SCHEMA_VERSION, } from "./model.js";
2
3
  const LEGACY_SCHEMA_VERSION = 2;
3
4
  /** Returns migrated index and whether the file should be rewritten. */
4
5
  export function migrateIndex(raw) {
@@ -9,7 +10,10 @@ export function migrateIndex(raw) {
9
10
  };
10
11
  }
11
12
  const obj = raw;
12
- const version = obj.schemaVersion;
13
+ const version = coerceIndexSchemaVersion(obj.schemaVersion);
14
+ if (version === null && obj.schemaVersion !== undefined) {
15
+ throw new TypeError(`Invalid index schemaVersion: ${String(obj.schemaVersion)}`);
16
+ }
13
17
  if (version === CURRENT_SCHEMA_VERSION) {
14
18
  const index = obj;
15
19
  return { index, changed: false };
@@ -24,7 +28,7 @@ export function migrateIndex(raw) {
24
28
  byCommentrayPath,
25
29
  };
26
30
  const before = JSON.stringify({
27
- schemaVersion: version ?? 0,
31
+ schemaVersion: version === undefined ? 0 : version,
28
32
  bySourceFile: obj.bySourceFile ?? {},
29
33
  byCommentrayPath: obj.byCommentrayPath ?? {},
30
34
  });
@@ -32,7 +36,19 @@ export function migrateIndex(raw) {
32
36
  const changed = before !== after;
33
37
  return { index: next, changed };
34
38
  }
35
- throw new Error(`Cannot migrate from schemaVersion ${String(version)}`);
39
+ if (typeof version === "number" && version > CURRENT_SCHEMA_VERSION) {
40
+ /**
41
+ * Future CLI may bump `schemaVersion` before every consumer updates. Prefer opening
42
+ * the repo over hard failure: keep `byCommentrayPath` as parsed, stamp this build’s
43
+ * schema, and let `assertValidIndex` reject only truly incompatible shapes.
44
+ */
45
+ const byCommentrayPath = toByCommentrayPath(obj);
46
+ return {
47
+ index: { schemaVersion: CURRENT_SCHEMA_VERSION, byCommentrayPath },
48
+ changed: true,
49
+ };
50
+ }
51
+ throw new Error(`Cannot migrate index.json from schemaVersion ${String(obj.schemaVersion)}. ${describeIndexSchemaRemediation(obj.schemaVersion)}`);
36
52
  }
37
53
  function toByCommentrayPath(obj) {
38
54
  if (obj.byCommentrayPath &&
@@ -1 +1 @@
1
- {"version":3,"file":"migrate.js","sourceRoot":"","sources":["../src/migrate.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"migrate.js","sourceRoot":"","sources":["../src/migrate.ts"],"names":[],"mappings":"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"}
package/dist/model.d.ts CHANGED
@@ -1,21 +1,3 @@
1
- /**
2
- * Content fingerprint of a source range, used to re-resolve the block's
3
- * anchor after lines drift (insertions or deletions in the source).
4
- *
5
- * A fingerprint is intentionally narrow: trimmed text of the first and last
6
- * lines plus the original line count. Re-resolution is a search, not a
7
- * guarantee: when the fingerprint still appears uniquely near the old
8
- * location we silently update the line numbers; otherwise we surface a
9
- * diagnostic so a human can decide.
10
- */
11
- export type CommentrayBlockFingerprint = {
12
- /** Trimmed content of the first line of the original range. */
13
- startLine: string;
14
- /** Trimmed content of the last line of the original range. */
15
- endLine: string;
16
- /** Number of lines the range originally spanned (end - start + 1). */
17
- lineCount: number;
18
- };
19
1
  /** Commentray block aligned to a region of a primary source file. */
20
2
  export type CommentrayBlock = {
21
3
  /** Stable id within the commentray markdown file. */
@@ -23,16 +5,16 @@ export type CommentrayBlock = {
23
5
  /** Human or machine anchor string (see anchor grammar in docs). */
24
6
  anchor: string;
25
7
  /**
26
- * Optional drift-resolution fingerprint. Present when the block's range
27
- * was captured from source content; absent when the anchor is purely a
28
- * symbol or marker reference that does not need content-based re-sync.
8
+ * Optional unified-diff–style capture of the anchored source lines (see
9
+ * `block-snippet.ts`). Self-contained string in index.json not a nested
10
+ * JSON region object.
29
11
  */
30
- fingerprint?: CommentrayBlockFingerprint;
12
+ snippet?: string;
31
13
  /**
32
- * Optional marker-based anchor. When set, drift resolution looks for a
33
- * pair of host-language comments of the form `commentray:start id=<markerId>`
34
- * and `commentray:end` in the source; the lines between them become the
35
- * block's effective range. Markers are drift-proof but invasive.
14
+ * When the anchor is `marker:<id>`, the same id appears in source as the
15
+ * region name `commentray:<id>` (e.g. `//#region` / `//#endregion` in
16
+ * TypeScript, aligned with the Region Marker extension), or in legacy
17
+ * `commentray:start id=…` / `commentray:end id=…` line comments.
36
18
  */
37
19
  markerId?: string;
38
20
  /** Last human-verified commit (full SHA) when this block was considered accurate. */
@@ -59,4 +41,9 @@ export type CommentrayIndex = {
59
41
  byCommentrayPath: Record<string, SourceFileIndexEntry>;
60
42
  };
61
43
  export declare const CURRENT_SCHEMA_VERSION: 3;
44
+ /**
45
+ * Normalizes `index.json` `schemaVersion` after `JSON.parse` (integer, or
46
+ * rare string forms like `"3"`).
47
+ */
48
+ export declare function coerceIndexSchemaVersion(raw: unknown): number | undefined | null;
62
49
  //# sourceMappingURL=model.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,MAAM,MAAM,0BAA0B,GAAG;IACvC,+DAA+D;IAC/D,SAAS,EAAE,MAAM,CAAC;IAClB,8DAA8D;IAC9D,OAAO,EAAE,MAAM,CAAC;IAChB,sEAAsE;IACtE,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,qEAAqE;AACrE,MAAM,MAAM,eAAe,GAAG;IAC5B,qDAAqD;IACrD,EAAE,EAAE,MAAM,CAAC;IACX,mEAAmE;IACnE,MAAM,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,WAAW,CAAC,EAAE,0BAA0B,CAAC;IACzC;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,qFAAqF;IACrF,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,0EAA0E;IAC1E,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,8CAA8C;IAC9C,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,yEAAyE;IACzE,UAAU,EAAE,MAAM,CAAC;IACnB,0DAA0D;IAC1D,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,eAAe,EAAE,CAAC;CAC3B,CAAC;AAEF,2EAA2E;AAC3E,MAAM,MAAM,eAAe,GAAG;IAC5B,aAAa,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC;CACxD,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAG,CAAU,CAAC"}
1
+ {"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,MAAM,MAAM,eAAe,GAAG;IAC5B,qDAAqD;IACrD,EAAE,EAAE,MAAM,CAAC;IACX,mEAAmE;IACnE,MAAM,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,qFAAqF;IACrF,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,0EAA0E;IAC1E,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,8CAA8C;IAC9C,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,yEAAyE;IACzE,UAAU,EAAE,MAAM,CAAC;IACnB,0DAA0D;IAC1D,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,eAAe,EAAE,CAAC;CAC3B,CAAC;AAEF,2EAA2E;AAC3E,MAAM,MAAM,eAAe,GAAG;IAC5B,aAAa,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC;CACxD,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAG,CAAU,CAAC;AAEjD;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,GAAG,IAAI,CAQhF"}
package/dist/model.js CHANGED
@@ -1,2 +1,18 @@
1
1
  export const CURRENT_SCHEMA_VERSION = 3;
2
+ /**
3
+ * Normalizes `index.json` `schemaVersion` after `JSON.parse` (integer, or
4
+ * rare string forms like `"3"`).
5
+ */
6
+ export function coerceIndexSchemaVersion(raw) {
7
+ if (raw === undefined)
8
+ return undefined;
9
+ if (typeof raw === "number" && Number.isInteger(raw))
10
+ return raw;
11
+ if (typeof raw === "string") {
12
+ const t = raw.trim();
13
+ if (/^\d+$/.test(t))
14
+ return Number.parseInt(t, 10);
15
+ }
16
+ return null;
17
+ }
2
18
  //# sourceMappingURL=model.js.map
package/dist/model.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"model.js","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"AAgEA,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAU,CAAC"}
1
+ {"version":3,"file":"model.js","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"AA6CA,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAU,CAAC;AAEjD;;;GAGG;AACH,MAAM,UAAU,wBAAwB,CAAC,GAAY;IACnD,IAAI,GAAG,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IACxC,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC;QAAE,OAAO,GAAG,CAAC;IACjE,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;QAC5B,MAAM,CAAC,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;QACrB,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;YAAE,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACrD,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
package/dist/paths.d.ts CHANGED
@@ -11,8 +11,14 @@
11
11
  * `..` segments are traversal.
12
12
  */
13
13
  export declare function normalizeRepoRelativePath(relativePath: string): string;
14
+ /**
15
+ * Resolve `repoRelative` under `repoRootAbs` after {@link normalizeRepoRelativePath} validation,
16
+ * then assert the absolute path cannot escape `repoRootAbs` (defense in depth for index or
17
+ * nav-derived paths, not only hand-edited config).
18
+ */
19
+ export declare function resolvePathUnderRepoRoot(repoRootAbs: string, repoRelative: string): string;
14
20
  /** Commentray Markdown path for a repo-relative source file (implicit default angle, flat layout). */
15
- export declare function commentrayMarkdownPath(sourceRepoRelativePath: string): string;
21
+ export declare function commentrayMarkdownPath(sourceRepoRelativePath: string, storageDir?: string): string;
16
22
  /**
17
23
  * Repo-relative path to the **Angles sentinel**: if this path exists as a file or directory under
18
24
  * the storage root, the repository opts into per-source **Angles** layout (see `docs/spec/storage.md`).
@@ -1 +1 @@
1
- {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAKA;;;;;;;;;;;GAWG;AACH,wBAAgB,yBAAyB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAWtE;AAED,sGAAsG;AACtG,wBAAgB,sBAAsB,CAAC,sBAAsB,EAAE,MAAM,GAAG,MAAM,CAG7E;AAED;;;;GAIG;AACH,wBAAgB,4BAA4B,CAAC,UAAU,SAAgB,GAAG,MAAM,CAG/E;AAED;;;GAGG;AACH,wBAAgB,6BAA6B,CAC3C,QAAQ,EAAE,MAAM,EAChB,UAAU,SAAgB,GACzB,OAAO,CAIT;AAED;;;GAGG;AACH,wBAAgB,8BAA8B,CAC5C,sBAAsB,EAAE,MAAM,EAC9B,OAAO,EAAE,MAAM,EACf,UAAU,SAAgB,GACzB,MAAM,CAKR;AAED,uDAAuD;AACvD,wBAAgB,wBAAwB,IAAI,MAAM,CAEjD"}
1
+ {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAKA;;;;;;;;;;;GAWG;AACH,wBAAgB,yBAAyB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAWtE;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,WAAW,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CAS1F;AAED,sGAAsG;AACtG,wBAAgB,sBAAsB,CACpC,sBAAsB,EAAE,MAAM,EAC9B,UAAU,SAAgB,GACzB,MAAM,CAIR;AAED;;;;GAIG;AACH,wBAAgB,4BAA4B,CAAC,UAAU,SAAgB,GAAG,MAAM,CAG/E;AAED;;;GAGG;AACH,wBAAgB,6BAA6B,CAC3C,QAAQ,EAAE,MAAM,EAChB,UAAU,SAAgB,GACzB,OAAO,CAIT;AAED;;;GAGG;AACH,wBAAgB,8BAA8B,CAC5C,sBAAsB,EAAE,MAAM,EAC9B,OAAO,EAAE,MAAM,EACf,UAAU,SAAgB,GACzB,MAAM,CAKR;AAED,uDAAuD;AACvD,wBAAgB,wBAAwB,IAAI,MAAM,CAEjD"}
package/dist/paths.js CHANGED
@@ -25,10 +25,26 @@ export function normalizeRepoRelativePath(relativePath) {
25
25
  }
26
26
  return segments.join("/");
27
27
  }
28
+ /**
29
+ * Resolve `repoRelative` under `repoRootAbs` after {@link normalizeRepoRelativePath} validation,
30
+ * then assert the absolute path cannot escape `repoRootAbs` (defense in depth for index or
31
+ * nav-derived paths, not only hand-edited config).
32
+ */
33
+ export function resolvePathUnderRepoRoot(repoRootAbs, repoRelative) {
34
+ const rel = normalizeRepoRelativePath(repoRelative);
35
+ const root = path.resolve(repoRootAbs);
36
+ const resolved = path.resolve(root, rel);
37
+ const back = path.relative(root, resolved);
38
+ if (back.startsWith("..") || path.isAbsolute(back)) {
39
+ throw new Error(`Resolved path leaves repository root: ${repoRelative}`);
40
+ }
41
+ return resolved;
42
+ }
28
43
  /** Commentray Markdown path for a repo-relative source file (implicit default angle, flat layout). */
29
- export function commentrayMarkdownPath(sourceRepoRelativePath) {
44
+ export function commentrayMarkdownPath(sourceRepoRelativePath, storageDir = ".commentray") {
30
45
  const normalized = normalizeRepoRelativePath(sourceRepoRelativePath);
31
- return path.posix.join(".commentray", "source", `${normalized}.md`);
46
+ const root = normalizeRepoRelativePath(storageDir.replaceAll("\\", "/"));
47
+ return path.posix.join(root, "source", `${normalized}.md`);
32
48
  }
33
49
  /**
34
50
  * Repo-relative path to the **Angles sentinel**: if this path exists as a file or directory under