@goondocks/myco 0.20.2 → 0.21.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 (196) hide show
  1. package/dist/agent-eval-RJSQI5S2.js +355 -0
  2. package/dist/agent-eval-RJSQI5S2.js.map +1 -0
  3. package/dist/{agent-run-X25Q2A6T.js → agent-run-2JSYFOKU.js} +10 -8
  4. package/dist/{agent-run-X25Q2A6T.js.map → agent-run-2JSYFOKU.js.map} +1 -1
  5. package/dist/{agent-tasks-7B6OFERB.js → agent-tasks-APFJIM2T.js} +10 -8
  6. package/dist/{agent-tasks-7B6OFERB.js.map → agent-tasks-APFJIM2T.js.map} +1 -1
  7. package/dist/{chunk-OD4AA7PV.js → chunk-53RPGOEN.js} +56 -8
  8. package/dist/chunk-53RPGOEN.js.map +1 -0
  9. package/dist/chunk-54SXG5HF.js +26 -0
  10. package/dist/chunk-54SXG5HF.js.map +1 -0
  11. package/dist/{chunk-DCSGJ7W4.js → chunk-5ZG4RMUH.js} +2 -2
  12. package/dist/{chunk-FLLBJLHM.js → chunk-6C6QZ4PM.js} +9 -5
  13. package/dist/chunk-6C6QZ4PM.js.map +1 -0
  14. package/dist/chunk-6LB7XELY.js +406 -0
  15. package/dist/chunk-6LB7XELY.js.map +1 -0
  16. package/dist/{chunk-JZGN33AY.js → chunk-75Z7UKDY.js} +4 -4
  17. package/dist/{chunk-XG5RRUYF.js → chunk-BUTL6IFS.js} +2 -2
  18. package/dist/chunk-CESKJD44.js +586 -0
  19. package/dist/chunk-CESKJD44.js.map +1 -0
  20. package/dist/chunk-CISWUP5W.js +101 -0
  21. package/dist/chunk-CISWUP5W.js.map +1 -0
  22. package/dist/chunk-DJ3IHNYO.js +50 -0
  23. package/dist/chunk-DJ3IHNYO.js.map +1 -0
  24. package/dist/chunk-F3OEQYLS.js +847 -0
  25. package/dist/chunk-F3OEQYLS.js.map +1 -0
  26. package/dist/{chunk-6RFZWV4R.js → chunk-FCJ5JV54.js} +1 -1
  27. package/dist/{chunk-6RFZWV4R.js.map → chunk-FCJ5JV54.js.map} +1 -1
  28. package/dist/{chunk-2PDWCDKY.js → chunk-G6QIBNZM.js} +9 -6
  29. package/dist/{chunk-2PDWCDKY.js.map → chunk-G6QIBNZM.js.map} +1 -1
  30. package/dist/{chunk-6X2ERTQV.js → chunk-ILJPRYES.js} +6 -4
  31. package/dist/{chunk-6X2ERTQV.js.map → chunk-ILJPRYES.js.map} +1 -1
  32. package/dist/{chunk-US4LNCAT.js → chunk-IPPMYQ2Y.js} +5 -1
  33. package/dist/chunk-IPPMYQ2Y.js.map +1 -0
  34. package/dist/{chunk-KESLPBKV.js → chunk-JR54LTPP.js} +4 -4
  35. package/dist/{chunk-CCRGY3QW.js → chunk-JZS6GZ6T.js} +16 -94
  36. package/dist/chunk-JZS6GZ6T.js.map +1 -0
  37. package/dist/{chunk-5XIVBO25.js → chunk-LVIY7P35.js} +2 -2
  38. package/dist/chunk-NGH7U6A3.js +13844 -0
  39. package/dist/chunk-NGH7U6A3.js.map +1 -0
  40. package/dist/chunk-OUJSQSKE.js +113 -0
  41. package/dist/chunk-OUJSQSKE.js.map +1 -0
  42. package/dist/{chunk-VVNL26WX.js → chunk-P66DLD6G.js} +22 -10
  43. package/dist/chunk-P66DLD6G.js.map +1 -0
  44. package/dist/{chunk-XATDZX7U.js → chunk-R2JIJBCL.js} +18 -4
  45. package/dist/{chunk-XATDZX7U.js.map → chunk-R2JIJBCL.js.map} +1 -1
  46. package/dist/{chunk-MYOZLMB2.js → chunk-RL5R4CQU.js} +538 -19
  47. package/dist/chunk-RL5R4CQU.js.map +1 -0
  48. package/dist/{chunk-EVDQKYCG.js → chunk-RQSJLWP4.js} +13 -2
  49. package/dist/chunk-RQSJLWP4.js.map +1 -0
  50. package/dist/{chunk-BPRIYNLE.js → chunk-TKAJ3JVF.js} +3 -3
  51. package/dist/{chunk-Q36VMZST.js → chunk-VHNRMM4O.js} +3 -2
  52. package/dist/{chunk-FMRZ26U5.js → chunk-X3IGT5RV.js} +5 -2
  53. package/dist/{chunk-FMRZ26U5.js.map → chunk-X3IGT5RV.js.map} +1 -1
  54. package/dist/{chunk-KHT24OWC.js → chunk-YDUOSRGD.js} +8 -94
  55. package/dist/{chunk-KHT24OWC.js.map → chunk-YDUOSRGD.js.map} +1 -1
  56. package/dist/{cli-GGPWH4UO.js → cli-LNYSTDQM.js} +49 -42
  57. package/dist/cli-LNYSTDQM.js.map +1 -0
  58. package/dist/{client-YXQUTXVZ.js → client-NWE4TCNO.js} +4 -4
  59. package/dist/{config-OMCYHG2S.js → config-VC4ACP42.js} +6 -4
  60. package/dist/{config-OMCYHG2S.js.map → config-VC4ACP42.js.map} +1 -1
  61. package/dist/{detect-providers-5KOPZ7J2.js → detect-providers-ILLQZROY.js} +4 -4
  62. package/dist/{doctor-5JXJ36KA.js → doctor-TI7EZ3RW.js} +48 -15
  63. package/dist/doctor-TI7EZ3RW.js.map +1 -0
  64. package/dist/executor-F2YU7HXJ.js +44 -0
  65. package/dist/{init-LMYOVZAV.js → init-KG3TYVGE.js} +14 -12
  66. package/dist/{init-LMYOVZAV.js.map → init-KG3TYVGE.js.map} +1 -1
  67. package/dist/{installer-FS257JRZ.js → installer-UMH7OJ5A.js} +6 -4
  68. package/dist/{llm-TH4NLIRM.js → llm-AGVEF5XD.js} +5 -4
  69. package/dist/{loader-CQYTFHEW.js → loader-LX7TFRM6.js} +5 -3
  70. package/dist/{loader-NOMBJUPW.js → loader-NAVVZK63.js} +4 -3
  71. package/dist/{main-YTBVRTBI.js → main-5PRQNEEE.js} +2453 -650
  72. package/dist/main-5PRQNEEE.js.map +1 -0
  73. package/dist/{open-HG2DX6RN.js → open-5A27BCSB.js} +10 -8
  74. package/dist/{open-HG2DX6RN.js.map → open-5A27BCSB.js.map} +1 -1
  75. package/dist/{post-compact-JSECI44W.js → post-compact-USAODKPQ.js} +6 -6
  76. package/dist/{post-tool-use-POGPTJBA.js → post-tool-use-GMMSYBII.js} +9 -7
  77. package/dist/post-tool-use-GMMSYBII.js.map +1 -0
  78. package/dist/{post-tool-use-failure-OT7BFWQW.js → post-tool-use-failure-NZVSL2PO.js} +6 -6
  79. package/dist/{pre-compact-OXVODKH4.js → pre-compact-LZ57DLUS.js} +6 -6
  80. package/dist/{provider-check-43LAMSMH.js → provider-check-ZEV5P4KM.js} +4 -4
  81. package/dist/{registry-U4CHXK6R.js → registry-M2Z5QBWH.js} +5 -4
  82. package/dist/{remove-N7ZPELFU.js → remove-T3KE6C5N.js} +10 -8
  83. package/dist/{remove-N7ZPELFU.js.map → remove-T3KE6C5N.js.map} +1 -1
  84. package/dist/{restart-ADG5GBTB.js → restart-YWDEVZUJ.js} +11 -9
  85. package/dist/{restart-ADG5GBTB.js.map → restart-YWDEVZUJ.js.map} +1 -1
  86. package/dist/{search-AHZEUNRR.js → search-GKFDGELR.js} +11 -9
  87. package/dist/{search-AHZEUNRR.js.map → search-GKFDGELR.js.map} +1 -1
  88. package/dist/{server-AGVYZVP5.js → server-AHUR6CWF.js} +368 -269
  89. package/dist/server-AHUR6CWF.js.map +1 -0
  90. package/dist/{session-6IU4AXYP.js → session-2ZEPLWW6.js} +11 -9
  91. package/dist/{session-6IU4AXYP.js.map → session-2ZEPLWW6.js.map} +1 -1
  92. package/dist/{session-end-FT27DWYZ.js → session-end-LWJYQAXX.js} +5 -5
  93. package/dist/session-start-WTA6GCOQ.js +134 -0
  94. package/dist/session-start-WTA6GCOQ.js.map +1 -0
  95. package/dist/{setup-llm-77MP4I2G.js → setup-llm-E7UU5IO7.js} +11 -9
  96. package/dist/{setup-llm-77MP4I2G.js.map → setup-llm-E7UU5IO7.js.map} +1 -1
  97. package/dist/src/agent/definitions/agent.yaml +9 -5
  98. package/dist/src/agent/definitions/tasks/cortex-instructions.yaml +93 -0
  99. package/dist/src/agent/definitions/tasks/cortex-prompt-builder.yaml +67 -0
  100. package/dist/src/agent/definitions/tasks/digest-only.yaml +1 -1
  101. package/dist/src/agent/definitions/tasks/extract-only.yaml +1 -1
  102. package/dist/src/agent/definitions/tasks/review-session.yaml +10 -39
  103. package/dist/src/agent/definitions/tasks/skill-evolve.yaml +4 -4
  104. package/dist/src/agent/definitions/tasks/skill-generate.yaml +1 -1
  105. package/dist/src/agent/definitions/tasks/skill-survey.yaml +2 -6
  106. package/dist/src/agent/definitions/tasks/supersession-sweep.yaml +1 -1
  107. package/dist/src/agent/definitions/tasks/title-summary.yaml +12 -19
  108. package/dist/src/agent/definitions/tasks/{full-intelligence.yaml → vault-evolve.yaml} +17 -82
  109. package/dist/src/agent/definitions/tasks/vault-seed.yaml +370 -0
  110. package/dist/src/agent/prompts/agent.md +12 -38
  111. package/dist/src/cli.js +1 -1
  112. package/dist/src/daemon/main.js +1 -1
  113. package/dist/src/hooks/post-tool-use.js +1 -1
  114. package/dist/src/hooks/session-end.js +1 -1
  115. package/dist/src/hooks/session-start.js +1 -1
  116. package/dist/src/hooks/stop.js +1 -1
  117. package/dist/src/hooks/user-prompt-submit.js +1 -1
  118. package/dist/src/mcp/server.js +1 -1
  119. package/dist/src/symbionts/manifests/claude-code.yaml +4 -0
  120. package/dist/src/symbionts/manifests/pi.yaml +22 -0
  121. package/dist/src/symbionts/templates/pi/package.json +6 -0
  122. package/dist/src/symbionts/templates/pi/plugin.ts +559 -0
  123. package/dist/{stats-NVPWOYTE.js → stats-DFG6S23S.js} +11 -9
  124. package/dist/{stats-NVPWOYTE.js.map → stats-DFG6S23S.js.map} +1 -1
  125. package/dist/{stop-ZPIKVLH4.js → stop-WRBTXEVT.js} +5 -5
  126. package/dist/{stop-failure-2PX67YJC.js → stop-failure-32MGIG2Q.js} +6 -6
  127. package/dist/{subagent-start-UUE6EHQD.js → subagent-start-VFGHQFVL.js} +6 -6
  128. package/dist/{subagent-stop-KQWWWPE6.js → subagent-stop-663FXG3P.js} +6 -6
  129. package/dist/{task-completed-WMHOFQ7B.js → task-completed-ZCQYEFMZ.js} +6 -6
  130. package/dist/{team-LRZ6GTQK.js → team-JTI5CDUO.js} +7 -5
  131. package/dist/{turns-YFNI5CQC.js → turns-HU2CTZAP.js} +2 -2
  132. package/dist/ui/assets/index-DGf1h-Ha.js +842 -0
  133. package/dist/ui/assets/index-_OP4ifzH.css +1 -0
  134. package/dist/ui/index.html +2 -2
  135. package/dist/{update-O6V4RC4W.js → update-3NBQTG32.js} +10 -8
  136. package/dist/{update-O6V4RC4W.js.map → update-3NBQTG32.js.map} +1 -1
  137. package/dist/{user-prompt-submit-N36KUPHI.js → user-prompt-submit-ME2TBKOS.js} +8 -7
  138. package/dist/{user-prompt-submit-N36KUPHI.js.map → user-prompt-submit-ME2TBKOS.js.map} +1 -1
  139. package/dist/{verify-LXPV7NYG.js → verify-R76ZFJSZ.js} +8 -5
  140. package/dist/{verify-LXPV7NYG.js.map → verify-R76ZFJSZ.js.map} +1 -1
  141. package/dist/{version-XMPPJQHR.js → version-GQAFBBPX.js} +2 -2
  142. package/dist/version-GQAFBBPX.js.map +1 -0
  143. package/package.json +3 -1
  144. package/skills/myco/SKILL.md +16 -1
  145. package/skills/myco/references/cli-usage.md +1 -1
  146. package/skills/myco-curate/SKILL.md +1 -1
  147. package/dist/chunk-4YFKBL3F.js +0 -195
  148. package/dist/chunk-4YFKBL3F.js.map +0 -1
  149. package/dist/chunk-CCRGY3QW.js.map +0 -1
  150. package/dist/chunk-EVDQKYCG.js.map +0 -1
  151. package/dist/chunk-FLLBJLHM.js.map +0 -1
  152. package/dist/chunk-MYOZLMB2.js.map +0 -1
  153. package/dist/chunk-OD4AA7PV.js.map +0 -1
  154. package/dist/chunk-US4LNCAT.js.map +0 -1
  155. package/dist/chunk-UYMFCYBF.js +0 -2326
  156. package/dist/chunk-UYMFCYBF.js.map +0 -1
  157. package/dist/chunk-VVNL26WX.js.map +0 -1
  158. package/dist/cli-GGPWH4UO.js.map +0 -1
  159. package/dist/doctor-5JXJ36KA.js.map +0 -1
  160. package/dist/executor-HWW2QNZQ.js +0 -2472
  161. package/dist/executor-HWW2QNZQ.js.map +0 -1
  162. package/dist/main-YTBVRTBI.js.map +0 -1
  163. package/dist/post-tool-use-POGPTJBA.js.map +0 -1
  164. package/dist/server-AGVYZVP5.js.map +0 -1
  165. package/dist/session-start-LAFICHII.js +0 -189
  166. package/dist/session-start-LAFICHII.js.map +0 -1
  167. package/dist/src/agent/definitions/tasks/graph-maintenance.yaml +0 -93
  168. package/dist/ui/assets/index-C2JuNtRB.css +0 -1
  169. package/dist/ui/assets/index-JLVaQKV2.js +0 -832
  170. /package/dist/{chunk-DCSGJ7W4.js.map → chunk-5ZG4RMUH.js.map} +0 -0
  171. /package/dist/{chunk-JZGN33AY.js.map → chunk-75Z7UKDY.js.map} +0 -0
  172. /package/dist/{chunk-XG5RRUYF.js.map → chunk-BUTL6IFS.js.map} +0 -0
  173. /package/dist/{chunk-KESLPBKV.js.map → chunk-JR54LTPP.js.map} +0 -0
  174. /package/dist/{chunk-5XIVBO25.js.map → chunk-LVIY7P35.js.map} +0 -0
  175. /package/dist/{chunk-BPRIYNLE.js.map → chunk-TKAJ3JVF.js.map} +0 -0
  176. /package/dist/{chunk-Q36VMZST.js.map → chunk-VHNRMM4O.js.map} +0 -0
  177. /package/dist/{client-YXQUTXVZ.js.map → client-NWE4TCNO.js.map} +0 -0
  178. /package/dist/{detect-providers-5KOPZ7J2.js.map → detect-providers-ILLQZROY.js.map} +0 -0
  179. /package/dist/{installer-FS257JRZ.js.map → executor-F2YU7HXJ.js.map} +0 -0
  180. /package/dist/{llm-TH4NLIRM.js.map → installer-UMH7OJ5A.js.map} +0 -0
  181. /package/dist/{loader-CQYTFHEW.js.map → llm-AGVEF5XD.js.map} +0 -0
  182. /package/dist/{loader-NOMBJUPW.js.map → loader-LX7TFRM6.js.map} +0 -0
  183. /package/dist/{provider-check-43LAMSMH.js.map → loader-NAVVZK63.js.map} +0 -0
  184. /package/dist/{post-compact-JSECI44W.js.map → post-compact-USAODKPQ.js.map} +0 -0
  185. /package/dist/{post-tool-use-failure-OT7BFWQW.js.map → post-tool-use-failure-NZVSL2PO.js.map} +0 -0
  186. /package/dist/{pre-compact-OXVODKH4.js.map → pre-compact-LZ57DLUS.js.map} +0 -0
  187. /package/dist/{registry-U4CHXK6R.js.map → provider-check-ZEV5P4KM.js.map} +0 -0
  188. /package/dist/{team-LRZ6GTQK.js.map → registry-M2Z5QBWH.js.map} +0 -0
  189. /package/dist/{session-end-FT27DWYZ.js.map → session-end-LWJYQAXX.js.map} +0 -0
  190. /package/dist/{stop-ZPIKVLH4.js.map → stop-WRBTXEVT.js.map} +0 -0
  191. /package/dist/{stop-failure-2PX67YJC.js.map → stop-failure-32MGIG2Q.js.map} +0 -0
  192. /package/dist/{subagent-start-UUE6EHQD.js.map → subagent-start-VFGHQFVL.js.map} +0 -0
  193. /package/dist/{subagent-stop-KQWWWPE6.js.map → subagent-stop-663FXG3P.js.map} +0 -0
  194. /package/dist/{task-completed-WMHOFQ7B.js.map → task-completed-ZCQYEFMZ.js.map} +0 -0
  195. /package/dist/{turns-YFNI5CQC.js.map → team-JTI5CDUO.js.map} +0 -0
  196. /package/dist/{version-XMPPJQHR.js.map → turns-HU2CTZAP.js.map} +0 -0
