@zuzuucodes/cli 1.5.0 → 1.6.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 (198) hide show
  1. package/bin/zuzuu.mjs +12 -3
  2. package/package.json +1 -1
  3. package/web-app/dist/auth.js +91 -0
  4. package/web-app/dist/server.js +16 -79
  5. package/web-app/dist/zuzuu-cli.js +124 -0
  6. package/web-app/dist/{zuzuu-api.js → zuzuu-routes.js} +46 -116
  7. package/web-app/web-dist/assets/CommandPalette-DhBdR7X3.js +45 -0
  8. package/web-app/web-dist/assets/DiffTab-CqxwSjI2.js +1 -0
  9. package/web-app/web-dist/assets/EditorPane-94QPFR9R.js +41 -0
  10. package/web-app/web-dist/assets/MonacoFile-D76epTrG.js +1 -0
  11. package/web-app/web-dist/assets/angular-html-BVBpGdXr.js +1 -0
  12. package/web-app/web-dist/assets/{angular-ts-CD_OonCa.js → angular-ts-BfdufMKP.js} +1 -1
  13. package/web-app/web-dist/assets/{apl-uOGC3x4e.js → apl-DWBSSoBH.js} +1 -1
  14. package/web-app/web-dist/assets/{astro-B6ybQmWG.js → astro-3LtMP0Sq.js} +1 -1
  15. package/web-app/web-dist/assets/{blade-B1QGRlVx.js → blade-llJRbbtR.js} +1 -1
  16. package/web-app/web-dist/assets/c-Wt1voDr2.js +1 -0
  17. package/web-app/web-dist/assets/{cobol-BgqgtYWn.js → cobol-x_HIyl2P.js} +1 -1
  18. package/web-app/web-dist/assets/{coffee-0wIRKYlr.js → coffee-CThvmt4R.js} +1 -1
  19. package/web-app/web-dist/assets/cpp-NtAeskI3.js +1 -0
  20. package/web-app/web-dist/assets/{crystal-CyTK3qFN.js → crystal-DNu_sX0G.js} +1 -1
  21. package/web-app/web-dist/assets/css-DJp_X0uY.js +1 -0
  22. package/web-app/web-dist/assets/{cssMode-Dx3ub8Pk.js → cssMode-ByQBaInt.js} +1 -1
  23. package/web-app/web-dist/assets/dist-DQqjtuhV.js +153 -0
  24. package/web-app/web-dist/assets/{edge-CvML9pwC.js → edge-ozw5tpLl.js} +1 -1
  25. package/web-app/web-dist/assets/{editor.api2-BmGoRSl4.js → editor.api2-C7skgoRB.js} +1 -1
  26. package/web-app/web-dist/assets/{elixir-CrjqTiSc.js → elixir-VhA6FeZt.js} +1 -1
  27. package/web-app/web-dist/assets/{elm-C4JtJ0Au.js → elm-dREJmIFz.js} +1 -1
  28. package/web-app/web-dist/assets/{erb-Cmeb-29V.js → erb-CIg6G69l.js} +1 -1
  29. package/web-app/web-dist/assets/{freemarker2-B5LAi19B.js → freemarker2-CBBwP9JV.js} +1 -1
  30. package/web-app/web-dist/assets/{git-rebase-CXqdToiP.js → git-rebase-B44mJPta.js} +1 -1
  31. package/web-app/web-dist/assets/{glimmer-js-Kq-kdTyV.js → glimmer-js-vH_gHG0-.js} +1 -1
  32. package/web-app/web-dist/assets/{glimmer-ts-D0RKLJNf.js → glimmer-ts--abOzSAQ.js} +1 -1
  33. package/web-app/web-dist/assets/glsl-Dv5r7kPw.js +1 -0
  34. package/web-app/web-dist/assets/graphql-CB4jsw2E.js +1 -0
  35. package/web-app/web-dist/assets/{hack-trjVF3Po.js → hack-DvEYX148.js} +1 -1
  36. package/web-app/web-dist/assets/haml-zE6W3STP.js +1 -0
  37. package/web-app/web-dist/assets/{handlebars-B8_x7Zx7.js → handlebars-CzBR2SDs.js} +1 -1
  38. package/web-app/web-dist/assets/{handlebars-g7ZhGhI_.js → handlebars-tXdfxEd6.js} +1 -1
  39. package/web-app/web-dist/assets/html-C8UlPnhE.js +1 -0
  40. package/web-app/web-dist/assets/{html-CfvRMgoC.js → html-DgPn1QYH.js} +1 -1
  41. package/web-app/web-dist/assets/{html-derivative-BYX_F_XH.js → html-derivative-CY6NRz-J.js} +1 -1
  42. package/web-app/web-dist/assets/{htmlMode-DM6oHc7c.js → htmlMode-BtdIDgA2.js} +1 -1
  43. package/web-app/web-dist/assets/{http-BIVDpHT-.js → http-Cyd7bS_S.js} +1 -1
  44. package/web-app/web-dist/assets/{hurl-CFsshMju.js → hurl-CWPsiEpf.js} +1 -1
  45. package/web-app/web-dist/assets/index-B27_WOhS.css +2 -0
  46. package/web-app/web-dist/assets/index-De6DWTZM.js +7 -0
  47. package/web-app/web-dist/assets/java-CGc3VwQr.js +1 -0
  48. package/web-app/web-dist/assets/{javascript-Bxx2wV4w.js → javascript-5m05n-Be.js} +1 -1
  49. package/web-app/web-dist/assets/javascript-CUt1pgmJ.js +1 -0
  50. package/web-app/web-dist/assets/{jinja-_ZS5zWwe.js → jinja-CD-Z-FLd.js} +1 -1
  51. package/web-app/web-dist/assets/{jison-D8mMEpcs.js → jison-imPNup1l.js} +1 -1
  52. package/web-app/web-dist/assets/json-Bg9ijW3F.js +1 -0
  53. package/web-app/web-dist/assets/{jsonMode-DflaUwqW.js → jsonMode-BG32YnTY.js} +1 -1
  54. package/web-app/web-dist/assets/jsx-CY6oMTks.js +1 -0
  55. package/web-app/web-dist/assets/{julia-D4h2DZrs.js → julia-Dc3O-irA.js} +1 -1
  56. package/web-app/web-dist/assets/{just-bMqQi3xg.js → just-BhOq_Kbv.js} +1 -1
  57. package/web-app/web-dist/assets/{latex-DThYi3CX.js → latex-Cu4Y1d5w.js} +1 -1
  58. package/web-app/web-dist/assets/lib-KIOQTlcs.js +1 -0
  59. package/web-app/web-dist/assets/{liquid-CUjzzP4r.js → liquid-3ZnQzTbs.js} +1 -1
  60. package/web-app/web-dist/assets/{liquid-CesB-zzl.js → liquid-CvXMrjlQ.js} +1 -1
  61. package/web-app/web-dist/assets/{lspLanguageFeatures-gTnJsses.js → lspLanguageFeatures-6KXALSrl.js} +1 -1
  62. package/web-app/web-dist/assets/lua-BjLEUjKY.js +1 -0
  63. package/web-app/web-dist/assets/{marko-yoGoLK2m.js → marko-DvhNOisQ.js} +1 -1
  64. package/web-app/web-dist/assets/{mdc-BvtXU6eH.js → mdc-Bm9TpL1X.js} +1 -1
  65. package/web-app/web-dist/assets/{mdx-DrXGQbNB.js → mdx-DffTEkNE.js} +1 -1
  66. package/web-app/web-dist/assets/{monaco-setup-wbBeb0oN.js → monaco-setup-DM3A5_VI.js} +3 -3
  67. package/web-app/web-dist/assets/{nginx-DoUz032F.js → nginx-Bhc82uuv.js} +1 -1
  68. package/web-app/web-dist/assets/{nim-B0Pl8B4R.js → nim-DXTVBFnF.js} +1 -1
  69. package/web-app/web-dist/assets/{perl-D2tfAALb.js → perl-C7veXV9z.js} +1 -1
  70. package/web-app/web-dist/assets/{php-BImCcX5X.js → php-BRiuMnnr.js} +1 -1
  71. package/web-app/web-dist/assets/{pug-BcnpC8P_.js → pug-C5hz5LQ7.js} +1 -1
  72. package/web-app/web-dist/assets/{python-ypRCBnvu.js → python-DyLAD3Wt.js} +1 -1
  73. package/web-app/web-dist/assets/{qml-DFDAunHY.js → qml-BdUV3aTS.js} +1 -1
  74. package/web-app/web-dist/assets/r-8R7vtdQc.js +1 -0
  75. package/web-app/web-dist/assets/{razor-aqrhpwqZ.js → razor-C49xQTPQ.js} +1 -1
  76. package/web-app/web-dist/assets/{razor-1_376SZM.js → razor-DRL52XO2.js} +1 -1
  77. package/web-app/web-dist/assets/react-vendor-CCIEwYL0.js +9 -0
  78. package/web-app/web-dist/assets/regexp-Omp9DhTb.js +1 -0
  79. package/web-app/web-dist/assets/{rst-2vG6f11Y.js → rst-BHX71KW9.js} +1 -1
  80. package/web-app/web-dist/assets/{ruby-Dj6bCFXR.js → ruby-B--HzjGU.js} +1 -1
  81. package/web-app/web-dist/assets/{sas-BhVZ4qL2.js → sas-DrLaYOK_.js} +1 -1
  82. package/web-app/web-dist/assets/scss-DdSxiZKl.js +1 -0
  83. package/web-app/web-dist/assets/shellscript-DwcUjJBL.js +1 -0
  84. package/web-app/web-dist/assets/{shellsession-CyO2fnhB.js → shellsession-CPZkydE6.js} +1 -1
  85. package/web-app/web-dist/assets/{soy-DIkw6E88.js → soy-Br5FhD7c.js} +1 -1
  86. package/web-app/web-dist/assets/sql-DNssxck8.js +1 -0
  87. package/web-app/web-dist/assets/{stata-DvkM932O.js → stata-DXn1tqOr.js} +1 -1
  88. package/web-app/web-dist/assets/{surrealql-B4-Q8tqV.js → surrealql-IeLNQw0f.js} +1 -1
  89. package/web-app/web-dist/assets/{svelte-p6yBy-Ki.js → svelte-DOdLCIlh.js} +1 -1
  90. package/web-app/web-dist/assets/{templ-C7EkuiZr.js → templ-CIwIngms.js} +1 -1
  91. package/web-app/web-dist/assets/{tex-DkmD8uFC.js → tex-D8QMumu5.js} +1 -1
  92. package/web-app/web-dist/assets/{ts-tags-U-hncHg4.js → ts-tags-BMVY4q-l.js} +1 -1
  93. package/web-app/web-dist/assets/{tsMode-DRwkDcoK.js → tsMode-BndVBac5.js} +1 -1
  94. package/web-app/web-dist/assets/tsx-5Eka4NBX.js +1 -0
  95. package/web-app/web-dist/assets/{twig-CU0OP-IA.js → twig-C8o_5mgw.js} +1 -1
  96. package/web-app/web-dist/assets/{typescript-DnLjiKtn.js → typescript-B1w9vqKF.js} +1 -1
  97. package/web-app/web-dist/assets/typescript-DOu2WMV5.js +1 -0
  98. package/web-app/web-dist/assets/{vue-Db7nY3ba.js → vue-BU18DNDL.js} +1 -1
  99. package/web-app/web-dist/assets/{vue-html-BvAbiAw1.js → vue-html-BeluIYX0.js} +1 -1
  100. package/web-app/web-dist/assets/{vue-vine-BEaIQIlA.js → vue-vine-DGUAbOCX.js} +1 -1
  101. package/web-app/web-dist/assets/{xml-an4Nuuqq.js → xml-D8uAlVv5.js} +1 -1
  102. package/web-app/web-dist/assets/xml-DIqSwXR3.js +1 -0
  103. package/web-app/web-dist/assets/{xsl-D3NQgH22.js → xsl-Ct_-YIAy.js} +1 -1
  104. package/web-app/web-dist/assets/xterm-B1ffpRuj.js +36 -0
  105. package/web-app/web-dist/assets/xterm-addons-psDEiUMC.js +136 -0
  106. package/web-app/web-dist/assets/{yaml-Diiu6O9P.js → yaml-Bb7jXyQv.js} +1 -1
  107. package/web-app/web-dist/assets/yaml-DTtCYNlS.js +1 -0
  108. package/web-app/web-dist/index.html +6 -3
  109. package/zuzuu/actions/trail.mjs +1 -1
  110. package/zuzuu/commands/act.mjs +1 -1
  111. package/zuzuu/commands/capture.mjs +2 -2
  112. package/zuzuu/commands/code.mjs +2 -2
  113. package/zuzuu/commands/digest.mjs +2 -2
  114. package/zuzuu/commands/distill.mjs +15 -16
  115. package/zuzuu/commands/doctor.mjs +39 -4
  116. package/zuzuu/commands/enable.mjs +1 -1
  117. package/zuzuu/commands/eval.mjs +3 -36
  118. package/zuzuu/commands/faculty.mjs +102 -19
  119. package/zuzuu/commands/generation.mjs +3 -4
  120. package/zuzuu/commands/hook.mjs +7 -7
  121. package/zuzuu/commands/inbox.mjs +1 -6
  122. package/zuzuu/commands/init.mjs +5 -4
  123. package/zuzuu/commands/knowledge.mjs +1 -1
  124. package/zuzuu/commands/migrations/home.mjs +96 -0
  125. package/zuzuu/commands/migrations/index.mjs +48 -0
  126. package/zuzuu/commands/{migrate.mjs → migrations/items.mjs} +34 -246
  127. package/zuzuu/commands/migrations/proposals.mjs +100 -0
  128. package/zuzuu/commands/proposals.mjs +131 -0
  129. package/zuzuu/commands/review.mjs +13 -227
  130. package/zuzuu/commands/session.mjs +8 -2
  131. package/zuzuu/commands/sessions.mjs +159 -0
  132. package/zuzuu/commands/status.mjs +3 -3
  133. package/zuzuu/commands/trace.mjs +1 -1
  134. package/zuzuu/{capture-core.mjs → core/capture-core.mjs} +3 -3
  135. package/zuzuu/{store.mjs → core/store.mjs} +1 -1
  136. package/zuzuu/digest/compose.mjs +96 -0
  137. package/zuzuu/eval/score.mjs +14 -1
  138. package/zuzuu/faculties/actions/index.mjs +283 -0
  139. package/zuzuu/faculties/guardrails/index.mjs +320 -0
  140. package/zuzuu/faculties/instructions/index.mjs +288 -0
  141. package/zuzuu/faculties/knowledge/index.mjs +185 -0
  142. package/zuzuu/{memory/adapter.mjs → faculties/memory/index.mjs} +37 -9
  143. package/zuzuu/faculty/generation/read.mjs +206 -0
  144. package/zuzuu/faculty/generation/write.mjs +207 -0
  145. package/zuzuu/faculty/items.mjs +11 -5
  146. package/zuzuu/faculty/module.mjs +74 -0
  147. package/zuzuu/faculty/pending.mjs +63 -0
  148. package/zuzuu/faculty/registry.mjs +204 -18
  149. package/zuzuu/faculty/render.mjs +59 -0
  150. package/zuzuu/faculty/trail.mjs +1 -1
  151. package/zuzuu/{guardrails.mjs → guardrails/engine.mjs} +1 -1
  152. package/zuzuu/{scaffold.mjs → home/scaffold.mjs} +12 -2
  153. package/zuzuu/live/live-store.mjs +2 -2
  154. package/zuzuu/live/reconcile.mjs +2 -2
  155. package/zuzuu/sessions/git.mjs +47 -0
  156. package/zuzuu/{session-git.mjs → sessions/session-git.mjs} +5 -43
  157. package/web-app/web-dist/assets/DiffTab-BpGp1akx.js +0 -1
  158. package/web-app/web-dist/assets/MonacoFile-CqbVacUZ.js +0 -1
  159. package/web-app/web-dist/assets/angular-html-CmT26mqM.js +0 -1
  160. package/web-app/web-dist/assets/c-BvoqrSVH.js +0 -1
  161. package/web-app/web-dist/assets/cpp-BXsk94m0.js +0 -1
  162. package/web-app/web-dist/assets/css-Z8oOGxII.js +0 -1
  163. package/web-app/web-dist/assets/dist-C6R6xoyX.js +0 -153
  164. package/web-app/web-dist/assets/glsl-KwyfU2aa.js +0 -1
  165. package/web-app/web-dist/assets/graphql-DSeOUAa2.js +0 -1
  166. package/web-app/web-dist/assets/haml-azVoxQRV.js +0 -1
  167. package/web-app/web-dist/assets/html-D_7P5S4m.js +0 -1
  168. package/web-app/web-dist/assets/index-DHpC851f.js +0 -268
  169. package/web-app/web-dist/assets/index-O-t1gyMG.css +0 -2
  170. package/web-app/web-dist/assets/java-D4RbCvBe.js +0 -1
  171. package/web-app/web-dist/assets/javascript-Cb010CKM.js +0 -1
  172. package/web-app/web-dist/assets/json-DWgqV4D1.js +0 -1
  173. package/web-app/web-dist/assets/jsx-CZjSJa1f.js +0 -1
  174. package/web-app/web-dist/assets/lua-TGj_6NzO.js +0 -1
  175. package/web-app/web-dist/assets/r-fCpuAR7u.js +0 -1
  176. package/web-app/web-dist/assets/regexp-B4yxx-Ty.js +0 -1
  177. package/web-app/web-dist/assets/scss-QdjMO_xV.js +0 -1
  178. package/web-app/web-dist/assets/shellscript-BnlgeVVx.js +0 -1
  179. package/web-app/web-dist/assets/sql-DGnQv6iD.js +0 -1
  180. package/web-app/web-dist/assets/tsx-MJ0-9sYG.js +0 -1
  181. package/web-app/web-dist/assets/typescript-C17ZkDe8.js +0 -1
  182. package/web-app/web-dist/assets/xml-CA9lHFQV.js +0 -1
  183. package/web-app/web-dist/assets/yaml-CwRYMJka.js +0 -1
  184. package/zuzuu/actions/adapter.mjs +0 -122
  185. package/zuzuu/digest.mjs +0 -154
  186. package/zuzuu/faculty/generation.mjs +0 -398
  187. package/zuzuu/guardrails/adapter.mjs +0 -103
  188. package/zuzuu/instructions/adapter.mjs +0 -93
  189. package/zuzuu/knowledge/adapter.mjs +0 -99
  190. package/zuzuu/miners/actions.mjs +0 -112
  191. package/zuzuu/miners/guardrails.mjs +0 -176
  192. package/zuzuu/miners/instructions.mjs +0 -157
  193. package/zuzuu/miners/knowledge.mjs +0 -25
  194. package/zuzuu/miners/memory.mjs +0 -27
  195. package/zuzuu/miners/registry.mjs +0 -31
  196. /package/web-app/web-dist/assets/{chunk-QTnfLwEv.js → rolldown-runtime-QTnfLwEv.js} +0 -0
  197. /package/zuzuu/{session.mjs → core/session.mjs} +0 -0
  198. /package/zuzuu/{inject.mjs → home/inject.mjs} +0 -0
