ctxr-cli 0.23.0 → 0.25.0

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 (197) hide show
  1. package/README.md +65 -5
  2. package/dist/commands/graph-diff.d.ts +33 -0
  3. package/dist/commands/graph-diff.d.ts.map +1 -0
  4. package/dist/commands/graph-diff.js +52 -0
  5. package/dist/commands/graph-diff.js.map +1 -0
  6. package/dist/commands/land.d.ts +50 -0
  7. package/dist/commands/land.d.ts.map +1 -0
  8. package/dist/commands/land.js +414 -0
  9. package/dist/commands/land.js.map +1 -0
  10. package/dist/commands/publish-check.d.ts +6 -0
  11. package/dist/commands/publish-check.d.ts.map +1 -1
  12. package/dist/commands/publish-check.js +78 -3
  13. package/dist/commands/publish-check.js.map +1 -1
  14. package/dist/commands/publish-gather.d.ts.map +1 -1
  15. package/dist/commands/publish-gather.js +4 -1
  16. package/dist/commands/publish-gather.js.map +1 -1
  17. package/dist/commands/publish-new.d.ts +5 -0
  18. package/dist/commands/publish-new.d.ts.map +1 -1
  19. package/dist/commands/publish-new.js +30 -10
  20. package/dist/commands/publish-new.js.map +1 -1
  21. package/dist/commands/publish-stamp.d.ts +32 -0
  22. package/dist/commands/publish-stamp.d.ts.map +1 -0
  23. package/dist/commands/publish-stamp.js +78 -0
  24. package/dist/commands/publish-stamp.js.map +1 -0
  25. package/dist/commands/publish-urls.d.ts +13 -0
  26. package/dist/commands/publish-urls.d.ts.map +1 -1
  27. package/dist/commands/publish-urls.js +23 -6
  28. package/dist/commands/publish-urls.js.map +1 -1
  29. package/dist/commands/review-list.d.ts +34 -0
  30. package/dist/commands/review-list.d.ts.map +1 -0
  31. package/dist/commands/review-list.js +49 -0
  32. package/dist/commands/review-list.js.map +1 -0
  33. package/dist/commands/serve.d.ts +3 -6
  34. package/dist/commands/serve.d.ts.map +1 -1
  35. package/dist/commands/serve.js +106 -9
  36. package/dist/commands/serve.js.map +1 -1
  37. package/dist/config/schema.d.ts +40 -0
  38. package/dist/config/schema.d.ts.map +1 -1
  39. package/dist/config/schema.js +39 -0
  40. package/dist/config/schema.js.map +1 -1
  41. package/dist/core/approval/decision.d.ts +73 -0
  42. package/dist/core/approval/decision.d.ts.map +1 -0
  43. package/dist/core/approval/decision.js +166 -0
  44. package/dist/core/approval/decision.js.map +1 -0
  45. package/dist/core/approval/file-diff.d.ts +32 -0
  46. package/dist/core/approval/file-diff.d.ts.map +1 -0
  47. package/dist/core/approval/file-diff.js +83 -0
  48. package/dist/core/approval/file-diff.js.map +1 -0
  49. package/dist/core/approval/identity.d.ts +34 -0
  50. package/dist/core/approval/identity.d.ts.map +1 -0
  51. package/dist/core/approval/identity.js +105 -0
  52. package/dist/core/approval/identity.js.map +1 -0
  53. package/dist/core/approval/landing-record.d.ts +17 -0
  54. package/dist/core/approval/landing-record.d.ts.map +1 -0
  55. package/dist/core/approval/landing-record.js +30 -0
  56. package/dist/core/approval/landing-record.js.map +1 -0
  57. package/dist/core/approval/resolver.d.ts +15 -0
  58. package/dist/core/approval/resolver.d.ts.map +1 -0
  59. package/dist/core/approval/resolver.js +41 -0
  60. package/dist/core/approval/resolver.js.map +1 -0
  61. package/dist/core/approval/sessions.d.ts +36 -0
  62. package/dist/core/approval/sessions.d.ts.map +1 -0
  63. package/dist/core/approval/sessions.js +76 -0
  64. package/dist/core/approval/sessions.js.map +1 -0
  65. package/dist/core/browse/approve.d.ts +45 -0
  66. package/dist/core/browse/approve.d.ts.map +1 -0
  67. package/dist/core/browse/approve.js +239 -0
  68. package/dist/core/browse/approve.js.map +1 -0
  69. package/dist/core/browse/diagram-assets.d.ts +15 -0
  70. package/dist/core/browse/diagram-assets.d.ts.map +1 -0
  71. package/dist/core/browse/diagram-assets.js +35 -0
  72. package/dist/core/browse/diagram-assets.js.map +1 -0
  73. package/dist/core/browse/page-url.d.ts +22 -0
  74. package/dist/core/browse/page-url.d.ts.map +1 -1
  75. package/dist/core/browse/page-url.js +31 -0
  76. package/dist/core/browse/page-url.js.map +1 -1
  77. package/dist/core/browse/render.d.ts +10 -1
  78. package/dist/core/browse/render.d.ts.map +1 -1
  79. package/dist/core/browse/render.js +23 -1
  80. package/dist/core/browse/render.js.map +1 -1
  81. package/dist/core/browse/review.d.ts +21 -0
  82. package/dist/core/browse/review.d.ts.map +1 -0
  83. package/dist/core/browse/review.js +52 -0
  84. package/dist/core/browse/review.js.map +1 -0
  85. package/dist/core/browse/templates.d.ts +4 -1
  86. package/dist/core/browse/templates.d.ts.map +1 -1
  87. package/dist/core/browse/templates.js +18 -2
  88. package/dist/core/browse/templates.js.map +1 -1
  89. package/dist/core/checks/organize-checks.d.ts +17 -0
  90. package/dist/core/checks/organize-checks.d.ts.map +1 -1
  91. package/dist/core/checks/organize-checks.js +116 -0
  92. package/dist/core/checks/organize-checks.js.map +1 -1
  93. package/dist/core/errors.d.ts +67 -0
  94. package/dist/core/errors.d.ts.map +1 -1
  95. package/dist/core/errors.js +160 -0
  96. package/dist/core/errors.js.map +1 -1
  97. package/dist/core/forge/credentials.d.ts +69 -0
  98. package/dist/core/forge/credentials.d.ts.map +1 -0
  99. package/dist/core/forge/credentials.js +197 -0
  100. package/dist/core/forge/credentials.js.map +1 -0
  101. package/dist/core/forge/github.d.ts +73 -0
  102. package/dist/core/forge/github.d.ts.map +1 -0
  103. package/dist/core/forge/github.js +101 -0
  104. package/dist/core/forge/github.js.map +1 -0
  105. package/dist/core/git/exec.d.ts +25 -0
  106. package/dist/core/git/exec.d.ts.map +1 -1
  107. package/dist/core/git/exec.js +100 -2
  108. package/dist/core/git/exec.js.map +1 -1
  109. package/dist/core/graph/diff-block.d.ts +6 -0
  110. package/dist/core/graph/diff-block.d.ts.map +1 -0
  111. package/dist/core/graph/diff-block.js +63 -0
  112. package/dist/core/graph/diff-block.js.map +1 -0
  113. package/dist/core/graph/diff-document.d.ts +38 -0
  114. package/dist/core/graph/diff-document.d.ts.map +1 -0
  115. package/dist/core/graph/diff-document.js +117 -0
  116. package/dist/core/graph/diff-document.js.map +1 -0
  117. package/dist/core/graph/diff.d.ts +123 -0
  118. package/dist/core/graph/diff.d.ts.map +1 -0
  119. package/dist/core/graph/diff.js +253 -0
  120. package/dist/core/graph/diff.js.map +1 -0
  121. package/dist/core/graph/tree.d.ts +24 -0
  122. package/dist/core/graph/tree.d.ts.map +1 -0
  123. package/dist/core/graph/tree.js +45 -0
  124. package/dist/core/graph/tree.js.map +1 -0
  125. package/dist/core/notes/list.d.ts +10 -0
  126. package/dist/core/notes/list.d.ts.map +1 -1
  127. package/dist/core/notes/list.js +35 -12
  128. package/dist/core/notes/list.js.map +1 -1
  129. package/dist/core/publish/filing.d.ts +12 -12
  130. package/dist/core/publish/filing.d.ts.map +1 -1
  131. package/dist/core/publish/filing.js +20 -18
  132. package/dist/core/publish/filing.js.map +1 -1
  133. package/dist/core/publish/lifespan.d.ts +37 -0
  134. package/dist/core/publish/lifespan.d.ts.map +1 -0
  135. package/dist/core/publish/lifespan.js +59 -0
  136. package/dist/core/publish/lifespan.js.map +1 -0
  137. package/dist/core/publish/represents.d.ts +72 -0
  138. package/dist/core/publish/represents.d.ts.map +1 -0
  139. package/dist/core/publish/represents.js +83 -0
  140. package/dist/core/publish/represents.js.map +1 -0
  141. package/dist/run.d.ts.map +1 -1
  142. package/dist/run.js +60 -4
  143. package/dist/run.js.map +1 -1
  144. package/dist/version.d.ts +1 -1
  145. package/dist/version.js +1 -1
  146. package/package.json +2 -1
  147. package/templates/approve/approve-button.md +1 -0
  148. package/templates/approve/author-heading.md +1 -0
  149. package/templates/approve/author-note.md +1 -0
  150. package/templates/approve/comment-label.md +1 -0
  151. package/templates/approve/comment-required.md +1 -0
  152. package/templates/approve/commits-heading.md +1 -0
  153. package/templates/approve/decision-heading.md +1 -0
  154. package/templates/approve/decision-note.md +1 -0
  155. package/templates/approve/diff-binary.md +1 -0
  156. package/templates/approve/diff-empty.md +1 -0
  157. package/templates/approve/diff-heading.md +1 -0
  158. package/templates/approve/facts-heading.md +1 -0
  159. package/templates/approve/forge-unreachable.md +1 -0
  160. package/templates/approve/github-app-manifest.json +15 -0
  161. package/templates/approve/head-missing.md +1 -0
  162. package/templates/approve/index-empty.md +1 -0
  163. package/templates/approve/index-heading.md +1 -0
  164. package/templates/approve/index-intro.md +1 -0
  165. package/templates/approve/landed.md +1 -0
  166. package/templates/approve/moved-head.md +1 -0
  167. package/templates/approve/no-pull.md +1 -0
  168. package/templates/approve/not-open.md +1 -0
  169. package/templates/approve/pages-heading.md +1 -0
  170. package/templates/approve/pages-note.md +1 -0
  171. package/templates/approve/record-failed.md +1 -0
  172. package/templates/approve/request-changes-button.md +1 -0
  173. package/templates/approve/state-line.md +1 -0
  174. package/templates/conventions/baseline-conventions.md +6 -0
  175. package/templates/graph/knowledge-changes/archived-item.md +1 -0
  176. package/templates/graph/knowledge-changes/archived.md +1 -0
  177. package/templates/graph/knowledge-changes/bare-route.md +2 -0
  178. package/templates/graph/knowledge-changes/block.md +10 -0
  179. package/templates/graph/knowledge-changes/counts.md +1 -0
  180. package/templates/graph/knowledge-changes/dangling-item.md +1 -0
  181. package/templates/graph/knowledge-changes/dangling.md +1 -0
  182. package/templates/graph/knowledge-changes/empty.md +1 -0
  183. package/templates/graph/knowledge-changes/reason-ambiguous.md +1 -0
  184. package/templates/graph/knowledge-changes/reason-not_found.md +1 -0
  185. package/templates/graph/knowledge-changes/review.md +4 -0
  186. package/templates/graph/review/moved-head.md +1 -0
  187. package/templates/land/resolver.md +12 -0
  188. package/templates/serve/diagrams.mjs +136 -0
  189. package/templates/serve/shell.html +1 -1
  190. package/templates/serve/style.css +90 -0
  191. package/templates/skills/ctxr-land.md +37 -31
  192. package/templates/skills/ctxr-organize-audit.md +19 -0
  193. package/templates/skills/ctxr-publish.md +100 -45
  194. package/templates/skills/ctxr-second-opinion/run.mjs +28 -17
  195. package/templates/skills/ctxr-second-opinion.md +19 -14
  196. package/templates/skills/ctxr-session-lifecycle.md +9 -0
  197. package/templates/skills/ctxr-submit.md +28 -17
