project-athena 0.2.1 → 0.4.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 (152) hide show
  1. package/CHANGELOG.md +63 -0
  2. package/README.md +61 -12
  3. package/dist/activity-BKW7G4I5.js +77 -0
  4. package/dist/agents-DFSNEOP5.js +69 -0
  5. package/dist/ai-ASL4FFQ7.js +96 -0
  6. package/dist/analyze-ZY3MXBOI.js +50 -0
  7. package/dist/chunk-2DY4PUR4.js +465 -0
  8. package/dist/chunk-2R6PXY6Z.js +33 -0
  9. package/dist/chunk-3IS2X2Z7.js +89 -0
  10. package/dist/chunk-3XSDI5WF.js +179 -0
  11. package/dist/chunk-65TSRDQ3.js +124 -0
  12. package/dist/chunk-673EPYYH.js +105 -0
  13. package/dist/chunk-7DZK6WSQ.js +65 -0
  14. package/dist/chunk-AD4OZCU2.js +34 -0
  15. package/dist/chunk-DZDI2HRT.js +169 -0
  16. package/dist/chunk-ELKFRTZT.js +221 -0
  17. package/dist/chunk-EUPETUWA.js +14 -0
  18. package/dist/chunk-FQEGEVLY.js +38 -0
  19. package/dist/chunk-FVCDMQUQ.js +343 -0
  20. package/dist/chunk-GGXPG6OE.js +904 -0
  21. package/dist/chunk-GHFRQAYT.js +112 -0
  22. package/dist/chunk-GR4DL2VM.js +47 -0
  23. package/dist/chunk-INT3IGMQ.js +111 -0
  24. package/dist/chunk-IQQBAWSM.js +90 -0
  25. package/dist/chunk-JCGDR4UV.js +182 -0
  26. package/dist/chunk-KBO7XRBW.js +26 -0
  27. package/dist/chunk-KHMBNT66.js +399 -0
  28. package/dist/chunk-LEMPCNAY.js +209 -0
  29. package/dist/chunk-MPG3IEGB.js +2691 -0
  30. package/dist/chunk-OLPSEQS5.js +264 -0
  31. package/dist/chunk-PVCIGUIT.js +64 -0
  32. package/dist/chunk-QCC4VJUH.js +217 -0
  33. package/dist/chunk-QLW657NT.js +95 -0
  34. package/dist/chunk-RVTNSNGK.js +182 -0
  35. package/dist/chunk-RXNRMIZP.js +390 -0
  36. package/dist/chunk-SHKXELUX.js +295 -0
  37. package/dist/chunk-SJ4DQFIJ.js +379 -0
  38. package/dist/chunk-SVTEJYMS.js +227 -0
  39. package/dist/chunk-TDNZ2RYA.js +702 -0
  40. package/dist/chunk-UAZLPNVC.js +108 -0
  41. package/dist/chunk-VSYBC3VY.js +28 -0
  42. package/dist/chunk-WVQC2EGO.js +166 -0
  43. package/dist/chunk-XDCKZ5TV.js +436 -0
  44. package/dist/chunk-XFN7UZCS.js +35 -0
  45. package/dist/chunk-XW3MLHI2.js +32 -0
  46. package/dist/chunk-YRIS7ZS6.js +919 -0
  47. package/dist/chunk-Z6QWMJLK.js +124 -0
  48. package/dist/chunk-ZB7LC6FP.js +221 -0
  49. package/dist/clean-MDBYH62P.js +23 -0
  50. package/dist/cli.js +18 -10716
  51. package/dist/context-PLPCAPCO.js +161 -0
  52. package/dist/doctor-BX677KRE.js +69 -0
  53. package/dist/event-TNT6CQZR.js +101 -0
  54. package/dist/git-hook-YZNZGAAP.js +252 -0
  55. package/dist/init-WQCAOJ2R.js +38 -0
  56. package/dist/mcp-U7EPH43L.js +393 -0
  57. package/dist/memory-VSVNLEJC.js +393 -0
  58. package/dist/open-UJZRYF4E.js +1450 -0
  59. package/dist/program-CWJNGCTZ.js +165 -0
  60. package/dist/review-OOKXSYMP.js +117 -0
  61. package/dist/rules-4FXJUCXB.js +83 -0
  62. package/dist/security-LME3XFL3.js +177 -0
  63. package/dist/staged-check-X24C3YRD.js +502 -0
  64. package/dist/status-RR57ZNGI.js +81 -0
  65. package/dist/sync-KFJANRXF.js +218 -0
  66. package/dist/watch-CY7QHIYN.js +123 -0
  67. package/dist/web/assets/{Editor-DAXvniWB.js → Editor-Bnilgch0.js} +1 -1
  68. package/dist/web/assets/{abnfDiagram-O67JEVCF-Az7EW1BC.js → abnfDiagram-O67JEVCF-DW9LWr8f.js} +1 -1
  69. package/dist/web/assets/architecture-7GRP2DOG-BWDZV2yn.js +1 -0
  70. package/dist/web/assets/{architectureDiagram-NJMV4G6O-BxeXqSTn.js → architectureDiagram-NJMV4G6O-0eKeQRhj.js} +1 -1
  71. package/dist/web/assets/{blockDiagram-BEXU5L5S-aeKZl9lJ.js → blockDiagram-BEXU5L5S-D5i3-ogI.js} +1 -1
  72. package/dist/web/assets/{c4Diagram-YGBWAQC7-CgmntYsG.js → c4Diagram-YGBWAQC7-BAWQZrEu.js} +1 -1
  73. package/dist/web/assets/channel-Bkh05NKd.js +1 -0
  74. package/dist/web/assets/{chunk-3FUC2YCW-BpmRD2yo.js → chunk-3FUC2YCW-fKRGOZF3.js} +1 -1
  75. package/dist/web/assets/{chunk-5DYCD2WN-CRIFDwod.js → chunk-5DYCD2WN-C5jOlx42.js} +1 -1
  76. package/dist/web/assets/{chunk-742MDFTN-hRW9VeNV.js → chunk-742MDFTN-urY4RP_A.js} +1 -1
  77. package/dist/web/assets/{chunk-7INBJB4K-C6VEpT0Y.js → chunk-7INBJB4K-nk48sKqZ.js} +1 -1
  78. package/dist/web/assets/{chunk-7M6MHVWA-Dnajov2w.js → chunk-7M6MHVWA-BfBD9X0F.js} +1 -1
  79. package/dist/web/assets/{chunk-7PRAP22T-DSAc0_CZ.js → chunk-7PRAP22T-jYf59QlI.js} +1 -1
  80. package/dist/web/assets/{chunk-GTNCS2PH-CefpYUjb.js → chunk-GTNCS2PH-BOCxryKf.js} +1 -1
  81. package/dist/web/assets/{chunk-GWA4HPMP-MLNflMmF.js → chunk-GWA4HPMP-CFpaW0ru.js} +1 -1
  82. package/dist/web/assets/{chunk-MBY4JIJT-D3GmmEiU.js → chunk-MBY4JIJT-BIB8HctN.js} +1 -1
  83. package/dist/web/assets/{chunk-NETBCI7D-DzTj6xVk.js → chunk-NETBCI7D-CpUUK6rh.js} +1 -1
  84. package/dist/web/assets/{chunk-O7XYJQB3-D1d0hCko.js → chunk-O7XYJQB3-BNx_V4Oi.js} +1 -1
  85. package/dist/web/assets/{chunk-UA2S7LBM-C9hIFeWR.js → chunk-UA2S7LBM-D3tMiIOY.js} +1 -1
  86. package/dist/web/assets/{chunk-WEXAMYUT-BFGtcjsi.js → chunk-WEXAMYUT-CC-3C32l.js} +1 -1
  87. package/dist/web/assets/{chunk-Z7XXMR3K-BRZ8_wtE.js → chunk-Z7XXMR3K-BzhxKQUc.js} +1 -1
  88. package/dist/web/assets/{chunk-ZIGJFQKS-CTKOioal.js → chunk-ZIGJFQKS-D4tBHzxg.js} +1 -1
  89. package/dist/web/assets/{classDiagram-v2-NBCMYWYE-DJGKtWJv.js → classDiagram-v2-NBCMYWYE-BbtyanXR.js} +1 -1
  90. package/dist/web/assets/{cynefin-OW5HDTMX-hNq1kGmA.js → cynefin-OW5HDTMX-BIArb8W1.js} +1 -1
  91. package/dist/web/assets/{cynefinDiagram-VND7K2PF-sODQM_ZZ.js → cynefinDiagram-VND7K2PF-BrAcfkXL.js} +1 -1
  92. package/dist/web/assets/{dagre-6A5THRUB-DEzTThIf.js → dagre-6A5THRUB-BcHXRl4s.js} +1 -1
  93. package/dist/web/assets/{diagram-22UHCM2B-s_eellsa.js → diagram-22UHCM2B-Dx9tSCdE.js} +1 -1
  94. package/dist/web/assets/{diagram-3UASUU5V-B2onY_Xw.js → diagram-3UASUU5V-CLLDP9yH.js} +1 -1
  95. package/dist/web/assets/{diagram-ATOU4E4O-B8V6s13s.js → diagram-ATOU4E4O-B46H9iPt.js} +1 -1
  96. package/dist/web/assets/{diagram-CDSNMT55-CJxiE6mf.js → diagram-CDSNMT55-CYtvB6aG.js} +1 -1
  97. package/dist/web/assets/{diagram-MLGK6HIB-m5OHPLAp.js → diagram-MLGK6HIB-Dar7ktoX.js} +1 -1
  98. package/dist/web/assets/{diagram-MPIPVDR6-Buvvrk_A.js → diagram-MPIPVDR6-C-DljnYN.js} +1 -1
  99. package/dist/web/assets/{ebnfDiagram-ZINNZB2B-CpL7Wt3R.js → ebnfDiagram-ZINNZB2B-Dv_3jWnh.js} +1 -1
  100. package/dist/web/assets/{elk-276RUBZZ-CwYhbsXa.js → elk-276RUBZZ-DnHciE9k.js} +1 -1
  101. package/dist/web/assets/{erDiagram-OPXOYQCR-DNikci2r.js → erDiagram-OPXOYQCR-Bn46KrHz.js} +1 -1
  102. package/dist/web/assets/eventmodeling-NTZA5JFV-DYwoptMd.js +1 -0
  103. package/dist/web/assets/flowDiagram-KWPJA3E3-y4rS0gIB.js +1 -0
  104. package/dist/web/assets/{ganttDiagram-FUAMR5RP-d-ynDlvJ.js → ganttDiagram-FUAMR5RP-DOjjJtqz.js} +1 -1
  105. package/dist/web/assets/{gitGraph-4MIJSDKK-DwIeBI91.js → gitGraph-4MIJSDKK-BIoMXJRQ.js} +1 -1
  106. package/dist/web/assets/{gitGraphDiagram-X574FWY7-04RZccu6.js → gitGraphDiagram-X574FWY7-BsJ01R0v.js} +1 -1
  107. package/dist/web/assets/{index-C3-8uYXr.js → index-Cen0jOXj.js} +5 -4
  108. package/dist/web/assets/{index-DKE3ojTe.css → index-WwRY6n68.css} +1 -1
  109. package/dist/web/assets/{info-A6RAGUB7-xf4Nzgv-.js → info-A6RAGUB7-BmlXzRWj.js} +1 -1
  110. package/dist/web/assets/{infoDiagram-VRGFBTTK-BYjw0eiK.js → infoDiagram-VRGFBTTK-CYPJPmBP.js} +1 -1
  111. package/dist/web/assets/{ishikawaDiagram-OU5B5YK6-Bx9s4nPM.js → ishikawaDiagram-OU5B5YK6-YN96geky.js} +1 -1
  112. package/dist/web/assets/{journeyDiagram-ZHPQQLJL-DrdHs7B-.js → journeyDiagram-ZHPQQLJL-20juojKY.js} +1 -1
  113. package/dist/web/assets/{kanban-definition-PNTS6WVX-CVd8v2Te.js → kanban-definition-PNTS6WVX-BhCKIEbP.js} +1 -1
  114. package/dist/web/assets/{line-V_WrJ-6y.js → line-BERsMFG6.js} +1 -1
  115. package/dist/web/assets/{mermaid-parser.core-B-ilyEpO.js → mermaid-parser.core-Bis_wTB-.js} +3 -3
  116. package/dist/web/assets/{mermaid.core-Bnyaa0nF.js → mermaid.core-DMsM3ZX7.js} +4 -4
  117. package/dist/web/assets/{mindmap-definition-NLK3R4M7-B3AbvHPR.js → mindmap-definition-NLK3R4M7-BkcGdOfv.js} +1 -1
  118. package/dist/web/assets/{packet-AYTQ26CC-CBAIUXIc.js → packet-AYTQ26CC-Bh30-JJX.js} +1 -1
  119. package/dist/web/assets/{pegDiagram-GJSIUBJH-DIdeELUM.js → pegDiagram-GJSIUBJH-DxnIo9RF.js} +1 -1
  120. package/dist/web/assets/{pie-WAS4IAKB-a1r3tzPR.js → pie-WAS4IAKB-ChaTr-GD.js} +1 -1
  121. package/dist/web/assets/{pieDiagram-5QR66LMP-pQBEio0x.js → pieDiagram-5QR66LMP-CzAp78FM.js} +1 -1
  122. package/dist/web/assets/{quadrantDiagram-O4NWA36T-CkJK5Y03.js → quadrantDiagram-O4NWA36T-BDSE-cfY.js} +1 -1
  123. package/dist/web/assets/{radar-RG4KPBEZ-BZfLYjx5.js → radar-RG4KPBEZ-DgJ-o_dq.js} +1 -1
  124. package/dist/web/assets/{railroad-74A4TZTK-CuIW1ZAU.js → railroad-74A4TZTK-C8MmcBKz.js} +1 -1
  125. package/dist/web/assets/railroad-abnf-HS5TGJTU-CTLXjcdP.js +1 -0
  126. package/dist/web/assets/railroad-ebnf-LZEXJU2U-ggWsTTL0.js +1 -0
  127. package/dist/web/assets/railroad-peg-WCYAUIDC-D1mCX705.js +1 -0
  128. package/dist/web/assets/{railroadDiagram-XR7U4H2S-_BpGE8aJ.js → railroadDiagram-XR7U4H2S-DfbcWRNh.js} +1 -1
  129. package/dist/web/assets/{requirementDiagram-PLB6GJNP-CnzF90GS.js → requirementDiagram-PLB6GJNP-DM3nksxs.js} +1 -1
  130. package/dist/web/assets/{sankeyDiagram-IPEJSGJF-DYeisDj_.js → sankeyDiagram-IPEJSGJF-DthUpiiC.js} +1 -1
  131. package/dist/web/assets/{sequenceDiagram-PO4LG4MO-ll9cBvca.js → sequenceDiagram-PO4LG4MO-DLA3nuvA.js} +1 -1
  132. package/dist/web/assets/{stateDiagram-v2-GCMORJYK-CdKcOIKQ.js → stateDiagram-v2-GCMORJYK-B0X6ihBW.js} +1 -1
  133. package/dist/web/assets/{swimlanes-2SLR337P-y6piTWEW.js → swimlanes-2SLR337P-B4qWe6vE.js} +1 -1
  134. package/dist/web/assets/swimlanesDiagram-TC7HE7FX-ClIk3e7S.js +8 -0
  135. package/dist/web/assets/{timeline-definition-EJHVYXUP-DuC_4xK0.js → timeline-definition-EJHVYXUP-F-cDzYrj.js} +1 -1
  136. package/dist/web/assets/{treeView-Q6P3EWNA-gCQFmND0.js → treeView-Q6P3EWNA-BaI30nLZ.js} +1 -1
  137. package/dist/web/assets/{treemap-WGGIJYW6-BQ2010OY.js → treemap-WGGIJYW6-D2jGGoMl.js} +1 -1
  138. package/dist/web/assets/{usecaseDiagram-POWQR4AR-CCTqzHz6.js → usecaseDiagram-POWQR4AR-B9qoAQCy.js} +1 -1
  139. package/dist/web/assets/{vennDiagram-UO4OBE2U-0_O7guNq.js → vennDiagram-UO4OBE2U-DGVNOaKO.js} +1 -1
  140. package/dist/web/assets/{wardley-WFR3VGLG-SsX7uMDs.js → wardley-WFR3VGLG-DbKqhNAh.js} +1 -1
  141. package/dist/web/assets/{wardleyDiagram-VNRHLVJA-DlqH6Hox.js → wardleyDiagram-VNRHLVJA-BgZ1gprw.js} +1 -1
  142. package/dist/web/assets/{xychartDiagram-PMCCYNJV-nr4UYDtd.js → xychartDiagram-PMCCYNJV-D73RYid1.js} +1 -1
  143. package/dist/web/index.html +2 -2
  144. package/package.json +4 -2
  145. package/dist/web/assets/architecture-7GRP2DOG-blXBarB2.js +0 -1
  146. package/dist/web/assets/channel-f4QzewnN.js +0 -1
  147. package/dist/web/assets/eventmodeling-NTZA5JFV-CA_ZFPZ2.js +0 -1
  148. package/dist/web/assets/flowDiagram-KWPJA3E3-DObsBuWT.js +0 -1
  149. package/dist/web/assets/railroad-abnf-HS5TGJTU-6B4Ffbxn.js +0 -1
  150. package/dist/web/assets/railroad-ebnf-LZEXJU2U-BGL9lIQc.js +0 -1
  151. package/dist/web/assets/railroad-peg-WCYAUIDC-DcqxTem7.js +0 -1
  152. package/dist/web/assets/swimlanesDiagram-TC7HE7FX-DFS8a3jO.js +0 -8