@@ -0,0 +1,131 @@
1
+ // `zuzuu proposals` — the human gate, non-interactive: list|show|approve|reject.
2
+ // The same adapter-driven path `zuzuu review` walks, minus the ceremony. Pure
3
+ // data fns (proposalsListData/approveData/rejectData) feed the --json surface
4
+ // and the web workbench.
5
+
6
+ import { paths } from '../core/store.mjs';
7
+ import { processInbox } from '../knowledge/inbox.mjs';
8
+ import { getProposal } from '../knowledge/proposals.mjs';
9
+ import * as registry from '../faculty/registry.mjs';
10
+ import * as gate from '../faculty/gate.mjs';
11
+ import { pendingByFaculty } from '../faculty/pending.mjs';
12
+ import { knowledgeLine, proposalTitle } from '../faculty/render.mjs';
13
+
14
+ /**
15
+ * Resolve which faculty owns a given proposal id (used when --faculty is omitted).
16
+ * Defaults to 'knowledge' (the historical path) when no other faculty claims it.
17
+ */
18
+ function facultyOf(agentDir, id, only) {
19
+ if (only) return only;
20
+ for (const { adapter, proposals } of pendingByFaculty(agentDir)) {
21
+ if (proposals.some((p) => p.id === id)) return adapter.name;
22
+ }
23
+ return 'knowledge';
24
+ }
25
+
26
+ /**
27
+ * Pure: the structured object for `proposals approve --json`.
28
+ * Calls gate.approve and returns the result object the branch prints.
29
+ * @param {string} agentDir
30
+ * @param {string} id
31
+ * @param {string} faculty
32
+ * @returns {object} the gate result (contains ok, action, etc.)
33
+ */
34
+ export function approveData(agentDir, id, faculty) {
35
+ return gate.approve(agentDir, faculty, id);
36
+ }
37
+
38
+ /**
39
+ * Pure: the structured object for `proposals reject --json`.
40
+ * Calls gate.reject and returns the result object the branch prints.
41
+ * @param {string} agentDir
42
+ * @param {string} id
43
+ * @param {string} faculty
44
+ * @param {string} [reason]
45
+ * @returns {object} { ok, id, ... }
46
+ */
47
+ export function rejectData(agentDir, id, faculty, reason = '') {
48
+ const r = gate.reject(agentDir, faculty, id, reason);
49
+ return { ...r, id };
50
+ }
51
+
52
+ /**
53
+ * Pure: list pending proposals as structured data — the zuzuu-web /proposals source.
54
+ * @param {string} agentDir
55
+ * @param {string} [only] optional faculty filter
56
+ * @returns {{ pending: Array<{id, faculty, title}> }}
57
+ */
58
+ export function proposalsListData(agentDir, only) {
59
+ const groups = pendingByFaculty(agentDir).filter((g) => !only || g.adapter.name === only);
60
+ const pending = [];
61
+ for (const { adapter, proposals } of groups) {
62
+ for (const p of proposals) {
63
+ pending.push({ id: p.id, faculty: adapter.name, title: proposalTitle(adapter, p) });
64
+ }
65
+ }
66
+ return { pending };
67
+ }
68
+
69
+ /** Non-interactive: zuzuu proposals list|show <id>|approve <id>|reject <id> [--reason r] [--faculty f] */
70
+ export function proposals(args) {
71
+ const agentDir = paths().dir;
72
+ const sub = args._[0] || 'list';
73
+ const only = args.faculty; // optional filter; default = all
74
+ if (sub === 'list') {
75
+ if (args.json) {
76
+ processInbox(agentDir); // promote plain-text inbox candidates, same as text path
77
+ const d = proposalsListData(agentDir, only);
78
+ console.log(JSON.stringify(d));
79
+ return;
80
+ }
81
+ const inbox = processInbox(agentDir);
82
+ if (inbox.processed) console.log(`(processed ${inbox.processed} inbox candidate(s))`);
83
+ const groups = pendingByFaculty(agentDir).filter((g) => !only || g.adapter.name === only);
84
+ const any = groups.some((g) => g.proposals.length);
85
+ if (!any) return console.log('no pending proposals');
86
+ for (const { adapter, proposals } of groups) {
87
+ for (const p of proposals) {
88
+ // knowledge keeps its historical one-liner; other faculties use adapter.render
89
+ if (adapter.name === 'knowledge') {
90
+ console.log(knowledgeLine(p));
91
+ } else {
92
+ console.log(` ${adapter.render(p).line}`);
93
+ }
94
+ }
95
+ }
96
+ return;
97
+ }
98
+ const id = args._[1];
99
+ if (sub === 'show') {
100
+ const faculty = facultyOf(agentDir, id, only);
101
+ const a = registry.get(faculty);
102
+ const p = (a && typeof a.getProposal === 'function') ? a.getProposal(agentDir, id) : getProposal(agentDir, id);
103
+ if (!p) return console.error('not found');
104
+ // show always prints JSON (both with and without --json flag)
105
+ console.log(JSON.stringify(p, null, 2));
106
+ return;
107
+ }
108
+ if (sub === 'approve') {
109
+ const faculty = facultyOf(agentDir, id, only);
110
+ const r = approveData(agentDir, id, faculty);
111
+ if (args.json) {
112
+ console.log(JSON.stringify(r));
113
+ } else {
114
+ console.log(r.ok ? `✓ ${r.action}` : `✗ ${(r.errors ?? [r.action]).join('; ')}`);
115
+ for (const w of r.warnings ?? []) console.log(`⚠ ${w}`);
116
+ }
117
+ process.exit(r.ok ? 0 : 1);
118
+ }
119
+ if (sub === 'reject') {
120
+ const faculty = facultyOf(agentDir, id, only);
121
+ const r = rejectData(agentDir, id, faculty, args.reason || '');
122
+ if (args.json) {
123
+ console.log(JSON.stringify(r));
124
+ } else {
125
+ console.log(r.ok ? '✓ rejected' : '✗ not found');
126
+ }
127
+ process.exit(r.ok ? 0 : 1);
128
+ }
129
+ console.error('usage: zuzuu proposals list|show <id>|approve <id>|reject <id> [--reason r] [--faculty f]');
130
+ process.exit(1);
131
+ }
@@ -1,105 +1,22 @@
1
- // `zuzuu review` — the human gate, as a daily ritual. Walks pending proposals
2
- // one-by-one: shows the candidate, its evidence, and the ER verdict (with the
3
- // matched item when enrich/duplicate) → y approve · n reject · e edit · s skip ·
4
- // q quit. Works piped (answers on stdin) — that's also how it's tested.
5
- // Non-interactive surface: `zuzuu proposals list|show|approve|reject`.
1
+ // `zuzuu review` — the human gate, as a daily ritual (the interactive ceremony).
2
+ // Walks pending proposals one-by-one: shows the candidate, its evidence, and
3
+ // the ER verdict (with the matched item when enrich/duplicate) → y approve ·
4
+ // n reject · e edit · s skip · q quit. Works piped (answers on stdin) — that's
5
+ // also how it's tested. The non-interactive surface lives in proposals.mjs.
6
6
 