@@ -0,0 +1,559 @@
1
+ // Managed by Myco. Regenerated on `myco update`. Edit src/symbionts/templates/pi/plugin.ts in the Myco repo instead.
2
+ // myco:plugin-marker:pi
3
+ //
4
+ // Myco Codebase Intelligence Extension for Pi.
5
+ //
6
+ // This extension runs inside pi's extension runtime (jiti) and communicates with
7
+ // the local Myco daemon over HTTP — no subprocess spawns, no hook CLI, no stdin piping.
8
+ //
9
+ // Capture: POST /sessions/register, /sessions/unregister, /events, /events/stop
10
+ // Context: POST /context, /context/resume
11
+ // Inject: before_agent_start → systemPrompt augmentation
12
+ //
13
+ // See https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/docs/extensions.md
14
+ //
15
+ // Degraded-mode safety: this extension ships committed inside any project that has
16
+ // run `myco init` — the file lives at .pi/extensions/myco/index.ts in that project's
17
+ // repo. When a teammate clones such a project WITHOUT having Myco installed
18
+ // locally, pi will still load this extension. Every path that would contact the
19
+ // Myco daemon gracefully no-ops when `.myco/daemon.json` is absent or the daemon
20
+ // is unreachable, so the extension becomes invisible rather than throwing.
21
+ // Do NOT add runtime imports from Myco packages — only use pi's own exports
22
+ // and Node.js built-ins.
23
+
24
+ import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
25
+ import { readFileSync, appendFileSync, mkdirSync } from "node:fs";
26
+ import { join } from "node:path";
27
+ import { Type } from "@sinclair/typebox";
28
+
29
+ // ---------------------------------------------------------------------------
30
+ // Constants
31
+ // ---------------------------------------------------------------------------
32
+
33
+ /**
34
+ * Keep in sync with `TOOL_OUTPUT_PREVIEW_CHARS` in src/constants.ts (currently 200).
35
+ * The extension file is standalone and cannot import from Myco — this value is copied
36
+ * so every symbiont records tool_output previews at the same length.
37
+ */
38
+ const TOOL_OUTPUT_PREVIEW_CHARS = 200;
39
+
40
+ /** Timeout for daemon HTTP calls — must be short so we never block pi. */
41
+ const MYCO_FETCH_TIMEOUT_MS = 3000;
42
+
43
+ /** Max size of resume context injection to keep resumed sessions lean. */
44
+ const RESUME_CONTEXT_MAX_CHARS = 4000;
45
+
46
+ // ---------------------------------------------------------------------------
47
+ // Daemon HTTP transport
48
+ // ---------------------------------------------------------------------------
49
+
50
+ let cachedDaemonPort: number | null | undefined = undefined;
51
+
52
+ function readDaemonPortFromDisk(directory: string): number | null {
53
+ try {
54
+ const raw = readFileSync(join(directory, ".myco", "daemon.json"), "utf-8");
55
+ const info = JSON.parse(raw) as { port?: number };
56
+ return typeof info.port === "number" ? info.port : null;
57
+ } catch {
58
+ return null;
59
+ }
60
+ }
61
+
62
+ function getDaemonPort(directory: string): number | null {
63
+ if (cachedDaemonPort === undefined) cachedDaemonPort = readDaemonPortFromDisk(directory);
64
+ return cachedDaemonPort;
65
+ }
66
+
67
+ function refreshDaemonPort(directory: string): number | null {
68
+ cachedDaemonPort = readDaemonPortFromDisk(directory);
69
+ return cachedDaemonPort;
70
+ }
71
+
72
+ async function fetchWithTimeout(url: string, init?: RequestInit): Promise<Response | null> {
73
+ const controller = new AbortController();
74
+ const timer = setTimeout(() => controller.abort(), MYCO_FETCH_TIMEOUT_MS);
75
+ try {
76
+ const res = await fetch(url, { ...init, signal: controller.signal });
77
+ return res.ok ? res : null;
78
+ } catch {
79
+ return null;
80
+ } finally {
81
+ clearTimeout(timer);
82
+ }
83
+ }
84
+
85
+ async function fetchFromDaemon(
86
+ directory: string,
87
+ urlPath: string,
88
+ init?: RequestInit,
89
+ ): Promise<Response | null> {
90
+ const port = getDaemonPort(directory);
91
+ if (!port) return null;
92
+
93
+ const first = await fetchWithTimeout(`http://localhost:${port}${urlPath}`, init);
94
+ if (first) return first;
95
+
96
+ // Retry once with a refreshed port — the daemon may have restarted.
97
+ const freshPort = refreshDaemonPort(directory);
98
+ if (!freshPort || freshPort === port) return null;
99
+ return fetchWithTimeout(`http://localhost:${freshPort}${urlPath}`, init);
100
+ }
101
+
102
+ async function postJson(
103
+ directory: string,
104
+ urlPath: string,
105
+ body: Record<string, unknown>,
106
+ ): Promise<{ ok: boolean; data?: unknown }> {
107
+ const res = await fetchFromDaemon(directory, urlPath, {
108
+ method: "POST",
109
+ headers: { "Content-Type": "application/json" },
110
+ body: JSON.stringify(body),
111
+ });
112
+ if (!res) return { ok: false };
113
+ try {
114
+ return { ok: true, data: await res.json() };
115
+ } catch {
116
+ return { ok: true };
117
+ }
118
+ }
119
+
120
+ async function getJson(
121
+ directory: string,
122
+ urlPath: string,
123
+ ): Promise<{ ok: boolean; data?: unknown }> {
124
+ const res = await fetchFromDaemon(directory, urlPath);
125
+ if (!res) return { ok: false };
126
+ try {
127
+ return { ok: true, data: await res.json() };
128
+ } catch {
129
+ return { ok: true };
130
+ }
131
+ }
132
+
133
+ // ---------------------------------------------------------------------------
134
+ // Buffer fallback — identical pattern to opencode plugin
135
+ // ---------------------------------------------------------------------------
136
+
137
+ function bufferEvent(
138
+ directory: string,
139
+ sessionId: string,
140
+ event: Record<string, unknown>,
141
+ ): void {
142
+ try {
143
+ const bufferDir = join(directory, ".myco", "buffer");
144
+ mkdirSync(bufferDir, { recursive: true });
145
+ const filePath = join(bufferDir, `${sessionId}.jsonl`);
146
+ const { session_id: _sid, ...payload } = event;
147
+ const line = JSON.stringify({
148
+ ...payload,
149
+ timestamp: payload.timestamp ?? new Date().toISOString(),
150
+ });
151
+ appendFileSync(filePath, line + "\n");
152
+ } catch {
153
+ // Best-effort — swallow to never crash pi
154
+ }
155
+ }
156
+
157
+ async function postEventWithBuffer(
158
+ directory: string,
159
+ sessionId: string,
160
+ event: Record<string, unknown>,
161
+ ): Promise<void> {
162
+ const result = await postJson(directory, "/events", event);
163
+ if (!result.ok) {
164
+ bufferEvent(directory, sessionId, event);
165
+ }
166
+ }
167
+
168
+ // ---------------------------------------------------------------------------
169
+ // Daemon API wrappers
170
+ // ---------------------------------------------------------------------------
171
+
172
+ async function mycoRegisterSession(
173
+ directory: string,
174
+ sessionId: string,
175
+ ): Promise<void> {
176
+ await postJson(directory, "/sessions/register", {
177
+ session_id: sessionId,
178
+ agent: "pi",
179
+ started_at: new Date().toISOString(),
180
+ });
181
+ }
182
+
183
+ async function mycoUnregisterSession(directory: string, sessionId: string): Promise<void> {
184
+ await postJson(directory, "/sessions/unregister", { session_id: sessionId });
185
+ }
186
+
187
+ async function mycoPostUserPrompt(
188
+ directory: string,
189
+ sessionId: string,
190
+ prompt: string,
191
+ images: Array<{ data: string; mediaType: string }>,
192
+ ): Promise<void> {
193
+ await postEventWithBuffer(directory, sessionId, {
194
+ type: "user_prompt",
195
+ session_id: sessionId,
196
+ agent: "pi",
197
+ prompt,
198
+ ...(images.length > 0 ? { images } : {}),
199
+ });
200
+ }
201
+
202
+ async function mycoPostToolUse(
203
+ directory: string,
204
+ sessionId: string,
205
+ toolName: string,
206
+ toolInput: unknown,
207
+ toolOutput: string,
208
+ ): Promise<void> {
209
+ await postEventWithBuffer(directory, sessionId, {
210
+ type: "tool_use",
211
+ session_id: sessionId,
212
+ agent: "pi",
213
+ tool_name: toolName,
214
+ tool_input: toolInput,
215
+ output_preview: toolOutput,
216
+ });
217
+ }
218
+
219
+ async function mycoPostStop(
220
+ directory: string,
221
+ sessionId: string,
222
+ lastAssistantMessage: string | undefined,
223
+ ): Promise<void> {
224
+ await postJson(directory, "/events/stop", {
225
+ session_id: sessionId,
226
+ agent: "pi",
227
+ last_assistant_message: lastAssistantMessage,
228
+ });
229
+ }
230
+
231
+ async function fetchMycoSessionContext(
232
+ directory: string,
233
+ sessionId: string,
234
+ ): Promise<string | null> {
235
+ const result = await postJson(directory, "/context", { session_id: sessionId });
236
+ if (!result.ok) return null;
237
+ const data = result.data as { text?: string } | undefined;
238
+ const text = data?.text?.trim() ?? "";
239
+ return text.length > 0 ? text : null;
240
+ }
241
+
242
+ async function fetchMycoResumeContext(
243
+ directory: string,
244
+ sessionId: string,
245
+ parentSessionId: string,
246
+ ): Promise<string | null> {
247
+ const result = await postJson(directory, "/context/resume", {
248
+ session_id: sessionId,
249
+ parent_session_id: parentSessionId,
250
+ });
251
+ if (!result.ok) return null;
252
+ const data = result.data as { text?: string } | undefined;
253
+ const text = data?.text?.trim() ?? "";
254
+ if (!text || text.length > RESUME_CONTEXT_MAX_CHARS) return null;
255
+ return text;
256
+ }
257
+
258
+ async function mycoPostCompact(
259
+ directory: string,
260
+ sessionId: string,
261
+ ): Promise<void> {
262
+ await postEventWithBuffer(directory, sessionId, {
263
+ type: "pre_compact",
264
+ session_id: sessionId,
265
+ agent: "pi",
266
+ });
267
+ }
268
+
269
+ // ---------------------------------------------------------------------------
270
+ // Helpers
271
+ // ---------------------------------------------------------------------------
272
+
273
+ function summarizeToolOutput(output: unknown): string {
274
+ if (typeof output !== "string") return "";
275
+ return output.length > TOOL_OUTPUT_PREVIEW_CHARS
276
+ ? output.slice(0, TOOL_OUTPUT_PREVIEW_CHARS) + "..."
277
+ : output;
278
+ }
279
+
280
+ /**
281
+ * Derive a stable session ID from pi's session file path.
282
+ * Pi sessions are stored as JSONL files with UUID-based names
283
+ * at ~/.pi/agent/sessions/<path-hash>/<timestamp>_<uuid>.jsonl.
284
+ * We extract the filename (without extension) as the session ID.
285
+ */
286
+ function deriveSessionId(sessionFile: string | null): string | null {
287
+ if (!sessionFile) return null;
288
+ const base = sessionFile.split("/").pop() ?? sessionFile;
289
+ return base.replace(/\.jsonl$/, "");
290
+ }
291
+
292
+ /**
293
+ * Extract text content from pi message content (string or content block array).
294
+ */
295
+ function extractTextFromContent(content: unknown): string {
296
+ if (typeof content === "string") return content;
297
+ if (!Array.isArray(content)) return "";
298
+ return content
299
+ .filter((c: { type?: string; text?: string }) => c.type === "text" && c.text)
300
+ .map((c: { text: string }) => c.text)
301
+ .join("\n");
302
+ }
303
+
304
+ /**
305
+ * Extract images from a pi message content array.
306
+ */
307
+ function extractImagesFromContent(content: unknown): Array<{ data: string; mediaType: string }> {
308
+ if (!Array.isArray(content)) return [];
309
+ return content
310
+ .filter((c: { type?: string; data?: string; mimeType?: string }) =>
311
+ c.type === "image" && c.data && c.mimeType)
312
+ .map((c: { data: string; mimeType: string }) => ({
313
+ data: c.data,
314
+ mediaType: c.mimeType,
315
+ }));
316
+ }
317
+
318
+ // ---------------------------------------------------------------------------
319
+ // Extension entry
320
+ // ---------------------------------------------------------------------------
321
+
322
+ export default function (pi: ExtensionAPI) {
323
+ let currentSessionId: string | null = null;
324
+ let currentCwd: string = process.cwd();
325
+ let lastAssistantMessage: string = "";
326
+
327
+ // ── Session lifecycle ──────────────────────────────────────────────────
328
+
329
+ pi.on("session_start", async (event, ctx) => {
330
+ currentCwd = ctx.cwd;
331
+
332
+ // Check if daemon is available — silent no-op if not
333
+ if (!getDaemonPort(currentCwd)) return;
334
+
335
+ const sessionFile = ctx.sessionManager.getSessionFile();
336
+ const sessionId = deriveSessionId(sessionFile);
337
+ if (!sessionId) return;
338
+
339
+ currentSessionId = sessionId;
340
+ lastAssistantMessage = "";
341
+
342
+ const isResume = event.reason === "resume";
343
+ const isFork = event.reason === "fork";
344
+
345
+ // Register with the daemon
346
+ await mycoRegisterSession(currentCwd, sessionId);
347
+
348
+ // Fetch and inject context as a persistent custom message.
349
+ // Pi's before_agent_start hook augments the system prompt each turn,
350
+ // but this initial injection ensures context is visible in the session
351
+ // history and survives compaction.
352
+ let contextText: string | null = null;
353
+
354
+ if (isResume && event.previousSessionFile) {
355
+ const previousSessionId = deriveSessionId(event.previousSessionFile);
356
+ if (previousSessionId) {
357
+ contextText = await fetchMycoResumeContext(currentCwd, sessionId, previousSessionId);
358
+ }
359
+ } else if (!isFork) {
360
+ contextText = await fetchMycoSessionContext(currentCwd, sessionId);
361
+ }
362
+
363
+ if (contextText) {
364
+ pi.sendMessage({
365
+ customType: "myco-context",
366
+ content: contextText,
367
+ display: false,
368
+ }, {
369
+ deliverAs: "nextTurn",
370
+ });
371
+ }
372
+ });
373
+
374
+ pi.on("session_shutdown", async () => {
375
+ if (!currentSessionId) return;
376
+
377
+ await mycoPostStop(currentCwd, currentSessionId, lastAssistantMessage || undefined);
378
+ await mycoUnregisterSession(currentCwd, currentSessionId);
379
+ currentSessionId = null;
380
+ lastAssistantMessage = "";
381
+ });
382
+
383
+ // ── User prompt capture + context injection ────────────────────────────
384
+ //
385
+ // Single before_agent_start handler: captures the user prompt AND
386
+ // augments the system prompt with Myco context. This avoids registering
387
+ // two handlers for the same event (pi chains them, but the second
388
+ // handler's return value would overwrite the first).
389
+
390
+ pi.on("before_agent_start", async (event, _ctx) => {
391
+ if (!currentSessionId) return;
392
+
393
+ // 1. Capture the user prompt
394
+ const prompt = event.prompt ?? "";
395
+ const images = extractImagesFromContent(event.images);
396
+ if (prompt) {
397
+ // Fire-and-forget capture — don't block the agent start
398
+ mycoPostUserPrompt(currentCwd, currentSessionId, prompt, images);
399
+ }
400
+
401
+ // 2. Augment system prompt with Myco context
402
+ const contextText = await fetchMycoSessionContext(currentCwd, currentSessionId);
403
+ if (contextText) {
404
+ return {
405
+ systemPrompt: event.systemPrompt + "\n\n" + contextText,
406
+ };
407
+ }
408
+ return undefined;
409
+ });
410
+
411
+ // ── Tool use capture ───────────────────────────────────────────────────
412
+
413
+ pi.on("tool_result", async (event) => {
414
+ if (!currentSessionId) return;
415
+
416
+ const toolName = event.toolName ?? "unknown";
417
+ const toolInput = event.input ?? {};
418
+ const rawOutput = Array.isArray(event.content)
419
+ ? event.content
420
+ .filter((c: { type?: string; text?: string }) => c.type === "text")
421
+ .map((c: { text: string }) => c.text)
422
+ .join("\n")
423
+ : "";
424
+ const toolOutput = summarizeToolOutput(rawOutput);
425
+
426
+ // Fire-and-forget — don't block tool result processing
427
+ mycoPostToolUse(currentCwd, currentSessionId, toolName, toolInput, toolOutput);
428
+ return undefined;
429
+ });
430
+
431
+ // ── Track last assistant message ───────────────────────────────────────
432
+
433
+ pi.on("message_end", async (event) => {
434
+ if (!currentSessionId) return;
435
+ if (event.message?.role === "assistant") {
436
+ const text = extractTextFromContent(event.message.content);
437
+ if (text) {
438
+ lastAssistantMessage = text;
439
+ }
440
+ }
441
+ });
442
+
443
+ // ── Agent end → post stop for agentic loop completion ──────────────────
444
+ //
445
+ // Pi fires agent_end after each user prompt's agentic loop completes.
446
+ // We post a stop event so the daemon can process the turn. session_shutdown
447
+ // handles the final cleanup on exit.
448
+
449
+ pi.on("agent_end", async () => {
450
+ if (!currentSessionId) return;
451
+ await mycoPostStop(currentCwd, currentSessionId, lastAssistantMessage || undefined);
452
+ });
453
+
454
+ // ── Compaction hook — notify daemon of context compaction ──────────────
455
+
456
+ pi.on("session_before_compact", async () => {
457
+ if (!currentSessionId) return;
458
+ await mycoPostCompact(currentCwd, currentSessionId);
459
+ return undefined;
460
+ });
461
+
462
+ // ── MCP tool proxies — expose Myco's intelligence to the LLM ──────────
463
+ //
464
+ // Pi has no native MCP support. Instead, we register Myco's core tools
465
+ // directly via pi.registerTool() so the LLM can query the knowledge vault.
466
+
467
+ pi.registerTool({
468
+ name: "myco_context",
469
+ label: "Myco Context",
470
+ description:
471
+ "Get project context, observations, and intelligence from Myco's knowledge vault. " +
472
+ "Use this to understand the project's history, prior decisions, gotchas, and patterns.",
473
+ promptSnippet: "Query Myco vault for project intelligence, prior decisions, and observations",
474
+ promptGuidelines: [
475
+ "Use myco_context at the start of complex tasks to understand project history and prior decisions.",
476
+ "Use myco_context when you encounter unfamiliar code patterns or architecture choices.",
477
+ ],
478
+ parameters: Type.Object({}),
479
+ async execute() {
480
+ if (!currentSessionId) {
481
+ return { content: [{ type: "text" as const, text: "No active session" }], details: {} };
482
+ }
483
+ const result = await fetchMycoSessionContext(currentCwd, currentSessionId);
484
+ return {
485
+ content: [{ type: "text" as const, text: result ?? "No context available from Myco vault." }],
486
+ details: {},
487
+ };
488
+ },
489
+ });
490
+
491
+ pi.registerTool({
492
+ name: "myco_search",
493
+ label: "Myco Search",
494
+ description:
495
+ "Search Myco's knowledge vault for specific topics, patterns, or prior observations. " +
496
+ "Returns relevant spores (observations), session summaries, and related intelligence.",
497
+ promptSnippet: "Search Myco vault for specific topics, patterns, or observations",
498
+ promptGuidelines: [
499
+ "Use myco_search when you need specific information about a topic, pattern, or past decision.",
500
+ "Prefer myco_search over myco_context when you have a focused query.",
501
+ ],
502
+ parameters: Type.Object({
503
+ query: Type.String({ description: "Search query — topic, pattern, or question" }),
504
+ }),
505
+ async execute(_toolCallId, params) {
506
+ if (!currentSessionId) {
507
+ return { content: [{ type: "text" as const, text: "No active session" }], details: {} };
508
+ }
509
+ const result = await getJson(currentCwd, `/api/search?q=${encodeURIComponent(params.query)}`);
510
+ if (!result.ok || !result.data) {
511
+ return { content: [{ type: "text" as const, text: "Search unavailable — Myco daemon may not be running." }], details: {} };
512
+ }
513
+ return {
514
+ content: [{ type: "text" as const, text: JSON.stringify(result.data, null, 2) }],
515
+ details: {},
516
+ };
517
+ },
518
+ });
519
+
520
+ pi.registerTool({
521
+ name: "myco_observe",
522
+ label: "Myco Observe",
523
+ description:
524
+ "Record an observation (gotcha, decision, discovery, trade-off, bug fix) in Myco's knowledge vault. " +
525
+ "Use this when you discover something important about the codebase that future sessions should know.",
526
+ promptSnippet: "Record an observation in Myco vault for future sessions",
527
+ promptGuidelines: [
528
+ "Use myco_observe to record important discoveries, gotchas, decisions, and trade-offs.",
529
+ "Include enough context that a future session can understand the observation without seeing this conversation.",
530
+ ],
531
+ parameters: Type.Object({
532
+ observation_type: Type.String({
533
+ description: "Type: gotcha, decision, discovery, trade-off, bug_fix, pattern, or any descriptive string",
534
+ }),
535
+ title: Type.String({ description: "Short title for the observation" }),
536
+ content: Type.String({ description: "Detailed observation with context" }),
537
+ tags: Type.Optional(Type.Array(Type.String(), { description: "Optional tags for categorization" })),
538
+ }),
539
+ async execute(_toolCallId, params) {
540
+ if (!currentSessionId) {
541
+ return { content: [{ type: "text" as const, text: "No active session" }], details: {} };
542
+ }
543
+ const result = await postJson(currentCwd, "/api/spores", {
544
+ session_id: currentSessionId,
545
+ observation_type: params.observation_type,
546
+ title: params.title,
547
+ content: params.content,
548
+ tags: params.tags ?? [],
549
+ });
550
+ if (!result.ok) {
551
+ return { content: [{ type: "text" as const, text: "Failed to record observation — Myco daemon may not be running." }], details: {} };
552
+ }
553
+ return {
554
+ content: [{ type: "text" as const, text: `Observation recorded: ${params.title}` }],
555
+ details: {},
556
+ };
557
+ },
558
+ });
559
+ }
@@ -1,19 +1,21 @@
1
1
  import { createRequire as __cr } from 'node:module'; const require = __cr(import.meta.url);