package/CHANGELOG.md CHANGED
@@ -1,5 +1,68 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.4.0 — 2026-10-03
4
+
5
+ Agent memory: coding agents can now record what they learn — decisions and why, gotchas, bug root causes, conventions — and later sessions recall it. Memory lives in `.athena/memory/` as plain Markdown you commit and review like code. Anything an agent writes is `unreviewed` (INFERRED) until you confirm it (`athena memory review`, or the Memory page in `athena open`); entries turn `stale` when the files they describe change. Secrets are refused, and text that looks like it is trying to instruct the agent is flagged and kept out of recall.
6
+
7
+ After upgrading, run `athena analyze` (or `athena agents add <agent>`) so your agent instructions mention `recall` and `remember`.
8
+
9
+ ### Project memory
10
+
11
+ - New `athena memory` commands for the project memory in `.athena/memory/`: `list` (`--kind`, `--status`, `--stale`), `show`, `add` (`--kind`, `--title`, `--details` or `--details -` for stdin, repeatable `--file`/`--tag`, `--evidence`, `--supersedes`), `search`, `recall <task…>` (`--file`, `--tag`, `--limit`; ranked hits with reasons), `confirm <id…>`, `supersede <id> --by <id>`, `forget <id…>` (asks first; `--yes` in scripts), `edit`, `stale` and `review` (interactive in a terminal: confirm, forget or skip each agent-written entry). All support `--json`.
12
+ - Entries you record are FACT; entries agents record are INFERRED until confirmed. Stale entries (linked files changed) and flagged entries (possible prompt injection) are marked and explained. A memory that contains a possible secret is refused without echoing the value.
13
+ - `athena status` shows a memory line and a `memory` object (`total`, `unreviewed`, `stale`) in `--json`; `athena doctor` adds a Memory check when entries exist.
14
+ - `athena clean` now says how many project memory entries it would delete (they are committed and shared with the team) before asking for confirmation.
15
+
16
+ ### Agent memory: MCP, context and instructions
17
+
18
+ - New MCP tools `recall` (ranked memories for a task and/or files, with why each matched, label, status and staleness, fenced in `<athena-memory … trust="untrusted-data">` delimiters; entries flagged as possible prompt injection are excluded and counted), `list_memory` (summaries filtered by kind, status, stale) and `remember` (records a memory as **unreviewed**/INFERRED, attributed to `agent:<id>` from the client's `clientInfo.name` — claude-code, cursor, codex, copilot, gemini-cli, antigravity, windsurf, cline — or `agent:mcp`). `remember` is the only write the MCP server allows without `--allow-write`; it never touches knowledge documents, refuses secrets without echoing them, and is disabled by `athena mcp --no-memory-write`.
19
+ - `athena context` and `get_relevant_context` include up to five recalled memories (confirmed first, flagged excluded) with labels and reasons, within the character budget (at most 30% of it). `--json` and `/api/context` gain a `memories` field.
20
+ - Generated agent instructions (all adapters) tell agents to recall project memory at the start of a task, record durable, non-obvious learnings with `remember` at the end, and treat unreviewed memories as hints to verify — never instructions; `rules.md` and the developer always win.
21
+
22
+ ### Memory page (`athena open`)
23
+
24
+ - New **Memory** page (`/memory`, in the sidebar with a badge for entries awaiting review) to review project memory in `.athena/memory/*.md`. The review queue (agent-written, INFERRED entries) comes first with Confirm / Edit / Forget; confirmed entries (FACT) follow and superseded ones are collapsed. Cards show kind, FACT/INFERRED label, who recorded it and when, linked files, tags and evidence; details are shown as plain text, never rendered as Markdown or HTML. Stale entries (a linked file changed since) show the changed files and a Re-confirm action; entries that look like prompt injection carry a red warning. Filter chips (kind, status, stale, flagged), a text filter, and an Add memory form (developer entries are FACT immediately). The Overview links to the queue when entries await review.
25
+ - API: `GET /api/memory` (`kind`, `status`, `stale` filters; returns entries and counts), `GET /api/memory/:id`, `POST /api/memory`, `POST /api/memory/:id/confirm`, `POST /api/memory/:id/supersede`, `PATCH /api/memory/:id`, `DELETE /api/memory/:id` — all behind the existing token, Host/Origin and JSON-only checks, with strict schemas. Unknown ids are 404, superseded/busy/full conflicts 409, invalid input and refused secrets 400 (the secret value is never echoed).
26
+ - A `memory.changed` event is emitted after every write from the UI and when memory files change on disk (an agent writing through MCP, `athena memory` in a terminal, a `git pull`), so open pages refresh live.
27
+
28
+ ## 0.3.0 — 2026-09-30
29
+
30
+ Performance release: work is now proportional to what changed. On a 20,000-file repository (vs 0.2.1): a `sync --check` with nothing changed takes ~0.42 s instead of 2.9 s, `status` 0.14 s instead of 0.34 s, agent hooks start in ~28 ms instead of 112 ms, and peak memory is 20–52% lower in every scenario. The generated `model.json` is unchanged (golden-tested against the 0.2.1 analyzer). Benchmarks: `npm run bench`.
31
+
32
+ After upgrading, the first run rebuilds `.athena/state.json` in the new format automatically. If you use the pre-commit hook, run `athena git-hook install` again so it checks staged content.
33
+
34
+ ### Performance
35
+
36
+ - `athena open` reuses parsed `.athena` artifacts: a new `ProjectSession` loads `model.json`, `graph.json`, `security-scan.json` and `state.json` once and re-reads them only when the file changes (inode, size or mtime). The overview, graph, context, security and `athena security` paths share it, and the graph summary checks for `model.json` with a stat instead of parsing and validating the whole model.
37
+ - The event stream (`/api/events`) coalesces bursts into one write per 250 ms (intermediate activity states collapse to the latest), serializes each event once for all clients, and applies backpressure: a client that stops reading gets nothing more until its socket drains, keeps at most 100 queued events (oldest dropped) plus the latest activity, and then receives a `resync` frame with the number of events it missed. At most 16 event streams are open at once (503 beyond that).
38
+ - `GET /api/sync` no longer includes each proposed document's full diff; the Sync page fetches a diff from the new `GET /api/sync/:doc` only when the document is expanded.
39
+ - `athena event` (run by agent hooks on every tool call) starts about 2.5× faster and uses about 40% less memory (p50 112 ms / 100 MB → ~45 ms / 57 MB on the 20k-file benchmark): it no longer loads commander or any other command's dependencies. All other commands load their code on demand, which also lowers memory for `status`, `review` and `sync`.
40
+ - `athena event` no longer loads zod: the paths it needs moved to a dependency-free module (`src/core/paths.ts`). p50 of 10 on an Apple M-series laptop: ~43 ms / 57 MB → ~26 ms / 49 MB. The startup test now fails if zod reaches the event chunk.
41
+ - The CLI is now built with code splitting: `dist/cli.js` is a small entry that loads chunks from `dist/` as needed.
42
+ - Project graph building is linear in the number of edges (edge de-duplication, import traversal and package lookups no longer rescan everything); 50k import edges now build in about 0.1 s instead of 3.2 s, and 100k in about 0.25 s. Graph output is unchanged. `athena graph --node` and task-context expansion use a per-graph index.
43
+ - Git metadata is collected with concurrent `git` processes, the `git --version` check runs once per process, and history is read once, bounded to the last 180 days / 2,000 commits. The contributor count in `model.json` (`git.contributorCount`) now counts authors in that window instead of the whole history.
44
+ - Nested `.gitignore` matching only consults the path's own ancestor directories instead of every `.gitignore` in the project.
45
+ - Analysis is staged and incremental: a stat-only walk, one content pass in which every new or changed file is read exactly once (hashing and all per-file detector work share the same bytes), then an aggregate stage that builds the model from cached per-file facts. Unchanged files are not read at all. The generated `model.json` is unchanged (guarded by a golden test against the 0.2.1 analyzer).
46
+ - 20,000-file benchmark (Apple M-series, vs 0.2.1): warm `sync --check` 2.9 s → 0.50 s (×5.8), `sync --check` after a one-file change 2.9 s → 0.49 s, cold `init` 3.5 s → 2.3 s; peak memory lower in every scenario (warm sync 195 → 162 MB). 200,000 files: warm `sync --check` 46 s → 4.1 s, cold `init` 51 s → 40 s, peak memory 730 → 589 MB (init).
47
+ - File text is no longer cached without limit during analysis: a 64 MB byte-budgeted LRU serves the rare aggregate-stage lookup, and text is dropped as soon as a file's facts are computed.
48
+ - Sync planning goes through one scheduler per project (`src/services/scheduler.ts`): at most one analysis runs at a time, requests that arrive meanwhile share a single follow-up run, and new file changes can cancel a plan that is still in progress (planning is read-only). The file watcher, the local server (`POST /api/sync/check`, review, re-plans after edits) and the MCP server use it, so concurrent checks no longer start concurrent full analyses; applying a proposal and a full re-analysis from the web UI never interleave with planning.
49
+ - While `athena open` (or another watcher) is running, a plan after file changes re-checks only the paths the watcher reported instead of walking the whole tree (about 265 → 170 ms for a one-file change in the 20k-file benchmark, in-process). It walks the whole tree on the first plan, after a `.gitignore`, `.athena/config.json` or `.git/info/exclude` change, a directory add/delete, a watcher error, when the project contains symbolic links, and at least every 5 minutes.
50
+ - `athena status` (and the server's status, the MCP `get_project_changes` tool) no longer walks the tree: it stats the files in the cached index and asks Git for new files (`git ls-files`, `git status --porcelain=v2 -z`). 254 → ~140 ms on the 20k-file benchmark; ~0.85 s for 200k files. The output is unchanged; it falls back to walking when Git can't give the same answer (no Git or no index, `include` patterns, ignore rules changed since the last analysis, submodules, nested repositories, symlinked directories).
51
+ - The server's status report is cached until the watcher reports a change (with a 30 s safety TTL, instead of a flat 3 s), and concurrent requests share one computation.
52
+
53
+ ### Changed
54
+
55
+ - **The pre-commit hook checks what is being committed.** New `athena sync --check --staged` compares the `.athena/` knowledge as staged with what Athena generates from the code as staged, so untracked files (a scratch file, a local `.env`) and unstaged edits no longer block a commit, and a staged change reverted in the working tree still counts. It mirrors the index into `.athena/cache/staged/` (gitignored, updated incrementally): files that match the working tree are sparse stand-ins that reuse the last analysis's hashes and the facts cache, so only staged changes are read (20k files, warm: ~0.54 s vs ~0.44 s for the working-tree check). When `athena sync` already wrote a document that isn't staged, the output says which files to `git add`; JSON output has `staged`, `inSync`, `stale` and per-document details. Exit code 3 when `.athena/` is not in the index; 2 when the index has unresolved conflicts. `athena git-hook install` writes the new command (re-run it to update an existing hook; `athena git-hook status` shows `staged: false` and a hint for old hooks), and the suggested husky/lefthook line is now `npx --no-install athena sync --check --staged`.
56
+ - The manifest detector is split into one module per ecosystem (`src/core/analyzer/detectors/manifests/`); `model.json` output is byte-identical.
57
+ - Files modified within 2 seconds of the file index being written are re-read on the next run instead of trusted by size and mtime (Git's "racily clean" rule), so a same-size edit in the same clock tick is never missed.
58
+ - The local server is split into route modules (`src/server/routes/*`) sharing one server context; routes, authentication, Host/Origin checks, security headers, CSP and rate limiting are unchanged.
59
+ - `GET /api/sync` returns the proposal without `documents[].diff` (reasons, changed and preserved sections, additions/deletions and `diffTruncated` are still included). New `GET /api/sync/:doc[?planId=…]` returns one proposed document's diff; the id must be a knowledge document in the current proposal (404 otherwise, 409 when `planId` is stale). `POST /api/sync/check` still returns the full plan.
60
+ - A corrupted `model.json` now gives a clear error with a hint (`model.json is corrupted (…)`, run `athena analyze`) instead of an internal error when starting a security scan from the web UI.
61
+ - Test, source, auth, API and schema path patterns now come from one module (`src/core/patterns.ts`). `athena review` recognizes more test layouts (`integration_tests/`, `androidTest/`, `test_driver/`, `*_test.dart`), and change impact recognizes the same test files as review plus test runner configs.
62
+ - New per-file facts cache in `.athena/cache/v1/` (gitignored; `cache/` is added to `.athena/.gitignore`, also for existing projects). Facts are keyed by content hash and discarded automatically when detector versions or the `ignore`/`include`/`maxFileBytes` settings change. Safe to delete; `athena clean` removes it with `.athena/`.
63
+ - `state.json` schema 2: the file index moved to `.athena/cache/v1/files.json` (full SHA-256 hashes), so `state.json` stays small regardless of repository size. Version-1 files are migrated automatically on first read; older Athena versions will treat a v2 `state.json` as corrupted and rebuild it.
64
+ - `athena init` creates the machine-local fingerprint salt (`.athena/local.json`) together with `.athena/`, so secret-finding fingerprints in the first `model.json` already use the project's stable key.
65
+
3
66
  ## 0.2.1 — 2026-09-30
4
67
 
5
68
  Security release. Upgrading is recommended for everyone. After upgrading, run `athena sync` once (the `security.md` format changed) and, if you use the pre-commit hook with `--review`, run `athena git-hook install --review` again so it reviews staged changes.
package/README.md CHANGED
@@ -58,6 +58,7 @@ Generated content sits between `athena:generated` markers. Anything outside the
58
58
  | `athena sync` | Show which documents would change and why (with diffs), then apply after confirmation (`--yes`, `--dry-run`, `--diff`, `--check` for CI) |
59
59
  | `athena watch` | Watch the project and propose updates as files change (`--auto-apply` to write automatically) |
60
60
  | `athena doctor` | Check the installation, project, knowledge files and agent integrations |
61
+ | `athena memory` | `list`, `show`, `add`, `search`, `recall`, `confirm`, `supersede`, `forget`, `edit`, `stale`, `review` — project memory in `.athena/memory/` (see [Project memory](#project-memory)) |
61
62
  | `athena rules` | `list`, `add "<rule>" --section <name>`, `edit`, `enable`, `disable`, `remove` |
62
63
  | `athena agents` | `list`, `add <claude-code\|cursor\|codex\|copilot\|gemini-cli\|antigravity\|windsurf\|cline\|agents-md\|all>`, `remove` |
63
64
  | `athena activity` | Show AI agent activity observed through hooks (`-n`, `--agent`) |
@@ -66,15 +67,48 @@ Generated content sits between `athena:generated` markers. Anything outside the
66
67
  | `athena git-hook` | `install` (`--review`), `uninstall`, `status` — a Git pre-commit hook that blocks commits when knowledge is out of date |
67
68
  | `athena context <task>` | Show which knowledge an agent should read for a task (`--full`, `--json`) |
68
69
  | `athena graph` | Inspect the project graph (`--build`, `--search`, `--node`, `--kind`) |
69
- | `athena mcp` | Serve project intelligence to agents over MCP (stdio; `--allow-write`) |
70
+ | `athena mcp` | Serve project intelligence to agents over MCP (stdio; `--allow-write`, `--no-memory-write`) |
70
71
  | `athena ai` | `status`, `enrich` — optional AI suggestions (`--consent`, `--dry-run`) |
71
72
  | `athena open` | Start (or reuse) the local web UI on `127.0.0.1`, watch for changes, and open it (`--port`, `--no-open`, `--no-watch`) |
72
- | `athena clean` | Remove `.athena/` and Athena integration blocks |
73
+ | `athena clean` | Remove `.athena/` (including project memory) and Athena integration blocks |
73
74
 
74
75
  Global flags: `--json`, `--quiet`, `--cwd <dir>`, `--no-color`.
75
76
 
76
77
  They print *Not available yet* and exit with code 2. See [docs/ROADMAP.md](docs/ROADMAP.md).
77
78
 
79
+ ## Project memory
80
+
81
+ Agents rediscover the same things every session: why the queue uses advisory locks, that tests need `TZ=UTC`, which bug the retry guard fixes. Athena keeps these as **project memory** in `.athena/memory/` — one Markdown file per kind (`decisions.md`, `gotchas.md`, `bugs.md`, `conventions.md`, `todos.md`, `facts.md`). Commit it: the team shares it and reviews changes in pull requests. Text you write outside the `athena:memory` markers is kept as written.
82
+
83
+ - **Evidence labels.** An entry you record is `confirmed` (**FACT**). An entry an agent records is `unreviewed` (**INFERRED**) until you confirm it.
84
+ - **Staleness.** Entries can link files. When a linked file changes, the entry is reported **stale** until you confirm it again (which re-anchors it), edit it or forget it.
85
+ - **Safety.** Entries that look like a secret are refused (the value is never stored or printed). Entries that address the agent instead of describing the project (possible prompt injection) are flagged and never recalled automatically.
86
+
87
+ ```bash
88
+ athena memory add --kind decision --title "Queue uses advisory locks" \
89
+ --file src/jobs/queue.ts --tag jobs --evidence "PR #412"
90
+ git log -1 --format=%B | athena memory add --kind bug --title "Double refund on webhook retry" --details -
91
+ athena memory list # --kind, --status unreviewed|confirmed|superseded, --stale
92
+ athena memory review # walk agent-written entries: [c]onfirm [e]dit later [f]orget [s]kip [q]uit
93
+ athena memory recall "change the refund flow" --file src/api/refunds.ts
94
+ athena memory stale # entries whose linked files changed
95
+ athena memory confirm m-1a2b3c m-4d5e6f
96
+ athena memory supersede m-1a2b3c --by m-7a8b9c # keep as history
97
+ athena memory forget m-1a2b3c # asks first; --yes in scripts
98
+ ```
99
+
100
+ ```text
101
+ $ athena memory list
102
+ ID KIND LABEL STATUS TITLE · SOURCE
103
+ m-b74d24 gotcha INFERRED unreviewed Refund webhook retries twice · agent:claude-code
104
+ m-815cd7 decision FACT confirmed stale Queue uses advisory locks · developer
105
+
106
+ 2 entries · 1 confirmed · 1 unreviewed · 1 stale · source: .athena/memory/
107
+ 1 entry written by agents is INFERRED until reviewed: run `athena memory review`.
108
+ ```
109
+
110
+ Every command supports `--json`. `athena memory review` is interactive only in a terminal; elsewhere it lists the unreviewed entries and exits 0. `athena status` and `athena doctor` show how many entries are unreviewed or stale, and `athena clean` warns before deleting project memory.
111
+
78
112
  ## Keeping knowledge in sync
79
113
 
80
114
  ```text
@@ -104,6 +138,7 @@ Apply updates to 2 documents? [y/N]
104
138
  - **Your edits are still safe.** Developer-edited sections are preserved and listed. Applying is refused if a document changed after the proposal was made.
105
139
  - When files change but no knowledge is affected, only the local index is refreshed.
106
140
  - `athena sync --check` exits with 1 when knowledge is out of date, which is useful in CI or a pre-commit hook (see [Use in CI and git hooks](#use-in-ci-and-git-hooks)). Change hotspots come from Git history and move with every commit, so the check ignores them; `athena sync` still refreshes them.
141
+ - `athena sync --check --staged` checks what a commit would contain instead of the working tree: the `.athena/` knowledge as staged against the code as staged. Untracked files and unstaged edits don't count. This is what the pre-commit hook runs.
107
142
  - Ignore rules: defaults, root and nested `.gitignore` files, `.git/info/exclude`, and `.athena/config.json`.
108
143
 
109
144
  ## Watching what agents do
@@ -192,16 +227,22 @@ A complete workflow is in [examples/github-workflow.yml](examples/github-workflo
192
227
  ```text
193
228
  $ athena git-hook install
194
229
  ✓ Installed the pre-commit hook (knowledge check) at .git/hooks/pre-commit
195
- Commits are blocked when .athena/ knowledge is out of date. Teammates without Athena installed are not blocked.
196
- Using husky, lefthook or pre-commit? Add `npx --no-install athena sync --check` to its pre-commit config instead.
230
+ Commits are blocked when the staged .athena/ knowledge is out of date for the staged code (untracked and unstaged files are ignored). Teammates without Athena installed are not blocked.
231
+ Using husky, lefthook or pre-commit? Add `npx --no-install athena sync --check --staged` to its pre-commit config instead.
197
232
 
198
233
  $ git commit -m "Add refunds"
199
- Proposed: api.md, security.md
200
- Knowledge is out of date. Run `athena sync` to review and apply.
201
- athena: commit blocked: .athena/ knowledge is out of date. Run `athena sync`, stage .athena/ and commit again (or skip once with `git commit --no-verify`).
234
+ ~ api.md endpoints
235
+ ~ security.md attack-surface
236
+ Staged knowledge is out of date for the staged code. Run `athena sync`, then stage .athena/.
237
+ athena: commit blocked: staged .athena/ knowledge is out of date. Run `athena sync`, stage .athena/ and commit again (or skip once with `git commit --no-verify`).
202
238
  ```
203
239
 
204
- - `athena git-hook install --review` also runs `athena review` and blocks commits that add possible secrets or env files. It checks the whole working tree (staged, unstaged and untracked files that aren't ignored), not only what is staged.
240
+ - The hook checks the commit, not the working tree: an untracked scratch file, a local `.env` or an unstaged edit never blocks a commit, and a change you staged and then reverted in the working tree still counts. If `athena sync` already updated a document but it isn't staged, the output says which files to `git add`.
241
+ - The check mirrors the index into `.athena/cache/staged/` (gitignored). Files that match the working tree are stand-ins that reuse the last analysis and the facts cache, so only staged changes are read; the directory is updated incrementally and is safe to delete. Submodules are checked as they are in the working tree. Local env files that aren't committed (such as `.env`) are machine-local: the check accepts staged knowledge written with or without them.
242
+ - Knowledge generated by `athena sync` describes the working tree. If untracked files that are not gitignored change it (a new route in a file you don't commit), the staged check reports the difference; commit, ignore or stash those files before syncing.
243
+ - Hooks installed by earlier versions check the working tree; `athena git-hook status` points them out and `athena git-hook install` updates them.
244
+
245
+ - `athena git-hook install --review` also runs `athena review --staged` and blocks commits that add possible secrets or env files. Like the knowledge check, it only looks at what is staged.
205
246
  - The hook is a `#!/bin/sh` script in the directory Git actually uses (`git rev-parse --git-path hooks`), so `core.hooksPath` and linked worktrees work. For a project in a subfolder of the repository, the hook runs Athena there.
206
247
  - If `athena` is not on `PATH`, the hook prints a note and lets the commit through, so it never blocks teammates who don't use Athena.
207
248
  - **An existing pre-commit hook is kept.** If it is a shell script, Athena adds its block between `# athena:start` and `# athena:end` right after the shebang, so it runs before your own commands. Athena refuses to touch hooks written in other languages and hooks it recognizes as managed by husky, lefthook or pre-commit (from `core.hooksPath` or the hook's contents), and prints the line to add instead.
@@ -211,7 +252,7 @@ athena: commit blocked: .athena/ knowledge is out of date. Run `athena sync`, st
211
252
 
212
253
  ```bash
213
254
  # .husky/pre-commit
214
- npx --no-install athena sync --check
255
+ npx --no-install athena sync --check --staged
215
256
  ```
216
257
 
217
258
  ```yaml
@@ -219,7 +260,7 @@ npx --no-install athena sync --check
219
260
  pre-commit:
220
261
  commands:
221
262
  athena:
222
- run: npx --no-install athena sync --check
263
+ run: npx --no-install athena sync --check --staged
223
264
  ```
224
265
 
225
266
  ### Example project
@@ -242,11 +283,19 @@ Documents to read
242
283
 
243
284
  - **Deterministic.** The same task and project state always produce the same selection, with a stated reason for each document. No AI is involved.
244
285
  - **Sections, not whole files.** Only the relevant sections are returned, under a character budget, with your rules always included.
286
+ - **Project memory.** Up to five recalled memories from `.athena/memory/` (confirmed ones first, possible prompt injections excluded) are included with their label (`FACT` once a developer confirmed them, `INFERRED` while unreviewed), whether they are stale, and why they matched. They share the character budget (at most 30% of it) and appear in `--full` output and as `memories` in `--json`.
245
287
  - **Project graph.** `athena graph --build` writes `.athena/graph.json`: packages, files, routes, entities, frameworks and commands, connected by `contains`, `imports`, `handles`, `defines` and `depends_on`. It comes from the analysis, so it never asserts more than DETECTED evidence.
246
288
 
247
- **MCP.** `athena mcp` serves this to any MCP-capable agent over stdio, and `athena agents add` registers it (`.mcp.json` for Claude Code, `.cursor/mcp.json` for Cursor, `[mcp_servers.athena]` in `.codex/config.toml` for Codex, `servers.athena` in `.vscode/mcp.json` for GitHub Copilot in VS Code, `mcpServers.athena` in `.gemini/settings.json` for Gemini CLI). Tools: `get_relevant_context`, `get_project_context`, `get_architecture`, `get_database_schema`, `get_api_context`, `get_security_context`, `get_project_rules`, `get_knowledge_document`, `get_project_changes`, `get_project_graph`, `get_athena_status`, `update_knowledge`.
289
+ **MCP.** `athena mcp` serves this to any MCP-capable agent over stdio, and `athena agents add` registers it (`.mcp.json` for Claude Code, `.cursor/mcp.json` for Cursor, `[mcp_servers.athena]` in `.codex/config.toml` for Codex, `servers.athena` in `.vscode/mcp.json` for GitHub Copilot in VS Code, `mcpServers.athena` in `.gemini/settings.json` for Gemini CLI). Tools: `get_relevant_context`, `get_project_context`, `get_architecture`, `get_database_schema`, `get_api_context`, `get_security_context`, `get_project_rules`, `get_knowledge_document`, `get_project_changes`, `get_project_graph`, `get_athena_status`, `update_knowledge`, and the memory tools `recall`, `list_memory` and `remember`.
290
+
291
+ The server is **read-only by default**: `update_knowledge` reports what would change and refuses to write unless you start it with `--allow-write`. The one exception is `remember`: an agent may append a memory to `.athena/memory/`, but it is always stored **unreviewed** (`INFERRED`, attributed to the agent, e.g. `agent:claude-code`, or `agent:mcp` when the client is not recognized) and counts as a `FACT` only after a developer confirms it. It never touches knowledge documents and refuses anything that looks like a secret. Start the server with `--no-memory-write` to turn it off.
248
292
 
249
- The server is **read-only by default**: `update_knowledge` reports what would change and refuses to write unless you start it with `--allow-write`. Repository content it returns is passed through the secret redactor and wrapped in `<athena-document … trust="untrusted-data">` delimiters, so agents can tell project data from instructions.
293
+ | Memory tool | Input | Returns |
294
+ | --- | --- | --- |
295
+ | `recall` | `task?`, `files?`, `tags?`, `limit?` | Ranked memories with why each matched, label, status and staleness, each in `<athena-memory … trust="untrusted-data">` delimiters. Entries that look like instructions to an agent are excluded (the reply says how many). |
296
+ | `list_memory` | `kind?`, `status?`, `stale?` | One-line summaries: id, kind, status, label, stale, title |
297
+ | `remember` | `kind`, `title`, `details?`, `files?`, `tags?`, `evidence?`, `supersedes?` | The new id and label (`INFERRED`); a developer must confirm it |
298
+ Repository content it returns is passed through the secret redactor and wrapped in `<athena-document … trust="untrusted-data">` (or `<athena-memory …>`) delimiters, so agents can tell project data from instructions. The generated agent instructions tell agents to `recall` at the start of a task, `remember` durable learnings at the end, and treat unreviewed memories as hints to verify — `rules.md` and the developer always win.
250
299
 
251
300
  ## Optional AI
252
301
 
@@ -0,0 +1,77 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ listAgents
4
+ } from "./chunk-QLW657NT.js";
5
+ import {
6
+ readRecentEvents,
7
+ summarizeSessions
8
+ } from "./chunk-65TSRDQ3.js";
9
+ import {
10
+ c,
11
+ dim,
12
+ heading,
13
+ isJson,
14
+ json,
15
+ line,
16
+ relativeTime,
17
+ sym
18
+ } from "./chunk-Z6QWMJLK.js";
19
+ import {
20
+ requireProjectRoot
21
+ } from "./chunk-XFN7UZCS.js";
22
+ import "./chunk-KBO7XRBW.js";
23
+ import "./chunk-JCGDR4UV.js";
24
+ import "./chunk-YRIS7ZS6.js";
25
+ import "./chunk-GHFRQAYT.js";
26
+ import "./chunk-INT3IGMQ.js";
27
+ import "./chunk-673EPYYH.js";
28
+ import "./chunk-FQEGEVLY.js";
29
+ import "./chunk-2DY4PUR4.js";
30
+ import "./chunk-IQQBAWSM.js";
31
+ import "./chunk-AD4OZCU2.js";
32
+ import "./chunk-XW3MLHI2.js";
33
+ import "./chunk-EUPETUWA.js";
34
+
35
+ // src/cli/commands/activity.ts
36
+ var STATE_COLOR = {
37
+ ANALYZING: c.cyan,
38
+ PLANNING: c.magenta,
39
+ CODING: c.blue,
40
+ TESTING: c.yellow,
41
+ REVIEWING: c.cyan,
42
+ SUCCESS: c.green,
43
+ IDLE: c.dim
44
+ };
45
+ async function activityCommand(opts) {
46
+ const root = await requireProjectRoot(opts);
47
+ const limit = Math.min(Math.max(Number(opts.limit ?? 30) || 30, 1), 500);
48
+ const all = await readRecentEvents(root, 500);
49
+ const events = (opts.agent ? all.filter((e) => e.agent === opts.agent) : all).slice(-limit);
50
+ if (isJson()) {
51
+ json({ events, sessions: summarizeSessions(all) });
52
+ return;
53
+ }
54
+ heading("AI Agent Activity");
55
+ line();
56
+ if (!events.length) {
57
+ const agents = await listAgents(root);
58
+ const reporting = agents.filter((a) => a.activityObservation === "hooks");
59
+ line(dim("No agent activity recorded yet."));
60
+ line(dim(reporting.length ? `Hooks are installed for: ${reporting.map((a) => a.name).join(", ")}. Events appear once an agent runs in this project.` : "Install hooks with `athena agents add claude-code` (or cursor, codex, copilot, gemini-cli) to record agent activity."));
61
+ return;
62
+ }
63
+ for (const e of events) {
64
+ const time = new Date(e.ts).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit", second: "2-digit", hour12: false });
65
+ const color = STATE_COLOR[e.state] ?? ((s) => s);
66
+ line(`${dim(time)} ${color(sym.dot)} ${c.bold(e.agent)} ${dim("\xB7")} ${e.message}`);
67
+ }
68
+ line();
69
+ for (const s of summarizeSessions(all).slice(0, 5)) {
70
+ line(dim(`${s.agent} ${s.session ? `(${s.session.slice(0, 8)})` : ""}: ${s.events} events, last ${relativeTime(s.lastEventAt)}`));
71
+ }
72
+ line(dim("Only hook-reported tool use is shown. Athena cannot see agent reasoning."));
73
+ }
74
+ export {
75
+ activityCommand
76
+ };
77
+ //# sourceMappingURL=activity-BKW7G4I5.js.map
@@ -0,0 +1,69 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ configureAgents,
4
+ listAgents,
5
+ removeAgents
6
+ } from "./chunk-QLW657NT.js";
7
+ import "./chunk-65TSRDQ3.js";
8
+ import {
9
+ c,
10
+ dim,
11
+ heading,
12
+ isJson,
13
+ json,
14
+ line,
15
+ ok,
16
+ sym
17
+ } from "./chunk-Z6QWMJLK.js";
18
+ import {
19
+ requireProjectRoot
20
+ } from "./chunk-XFN7UZCS.js";
21
+ import "./chunk-KBO7XRBW.js";
22
+ import "./chunk-JCGDR4UV.js";
23
+ import "./chunk-YRIS7ZS6.js";
24
+ import "./chunk-GHFRQAYT.js";
25
+ import "./chunk-INT3IGMQ.js";
26
+ import "./chunk-673EPYYH.js";
27
+ import "./chunk-FQEGEVLY.js";
28
+ import "./chunk-2DY4PUR4.js";
29
+ import "./chunk-IQQBAWSM.js";
30
+ import "./chunk-AD4OZCU2.js";
31
+ import "./chunk-XW3MLHI2.js";
32
+ import "./chunk-EUPETUWA.js";
33
+
34
+ // src/cli/commands/agents.ts
35
+ async function agentsListCommand(opts) {
36
+ const root = await requireProjectRoot(opts);
37
+ const rows = await listAgents(root);
38
+ if (isJson()) {
39
+ json(rows);
40
+ return;
41
+ }
42
+ heading("AI Agent Integrations");
43
+ line();
44
+ for (const r of rows) {
45
+ const icon = r.configured ? c.green(sym.dot) : c.dim(sym.ring);
46
+ line(`${icon} ${c.bold(r.name)} ${dim(`(${r.id})`)} \u2014 ${r.configured ? "configured" : "not configured"}${r.detectedInProject ? dim(` \xB7 detected: ${r.evidence.join(", ")}`) : ""}`);
47
+ line(` ${dim(r.note)}`);
48
+ }
49
+ line();
50
+ line(dim('"Configured" means Athena instruction files are in place. Agents with hooks also report their tool use \u2014 see `athena activity`.'));
51
+ }
52
+ async function agentsAddCommand(names, opts) {
53
+ const root = await requireProjectRoot(opts);
54
+ const results = await configureAgents(root, names);
55
+ if (isJson()) json({ ok: true, agents: results });
56
+ else for (const r of results) ok(`${r.id}: ${r.files.map((f) => `${f.path} (${f.action})`).join(", ")}`);
57
+ }
58
+ async function agentsRemoveCommand(names, opts) {
59
+ const root = await requireProjectRoot(opts);
60
+ const removed = await removeAgents(root, names);
61
+ if (isJson()) json({ ok: true, removed });
62
+ else ok(removed.length ? `Removed Athena integration from ${removed.join(", ")}` : "Nothing to remove");
63
+ }
64
+ export {
65
+ agentsAddCommand,
66
+ agentsListCommand,
67
+ agentsRemoveCommand
68
+ };
69
+ //# sourceMappingURL=agents-DFSNEOP5.js.map
@@ -0,0 +1,96 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ aiStatus,
4
+ buildEnrichPayload,
5
+ enrich
6
+ } from "./chunk-RXNRMIZP.js";
7
+ import {
8
+ c,
9
+ dim,
10
+ heading,
11
+ isJson,
12
+ json,
13
+ line,
14
+ spinner,
15
+ sym,
16
+ warn
17
+ } from "./chunk-Z6QWMJLK.js";
18
+ import {
19
+ requireProjectRoot
20
+ } from "./chunk-XFN7UZCS.js";
21
+ import "./chunk-KBO7XRBW.js";
22
+ import "./chunk-PVCIGUIT.js";
23
+ import "./chunk-JCGDR4UV.js";
24
+ import "./chunk-FQEGEVLY.js";
25
+ import "./chunk-2DY4PUR4.js";
26
+ import "./chunk-IQQBAWSM.js";
27
+ import "./chunk-AD4OZCU2.js";
28
+ import "./chunk-EUPETUWA.js";
29
+
30
+ // src/cli/commands/ai.ts
31
+ var CONSENT_SOURCE = { env: "ATHENA_AI_CONSENT", local: ".athena/local.json", user: "user config" };
32
+ async function aiStatusCommand(opts) {
33
+ const root = await requireProjectRoot(opts);
34
+ const status = await aiStatus(root);
35
+ if (isJson()) {
36
+ json(status);
37
+ return;
38
+ }
39
+ heading("AI providers");
40
+ line();
41
+ for (const w of status.warnings) warn(c.yellow(w));
42
+ if (status.warnings.length) line();
43
+ for (const p of status.providers) {
44
+ const icon = p.availability.ok ? c.green(sym.ok) : c.dim(sym.ring);
45
+ line(`${icon} ${c.bold(p.name)}${p.selected ? c.cyan(" (selected)") : ""}`);
46
+ line(` ${dim(`${p.remote ? "sends data to" : "runs locally at"} ${p.availability.endpoint} \xB7 default model ${p.defaultModel}`)}`);
47
+ if (!p.availability.ok) line(` ${dim(p.availability.reason ?? "")}`);
48
+ }
49
+ line();
50
+ line(`Consent to send project knowledge: ${status.consent ? c.green(`granted (${CONSENT_SOURCE[status.consentSource ?? "env"]})`) : c.yellow("not granted")}`);
51
+ line(dim("Athena never needs AI: analysis, sync, context and MCP are deterministic. AI only produces INFERRED suggestions you review."));
52
+ line(dim('Configure in .athena/config.json \u2192 "ai": { "provider": "ollama" } for a fully local setup.'));
53
+ line(dim("Endpoint (baseUrl) and consent are machine-local only: ATHENA_AI_BASE_URL / ATHENA_AI_CONSENT=1, .athena/local.json, or ~/.config/athena/config.json."));
54
+ }
55
+ async function aiEnrichCommand(opts) {
56
+ const root = await requireProjectRoot(opts);
57
+ const docs = opts.docs?.split(",").map((d) => d.trim()).filter(Boolean);
58
+ const payload = await buildEnrichPayload(root, { docs });
59
+ if (!isJson()) {
60
+ heading("AI enrichment");
61
+ line();
62
+ for (const w of payload.warnings) warn(c.yellow(w));
63
+ if (payload.warnings.length) line();
64
+ line(`Provider: ${c.bold(payload.provider.name)} ${dim(`(${payload.model})`)}`);
65
+ line(`Sends to: ${payload.remote ? c.yellow(payload.endpoint) : c.green(`${payload.endpoint} (local)`)}`);
66
+ line(`Content: ${payload.documents.join(", ")} ${dim(`(${payload.chars} characters, redacted knowledge only \u2014 no source code)`)}`);
67
+ line();
68
+ }
69
+ if (opts.dryRun) {
70
+ if (isJson()) json({ ...payload, provider: payload.provider.id });
71
+ else line(dim("Dry run \u2014 nothing was sent."));
72
+ return 0;
73
+ }
74
+ const sp = spinner(`Asking ${payload.provider.name}...`);
75
+ let result;
76
+ try {
77
+ result = await enrich(root, { docs, consent: opts.consent, signal: opts.signal });
78
+ sp.succeed(`Suggestions written to .athena/${result.file}`);
79
+ } catch (err) {
80
+ sp.stop();
81
+ throw err;
82
+ }
83
+ if (isJson()) json(result);
84
+ else {
85
+ line();
86
+ line(result.markdown.split("\n").slice(0, 40).join("\n"));
87
+ line();
88
+ line(dim(`Full suggestions: .athena/${result.file} (gitignored). These are INFERRED \u2014 nothing was added to your knowledge base.`));
89
+ }
90
+ return 0;
91
+ }
92
+ export {
93
+ aiEnrichCommand,
94
+ aiStatusCommand
95
+ };
96
+ //# sourceMappingURL=ai-ASL4FFQ7.js.map
@@ -0,0 +1,50 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ parseAgentsOption,
4
+ printSummary,
5
+ runWithProgress,
6
+ summarize
7
+ } from "./chunk-XDCKZ5TV.js";
8
+ import {
9
+ printHeader
10
+ } from "./chunk-SHKXELUX.js";
11
+ import {
12
+ isJson,
13
+ json
14
+ } from "./chunk-Z6QWMJLK.js";
15
+ import {
16
+ requireProjectRoot
17
+ } from "./chunk-XFN7UZCS.js";
18
+ import "./chunk-KBO7XRBW.js";
19
+ import "./chunk-GGXPG6OE.js";
20
+ import "./chunk-MPG3IEGB.js";
21
+ import "./chunk-ELKFRTZT.js";
22
+ import "./chunk-2R6PXY6Z.js";
23
+ import "./chunk-PVCIGUIT.js";
24
+ import "./chunk-OLPSEQS5.js";
25
+ import "./chunk-QCC4VJUH.js";
26
+ import "./chunk-JCGDR4UV.js";
27
+ import "./chunk-YRIS7ZS6.js";
28
+ import "./chunk-GHFRQAYT.js";
29
+ import "./chunk-INT3IGMQ.js";
30
+ import "./chunk-673EPYYH.js";
31
+ import "./chunk-FQEGEVLY.js";
32
+ import "./chunk-2DY4PUR4.js";
33
+ import "./chunk-IQQBAWSM.js";
34
+ import "./chunk-AD4OZCU2.js";
35
+ import "./chunk-XW3MLHI2.js";
36
+ import "./chunk-EUPETUWA.js";
37
+
38
+ // src/cli/commands/analyze.ts
39
+ async function analyzeCommand(opts) {
40
+ const root = await requireProjectRoot(opts);
41
+ const agents = parseAgentsOption(opts.agents, false);
42
+ printHeader();
43
+ const result = await runWithProgress(root, { mode: "analyze", force: opts.force, agents, signal: opts.signal });
44
+ if (isJson()) json(summarize(result, root, false));
45
+ else printSummary(result, false, "analyze");
46
+ }
47
+ export {
48
+ analyzeCommand
49
+ };
50
+ //# sourceMappingURL=analyze-ZY3MXBOI.js.map