7
7
  import { spawnSync } from 'node:child_process';
8
8
  import { join } from 'node:path';
9
9
  import { createInterface } from 'node:readline';
10
- import { paths, readIndex } from '../store.mjs';
10
+ import { paths } from '../core/store.mjs';
11
11
  import { processInbox } from '../knowledge/inbox.mjs';
12
12
  import { getProposal, proposalsDir } from '../knowledge/proposals.mjs';
13
- import { readItem } from '../knowledge/items.mjs';
14
- import * as registry from '../faculty/registry.mjs';
15
13
  import * as gate from '../faculty/gate.mjs';
16
- import { listProposals as spineListProposals } from '../faculty/proposal.mjs';
17
- import { mintGeneration, activeGeneration } from '../faculty/generation.mjs';
18
- import { rank } from '../eval/rank.mjs';
19
- import { getScorer, mechanicalScore } from '../eval/score.mjs';
14
+ import { pendingByFaculty, buildSessionMtimes } from '../faculty/pending.mjs';
15
+ import { knowledgeCard } from '../faculty/render.mjs';
16
+ import { activeGeneration } from '../faculty/generation/read.mjs';
17
+ import { mintGeneration } from '../faculty/generation/write.mjs';
18
+ import { getScorer } from '../eval/score.mjs';
20
19
  import { evalLine } from './eval.mjs';