2
2
  import {
3
3
  gatherStats
4
- } from "./chunk-JZGN33AY.js";
4
+ } from "./chunk-75Z7UKDY.js";
5
5
  import {
6
6
  initVaultDb
7
- } from "./chunk-KESLPBKV.js";
7
+ } from "./chunk-JR54LTPP.js";
8
8
  import "./chunk-SAKJMNSR.js";
9
- import "./chunk-Q36VMZST.js";
10
- import "./chunk-FMRZ26U5.js";
11
- import "./chunk-OD4AA7PV.js";
9
+ import "./chunk-VHNRMM4O.js";
10
+ import "./chunk-X3IGT5RV.js";
11
+ import "./chunk-53RPGOEN.js";
12
+ import "./chunk-OUJSQSKE.js";
13
+ import "./chunk-POEPHBQK.js";
12
14
  import "./chunk-MYX5NCRH.js";
13
- import "./chunk-VVNL26WX.js";
14
- import "./chunk-XG5RRUYF.js";
15
+ import "./chunk-P66DLD6G.js";
16
+ import "./chunk-BUTL6IFS.js";
15
17
  import "./chunk-LPUQPDC2.js";
16
- import "./chunk-FLLBJLHM.js";
18
+ import "./chunk-6C6QZ4PM.js";
17
19
  import "./chunk-UUHLLQXO.js";