@@ -0,0 +1,101 @@
1
+ import { execFile } from 'node:child_process';
2
+ import { promisify } from 'node:util';
3
+ const execFileAsync = promisify(execFile);
4
+ /** A `gh api` call that did not succeed. `status` is the HTTP status when `gh` reported one. */
5
+ export class ForgeRequestError extends Error {
6
+ status;
7
+ constructor(endpoint, status, detail) {
8
+ super(`forge request ${endpoint} failed${status === null ? '' : ` (HTTP ${status})`}: ${detail}`);
9
+ this.name = 'ForgeRequestError';
10
+ this.status = status;
11
+ }
12
+ }
13
+ function toPull(raw) {
14
+ return {
15
+ number: raw.number,
16
+ state: raw.state,
17
+ merged: raw.merged ?? (raw.merged_at !== undefined && raw.merged_at !== null),
18
+ title: raw.title,
19
+ body: raw.body ?? '',
20
+ url: raw.html_url,
21
+ author: raw.user?.login ?? '',
22
+ headRef: raw.head.ref,
23
+ headSha: raw.head.sha,
24
+ baseRef: raw.base.ref,
25
+ mergeable: raw.mergeable ?? null,
26
+ mergeCommitSha: raw.merge_commit_sha ?? null,
27
+ };
28
+ }
29
+ /**
30
+ * `credentials` supplies the environment of every `gh` call: the caller's own
31
+ * for `gh`'s credential, or with `GH_TOKEN` set to a fresh installation token
32
+ * for a GitHub App (github-app-recording-identity D3) — fetched per call, so a
33
+ * long-running server never uses an expired one.
34
+ */
35
+ export function createGhForgeClient(cwd, credentials) {
36
+ async function api(endpoint, opts = {}) {
37
+ const env = await credentials.env();
38
+ const args = ['api', endpoint];
39
+ if (opts.method !== undefined)
40
+ args.push('--method', opts.method);
41
+ if (opts.input !== undefined)
42
+ args.push('--input', '-');
43
+ try {
44
+ const child = execFileAsync('gh', args, { cwd, env: env, maxBuffer: 64 * 1024 * 1024 });
45
+ if (opts.input !== undefined)
46
+ child.child.stdin?.end(JSON.stringify(opts.input));
47
+ const { stdout } = await child;
48
+ return stdout.trim() === '' ? null : JSON.parse(stdout);
49
+ }
50
+ catch (err) {
51
+ const e = err;
52
+ const detail = (e.stderr ?? '').trim() || (e.stdout ?? '').trim() || (e.message ?? String(err));
53
+ const status = /\(HTTP (\d{3})\)/.exec(detail)?.[1];
54
+ throw new ForgeRequestError(endpoint, status === undefined ? null : Number.parseInt(status, 10), detail);
55
+ }
56
+ }
57
+ const repo = 'repos/{owner}/{repo}';
58
+ return {
59
+ credential: credentials.kind,
60
+ async login() {
61
+ // An installation token cannot call GET /user; an App's login is its bot login (change-approval spec).
62
+ const bot = await credentials.botLogin();
63
+ if (bot !== null)
64
+ return bot;
65
+ return (await api('user')).login;
66
+ },
67
+ async pull(number) {
68
+ return toPull((await api(`${repo}/pulls/${number}`)));
69
+ },
70
+ async openPulls() {
71
+ return (await api(`${repo}/pulls?state=open&per_page=100`)).map(toPull);
72
+ },
73
+ async reviews(number) {
74
+ const raw = (await api(`${repo}/pulls/${number}/reviews?per_page=100`));
75
+ return raw.map((r) => ({
76
+ author: r.user?.login ?? '',
77
+ state: r.state,
78
+ body: r.body ?? '',
79
+ commitId: r.commit_id ?? null,
80
+ submittedAt: r.submitted_at ?? null,
81
+ }));
82
+ },
83
+ async comments(number) {
84
+ const raw = (await api(`${repo}/issues/${number}/comments?per_page=100`));
85
+ return raw.map((c) => ({ author: c.user?.login ?? '', body: c.body ?? '', createdAt: c.created_at }));
86
+ },
87
+ async createReview(number, input) {
88
+ await api(`${repo}/pulls/${number}/reviews`, {
89
+ method: 'POST',
90
+ input: { event: input.event, body: input.body, commit_id: input.commitId },
91
+ });
92
+ },
93
+ async createComment(number, body) {
94
+ await api(`${repo}/issues/${number}/comments`, { method: 'POST', input: { body } });
95
+ },
96
+ async merge(number, input) {
97
+ await api(`${repo}/pulls/${number}/merge`, { method: 'PUT', input: { merge_method: input.method, sha: input.sha } });
98
+ },
99
+ };
100
+ }
101
+ //# sourceMappingURL=github.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github.js","sourceRoot":"","sources":["../../../src/core/forge/github.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAGtC,MAAM,aAAa,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;AA2D1C,gGAAgG;AAChG,MAAM,OAAO,iBAAkB,SAAQ,KAAK;IACjC,MAAM,CAAgB;IAC/B,YAAY,QAAgB,EAAE,MAAqB,EAAE,MAAc;QACjE,KAAK,CAAC,iBAAiB,QAAQ,UAAU,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,MAAM,GAAG,KAAK,MAAM,EAAE,CAAC,CAAC;QAClG,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;QAChC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;CACF;AAiBD,SAAS,MAAM,CAAC,GAAY;IAC1B,OAAO;QACL,MAAM,EAAE,GAAG,CAAC,MAAM;QAClB,KAAK,EAAE,GAAG,CAAC,KAAK;QAChB,MAAM,EAAE,GAAG,CAAC,MAAM,IAAI,CAAC,GAAG,CAAC,SAAS,KAAK,SAAS,IAAI,GAAG,CAAC,SAAS,KAAK,IAAI,CAAC;QAC7E,KAAK,EAAE,GAAG,CAAC,KAAK;QAChB,IAAI,EAAE,GAAG,CAAC,IAAI,IAAI,EAAE;QACpB,GAAG,EAAE,GAAG,CAAC,QAAQ;QACjB,MAAM,EAAE,GAAG,CAAC,IAAI,EAAE,KAAK,IAAI,EAAE;QAC7B,OAAO,EAAE,GAAG,CAAC,IAAI,CAAC,GAAG;QACrB,OAAO,EAAE,GAAG,CAAC,IAAI,CAAC,GAAG;QACrB,OAAO,EAAE,GAAG,CAAC,IAAI,CAAC,GAAG;QACrB,SAAS,EAAE,GAAG,CAAC,SAAS,IAAI,IAAI;QAChC,cAAc,EAAE,GAAG,CAAC,gBAAgB,IAAI,IAAI;KAC7C,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAAC,GAAW,EAAE,WAA6B;IAC5E,KAAK,UAAU,GAAG,CAAC,QAAgB,EAAE,IAAI,GAAyC,EAAE;QAClF,MAAM,GAAG,GAAG,MAAM,WAAW,CAAC,GAAG,EAAE,CAAC;QACpC,MAAM,IAAI,GAAG,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;QAC/B,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS;YAAE,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QAClE,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS;YAAE,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;QACxD,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,aAAa,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,GAAwB,EAAE,SAAS,EAAE,EAAE,GAAG,IAAI,GAAG,IAAI,EAAE,CAAC,CAAC;YAC7G,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS;gBAAE,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;YACjF,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,KAAK,CAAC;YAC/B,OAAO,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QAC1D,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,CAAC,GAAG,GAA6D,CAAC;YACxE,MAAM,MAAM,GAAG,CAAC,CAAC,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,OAAO,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;YAChG,MAAM,MAAM,GAAG,kBAAkB,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;YACpD,MAAM,IAAI,iBAAiB,CAAC,QAAQ,EAAE,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,CAAC,CAAC;QAC3G,CAAC;IACH,CAAC;IAED,MAAM,IAAI,GAAG,sBAAsB,CAAC;IACpC,OAAO;QACL,UAAU,EAAE,WAAW,CAAC,IAAI;QAC5B,KAAK,CAAC,KAAK;YACT,uGAAuG;YACvG,MAAM,GAAG,GAAG,MAAM,WAAW,CAAC,QAAQ,EAAE,CAAC;YACzC,IAAI,GAAG,KAAK,IAAI;gBAAE,OAAO,GAAG,CAAC;YAC7B,OAAQ,CAAC,MAAM,GAAG,CAAC,MAAM,CAAC,CAAuB,CAAC,KAAK,CAAC;QAC1D,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,MAAM;YACf,OAAO,MAAM,CAAC,CAAC,MAAM,GAAG,CAAC,GAAG,IAAI,UAAU,MAAM,EAAE,CAAC,CAAY,CAAC,CAAC;QACnE,CAAC;QACD,KAAK,CAAC,SAAS;YACb,OAAQ,CAAC,MAAM,GAAG,CAAC,GAAG,IAAI,gCAAgC,CAAC,CAAe,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACzF,CAAC;QACD,KAAK,CAAC,OAAO,CAAC,MAAM;YAClB,MAAM,GAAG,GAAG,CAAC,MAAM,GAAG,CAAC,GAAG,IAAI,UAAU,MAAM,uBAAuB,CAAC,CAMnE,CAAC;YACJ,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBACrB,MAAM,EAAE,CAAC,CAAC,IAAI,EAAE,KAAK,IAAI,EAAE;gBAC3B,KAAK,EAAE,CAAC,CAAC,KAAK;gBACd,IAAI,EAAE,CAAC,CAAC,IAAI,IAAI,EAAE;gBAClB,QAAQ,EAAE,CAAC,CAAC,SAAS,IAAI,IAAI;gBAC7B,WAAW,EAAE,CAAC,CAAC,YAAY,IAAI,IAAI;aACpC,CAAC,CAAC,CAAC;QACN,CAAC;QACD,KAAK,CAAC,QAAQ,CAAC,MAAM;YACnB,MAAM,GAAG,GAAG,CAAC,MAAM,GAAG,CAAC,GAAG,IAAI,WAAW,MAAM,wBAAwB,CAAC,CAIrE,CAAC;YACJ,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,IAAI,EAAE,KAAK,IAAI,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,IAAI,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;QACxG,CAAC;QACD,KAAK,CAAC,YAAY,CAAC,MAAM,EAAE,KAAK;YAC9B,MAAM,GAAG,CAAC,GAAG,IAAI,UAAU,MAAM,UAAU,EAAE;gBAC3C,MAAM,EAAE,MAAM;gBACd,KAAK,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,SAAS,EAAE,KAAK,CAAC,QAAQ,EAAE;aAC3E,CAAC,CAAC;QACL,CAAC;QACD,KAAK,CAAC,aAAa,CAAC,MAAM,EAAE,IAAI;YAC9B,MAAM,GAAG,CAAC,GAAG,IAAI,WAAW,MAAM,WAAW,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;QACtF,CAAC;QACD,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK;YACvB,MAAM,GAAG,CAAC,GAAG,IAAI,UAAU,MAAM,QAAQ,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,YAAY,EAAE,KAAK,CAAC,MAAM,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QACvH,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -20,9 +20,34 @@ export interface GitRunOptions {
20
20
  cwd: string;