21
- import '../knowledge/adapter.mjs'; // self-registers the 'knowledge' adapter
22
- import '../actions/adapter.mjs'; // self-registers the 'actions' adapter
23
- import '../guardrails/adapter.mjs'; // self-registers the 'guardrails' adapter
24
- import '../instructions/adapter.mjs'; // self-registers the 'instructions' adapter
25
- import '../memory/adapter.mjs'; // self-registers the 'memory' adapter
26
-
27
- /** Build sessionMtimes map from the sessions index — best-effort, fail-open. */
28
- function buildSessionMtimes() {
29
- try {
30
- const idx = readIndex();
31
- const map = {};
32
- for (const s of idx.sessions ?? []) {
33
- if (!s.id) continue;
34
- const ms = s.startedAt ? Date.parse(s.startedAt) : 0;
35
- if (!isNaN(ms) && ms > 0) map[s.id] = ms;
36
- }
37
- return map;
38
- } catch {
39
- return {};
40
- }
41
- }
42
-
43
- // Review walks faculties in a fixed order so piped sessions are deterministic
44
- // (the combo smoke test feeds one stdin across the actions pass then knowledge).
45
- const REVIEW_ORDER = ['actions', 'knowledge', 'guardrails', 'instructions', 'memory'];
46
-
47
- /** Ordered list of adapters that have pending proposals to review. */
48
- function pendingByFaculty(agentDir) {
49
- const adapters = registry.all();
50
- const seen = new Set();
51
- const ordered = [];
52
- for (const name of REVIEW_ORDER) {
53
- const a = adapters.find((x) => x.name === name);
54
- if (a) { ordered.push(a); seen.add(name); }
55
- }
56
- for (const a of adapters) if (!seen.has(a.name)) ordered.push(a);
57
- const sessionMtimes = buildSessionMtimes();
58
- const now = Date.now();
59
- const scorer = getScorer();
60
- const out = [];
61
- for (const a of ordered) {
62
- let proposals = facultyPending(agentDir, a);
63
- if (!proposals.length) continue;
64
- // Rank proposals highest-score-first (display only — never changes approval/mint).
65
- const ranked = rank(proposals, scorer, { now, sessionMtimes });
66
- proposals = ranked.map((r) => r.proposal);
67
- out.push({ adapter: a, proposals });
68
- }
69
- return out;
70
- }
71
-
72
- /** Pending proposals for one adapter (dir-shaped adapters override listProposals). */
73
- function facultyPending(agentDir, a) {
74
- if (typeof a.listProposals === 'function') return a.listProposals(agentDir);
75
- // JSON-record faculties: read via the spine (records carry both the spine shape
76
- // and the legacy candidate/er keys the knowledge card renders from).
77
- return spineListProposals(agentDir, a.name);
78
- }
79
-
80
- function card(agentDir, p, i, total, scoreResult) {
81
- const lines = [];
82
- lines.push(`\n━━ proposal ${i + 1}/${total} ── ${p.id} ── ${p.kind} ── source: ${p.source ?? '-'} ━━`);
83
- if (p.kind === 'registry') {
84
- lines.push(` register ${p.registry.slice(0, -1)}: '${p.key}' (seen ${p.evidence?.occurrences}× in candidates)`);
85
- } else {
86
- const c = p.candidate;
87
- lines.push(` ${c.type}: ${c.body?.slice(0, 100).replace(/\n/g, ' ')}`);
88
- for (const [k, v] of Object.entries(c.attributes ?? {})) lines.push(` · ${k} = ${v}`);
89
- for (const r of c.relations ?? []) lines.push(` → ${r.type} ${r.target}`);
90
- const ev = p.evidence ?? {};
91
- if (Object.keys(ev).length) lines.push(` evidence: ${Object.entries(ev).map(([k, v]) => `${k}=${JSON.stringify(v)}`).join(' ')}`);
92
- const er = p.er ?? {};
93
- lines.push(` er: ${er.verdict}${er.match ? ` → ${er.match}` : ''} (${(er.confidence ?? 0).toFixed(2)} · ${er.reason ?? ''})`);
94
- if (er.match) {
95
- const m = readItem(agentDir, er.match);
96
- if (m) lines.push(` existing: ${m.body.slice(0, 80).replace(/\n/g, ' ')}`);
97
- }
98
- }
99
- // Eval line — always shown; scoreResult computed by caller from ranked array.
100
- if (scoreResult) lines.push(` ${evalLine(scoreResult)}`);
101
- return lines.join('\n');
102
- }
103
20
 