18
20
  import "./chunk-6LQIMRTC.js";
19
21
  import "./chunk-ODXLRR4U.js";
@@ -92,4 +94,4 @@ function formatUptime(seconds) {
92
94
  export {
93
95
  run
94
96
  };
95
- //# sourceMappingURL=stats-NVPWOYTE.js.map
97
+ //# sourceMappingURL=stats-DFG6S23S.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli/stats.ts"],"sourcesContent":["/**\n * CLI: myco stats — display vault statistics.\n *\n * Opens the SQLite database directly (WAL mode allows concurrent reads).\n * Does NOT require the daemon to be running.\n */\n\nimport type { V2Stats } from '../services/stats.js';\nimport { gatherStats } from '../services/stats.js';\nimport { initVaultDb } from './shared.js';\n\nexport async function run(_args: string[], vaultDir: string): Promise<void> {\n const cleanup = initVaultDb(vaultDir);\n let stats: V2Stats;\n try {\n stats = gatherStats(vaultDir);\n } catch (err) {\n cleanup();\n console.error('Failed to read vault database:', (err as Error).message);\n process.exit(1);\n }\n cleanup();\n\n console.log('=== Myco Vault ===');\n console.log(`Path: ${stats.vault.path}`);\n console.log(`Name: ${stats.vault.name}`);\n\n console.log('\\n--- Data ---');\n console.log(`Sessions: ${stats.vault.session_count}`);\n console.log(`Batches: ${stats.vault.batch_count}`);\n console.log(`Spores: ${stats.vault.spore_count}`);\n console.log(`Plans: ${stats.vault.plan_count}`);\n console.log(`Artifacts: ${stats.vault.artifact_count}`);\n console.log(`Entities: ${stats.vault.entity_count}`);\n console.log(`Edges: ${stats.vault.edge_count}`);\n\n console.log('\\n--- Embeddings ---');\n console.log(`Provider: ${stats.embedding.provider} (${stats.embedding.model})`);\n console.log(`Embedded: ${stats.embedding.embedded_count} / ${stats.embedding.total_embeddable}`);\n if (stats.embedding.queue_depth > 0) {\n console.log(`Queue: ${stats.embedding.queue_depth} pending`);\n }\n\n console.log('\\n--- Agent ---');\n if (stats.agent.total_runs === 0) {\n console.log('No runs yet');\n } else {\n const lastAt = stats.agent.last_run_at\n ? new Date(stats.agent.last_run_at * 1000).toISOString()\n : 'never';\n console.log(`Last run: ${lastAt} (${stats.agent.last_run_status ?? 'unknown'})`);\n console.log(`Total runs: ${stats.agent.total_runs}`);\n }\n if (stats.unprocessed_batches > 0) {\n console.log(`Pending: ${stats.unprocessed_batches} unprocessed batch(es)`);\n }\n\n console.log('\\n--- Digest ---');\n if (stats.digest.tiers_available.length === 0) {\n console.log('No digest extracts yet');\n } else {\n const generatedAt = stats.digest.generated_at\n ? new Date(stats.digest.generated_at * 1000).toISOString()\n : 'unknown';\n console.log(`Tiers: ${stats.digest.tiers_available.join(', ')}`);\n console.log(`Freshest: tier ${stats.digest.freshest_tier} (generated ${generatedAt})`);\n }\n\n // Daemon section — from the live daemon stats\n const { pid, port, version, uptime_seconds, active_sessions } = stats.daemon;\n if (pid > 0) {\n console.log('\\n--- Daemon ---');\n console.log(`PID: ${pid} (running)`);\n console.log(`Port: ${port}`);\n if (version) console.log(`Version: ${version}`);\n if (uptime_seconds > 0) {\n console.log(`Uptime: ${formatUptime(uptime_seconds)}`);\n }\n console.log(`Dashboard: http://localhost:${port}/`);\n console.log(`Sessions: ${active_sessions.length}`);\n }\n}\n\nfunction formatUptime(seconds: number): string {\n const h = Math.floor(seconds / 3600);\n const m = Math.floor((seconds % 3600) / 60);\n const s = seconds % 60;\n if (h > 0) return `${h}h ${m}m ${s}s`;\n if (m > 0) return `${m}m ${s}s`;\n return `${s}s`;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/cli/stats.ts"],"sourcesContent":["/**\n * CLI: myco stats — display vault statistics.\n *\n * Opens the SQLite database directly (WAL mode allows concurrent reads).\n * Does NOT require the daemon to be running.\n */\n\nimport type { V2Stats } from '../services/stats.js';\nimport { gatherStats } from '../services/stats.js';\nimport { initVaultDb } from './shared.js';\n\nexport async function run(_args: string[], vaultDir: string): Promise<void> {\n const cleanup = initVaultDb(vaultDir);\n let stats: V2Stats;\n try {\n stats = gatherStats(vaultDir);\n } catch (err) {\n cleanup();\n console.error('Failed to read vault database:', (err as Error).message);\n process.exit(1);\n }\n cleanup();\n\n console.log('=== Myco Vault ===');\n console.log(`Path: ${stats.vault.path}`);\n console.log(`Name: ${stats.vault.name}`);\n\n console.log('\\n--- Data ---');\n console.log(`Sessions: ${stats.vault.session_count}`);\n console.log(`Batches: ${stats.vault.batch_count}`);\n console.log(`Spores: ${stats.vault.spore_count}`);\n console.log(`Plans: ${stats.vault.plan_count}`);\n console.log(`Artifacts: ${stats.vault.artifact_count}`);\n console.log(`Entities: ${stats.vault.entity_count}`);\n console.log(`Edges: ${stats.vault.edge_count}`);\n\n console.log('\\n--- Embeddings ---');\n console.log(`Provider: ${stats.embedding.provider} (${stats.embedding.model})`);\n console.log(`Embedded: ${stats.embedding.embedded_count} / ${stats.embedding.total_embeddable}`);\n if (stats.embedding.queue_depth > 0) {\n console.log(`Queue: ${stats.embedding.queue_depth} pending`);\n }\n\n console.log('\\n--- Agent ---');\n if (stats.agent.total_runs === 0) {\n console.log('No runs yet');\n } else {\n const lastAt = stats.agent.last_run_at\n ? new Date(stats.agent.last_run_at * 1000).toISOString()\n : 'never';\n console.log(`Last run: ${lastAt} (${stats.agent.last_run_status ?? 'unknown'})`);\n console.log(`Total runs: ${stats.agent.total_runs}`);\n }\n if (stats.unprocessed_batches > 0) {\n console.log(`Pending: ${stats.unprocessed_batches} unprocessed batch(es)`);\n }\n\n console.log('\\n--- Digest ---');\n if (stats.digest.tiers_available.length === 0) {\n console.log('No digest extracts yet');\n } else {\n const generatedAt = stats.digest.generated_at\n ? new Date(stats.digest.generated_at * 1000).toISOString()\n : 'unknown';\n console.log(`Tiers: ${stats.digest.tiers_available.join(', ')}`);\n console.log(`Freshest: tier ${stats.digest.freshest_tier} (generated ${generatedAt})`);\n }\n\n // Daemon section — from the live daemon stats\n const { pid, port, version, uptime_seconds, active_sessions } = stats.daemon;\n if (pid > 0) {\n console.log('\\n--- Daemon ---');\n console.log(`PID: ${pid} (running)`);\n console.log(`Port: ${port}`);\n if (version) console.log(`Version: ${version}`);\n if (uptime_seconds > 0) {\n console.log(`Uptime: ${formatUptime(uptime_seconds)}`);\n }\n console.log(`Dashboard: http://localhost:${port}/`);\n console.log(`Sessions: ${active_sessions.length}`);\n }\n}\n\nfunction formatUptime(seconds: number): string {\n const h = Math.floor(seconds / 3600);\n const m = Math.floor((seconds % 3600) / 60);\n const s = seconds % 60;\n if (h > 0) return `${h}h ${m}m ${s}s`;\n if (m > 0) return `${m}m ${s}s`;\n return `${s}s`;\n}\n"],"mappings":"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","names":[]}
@@ -2,18 +2,18 @@ import { createRequire as __cr } from 'node:module'; const require = __cr(import
2
2
  import {
3
3
  normalizeHookInput,
4
4
  readStdin
5
- } from "./chunk-DCSGJ7W4.js";
5
+ } from "./chunk-5ZG4RMUH.js";
6
6
  import "./chunk-ZXZPJJN3.js";
7
7
  import {
8
8
  resolveVaultDir
9
9
  } from "./chunk-CUDIZJY7.js";
10
10
  import {
11
11
  DaemonClient
12
- } from "./chunk-VVNL26WX.js";
13
- import "./chunk-XG5RRUYF.js";
12
+ } from "./chunk-P66DLD6G.js";
13
+ import "./chunk-BUTL6IFS.js";
14
14
  import "./chunk-NGROSFOH.js";
