otacon 0.1.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 (175) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +88 -0
  3. package/dist/cli/client.js +188 -0
  4. package/dist/cli/client.js.map +1 -0
  5. package/dist/cli/commands/answer.js +63 -0
  6. package/dist/cli/commands/answer.js.map +1 -0
  7. package/dist/cli/commands/ask.js +117 -0
  8. package/dist/cli/commands/ask.js.map +1 -0
  9. package/dist/cli/commands/clean.js +48 -0
  10. package/dist/cli/commands/clean.js.map +1 -0
  11. package/dist/cli/commands/doctor.js +86 -0
  12. package/dist/cli/commands/doctor.js.map +1 -0
  13. package/dist/cli/commands/expose.js +104 -0
  14. package/dist/cli/commands/expose.js.map +1 -0
  15. package/dist/cli/commands/implement-done.js +53 -0
  16. package/dist/cli/commands/implement-done.js.map +1 -0
  17. package/dist/cli/commands/install.js +113 -0
  18. package/dist/cli/commands/install.js.map +1 -0
  19. package/dist/cli/commands/open.js +37 -0
  20. package/dist/cli/commands/open.js.map +1 -0
  21. package/dist/cli/commands/progress.js +45 -0
  22. package/dist/cli/commands/progress.js.map +1 -0
  23. package/dist/cli/commands/start.js +66 -0
  24. package/dist/cli/commands/start.js.map +1 -0
  25. package/dist/cli/commands/status.js +44 -0
  26. package/dist/cli/commands/status.js.map +1 -0
  27. package/dist/cli/commands/submit.js +64 -0
  28. package/dist/cli/commands/submit.js.map +1 -0
  29. package/dist/cli/commands/wait.js +66 -0
  30. package/dist/cli/commands/wait.js.map +1 -0
  31. package/dist/cli/install/assets.js +285 -0
  32. package/dist/cli/install/assets.js.map +1 -0
  33. package/dist/cli/install/locations.js +92 -0
  34. package/dist/cli/install/locations.js.map +1 -0
  35. package/dist/cli/install/tailscale.js +39 -0
  36. package/dist/cli/install/tailscale.js.map +1 -0
  37. package/dist/cli/main.js +73 -0
  38. package/dist/cli/main.js.map +1 -0
  39. package/dist/cli/output.js +39 -0
  40. package/dist/cli/output.js.map +1 -0
  41. package/dist/cli/session.js +77 -0
  42. package/dist/cli/session.js.map +1 -0
  43. package/dist/daemon/activity.js +56 -0
  44. package/dist/daemon/activity.js.map +1 -0
  45. package/dist/daemon/anchor.js +143 -0
  46. package/dist/daemon/anchor.js.map +1 -0
  47. package/dist/daemon/app.js +1081 -0
  48. package/dist/daemon/app.js.map +1 -0
  49. package/dist/daemon/approve.js +71 -0
  50. package/dist/daemon/approve.js.map +1 -0
  51. package/dist/daemon/desktop-notify.js +69 -0
  52. package/dist/daemon/desktop-notify.js.map +1 -0
  53. package/dist/daemon/diff.js +187 -0
  54. package/dist/daemon/diff.js.map +1 -0
  55. package/dist/daemon/linter/index.js +19 -0
  56. package/dist/daemon/linter/index.js.map +1 -0
  57. package/dist/daemon/linter/parse.js +350 -0
  58. package/dist/daemon/linter/parse.js.map +1 -0
  59. package/dist/daemon/linter/rules.js +359 -0
  60. package/dist/daemon/linter/rules.js.map +1 -0
  61. package/dist/daemon/main.js +48 -0
  62. package/dist/daemon/main.js.map +1 -0
  63. package/dist/daemon/notify.js +23 -0
  64. package/dist/daemon/notify.js.map +1 -0
  65. package/dist/daemon/presence.js +37 -0
  66. package/dist/daemon/presence.js.map +1 -0
  67. package/dist/daemon/queue.js +160 -0
  68. package/dist/daemon/queue.js.map +1 -0
  69. package/dist/daemon/store.js +393 -0
  70. package/dist/daemon/store.js.map +1 -0
  71. package/dist/daemon/threads.js +153 -0
  72. package/dist/daemon/threads.js.map +1 -0
  73. package/dist/daemon/transcript.js +89 -0
  74. package/dist/daemon/transcript.js.map +1 -0
  75. package/dist/daemon/ui.js +175 -0
  76. package/dist/daemon/ui.js.map +1 -0
  77. package/dist/shared/config.js +93 -0
  78. package/dist/shared/config.js.map +1 -0
  79. package/dist/shared/gwt.js +69 -0
  80. package/dist/shared/gwt.js.map +1 -0
  81. package/dist/shared/paths.js +67 -0
  82. package/dist/shared/paths.js.map +1 -0
  83. package/dist/shared/question-spec.js +44 -0
  84. package/dist/shared/question-spec.js.map +1 -0
  85. package/dist/shared/types.js +35 -0
  86. package/dist/shared/types.js.map +1 -0
  87. package/dist/shared/version.js +5 -0
  88. package/dist/shared/version.js.map +1 -0
  89. package/dist/ui/assets/arc-HhPfdCPZ.js +1 -0
  90. package/dist/ui/assets/architecture-7EHR7CIX-BPLblcyi.js +1 -0
  91. package/dist/ui/assets/architectureDiagram-3BPJPVTR-D2PIxGOb.js +36 -0
  92. package/dist/ui/assets/array-BifhSqXX.js +1 -0
  93. package/dist/ui/assets/blockDiagram-GPEHLZMM-DQ3Dn17h.js +132 -0
  94. package/dist/ui/assets/c4Diagram-AAUBKEIU-DxITrQgS.js +10 -0
  95. package/dist/ui/assets/channel-ipcU8ZNI.js +1 -0
  96. package/dist/ui/assets/chunk-2J33WTMH-Du1JoPx5.js +1 -0
  97. package/dist/ui/assets/chunk-3OPIFGDE-Dn7x2Yqf.js +62 -0
  98. package/dist/ui/assets/chunk-4BX2VUAB-DVnrE-4n.js +1 -0
  99. package/dist/ui/assets/chunk-55IACEB6-BAhFAimA.js +1 -0
  100. package/dist/ui/assets/chunk-5ZQYHXKU-0hEZptem.js +2 -0
  101. package/dist/ui/assets/chunk-727SXJPM-C1FN_cI3.js +206 -0
  102. package/dist/ui/assets/chunk-AQP2D5EJ-A656OBd4.js +231 -0
  103. package/dist/ui/assets/chunk-BSJP7CBP-D8oMbjm8.js +1 -0
  104. package/dist/ui/assets/chunk-CSCIHK7Q-DjIL8GLi.js +122 -0
  105. package/dist/ui/assets/chunk-FMBD7UC4-Otblfqvz.js +15 -0
  106. package/dist/ui/assets/chunk-KSCS5N6A-BOjTvm3H.js +10 -0
  107. package/dist/ui/assets/chunk-L5ZTLDWV-CaTLaw6L.js +1 -0
  108. package/dist/ui/assets/chunk-LZXEDZCA-Dq5p7qrD.js +2 -0
  109. package/dist/ui/assets/chunk-ND2GUHAM-jZ_NNnWi.js +1 -0
  110. package/dist/ui/assets/chunk-NNHCCRGN-DlpIbxXb.js +159 -0
  111. package/dist/ui/assets/chunk-NZK2D7GU-U_7l_sCh.js +1 -0
  112. package/dist/ui/assets/chunk-O5CBEL6O-MewqqNB7.js +70 -0
  113. package/dist/ui/assets/chunk-QZHKN3VN-DzGPH44B.js +1 -0
  114. package/dist/ui/assets/chunk-WU5MYG2G-DyEIVjoo.js +1 -0
  115. package/dist/ui/assets/chunk-XPW4576I-D5ArxNEF.js +32 -0
  116. package/dist/ui/assets/classDiagram-4FO5ZUOK-Byg2Hl9D.js +1 -0
  117. package/dist/ui/assets/classDiagram-v2-Q7XG4LA2-Byg2Hl9D.js +1 -0
  118. package/dist/ui/assets/cose-bilkent-S5V4N54A-PFXzf7WV.js +1 -0
  119. package/dist/ui/assets/cytoscape.esm-h6BdjjI9.js +321 -0
  120. package/dist/ui/assets/dagre-BM42HDAG-xrCfjZuZ.js +4 -0
  121. package/dist/ui/assets/dagre-Bx709z4p.js +1 -0
  122. package/dist/ui/assets/defaultLocale-C8Fc0cco.js +1 -0
  123. package/dist/ui/assets/diagram-2AECGRRQ-BFf-cyKY.js +43 -0
  124. package/dist/ui/assets/diagram-5GNKFQAL-kNPV4NfV.js +10 -0
  125. package/dist/ui/assets/diagram-KO2AKTUF-ByC1IUwG.js +3 -0
  126. package/dist/ui/assets/diagram-LMA3HP47-DZIJMPK0.js +24 -0
  127. package/dist/ui/assets/diagram-OG6HWLK6-CSDED9A-.js +24 -0
  128. package/dist/ui/assets/dist-YwjsDswi.js +1 -0
  129. package/dist/ui/assets/erDiagram-TEJ5UH35-yuzvjE6J.js +85 -0
  130. package/dist/ui/assets/eventmodeling-FCH6USID-CZR4eNG-.js +1 -0
  131. package/dist/ui/assets/flowDiagram-I6XJVG4X-ApPtVyYM.js +162 -0
  132. package/dist/ui/assets/ganttDiagram-6RSMTGT7-BeMLXtAr.js +292 -0
  133. package/dist/ui/assets/gitGraph-WXDBUCRP-JmTTBa7j.js +1 -0
  134. package/dist/ui/assets/gitGraphDiagram-PVQCEYII-Cjjnjs71.js +106 -0
  135. package/dist/ui/assets/graphlib-B8gBHxth.js +1 -0
  136. package/dist/ui/assets/index-BFQVRcSI.js +11 -0
  137. package/dist/ui/assets/index-Bj_kTrwP.css +1 -0
  138. package/dist/ui/assets/info-J43DQDTF-8vZ3gome.js +1 -0
  139. package/dist/ui/assets/infoDiagram-5YYISTIA-CnMk1cA-.js +2 -0
  140. package/dist/ui/assets/init-D6jRqBbL.js +1 -0
  141. package/dist/ui/assets/ishikawaDiagram-YF4QCWOH-Bl8z6huD.js +70 -0
  142. package/dist/ui/assets/journeyDiagram-JHISSGLW-DYIVfMpS.js +139 -0
  143. package/dist/ui/assets/kanban-definition-UN3LZRKU-BnR0ZzOz.js +89 -0
  144. package/dist/ui/assets/katex-Vhh-h91d.js +257 -0
  145. package/dist/ui/assets/line-DcBdQit6.js +1 -0
  146. package/dist/ui/assets/linear-HKjRHFAO.js +1 -0
  147. package/dist/ui/assets/mermaid-parser.core-DkYXrPlA.js +4 -0
  148. package/dist/ui/assets/mermaid.core-BmkfCI3b.js +9 -0
  149. package/dist/ui/assets/mindmap-definition-RKZ34NQL-sIAd4nDi.js +96 -0
  150. package/dist/ui/assets/ordinal-hYBb2elL.js +1 -0
  151. package/dist/ui/assets/otacon-DPXGiaVj.svg +11 -0
  152. package/dist/ui/assets/packet-YPE3B663-BxbxcfXN.js +1 -0
  153. package/dist/ui/assets/path-BWPyau1x.js +1 -0
  154. package/dist/ui/assets/pie-LRSECV5Y-BJxazjNs.js +1 -0
  155. package/dist/ui/assets/pieDiagram-4H26LBE5-BiOhc9GR.js +30 -0
  156. package/dist/ui/assets/plan-view-CH6NzUDb.js +74 -0
  157. package/dist/ui/assets/purify.es-CDvCXckx.js +3 -0
  158. package/dist/ui/assets/quadrantDiagram-W4KKPZXB-CVyHbWgo.js +7 -0
  159. package/dist/ui/assets/radar-GUYGQ44K-D9ohbnbV.js +1 -0
  160. package/dist/ui/assets/requirementDiagram-4Y6WPE33-Ba24_hqc.js +84 -0
  161. package/dist/ui/assets/rough.esm-CSKSodPl.js +1 -0
  162. package/dist/ui/assets/sankeyDiagram-5OEKKPKP-CxD4wiPL.js +40 -0
  163. package/dist/ui/assets/sequenceDiagram-3UESZ5HK-7qA7lD61.js +162 -0
  164. package/dist/ui/assets/src-IM8AE8MK.js +1 -0
  165. package/dist/ui/assets/stateDiagram-AJRCARHV-DNElRCuH.js +1 -0
  166. package/dist/ui/assets/stateDiagram-v2-BHNVJYJU-D6qTYpY3.js +1 -0
  167. package/dist/ui/assets/timeline-definition-PNZ67QCA-ChYC4Grd.js +120 -0
  168. package/dist/ui/assets/treeView-BLDUP644-Il0KnMi_.js +1 -0
  169. package/dist/ui/assets/treemap-LRROVOQU-CIiKcdRo.js +1 -0
  170. package/dist/ui/assets/vennDiagram-CIIHVFJN-Ulhkum9i.js +34 -0
  171. package/dist/ui/assets/wardley-L42UT6IY-BNd4ljz7.js +1 -0
  172. package/dist/ui/assets/wardleyDiagram-YWT4CUSO-BicXxh84.js +78 -0
  173. package/dist/ui/assets/xychartDiagram-2RQKCTM6-Duf-m_th.js +7 -0
  174. package/dist/ui/index.html +20 -0
  175. package/package.json +66 -0