104
21
  /**
105
22
  * Pure: the graduation ceremony block shown when a generation is minted.
@@ -177,7 +94,7 @@ export async function review() {
177
94
  try { scoreResult = scorer(p, { now, sessionMtimes }); } catch { /* fail-open */ }
178
95
  // Card: knowledge keeps its rich card (ER + existing-item lookup); other
179
96
  // faculties render through the adapter contract.
180
- if (adapter.name === 'knowledge') console.log(card(agentDir, p, i, proposals.length, scoreResult));
97
+ if (adapter.name === 'knowledge') console.log(knowledgeCard(agentDir, p, i, proposals.length, scoreResult));
181
98
  else {
182
99
  const r = adapter.render(p);
183
100
  const [head, ...rest] = r.card.split('\n');
@@ -210,7 +127,7 @@ export async function review() {
210
127
  proposals[i] = fresh;
211
128
  let freshScore = null;
212
129
  try { freshScore = scorer(fresh, { now, sessionMtimes }); } catch { /* fail-open */ }
213
- console.log(card(agentDir, fresh, i, proposals.length, freshScore));
130
+ console.log(knowledgeCard(agentDir, fresh, i, proposals.length, freshScore));
214
131
  }
215
132
  } else if (a === 's') {
216
133
  skipped++; totalLeft--; acted = true;
@@ -233,134 +150,3 @@ export async function review() {
233
150
  console.log(ceremonyBlock(gen.id, approvedIds, approvedByFaculty));
234
151
  }
235
152
  }