21
21
  /** When true, a non-zero exit resolves with the result instead of throwing. */
22
22
  allowFailure?: boolean;
23
+ /**
24
+ * github-app-recording-identity (D4): the whole environment for this one git
25
+ * process, in place of this process's own — how `ctxr land` hands a token to
26
+ * a credential helper without writing it anywhere.
27
+ */
28
+ env?: Readonly<Record<string, string | undefined>>;
23
29
  }
24
30
  export interface GitRunner {
25
31
  run(args: readonly string[], opts: GitRunOptions): Promise<GitResult>;
26
32
  }
27
33
  export declare function createExecFileGitRunner(): GitRunner;
34
+ /**
35
+ * review-the-knowledge-diff (D2): the contents of many blobs through ONE
36
+ * `git cat-file --batch` process, keyed by object id, decoded as UTF-8. A
37
+ * process per blob would put a fork behind every note on both sides of a
38
+ * graph diff, and `ctxr serve` runs that diff on a request path.
39
+ *
40
+ * Reads git's object store only: nothing is checked out, and nothing is
41
+ * written. An id the object store does not hold rejects, naming it.
42
+ */
43
+ export declare function readBlobs(cwd: string, objectIds: readonly string[]): Promise<Map<string, string>>;
44
+ /**
45
+ * approve-from-the-review-page (design.md D5): the stable patch identity of
46
+ * every commit in `range` (`<base>..<head>`), oldest first — `git log -p`
47
+ * piped into `git patch-id --stable`, two processes and no shell. Two ranges
48
+ * with equal lists carry the same changes commit for commit, whatever base
49
+ * each was applied to. Rejects when either process fails, as for an unknown
50
+ * commit; the caller treats that as "not the same".
51
+ */
52
+ export declare function patchIds(cwd: string, range: string): Promise<string[]>;
28
53
  //# sourceMappingURL=exec.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"exec.d.ts","sourceRoot":"","sources":["../../../src/core/git/exec.ts"],"names":[],"mappings":"AAKA;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,+EAA+E;IAC/E,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,SAAS;IACxB,GAAG,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;CACvE;AAED,wBAAgB,uBAAuB,IAAI,SAAS,CAenD"}