@@ -0,0 +1,77 @@
1
+ // Registry-first session resolution (DESIGN.md §7): explicit --session always
2
+ // wins; otherwise the repo's single active session in the daemon registry — the
3
+ // registry is the single source of truth, there is no local pointer. Zero active
4
+ // sessions for the repo, or two or more, is a refusal carrying the candidates,
5
+ // never a guess (DECISIONS.md "Session resolution precedence").
6
+ import { execFileSync } from "node:child_process";
7
+ import { realpathSync } from "node:fs";
8
+ import { TERMINAL_STATUSES } from "../shared/types.js";
9
+ import { api } from "./client.js";
10
+ import { fail } from "./output.js";
11
+ /** Resolve symlinks (mktemp dirs on macOS live behind /var → /private/var). */
12
+ export function realpathOr(path) {
13
+ try {
14
+ return realpathSync(path);
15
+ }
16
+ catch {
17
+ return path;
18
+ }
19
+ }
20
+ function git(cwd, args) {
21
+ try {
22
+ return execFileSync("git", args, {
23
+ cwd,
24
+ encoding: "utf8",
25
+ stdio: ["ignore", "pipe", "ignore"],
26
+ }).trim();
27
+ }
28
+ catch {
29
+ return undefined;
30
+ }
31
+ }
32
+ /**
33
+ * Git repo root above cwd (DECISIONS.md "`.otacon/` lives at the git repo
34
+ * root"); undefined outside any git repo (callers fall back to cwd).
35
+ */
36
+ export function findRepoRoot(cwd) {
37
+ const root = git(cwd, ["rev-parse", "--show-toplevel"]);
38
+ return root === undefined || root === "" ? undefined : realpathOr(root);
39
+ }
40
+ /** Current branch name; "" when detached, unborn-without-name, or not a repo. */
41
+ export function currentBranch(cwd) {
42
+ return git(cwd, ["branch", "--show-current"]) ?? "";
43
+ }
44
+ /** The daemon registry — callers ensureDaemon() first. */
45
+ export async function listSessions() {
46
+ const response = await api("GET", "/api/sessions");
47
+ return (response.body.sessions ?? []);
48
+ }
49
+ // Exactly the terminal states are inactive (the single source of truth in
50
+ // shared/types.ts): `implementing` resolves as the active session so the agent
51
+ // can keep narrating/asking mid-build and `otacon resume` re-adopts it, while
52
+ // `implemented`/`implement_failed` no longer count once the build is over.
53
+ const isActive = (s) => !TERMINAL_STATUSES.includes(s.status);
54
+ export function resolveSession(sessions, explicit, cwd) {
55
+ if (explicit !== undefined) {
56
+ const session = sessions.find((s) => s.id === explicit);
57
+ if (!session) {
58
+ fail("E_UNKNOWN_SESSION", `--session ${explicit}: not in the daemon registry`);
59
+ }
60
+ return session;
61
+ }
62
+ // No local pointer: the repo's single active (non-terminal) session is the
63
+ // implicit default. A terminal session is over (DESIGN.md §6) — approved, or
64
+ // a finished build (implemented/implement_failed) — so it never counts;
65
+ // reaching it needs an explicit --session. Two or more active sessions refuse
66
+ // with the candidate list rather than guess: cross-posting feedback to the
67
+ // wrong plan is unrecoverable confusion.
68
+ const root = findRepoRoot(cwd) ?? realpathOr(cwd);
69
+ const here = sessions.filter((s) => isActive(s) && realpathOr(s.repo) === root);
70
+ if (here.length === 1)
71
+ return here[0];
72
+ if (here.length === 0) {
73
+ fail("E_NO_SESSION", `no active otacon session for ${root}; run otacon start (or pass --session <id>)`);
74
+ }
75
+ fail("E_AMBIGUOUS_SESSION", `${here.length} active sessions for ${root}; pass --session <id>`, { sessions: here.map((s) => ({ id: s.id, title: s.title, status: s.status })) });
76
+ }
77
+ //# sourceMappingURL=session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/cli/session.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,56 @@
1
+ // Per-session live-activity feed: .otacon/<id>/activity.json holds the agent's
2
+ // recent `otacon progress` notes (DESIGN.md §6) — the append-only telemetry the
3
+ // review UI watches while the agent researches and drafts. Append-only and
4
+ // capped to the newest N (config), so it stays small and the feed never grows
5
+ // without bound. Same storage posture as the queue/transcript readers: atomic
6
+ // writes, corrupt files quarantined and rebuilt empty, never fatal.
7
+ import { existsSync } from "node:fs";
8
+ import { quarantineCorruptFile, readJsonOr, stringify, writeFileAtomic } from "./store.js";
9
+ function isNote(raw) {
10
+ const note = raw;
11
+ return (typeof note === "object" &&
12
+ note !== null &&
13
+ typeof note.at === "string" &&
14
+ typeof note.text === "string");
15
+ }
16
+ // Every note is validated, not just the envelope (same argument as
17
+ // transcript.ts): a JSON-valid file with a corrupt note would otherwise flow a
18
+ // non-note into the chip and the activity log.
19
+ function parseActivity(raw) {
20
+ const file = raw;
21
+ const valid = typeof file === "object" &&
22
+ file !== null &&
23
+ file.version === 1 &&
24
+ Array.isArray(file.notes) &&
25
+ file.notes.every(isNote);
26
+ return valid ? file : undefined;
27
+ }
28
+ /** All notes, oldest first (already capped). Missing file = none yet; corrupt = quarantined, []. */
29
+ export function readActivity(path) {
30
+ if (!existsSync(path))
31
+ return [];
32
+ const file = parseActivity(readJsonOr(path));
33
+ if (!file) {
34
+ quarantineCorruptFile(path, "activity feed");
35
+ return [];
36
+ }
37
+ return file.notes;
38
+ }
39
+ /** The newest note (the chip's source), or undefined when the feed is empty. */
40
+ export function latestNote(path) {
41
+ const notes = readActivity(path);
42
+ return notes[notes.length - 1];
43
+ }
44
+ /**
45
+ * Durably append one note, keeping only the newest `cap` (older notes drop off
46
+ * the front); returns the appended note. `at` is passed in so the route owns
47
+ * the single clock read alongside its other timestamps.
48
+ */
49
+ export function appendActivity(path, text, cap, at) {
50
+ const note = { at, text };
51
+ const notes = [...readActivity(path), note];
52
+ const capped = cap > 0 && notes.length > cap ? notes.slice(notes.length - cap) : notes;
53
+ writeFileAtomic(path, stringify({ version: 1, notes: capped }));
54
+ return note;
55
+ }
56
+ //# sourceMappingURL=activity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"activity.js","sourceRoot":"","sources":["../../src/daemon/activity.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,gFAAgF;AAChF,2EAA2E;AAC3E,8EAA8E;AAC9E,8EAA8E;AAC9E,oEAAoE;AAEpE,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAErC,OAAO,EAAE,qBAAqB,EAAE,UAAU,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAE3F,SAAS,MAAM,CAAC,GAAY;IAC1B,MAAM,IAAI,GAAG,GAAmB,CAAC;IACjC,OAAO,CACL,OAAO,IAAI,KAAK,QAAQ;QACxB,IAAI,KAAK,IAAI;QACb,OAAO,IAAI,CAAC,EAAE,KAAK,QAAQ;QAC3B,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,CAC9B,CAAC;AACJ,CAAC;AAED,mEAAmE;AACnE,+EAA+E;AAC/E,+CAA+C;AAC/C,SAAS,aAAa,CAAC,GAAY;IACjC,MAAM,IAAI,GAAG,GAAmB,CAAC;IACjC,MAAM,KAAK,GACT,OAAO,IAAI,KAAK,QAAQ;QACxB,IAAI,KAAK,IAAI;QACb,IAAI,CAAC,OAAO,KAAK,CAAC;QAClB,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC;QACzB,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAC3B,OAAO,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;AAClC,CAAC;AAED,oGAAoG;AACpG,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,CAAC;IACjC,MAAM,IAAI,GAAG,aAAa,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC;IAC7C,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,qBAAqB,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC;QAC7C,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,OAAO,IAAI,CAAC,KAAK,CAAC;AACpB,CAAC;AAED,gFAAgF;AAChF,MAAM,UAAU,UAAU,CAAC,IAAY;IACrC,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IACjC,OAAO,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AACjC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAC5B,IAAY,EACZ,IAAY,EACZ,GAAW,EACX,EAAU;IAEV,MAAM,IAAI,GAAiB,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;IACxC,MAAM,KAAK,GAAG,CAAC,GAAG,YAAY,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,CAAC;IAC5C,MAAM,MAAM,GAAG,GAAG,GAAG,CAAC,IAAI,KAAK,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;IACvF,eAAe,CAAC,IAAI,EAAE,SAAS,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,EAAyB,CAAC,CAAC,CAAC;IACvF,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,143 @@
1
+ // Re-anchoring across revisions (DESIGN.md §4): when a new revision is
2
+ // accepted, every thread's text quote is re-located in the new plan. The
3
+ // ladder is strict-to-fuzzy: raw exact match → prefix/suffix-scored
4
+ // disambiguation → normalized match (whitespace collapsed, markdown emphasis
5
+ // markers stripped — quotes come from *rendered* text, the plan is markdown
6
+ // source). A unique match re-anchors, possibly rewriting the anchor to the
7
+ // new revision's text; no match or an ambiguous one orphans the thread —
8
+ // never a guess, never a drop (DECISIONS.md "Re-anchoring ladder").
9
+ import { segmentPlan } from "./diff.js";
10
+ /** How much context to capture when an anchor is rewritten from the new text. */
11
+ const CONTEXT_CHARS = 32;
12
+ /** Markdown emphasis/code markers that exist in source but not in rendered text. */
13
+ const MARKER = /[*_`]/;
14
+ /** Collapse whitespace runs to single spaces and drop emphasis markers, with an index map. */
15
+ export function normalize(raw) {
16
+ let text = "";
17
+ const map = [];
18
+ for (let i = 0; i < raw.length; i++) {
19
+ const ch = raw[i];
20
+ if (MARKER.test(ch))
21
+ continue;
22
+ if (/\s/.test(ch)) {
23
+ if (text.endsWith(" ") || text === "")
24
+ continue;
25
+ text += " ";
26
+ }
27
+ else {
28
+ text += ch;
29
+ }
30
+ map.push(i);
31
+ }
32
+ if (text.endsWith(" ")) {
33
+ text = text.slice(0, -1);
34
+ map.pop();
35
+ }
36
+ return { text, map };
37
+ }
38
+ function findAll(haystack, needle) {
39
+ const hits = [];
40
+ for (let idx = haystack.indexOf(needle); idx !== -1; idx = haystack.indexOf(needle, idx + 1)) {
41
+ hits.push(idx);
42
+ }
43
+ return hits;
44
+ }
45
+ function longestCommonSuffix(a, b) {
46
+ let n = 0;
47
+ while (n < a.length && n < b.length && a[a.length - 1 - n] === b[b.length - 1 - n])
48
+ n++;
49
+ return n;
50
+ }
51
+ function longestCommonPrefix(a, b) {
52
+ let n = 0;
53
+ while (n < a.length && n < b.length && a[n] === b[n])
54
+ n++;
55
+ return n;
56
+ }
57
+ /** Prefix/suffix assist: how well the stored context matches around a candidate. */
58
+ function contextScore(anchor, text, candidate) {
59
+ const before = normalize(text.slice(Math.max(0, candidate.start - 256), candidate.start)).text;
60
+ const after = normalize(text.slice(candidate.end, candidate.end + 256)).text;
61
+ const prefix = normalize(anchor.prefix ?? "").text;
62
+ const suffix = normalize(anchor.suffix ?? "").text;
63
+ return longestCommonSuffix(prefix, before) + longestCommonPrefix(suffix, after);
64
+ }
65
+ /**
66
+ * Pick the one candidate the evidence singles out: a strictly best context
67
+ * score wins; failing that, a single candidate in the anchor's original
68
+ * section wins; anything still ambiguous is undefined (→ orphaned).
69
+ */
70
+ function disambiguate(anchor, candidates) {
71
+ if (candidates.length === 1)
72
+ return candidates[0]?.candidate;
73
+ const scored = candidates.map(({ candidate, text }) => ({
74
+ candidate,
75
+ score: contextScore(anchor, text, candidate),
76
+ }));
77
+ scored.sort((a, b) => b.score - a.score);
78
+ const [best, second] = scored;
79
+ if (best && (!second || best.score > second.score))
80
+ return best.candidate;
81
+ const inSection = scored.filter((s) => s.candidate.unit.id === anchor.section);
82
+ return inSection.length === 1 ? inSection[0]?.candidate : undefined;
83
+ }
84
+ /**
85
+ * Re-locate one anchor in a (linted, stored) plan revision. Anchors without a
86
+ * quote only need their section to still exist; quoted anchors walk the
87
+ * match ladder. A normalized (fuzzy) match rewrites the anchor to the new
88
+ * revision's raw text so the quote tracks the plan. Callers re-locating many
89
+ * anchors in the same plan pass the segmented `units` once instead of paying
90
+ * a full plan parse per anchor.
91
+ */
92
+ export function relocateAnchor(anchor, plan, units = segmentPlan(plan)) {
93
+ const exact = anchor.exact ?? "";
94
+ if (exact.trim() === "") {
95
+ return units.some((u) => u.id === anchor.section)
96
+ ? { state: "anchored", anchor }
97
+ : { state: "orphaned" };
98
+ }
99
+ // Rung 1: raw occurrences of the quote, anywhere in the plan.
100
+ const raw = [];
101
+ for (const unit of units) {
102
+ const text = unit.lines.join("\n");
103
+ for (const start of findAll(text, exact)) {
104
+ raw.push({ candidate: { unit, start, end: start + exact.length }, text });
105
+ }
106
+ }
107
+ if (raw.length > 0) {
108
+ const match = disambiguate(anchor, raw);
109
+ return match
110
+ ? { state: "anchored", anchor: { ...anchor, section: match.unit.id } }
111
+ : { state: "orphaned" };
112
+ }
113
+ // Rung 2: normalized match — whitespace reflow and emphasis markers forgiven.
114
+ const needle = normalize(exact).text;
115
+ if (needle === "")
116
+ return { state: "orphaned" };
117
+ const fuzzy = [];
118
+ for (const unit of units) {
119
+ const text = unit.lines.join("\n");
120
+ const norm = normalize(text);
121
+ for (const idx of findAll(norm.text, needle)) {
122
+ const start = norm.map[idx];
123
+ const end = norm.map[idx + needle.length - 1] + 1;
124
+ fuzzy.push({ candidate: { unit, start, end }, text, norm });
125
+ }
126
+ }
127
+ if (fuzzy.length === 0)
128
+ return { state: "orphaned" };
129
+ const match = disambiguate(anchor, fuzzy);
130
+ if (!match)
131
+ return { state: "orphaned" };
132
+ const text = match.unit.lines.join("\n");
133
+ // Rewrite the anchor to the matched raw text: the stored quote must mean
134
+ // something in the revision the user is now looking at.
135
+ const rewritten = {
136
+ section: match.unit.id,
137
+ exact: text.slice(match.start, match.end),
138
+ prefix: normalize(text.slice(Math.max(0, match.start - CONTEXT_CHARS), match.start)).text,
139
+ suffix: normalize(text.slice(match.end, match.end + CONTEXT_CHARS)).text,
140
+ };
141
+ return { state: "anchored", anchor: rewritten };
142
+ }
143
+ //# sourceMappingURL=anchor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"anchor.js","sourceRoot":"","sources":["../../src/daemon/anchor.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,yEAAyE;AACzE,oEAAoE;AACpE,6EAA6E;AAC7E,4EAA4E;AAC5E,2EAA2E;AAC3E,yEAAyE;AACzE,oEAAoE;AAIpE,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAIxC,iFAAiF;AACjF,MAAM,aAAa,GAAG,EAAE,CAAC;AAEzB,oFAAoF;AACpF,MAAM,MAAM,GAAG,OAAO,CAAC;AAQvB,8FAA8F;AAC9F,MAAM,UAAU,SAAS,CAAC,GAAW;IACnC,IAAI,IAAI,GAAG,EAAE,CAAC;IACd,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACpC,MAAM,EAAE,GAAG,GAAG,CAAC,CAAC,CAAW,CAAC;QAC5B,IAAI,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;YAAE,SAAS;QAC9B,IAAI,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;YAClB,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,IAAI,KAAK,EAAE;gBAAE,SAAS;YAChD,IAAI,IAAI,GAAG,CAAC;QACd,CAAC;aAAM,CAAC;YACN,IAAI,IAAI,EAAE,CAAC;QACb,CAAC;QACD,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACd,CAAC;IACD,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACvB,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QACzB,GAAG,CAAC,GAAG,EAAE,CAAC;IACZ,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC;AACvB,CAAC;AASD,SAAS,OAAO,CAAC,QAAgB,EAAE,MAAc;IAC/C,MAAM,IAAI,GAAa,EAAE,CAAC;IAC1B,KAAK,IAAI,GAAG,GAAG,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,GAAG,KAAK,CAAC,CAAC,EAAE,GAAG,GAAG,QAAQ,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,GAAG,CAAC,CAAC,EAAE,CAAC;QAC7F,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACjB,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,mBAAmB,CAAC,CAAS,EAAE,CAAS;IAC/C,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,IAAI,CAAC,GAAG,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,CAAC;QAAE,CAAC,EAAE,CAAC;IACxF,OAAO,CAAC,CAAC;AACX,CAAC;AAED,SAAS,mBAAmB,CAAC,CAAS,EAAE,CAAS;IAC/C,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,IAAI,CAAC,GAAG,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAAE,CAAC,EAAE,CAAC;IAC1D,OAAO,CAAC,CAAC;AACX,CAAC;AAED,oFAAoF;AACpF,SAAS,YAAY,CAAC,MAAc,EAAE,IAAY,EAAE,SAAoB;IACtE,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,CAAC,KAAK,GAAG,GAAG,CAAC,EAAE,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;IAC/F,MAAM,KAAK,GAAG,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE,SAAS,CAAC,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;IAC7E,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC;IACnD,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC;IACnD,OAAO,mBAAmB,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,mBAAmB,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;AAClF,CAAC;AAED;;;;GAIG;AACH,SAAS,YAAY,CACnB,MAAc,EACd,UAAoD;IAEpD,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,UAAU,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC;IAC7D,MAAM,MAAM,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;QACtD,SAAS;QACT,KAAK,EAAE,YAAY,CAAC,MAAM,EAAE,IAAI,EAAE,SAAS,CAAC;KAC7C,CAAC,CAAC,CAAC;IACJ,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;IACzC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,GAAG,MAAM,CAAC;IAC9B,IAAI,IAAI,IAAI,CAAC,CAAC,MAAM,IAAI,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC,SAAS,CAAC;IAC1E,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,KAAK,MAAM,CAAC,OAAO,CAAC,CAAC;IAC/E,OAAO,SAAS,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;AACtE,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,cAAc,CAC5B,MAAc,EACd,IAAY,EACZ,QAAoB,WAAW,CAAC,IAAI,CAAC;IAErC,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC;IACjC,IAAI,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;QACxB,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,MAAM,CAAC,OAAO,CAAC;YAC/C,CAAC,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE;YAC/B,CAAC,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC;IAC5B,CAAC;IAED,8DAA8D;IAC9D,MAAM,GAAG,GAA6C,EAAE,CAAC;IACzD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACnC,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,CAAC;YACzC,GAAG,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,GAAG,KAAK,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;QAC5E,CAAC;IACH,CAAC;IACD,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACnB,MAAM,KAAK,GAAG,YAAY,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QACxC,OAAO,KAAK;YACV,CAAC,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,EAAE,GAAG,MAAM,EAAE,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE;YACtE,CAAC,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC;IAC5B,CAAC;IAED,8EAA8E;IAC9E,MAAM,MAAM,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC;IACrC,IAAI,MAAM,KAAK,EAAE;QAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC;IAChD,MAAM,KAAK,GAA+D,EAAE,CAAC;IAC7E,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACnC,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;QAC7B,KAAK,MAAM,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,CAAC;YAC7C,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAW,CAAC;YACtC,MAAM,GAAG,GAAI,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,CAAY,GAAG,CAAC,CAAC;YAC9D,KAAK,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QAC9D,CAAC;IACH,CAAC;IACD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC;IACrD,MAAM,KAAK,GAAG,YAAY,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IAC1C,IAAI,CAAC,KAAK;QAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC;IACzC,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACzC,yEAAyE;IACzE,wDAAwD;IACxD,MAAM,SAAS,GAAW;QACxB,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,EAAE;QACtB,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC;QACzC,MAAM,EAAE,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,KAAK,GAAG,aAAa,CAAC,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI;QACzF,MAAM,EAAE,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,EAAE,KAAK,CAAC,GAAG,GAAG,aAAa,CAAC,CAAC,CAAC,IAAI;KACzE,CAAC;IACF,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;AAClD,CAAC"}