236
-
237
- /**
238
- * Resolve which faculty owns a given proposal id (used when --faculty is omitted).
239
- * Defaults to 'knowledge' (the historical path) when no other faculty claims it.
240
- */
241
- function facultyOf(agentDir, id, only) {
242
- if (only) return only;
243
- for (const { adapter, proposals } of pendingByFaculty(agentDir)) {
244
- if (proposals.some((p) => p.id === id)) return adapter.name;
245
- }
246
- return 'knowledge';
247
- }
248
-
249
- /**
250
- * Pure: the structured object for `proposals approve --json`.
251
- * Calls gate.approve and returns the result object the branch prints.
252
- * @param {string} agentDir
253
- * @param {string} id
254
- * @param {string} faculty
255
- * @returns {object} the gate result (contains ok, action, etc.)
256
- */
257
- export function approveData(agentDir, id, faculty) {
258
- return gate.approve(agentDir, faculty, id);
259
- }
260
-
261
- /**
262
- * Pure: the structured object for `proposals reject --json`.
263
- * Calls gate.reject and returns the result object the branch prints.
264
- * @param {string} agentDir
265
- * @param {string} id
266
- * @param {string} faculty
267
- * @param {string} [reason]
268
- * @returns {object} { ok, id, ... }
269
- */
270
- export function rejectData(agentDir, id, faculty, reason = '') {
271
- const r = gate.reject(agentDir, faculty, id, reason);
272
- return { ...r, id };
273
- }
274
-
275
- /**
276
- * Pure: list pending proposals as structured data — the zuzuu-web /proposals source.
277
- * @param {string} agentDir
278
- * @param {string} [only] optional faculty filter
279
- * @returns {{ pending: Array<{id, faculty, title}> }}
280
- */
281
- export function proposalsListData(agentDir, only) {
282
- const groups = pendingByFaculty(agentDir).filter((g) => !only || g.adapter.name === only);
283
- const pending = [];
284
- for (const { adapter, proposals } of groups) {
285
- for (const p of proposals) {
286
- // derive a human title the same way the table does
287
- let title;
288
- if (adapter.name === 'knowledge') {
289
- title = p.kind === 'registry'
290
- ? `register ${p.registry?.slice(0, -1) ?? ''} '${p.key ?? ''}'`
291
- : (p.candidate?.body ?? p.payload?.body ?? p.id)?.slice(0, 80);
292
- } else {
293
- title = p.title ?? adapter.render(p).line;
294
- }
295
- pending.push({ id: p.id, faculty: adapter.name, title: title ?? p.id });
296
- }
297
- }
298
- return { pending };
299
- }
300
-
301
- /** Non-interactive: zuzuu proposals list|show <id>|approve <id>|reject <id> [--reason r] [--faculty f] */
302
- export function proposals(args) {
303
- const agentDir = paths().dir;
304
- const sub = args._[0] || 'list';
305
- const only = args.faculty; // optional filter; default = all
306
- if (sub === 'list') {
307
- if (args.json) {
308
- processInbox(agentDir); // promote plain-text inbox candidates, same as text path
309
- const d = proposalsListData(agentDir, only);
310
- console.log(JSON.stringify(d));
311
- return;
312
- }
313
- const inbox = processInbox(agentDir);
314
- if (inbox.processed) console.log(`(processed ${inbox.processed} inbox candidate(s))`);
315
- const groups = pendingByFaculty(agentDir).filter((g) => !only || g.adapter.name === only);
316
- const any = groups.some((g) => g.proposals.length);
317
- if (!any) return console.log('no pending proposals');
318
- for (const { adapter, proposals } of groups) {
319
- for (const p of proposals) {
320
- // knowledge keeps its historical one-liner; other faculties use adapter.render
321
- if (adapter.name === 'knowledge') {
322
- const what = p.kind === 'registry'
323
- ? `register ${p.registry.slice(0, -1)} '${p.key}'`
324
- : `${p.candidate.type}: ${p.candidate.body?.slice(0, 60).replace(/\n/g, ' ')}`;
325
- console.log(` ${p.id} [${p.er?.verdict ?? p.kind}] ${what}`);
326
- } else {
327
- console.log(` ${adapter.render(p).line}`);
328
- }
329
- }
330
- }
331
- return;
332
- }
333
- const id = args._[1];
334
- if (sub === 'show') {
335
- const faculty = facultyOf(agentDir, id, only);
336
- const a = registry.get(faculty);
337
- const p = (a && typeof a.getProposal === 'function') ? a.getProposal(agentDir, id) : getProposal(agentDir, id);
338
- if (!p) return console.error('not found');
339
- // show always prints JSON (both with and without --json flag)
340
- console.log(JSON.stringify(p, null, 2));
341
- return;
342
- }
343
- if (sub === 'approve') {
344
- const faculty = facultyOf(agentDir, id, only);
345
- const r = approveData(agentDir, id, faculty);
346
- if (args.json) {
347
- console.log(JSON.stringify(r));
348
- } else {
349
- console.log(r.ok ? `✓ ${r.action}` : `✗ ${(r.errors ?? [r.action]).join('; ')}`);
350
- for (const w of r.warnings ?? []) console.log(`⚠ ${w}`);
351
- }
352
- process.exit(r.ok ? 0 : 1);
353
- }
354
- if (sub === 'reject') {
355
- const faculty = facultyOf(agentDir, id, only);
356
- const r = rejectData(agentDir, id, faculty, args.reason || '');
357
- if (args.json) {
358
- console.log(JSON.stringify(r));
359
- } else {
360
- console.log(r.ok ? '✓ rejected' : '✗ not found');
361
- }
362
- process.exit(r.ok ? 0 : 1);
363
- }
364
- console.error('usage: zuzuu proposals list|show <id>|approve <id>|reject <id> [--reason r] [--faculty f]');
365
- process.exit(1);
366
- }
@@ -8,7 +8,8 @@
8
8
  // All git mutation lives in session-git.mjs (fail-soft, never throws); this is