1
+ {"version":3,"file":"exec.d.ts","sourceRoot":"","sources":["../../../src/core/git/exec.ts"],"names":[],"mappings":"AAKA;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,+EAA+E;IAC/E,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB;;;;OAIG;IACH,GAAG,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC;CACpD;AAED,MAAM,WAAW,SAAS;IACxB,GAAG,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;CACvE;AAUD,wBAAgB,uBAAuB,IAAI,SAAS,CAmBnD;AAED;;;;;;;;GAQG;AACH,wBAAsB,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CA+BvG;AAED;;;;;;;GAOG;AACH,wBAAsB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAoC5E"}
@@ -1,11 +1,22 @@
1
- import { execFile } from 'node:child_process';
1
+ import { execFile, spawn } from 'node:child_process';
2
2
  import { promisify } from 'node:util';
3
3
  const execFileAsync = promisify(execFile);
4
+ /**
5
+ * review-the-knowledge-diff: `git ls-tree -r` over a whole store prints one
6
+ * line per tracked file, which passes execFile's 1 MiB default on a store of
7
+ * a few thousand notes. Raised for every call rather than per call, since no
8
+ * caller wants a truncated listing.
9
+ */
10
+ const MAX_OUTPUT_BYTES = 256 * 1024 * 1024;
4
11
  export function createExecFileGitRunner() {
5
12
  return {
6
13
  async run(args, opts) {
7
14
  try {
8
- const { stdout, stderr } = await execFileAsync('git', [...args], { cwd: opts.cwd });
15
+ const { stdout, stderr } = await execFileAsync('git', [...args], {
16
+ cwd: opts.cwd,
17
+ maxBuffer: MAX_OUTPUT_BYTES,
18
+ ...(opts.env === undefined ? {} : { env: opts.env }),
19
+ });
9
20
  return { stdout, stderr, exitCode: 0 };
10
21
  }
11
22
  catch (err) {
@@ -18,4 +29,91 @@ export function createExecFileGitRunner() {
18
29
  },
19
30
  };
20
31
  }
32
+ /**
33
+ * review-the-knowledge-diff (D2): the contents of many blobs through ONE
34
+ * `git cat-file --batch` process, keyed by object id, decoded as UTF-8. A
35
+ * process per blob would put a fork behind every note on both sides of a
36
+ * graph diff, and `ctxr serve` runs that diff on a request path.
37
+ *
38
+ * Reads git's object store only: nothing is checked out, and nothing is
39
+ * written. An id the object store does not hold rejects, naming it.
40
+ */
41
+ export async function readBlobs(cwd, objectIds) {
42
+ const unique = [...new Set(objectIds)];
43
+ const blobs = new Map();
44
+ if (unique.length === 0)
45
+ return blobs;
46
+ const output = await new Promise((resolve, reject) => {
47
+ const child = spawn('git', ['cat-file', '--batch'], { cwd, stdio: ['pipe', 'pipe', 'pipe'] });
48
+ const chunks = [];
49
+ const errors = [];
50
+ child.stdout.on('data', (chunk) => chunks.push(chunk));
51
+ child.stderr.on('data', (chunk) => errors.push(chunk));
52
+ child.on('error', reject);
53
+ child.on('close', (code) => {
54
+ if (code === 0)
55
+ resolve(Buffer.concat(chunks));
56
+ else
57
+ reject(new Error(`git cat-file --batch exited ${code}: ${Buffer.concat(errors).toString('utf8').trim()}`));
58
+ });
59
+ child.stdin.end(`${unique.join('\n')}\n`);
60
+ });
61
+ // Each record is "<id> <type> <size>\n<content>\n", or "<id> missing\n".
62
+ let offset = 0;
63
+ while (offset < output.length) {
64
+ const headerEnd = output.indexOf(0x0a, offset);
65
+ const header = output.subarray(offset, headerEnd).toString('utf8').split(' ');
66
+ if (header[1] === 'missing')
67
+ throw new Error(`git object ${header[0]} is missing`);
68
+ const size = Number.parseInt(header[2], 10);
69
+ const start = headerEnd + 1;
70
+ blobs.set(header[0], output.subarray(start, start + size).toString('utf8'));
71
+ offset = start + size + 1;
72
+ }
73
+ return blobs;
74
+ }
75
+ /**
76
+ * approve-from-the-review-page (design.md D5): the stable patch identity of
77
+ * every commit in `range` (`<base>..<head>`), oldest first — `git log -p`
78
+ * piped into `git patch-id --stable`, two processes and no shell. Two ranges
79
+ * with equal lists carry the same changes commit for commit, whatever base
80
+ * each was applied to. Rejects when either process fails, as for an unknown
81
+ * commit; the caller treats that as "not the same".
82
+ */
83
+ export async function patchIds(cwd, range) {
84
+ const order = await new Promise((resolve, reject) => {
85
+ execFile('git', ['rev-list', '--reverse', '--no-merges', range], { cwd, maxBuffer: MAX_OUTPUT_BYTES }, (err, stdout) => err ? reject(err) : resolve(stdout));
86
+ });
87
+ const commits = order.split('\n').filter(Boolean);
88
+ if (commits.length === 0)
89
+ return [];
90
+ const byCommit = await new Promise((resolve, reject) => {
91
+ const log = spawn('git', ['log', '-p', '--no-merges', '--no-color', '--format=commit %H', range], { cwd, stdio: ['ignore', 'pipe', 'pipe'] });
92
+ const patchId = spawn('git', ['patch-id', '--stable'], { cwd, stdio: ['pipe', 'pipe', 'pipe'] });
93
+ log.stdout.pipe(patchId.stdin);
94
+ const chunks = [];
95
+ patchId.stdout.on('data', (chunk) => chunks.push(chunk));
96
+ let logCode = null;
97
+ log.on('error', reject);
98
+ patchId.on('error', reject);
99
+ log.on('close', (code) => {
100
+ logCode = code;
101
+ });
102
+ patchId.on('close', (code) => {
103
+ if (code !== 0 || logCode !== 0) {
104
+ reject(new Error(`git patch-id over ${range} failed`));
105
+ return;
106
+ }
107
+ const map = new Map();
108
+ for (const line of Buffer.concat(chunks).toString('utf8').split('\n')) {
109
+ const [id, commit] = line.trim().split(' ');
110
+ if (id && commit)
111
+ map.set(commit, id);
112
+ }
113
+ resolve(map);
114
+ });
115
+ });
116
+ // A commit with an empty patch has no patch id; it still counts, as an empty one.
117
+ return commits.map((commit) => byCommit.get(commit) ?? '');
118
+ }
21
119
  //# sourceMappingURL=exec.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"exec.js","sourceRoot":"","sources":["../../../src/core/git/exec.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtC,MAAM,aAAa,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;AA+B1C,MAAM,UAAU,uBAAuB;IACrC,OAAO;QACL,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI;YAClB,IAAI,CAAC;gBACH,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,aAAa,CAAC,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC,EAAE,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;gBACpF,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;YACzC,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,MAAM,CAAC,GAAG,GAA0D,CAAC;gBACrE,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;oBACtB,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,IAAI,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,IAAI,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,IAAI,IAAI,CAAC,EAAE,CAAC;gBACnF,CAAC;gBACD,MAAM,GAAG,CAAC;YACZ,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"exec.js","sourceRoot":"","sources":["../../../src/core/git/exec.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import type { ServedAtRoute } from '../browse/page-url.js';
2
+ import { type GraphDelta } from './diff.js';
3
+ /** The review address with its reachability line, and the bare-route line when no base URL is declared; empty without an address. */
4
+ export declare function reviewLines(review: ServedAtRoute | null): string[];
5
+ export declare function renderKnowledgeChangesBlock(delta: GraphDelta, review: ServedAtRoute | null): string;
6
+ //# sourceMappingURL=diff-block.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff-block.d.ts","sourceRoot":"","sources":["../../../src/core/graph/diff-block.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAE3D,OAAO,EAAgB,KAAK,UAAU,EAAE,MAAM,WAAW,CAAC;AAyD1D,qIAAqI;AACrI,wBAAgB,WAAW,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI,GAAG,MAAM,EAAE,CAIlE;AAED,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,aAAa,GAAG,IAAI,GAAG,MAAM,CAKnG"}
@@ -0,0 +1,63 @@
1
+ import { packagedTemplate, substituteBlock } from '../templates.js';
2
+ import { isEmptyDelta } from './diff.js';
3
+ /**
4
+ * review-the-knowledge-diff (D9): the **Knowledge changes** block a pull
5
+ * request body carries verbatim, written by the command so the party under
6
+ * review writes none of it. It names both commits in full and the command
7
+ * that reproduces it, gives every kind as a count, and lists in full the two
8
+ * kinds most likely to be silent losses: introduced dangling links and
9
+ * archived notes. It carries no diagram and no judgment the delta does not
10
+ * make.
11
+ *
12
+ * Every fixed sentence lives in `templates/graph/knowledge-changes/`; this
13
+ * module fills in values only.
14
+ */
15
+ function template(name) {
16
+ return packagedTemplate('graph/knowledge-changes', name);
17
+ }
18
+ /** The reasons a dangling link carries a template for; any other reason is written as the delta names it. */
19
+ const REASON_TEMPLATES = new Set(['not_found', 'ambiguous']);
20
+ function reasonText(reason) {
21
+ return REASON_TEMPLATES.has(reason) ? template(`reason-${reason}`) : reason;
22
+ }
23
+ /** Fills `__TOKEN__` slots; a function replacement, so a `$` in a path is never read as a pattern. */
24
+ function fill(text, values) {
25
+ return Object.entries(values).reduce((out, [token, value]) => out.replaceAll(`__${token}__`, () => value), text);
26
+ }
27
+ function code(text) {
28
+ const longest = Math.max(0, ...[...text.matchAll(/`+/g)].map((match) => match[0].length));
29
+ const fence = '`'.repeat(longest + 1);
30
+ return `${fence}${text.startsWith('`') || text.endsWith('`') ? ` ${text} ` : text}${fence}`;
31
+ }
32
+ function bodyLines(delta) {
33
+ if (isEmptyDelta(delta))
34
+ return template('empty').split('\n');
35
+ const counts = Object.entries(delta.counts).reduce((text, [key, count]) => text.replaceAll(`__${key.toUpperCase()}__`, String(count)), template('counts'));
36
+ const lines = counts.split('\n');
37
+ if (delta.dangling.introduced.length > 0) {
38
+ lines.push('', ...template('dangling').split('\n'), '');
39
+ for (const d of delta.dangling.introduced) {
40
+ lines.push(fill(template('dangling-item'), { FROM: code(d.from), TARGET: code(d.target), REASON: reasonText(d.reason) }));
41
+ }
42
+ }
43
+ if (delta.notes.archived.length > 0) {
44
+ lines.push('', ...template('archived').split('\n'), '');
45
+ for (const r of delta.notes.archived)
46
+ lines.push(fill(template('archived-item'), { FROM: code(r.from), TO: code(r.to) }));
47
+ }
48
+ return lines;
49
+ }
50
+ /** The review address with its reachability line, and the bare-route line when no base URL is declared; empty without an address. */
51
+ export function reviewLines(review) {
52
+ if (review === null)
53
+ return [];
54
+ const text = template('review').replace('__ADDRESS__', () => review.url ?? review.route);
55
+ return ['', ...substituteBlock(text, '__BARE_ROUTE__', review.url === null ? template('bare-route').split('\n') : []).split('\n')];
56
+ }
57
+ export function renderKnowledgeChangesBlock(delta, review) {
58
+ let text = template('block').replaceAll('__BASE__', delta.base).replaceAll('__HEAD__', delta.head);
59
+ text = substituteBlock(text, '__BODY__', bodyLines(delta));
60
+ text = substituteBlock(text, '__REVIEW__', reviewLines(review));
61
+ return `${text}\n`;
62
+ }
63
+ //# sourceMappingURL=diff-block.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff-block.js","sourceRoot":"","sources":["../../../src/core/graph/diff-block.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ import { type GraphEdge } from './model.js';
2
+ import { type GraphDelta } from './diff.js';
3
+ /**
4
+ * review-the-knowledge-diff (D5): one render of a delta, used by the command's
5
+ * human summary and by the review view — one derivation, two renders, the
6
+ * same pattern as `graph.json` / `graph.md`. It carries only what the delta
7
+ * carries: paths, link targets, edge types, counts and source entries, never a
8
+ * note body, and no text an agent wrote about the change.
9
+ *
10
+ * The document is a list of parts rather than one string because the review
11
+ * view renders markdown with `html: false`: a `<details>` group is emitted by
12
+ * the caller around its rendered markdown, not parsed out of it. `toMarkdown`
13
+ * writes each group under a `##` heading instead, because its reader is a
14
+ * terminal, where a literal `<details>` tag is noise.
15
+ */
16
+ export type DiffDocumentPart = {
17
+ kind: 'markdown';
18
+ text: string;
19
+ } | {
20
+ kind: 'details';
21
+ summary: string;
22
+ text: string;
23
+ };
24
+ export interface DiffDocumentOptions {
25
+ /** The href for a path the caller can serve, or null to leave it as text. Absent: no path is linked. */
26
+ linkFor?: (notePath: string) => string | null;
27
+ /** Append the link-delta diagram (D8). The human summary omits it. */
28
+ diagram?: boolean;
29
+ }
30
+ /** D8: past this many changed links the diagram is replaced by one line, so it never becomes unreadable. */
31
+ export declare const MAX_DIAGRAM_EDGES = 50;
32
+ /** D8: added links solid, removed links dashed, nodes labelled by stem; edge types label a typed link. */
33
+ export declare function renderDiagram(added: readonly GraphEdge[], removed: readonly GraphEdge[]): string | null;
34
+ export declare function renderDiffParts(delta: GraphDelta, options?: DiffDocumentOptions): DiffDocumentPart[];
35
+ /** The parts as one markdown document, each group under a `##` heading naming it and its count. */
36
+ export declare function toMarkdown(parts: readonly DiffDocumentPart[]): string;
37
+ export declare function renderDiffDocument(delta: GraphDelta, options?: DiffDocumentOptions): string;
38
+ //# sourceMappingURL=diff-document.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff-document.d.ts","sourceRoot":"","sources":["../../../src/core/graph/diff-document.ts"],"names":[],"mappings":"AACA,OAAO,EAAkB,KAAK,SAAS,EAAE,MAAM,YAAY,CAAC;AAC5D,OAAO,EAAgB,KAAK,UAAU,EAAE,MAAM,WAAW,CAAC;AAE1D;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvH,MAAM,WAAW,mBAAmB;IAClC,wGAAwG;IACxG,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;IAC9C,sEAAsE;IACtE,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,4GAA4G;AAC5G,eAAO,MAAM,iBAAiB,KAAK,CAAC;AA8BpC,0GAA0G;AAC1G,wBAAgB,aAAa,CAAC,KAAK,EAAE,SAAS,SAAS,EAAE,EAAE,OAAO,EAAE,SAAS,SAAS,EAAE,GAAG,MAAM,GAAG,IAAI,CAsBvG;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,UAAU,EAAE,OAAO,GAAE,mBAAwB,GAAG,gBAAgB,EAAE,CAuExG;AAED,mGAAmG;AACnG,wBAAgB,UAAU,CAAC,KAAK,EAAE,SAAS,gBAAgB,EAAE,GAAG,MAAM,CAErE;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,UAAU,EAAE,OAAO,GAAE,mBAAwB,GAAG,MAAM,CAE/F"}
@@ -0,0 +1,117 @@
1
+ import path from 'node:path';
2
+ import { LINK_EDGE_TYPE } from './model.js';
3
+ import { isEmptyDelta } from './diff.js';
4
+ /** D8: past this many changed links the diagram is replaced by one line, so it never becomes unreadable. */
5
+ export const MAX_DIAGRAM_EDGES = 50;
6
+ /** A code span that survives any backtick run in the text, with table pipes escaped. */
7
+ function code(text) {
8
+ const longest = Math.max(0, ...[...text.matchAll(/`+/g)].map((match) => match[0].length));
9
+ const fence = '`'.repeat(longest + 1);
10
+ const padded = text.startsWith('`') || text.endsWith('`') ? ` ${text} ` : text;
11
+ return `${fence}${padded.replace(/\|/g, '\\|')}${fence}`;
12
+ }
13
+ function pathCell(notePath, options) {
14
+ const href = options.linkFor?.(notePath) ?? null;
15
+ return href === null ? code(notePath) : `[${code(notePath)}](${href})`;
16
+ }
17
+ function table(header, rows) {
18
+ return [`| ${header.join(' | ')} |`, `|${header.map(() => '---').join('|')}|`, ...rows.map((row) => `| ${row.join(' | ')} |`)].join('\n');
19
+ }
20
+ const REASON_TEXT = { not_found: 'not found', ambiguous: 'ambiguous' };
21
+ function stemOf(notePath) {
22
+ return path.posix.basename(notePath, '.md');
23
+ }
24
+ /** Mermaid's entity form, so a label's quotes, brackets and pipes cannot end the label early. */
25
+ function mermaidLabel(text) {
26
+ return text.replace(/[#"<>|[\]{}()]/g, (ch) => `#${ch.charCodeAt(0)};`);
27
+ }
28
+ /** D8: added links solid, removed links dashed, nodes labelled by stem; edge types label a typed link. */
29
+ export function renderDiagram(added, removed) {
30
+ const changed = added.length + removed.length;
31
+ if (changed === 0)
32
+ return null;
33
+ if (changed > MAX_DIAGRAM_EDGES) {
34
+ return `The link delta has ${changed} changed links, more than the diagram draws (${MAX_DIAGRAM_EDGES}); the tables above list every one.`;
35
+ }
36
+ const ids = new Map();
37
+ for (const edge of [...added, ...removed]) {
38
+ for (const notePath of [edge.src, edge.dst])
39
+ if (!ids.has(notePath))
40
+ ids.set(notePath, `n${ids.size}`);
41
+ }
42
+ const arrow = (edge, solid) => {
43
+ const label = edge.type === LINK_EDGE_TYPE ? '' : `|${mermaidLabel(edge.type)}|`;
44
+ return ` ${ids.get(edge.src)} ${solid ? '-->' : '-.->'}${label} ${ids.get(edge.dst)}`;
45
+ };
46
+ return [
47
+ '```mermaid',
48
+ 'flowchart LR',
49
+ ...[...ids].map(([notePath, id]) => ` ${id}["${mermaidLabel(stemOf(notePath))}"]`),
50
+ ...added.map((edge) => arrow(edge, true)),
51
+ ...removed.map((edge) => arrow(edge, false)),
52
+ '```',
53
+ ].join('\n');
54
+ }
55
+ export function renderDiffParts(delta, options = {}) {
56
+ const cell = (notePath) => pathCell(notePath, options);
57
+ const parts = [
58
+ {
59
+ kind: 'markdown',
60
+ text: ['# Knowledge changes', '', `- Base commit: ${code(delta.base)}`, `- Head commit: ${code(delta.head)}`].join('\n'),
61
+ },
62
+ ];
63
+ if (isEmptyDelta(delta)) {
64
+ parts.push({ kind: 'markdown', text: 'No knowledge changes: this range changes no note.' });
65
+ return parts;
66
+ }
67
+ const c = delta.counts;
68
+ parts.push({
69
+ kind: 'markdown',
70
+ text: table(['Kind', 'Count'], [
71
+ ['Notes added', String(c.notes_added)],
72
+ ['Notes removed', String(c.notes_removed)],
73
+ ['Notes modified', String(c.notes_modified)],
74
+ ['Notes moved', String(c.notes_moved)],
75
+ ['Notes archived', String(c.notes_archived)],
76
+ ['Links added', String(c.links_added)],
77
+ ['Links removed', String(c.links_removed)],
78
+ ['Dangling links introduced', String(c.dangling_introduced)],
79
+ ['Dangling links resolved', String(c.dangling_resolved)],
80
+ ['Notes whose inbound links changed', String(c.inbound_changed)],
81
+ ['Rollups touched', String(c.rollups_touched)],
82
+ ['Notes citing new sources', String(c.sources_cited)],
83
+ ]),
84
+ });
85
+ const group = (summary, count, text) => {
86
+ if (count > 0)
87
+ parts.push({ kind: 'details', summary: `${summary} (${count})`, text });
88
+ };
89
+ const edgeRows = (edges) => edges.map((e) => [cell(e.src), cell(e.dst), code(e.type)]);
90
+ const danglingRows = (links) => links.map((d) => [cell(d.from), code(d.target), REASON_TEXT[d.reason] ?? d.reason]);
91
+ group('Notes added', c.notes_added, table(['Note'], delta.notes.added.map((p) => [cell(p)])));
92
+ group('Notes removed', c.notes_removed, table(['Note'], delta.notes.removed.map((p) => [code(p)])));
93
+ group('Notes modified', c.notes_modified, table(['Note'], delta.notes.modified.map((p) => [cell(p)])));
94
+ group('Notes moved', c.notes_moved, table(['From', 'To'], delta.notes.moved.map((r) => [code(r.from), cell(r.to)])));
95
+ group('Notes archived', c.notes_archived, table(['From', 'To'], delta.notes.archived.map((r) => [code(r.from), cell(r.to)])));
96
+ group('Links added', c.links_added, table(['From', 'To', 'Type'], edgeRows(delta.links.added)));
97
+ group('Links removed', c.links_removed, table(['From', 'To', 'Type'], edgeRows(delta.links.removed)));
98
+ group('Dangling links introduced', c.dangling_introduced, table(['From', 'Target', 'Reason'], danglingRows(delta.dangling.introduced)));
99
+ group('Dangling links resolved', c.dangling_resolved, table(['From', 'Target', 'Reason'], danglingRows(delta.dangling.resolved)));
100
+ group('Notes whose inbound links changed', c.inbound_changed, table(['Note', 'Gained from', 'Lost from', 'Has rollup'], delta.inbound.map((i) => [cell(i.path), i.gained.map(code).join(', '), i.lost.map(code).join(', '), i.rollup ? 'yes' : 'no'])));
101
+ group('Rollups touched', c.rollups_touched, table(['Note', 'Region'], delta.rollups.map((r) => [cell(r.path), r.change])));
102
+ group('Sources newly cited', c.sources_cited, table(['Note', 'Sources'], delta.sources.map((s) => [cell(s.path), s.cited.map(code).join(', ')])));
103
+ if (options.diagram) {
104
+ const diagram = renderDiagram(delta.links.added, delta.links.removed);
105
+ if (diagram !== null)
106
+ parts.push({ kind: 'markdown', text: ['## Link delta', '', diagram].join('\n') });
107
+ }
108
+ return parts;
109
+ }
110
+ /** The parts as one markdown document, each group under a `##` heading naming it and its count. */
111
+ export function toMarkdown(parts) {
112
+ return parts.map((part) => (part.kind === 'markdown' ? part.text : [`## ${part.summary}`, '', part.text].join('\n'))).join('\n\n');
113
+ }
114
+ export function renderDiffDocument(delta, options = {}) {
115
+ return `${toMarkdown(renderDiffParts(delta, options))}\n`;
116
+ }
117
+ //# sourceMappingURL=diff-document.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff-document.js","sourceRoot":"","sources":["../../../src/core/graph/diff-document.ts"],"names":[],"mappings":"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"}