15
15
  import "./chunk-LPUQPDC2.js";
16
- import "./chunk-FLLBJLHM.js";
16
+ import "./chunk-6C6QZ4PM.js";
17
17
  import "./chunk-UUHLLQXO.js";
18
18
  import "./chunk-6LQIMRTC.js";
19
19
  import "./chunk-ODXLRR4U.js";
@@ -46,4 +46,4 @@ async function main() {
46
46
  export {
47
47
  main
48
48
  };
49
- //# sourceMappingURL=stop-ZPIKVLH4.js.map
49
+ //# sourceMappingURL=stop-WRBTXEVT.js.map
@@ -1,16 +1,16 @@
1
1
  import { createRequire as __cr } from 'node:module'; const require = __cr(import.meta.url);
2
2
  import {
3
3
  sendEvent
4
- } from "./chunk-2PDWCDKY.js";
4
+ } from "./chunk-G6QIBNZM.js";
5
5
  import "./chunk-V7XG6V6C.js";
6
- import "./chunk-DCSGJ7W4.js";
6
+ import "./chunk-5ZG4RMUH.js";
7
7
  import "./chunk-ZXZPJJN3.js";
8
8
  import "./chunk-CUDIZJY7.js";
9
- import "./chunk-VVNL26WX.js";
10
- import "./chunk-XG5RRUYF.js";
9
+ import "./chunk-P66DLD6G.js";
10
+ import "./chunk-BUTL6IFS.js";
11
11
  import "./chunk-NGROSFOH.js";
12
12
  import "./chunk-LPUQPDC2.js";
13
- import "./chunk-FLLBJLHM.js";
13
+ import "./chunk-6C6QZ4PM.js";
14
14
  import "./chunk-UUHLLQXO.js";
15
15
  import "./chunk-6LQIMRTC.js";
16
16
  import "./chunk-ODXLRR4U.js";
@@ -28,4 +28,4 @@ async function main() {
28
28
  export {
29
29
  main
30
30
  };
31
- //# sourceMappingURL=stop-failure-2PX67YJC.js.map
31
+ //# sourceMappingURL=stop-failure-32MGIG2Q.js.map