9
9
  // the thin print layer (xxxData pattern — pure data fns + --json everywhere).
10
10
 
11
- import { sessionStatus, closeSession, continueSession, discardSession } from '../session-git.mjs';
11
+ import { sessionStatus, closeSession, continueSession, discardSession } from '../sessions/session-git.mjs';
12
+ import { sessionInspect } from './sessions.mjs';
12
13
 
13
14
  /** Pure: structured session-git state (the leftover detector included). */
14
15
  export function sessionStatusData(cwd = process.cwd()) {
@@ -98,6 +99,11 @@ export function session(args = {}) {
98
99
  process.exit(1);
99
100
  }
100
101
 
101
- console.error(`unknown: zuzuu session ${sub}\nusage: zuzuu session [status|merge [--title t]|continue|discard --yes]`);
102
+ if (sub === 'inspect') {
103
+ sessionInspect(args);
104
+ return;
105
+ }
106
+
107
+ console.error(`unknown: zuzuu session ${sub}\nusage: zuzuu session [status|merge [--title t]|continue|discard --yes|inspect <id>]`);
102
108
  process.exit(1);
103
109
  }
@@ -0,0 +1,159 @@
1
+ // zuzuu/commands/sessions.mjs — the sessions observability surface (overhaul
2
+ // Part A, 2026-06-13).
3
+ //
4
+ // zuzuu sessions [--json] recorded sessions w/ state labels
5
+ // zuzuu session inspect <id> [--json] one session: trace summary +
6
+ // per-faculty mined signals
7
+ //
8
+ // inspect = { session, trace: {spans, tools, duration}, signals: {<faculty>:
9
+ // counts} } — the span count reads the stored OTLP blob; the signals re-mine
10
+ // the HOST transcript through the proven adapters' mineSignals and map the
11
+ // superset onto faculties via each module's sessionSignals hook. Fail-soft
12
+ // throughout: a gone blob/transcript degrades to warnings, never a throw.
13
+
14
+ import { readFileSync } from 'node:fs';
15
+ import { readIndex, resolveTrace, paths } from '../core/store.mjs';
16
+ import { transcriptsFor, mineHostSession } from '../knowledge/distill.mjs';
17
+ import { facultiesOf, invoke } from '../faculty/registry.mjs';
18
+
19
+ /** Pure: the sessions list with state labels — the web Sessions section source. */
20
+ export function sessionsListData(cwd = process.cwd()) {
21
+ const { sessions } = readIndex(cwd);
22
+ return {
23
+ sessions: sessions.map((s) => ({
24
+ id: s.id,
25
+ host: s.host,
26
+ state: s.status, // active | completed | abandoned | crashed | captured | opening
27
+ startedAt: s.startedAt ?? null,
28
+ endedAt: s.endedAt ?? null,
29
+ durationMs: s.durationMs ?? 0,
30
+ counts: s.counts ?? { turns: 0, tools: 0, errors: 0 },
31
+ generation: s.generation ?? null,
32
+ git: s.git ?? { commit: null, branch: null },
33
+ })),
34
+ };
35
+ }
36
+
37
+ /** Count spans across an OTLP/JSON NDJSON blob (one export request per line). */
38
+ function countTraceSpans(file) {
39
+ let spans = 0;
40
+ for (const line of readFileSync(file, 'utf8').split('\n')) {
41
+ if (!line.trim()) continue;
42
+ const req = JSON.parse(line);
43
+ for (const rs of req.resourceSpans ?? []) {
44
+ for (const ss of rs.scopeSpans ?? []) spans += (ss.spans ?? []).length;
45
+ }
46
+ }
47
+ return spans;
48
+ }
49
+
50
+ /**
51
+ * Pure-ish: one session's observability document, or null for an unknown id.
52
+ * Accepts a unique id prefix (the table shows 8-char ids).
53
+ * @param {string} cwd
54
+ * @param {string} idArg
55
+ * @param {{transcripts?: Array<{host,ref,sessionId}>}} [opts] injectable for hermetic tests
56
+ * @returns {{session, trace:{spans,tools,duration}, signals:object, warnings:string[]} | null}
57
+ */
58
+ export function sessionInspectData(cwd, idArg, { transcripts } = {}) {
59
+ if (!idArg) return null;
60
+ const { sessions } = readIndex(cwd);
61
+ const matches = sessions.filter((s) => s.id === idArg);
62
+ const byPrefix = matches.length ? matches : sessions.filter((s) => String(s.id).startsWith(idArg));
63
+ if (!byPrefix.length) return null;
64
+ const s = byPrefix[0];
65
+ const warnings = [];
66
+
67
+ // trace summary — span count from the stored OTLP blob (fail-soft)
68
+ let spans = null;
69
+ try {
70
+ spans = countTraceSpans(resolveTrace(s.traceRef, cwd));
71
+ } catch {
72
+ warnings.push('trace blob unavailable — span count unknown');
73
+ }
74
+ const trace = { spans, tools: s.counts?.tools ?? 0, duration: s.durationMs ?? 0 };
75
+
76
+ // per-faculty mined signals — re-mine the host transcript (fail-soft when gone)
77
+ const signals = {};
78
+ try {
79
+ const pairs = transcripts ?? transcriptsFor({ scope: 'all', cwd });
80
+ const pair = pairs.find((p) => p.host === s.host && String(p.sessionId) === String(s.id));
81
+ const mined = pair ? mineHostSession(pair) : null;
82
+ if (!mined) {
83
+ warnings.push('host transcript unavailable — signals empty');
84
+ } else {
85
+ const agentDir = paths(cwd).dir;
86
+ for (const entry of facultiesOf(agentDir)) {
87
+ const r = invoke(entry, 'sessionSignals', mined);
88
+ if (r.ok && r.value && typeof r.value === 'object') signals[entry.id] = r.value;
89
+ }
90
+ }
91
+ } catch {
92
+ warnings.push('signal mining failed — signals empty');
93
+ }
94
+
95
+ return {
96
+ session: {
97
+ id: s.id,
98
+ host: s.host,
99
+ state: s.status,
100
+ startedAt: s.startedAt ?? null,
101
+ endedAt: s.endedAt ?? null,
102
+ durationMs: s.durationMs ?? 0,
103
+ counts: s.counts ?? { turns: 0, tools: 0, errors: 0 },
104
+ generation: s.generation ?? null,
105
+ git: s.git ?? { commit: null, branch: null },
106
+ traceRef: s.traceRef ?? null,
107
+ },
108
+ trace,
109
+ signals,
110
+ warnings,
111
+ };
112
+ }
113
+
114
+ const fmtDur = (ms) => (ms < 60_000 ? `${(ms / 1000).toFixed(0)}s` : `${(ms / 60_000).toFixed(1)}m`);
115
+
116
+ /** `zuzuu sessions [--json]` — the recorded-sessions list with state labels. */
117
+ export function sessions(args = {}) {
118
+ const cwd = process.cwd();
119
+ const d = sessionsListData(cwd);
120
+ if (args.json) { console.log(JSON.stringify(d)); return; }
121
+ if (!d.sessions.length) {
122
+ console.log('no recorded sessions yet — run `zuzuu capture`, or just start your agent (live capture)');
123
+ return;
124
+ }
125
+ console.log(' STATE HOST DUR T/TOOLS/ERR STARTED SESSION');
126
+ for (const s of d.sessions) {
127
+ const dur = fmtDur(s.durationMs || 0).padStart(6);
128
+ const cnt = `${s.counts.turns}/${s.counts.tools}/${s.counts.errors}`.padEnd(11);
129
+ const started = (s.startedAt ?? '').slice(0, 19).padEnd(20);
130
+ console.log(` ${s.state.padEnd(10)} ${s.host.padEnd(13)} ${dur} ${cnt} ${started} ${String(s.id).slice(0, 8)}`);
131
+ }
132
+ console.log(`\n${d.sessions.length} session(s) — inspect one: zuzuu session inspect <id>`);
133
+ }
134
+
135
+ /** `zuzuu session inspect <id> [--json]` — print one session's document. */
136
+ export function sessionInspect(args = {}) {
137
+ const cwd = process.cwd();
138
+ const id = args._?.[1];
139
+ const d = sessionInspectData(cwd, id);
140
+ if (!d) {
141
+ console.error(id ? `no recorded session matching '${id}'` : 'usage: zuzuu session inspect <id> [--json]');
142
+ process.exit(1);
143
+ }
144
+ if (args.json) { console.log(JSON.stringify(d)); return; }
145
+ const s = d.session;
146
+ console.log(`${s.id} — ${s.host} · ${s.state}`);
147
+ console.log(` started: ${s.startedAt ?? '?'} ended: ${s.endedAt ?? '?'} dur: ${fmtDur(s.durationMs || 0)}`);
148
+ console.log(` git: ${s.git?.commit ? s.git.commit.slice(0, 8) : '-'} (${s.git?.branch ?? '-'}) generation: ${s.generation ?? '-'}`);
149
+ console.log(` trace: ${d.trace.spans ?? '?'} span(s) · ${d.trace.tools} tool(s) · ${fmtDur(d.trace.duration || 0)}`);
150
+ const sigs = Object.entries(d.signals);
151
+ if (sigs.length) {
152
+ console.log(' signals:');
153
+ for (const [faculty, counts] of sigs) {
154
+ const parts = Object.entries(counts).map(([k, v]) => `${k} ${v}`).join(' · ');
155
+ console.log(` ${faculty.padEnd(13)} ${parts}`);
156
+ }
157
+ }
158
+ for (const w of d.warnings) console.log(` ⚠ ${w}`);
159
+ }
@@ -3,11 +3,11 @@
3
3
  import { existsSync } from 'node:fs';
4
4
  import { dirname } from 'node:path';
5
5
  import { detected } from '../capture/adapters/registry.mjs';
6
- import { sessionStatus } from '../session-git.mjs';
7
- import { readIndex, paths } from '../store.mjs';
6
+ import { sessionStatus } from '../sessions/session-git.mjs';
7
+ import { readIndex, paths } from '../core/store.mjs';
8
8
  import { FACULTIES } from '../faculty/contract.mjs';
9
9
  import { listProposals } from '../faculty/proposal.mjs';
10
- import { activeGeneration as activeGenerationFn } from '../faculty/generation.mjs';
10
+ import { activeGeneration as activeGenerationFn } from '../faculty/generation/read.mjs';
11
11
  import { detectDrift } from './doctor.mjs';
12
12
 
13
13
  const fmtDur = (ms) => (ms < 60_000 ? `${(ms / 1000).toFixed(0)}s` : `${(ms / 60_000).toFixed(1)}m`);
@@ -2,7 +2,7 @@
2
2
 
3
3
  import { existsSync } from 'node:fs';
4
4
  import { loadSpans, renderTree } from '../capture/core/render.mjs';
5
- import { lastTrace } from '../store.mjs';
5
+ import { lastTrace } from '../core/store.mjs';
6
6
 
7
7
  export function trace(args) {
8
8
  let file = args._[0];
@@ -3,9 +3,9 @@
3
3
  // (`hook`/`reconcile`, statuses active/completed/abandoned). One proven path —
4
4
  // Design B: the hook never builds spans, it re-runs THIS.
5
5
 
6
- import { eventsToSpans } from './capture/core/spans.mjs';
7
- import { toExportRequest } from './capture/core/otlp.mjs';
8
- import { EventKind, Status } from './capture/core/event.mjs';
6
+ import { eventsToSpans } from '../capture/core/spans.mjs';
7
+ import { toExportRequest } from '../capture/core/otlp.mjs';
8
+ import { EventKind, Status } from '../capture/core/event.mjs';
9
9
  import { makeSession, SessionState } from './session.mjs';
10
10
  import { writeTrace, upsertSession, gitInfo } from './store.mjs';
11
11
 
@@ -11,7 +11,7 @@
11
11
  import { join, relative, resolve, isAbsolute } from 'node:path';
12
12
  import { existsSync, readFileSync, readdirSync, statSync, mkdirSync, writeFileSync, renameSync } from 'node:fs';
13
13
  import { spawnSync } from 'node:child_process';
14
- import { writeNdjson } from './capture/core/otlp.mjs';
14
+ import { writeNdjson } from '../capture/core/otlp.mjs';
15
15
 
16
16
  const INDEX_VERSION = 1;
17
17