project-athena 0.3.0 → 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 (124) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/README.md +46 -4
  3. package/dist/{activity-P4UUFHWV.js → activity-BKW7G4I5.js} +4 -4
  4. package/dist/{agents-3HTSQGL2.js → agents-DFSNEOP5.js} +4 -4
  5. package/dist/{analyze-F3YOILNL.js → analyze-ZY3MXBOI.js} +7 -6
  6. package/dist/{chunk-PR53DT7I.js → chunk-3XSDI5WF.js} +5 -5
  7. package/dist/{chunk-S7T6VX56.js → chunk-7DZK6WSQ.js} +8 -4
  8. package/dist/{chunk-32PRS2MG.js → chunk-DZDI2HRT.js} +4 -4
  9. package/dist/{chunk-EF6GHOIN.js → chunk-FVCDMQUQ.js} +2 -2
  10. package/dist/{chunk-SJOOXO34.js → chunk-GGXPG6OE.js} +3 -3
  11. package/dist/{chunk-TGJUUB44.js → chunk-KHMBNT66.js} +4 -4
  12. package/dist/{chunk-PANVPNYF.js → chunk-MPG3IEGB.js} +37 -238
  13. package/dist/chunk-QCC4VJUH.js +217 -0
  14. package/dist/{chunk-JY6BFIJJ.js → chunk-QLW657NT.js} +2 -2
  15. package/dist/{chunk-XB66PZ6Z.js → chunk-RVTNSNGK.js} +2 -2
  16. package/dist/{chunk-LMOFZNTQ.js → chunk-SJ4DQFIJ.js} +2 -2
  17. package/dist/{chunk-PDFQ5BFG.js → chunk-SVTEJYMS.js} +4 -155
  18. package/dist/chunk-TDNZ2RYA.js +702 -0
  19. package/dist/chunk-UAZLPNVC.js +108 -0
  20. package/dist/chunk-WVQC2EGO.js +166 -0
  21. package/dist/{chunk-DOQMAZL5.js → chunk-XDCKZ5TV.js} +3 -3
  22. package/dist/{chunk-2RS6TA3D.js → chunk-YRIS7ZS6.js} +28 -17
  23. package/dist/{clean-S7PKCOLM.js → clean-MDBYH62P.js} +4 -4
  24. package/dist/cli.js +1 -1
  25. package/dist/{context-AH5MFHRG.js → context-PLPCAPCO.js} +23 -9
  26. package/dist/{doctor-RSJMLE2P.js → doctor-BX677KRE.js} +13 -6
  27. package/dist/{init-2V34DVRQ.js → init-WQCAOJ2R.js} +7 -6
  28. package/dist/{mcp-T2GRTEX5.js → mcp-U7EPH43L.js} +153 -15
  29. package/dist/memory-VSVNLEJC.js +393 -0
  30. package/dist/{open-2QSZKKUG.js → open-UJZRYF4E.js} +246 -55
  31. package/dist/{program-V2USHGXN.js → program-CWJNGCTZ.js} +37 -20
  32. package/dist/{review-R3R2J5BJ.js → review-OOKXSYMP.js} +10 -8
  33. package/dist/{security-PI4LXCOB.js → security-LME3XFL3.js} +6 -4
  34. package/dist/{staged-check-HHIBKKMR.js → staged-check-X24C3YRD.js} +9 -7
  35. package/dist/{status-6M73WX5I.js → status-RR57ZNGI.js} +8 -2
  36. package/dist/{sync-3ZNJDSSU.js → sync-KFJANRXF.js} +11 -9
  37. package/dist/{watch-USN5CQIV.js → watch-CY7QHIYN.js} +11 -9
  38. package/dist/web/assets/{Editor-BI56-HX5.js → Editor-Bnilgch0.js} +1 -1
  39. package/dist/web/assets/{abnfDiagram-O67JEVCF-y_9px2ob.js → abnfDiagram-O67JEVCF-DW9LWr8f.js} +1 -1
  40. package/dist/web/assets/architecture-7GRP2DOG-BWDZV2yn.js +1 -0
  41. package/dist/web/assets/{architectureDiagram-NJMV4G6O-lB6fcVzU.js → architectureDiagram-NJMV4G6O-0eKeQRhj.js} +1 -1
  42. package/dist/web/assets/{blockDiagram-BEXU5L5S-DcM5pEjM.js → blockDiagram-BEXU5L5S-D5i3-ogI.js} +1 -1
  43. package/dist/web/assets/{c4Diagram-YGBWAQC7-CJgqxTY2.js → c4Diagram-YGBWAQC7-BAWQZrEu.js} +1 -1
  44. package/dist/web/assets/channel-Bkh05NKd.js +1 -0
  45. package/dist/web/assets/{chunk-3FUC2YCW-B8l_VuWR.js → chunk-3FUC2YCW-fKRGOZF3.js} +1 -1
  46. package/dist/web/assets/{chunk-5DYCD2WN-CZecgNhf.js → chunk-5DYCD2WN-C5jOlx42.js} +1 -1
  47. package/dist/web/assets/{chunk-742MDFTN-BeZ7P5jB.js → chunk-742MDFTN-urY4RP_A.js} +1 -1
  48. package/dist/web/assets/{chunk-7INBJB4K-IKy0pr5m.js → chunk-7INBJB4K-nk48sKqZ.js} +1 -1
  49. package/dist/web/assets/{chunk-7M6MHVWA-Dg_QqJEX.js → chunk-7M6MHVWA-BfBD9X0F.js} +1 -1
  50. package/dist/web/assets/{chunk-7PRAP22T-DqQNS8oq.js → chunk-7PRAP22T-jYf59QlI.js} +1 -1
  51. package/dist/web/assets/{chunk-GTNCS2PH-x4sM51nJ.js → chunk-GTNCS2PH-BOCxryKf.js} +1 -1
  52. package/dist/web/assets/{chunk-GWA4HPMP-CE5GcwVN.js → chunk-GWA4HPMP-CFpaW0ru.js} +1 -1
  53. package/dist/web/assets/{chunk-MBY4JIJT-DA_D1hjF.js → chunk-MBY4JIJT-BIB8HctN.js} +1 -1
  54. package/dist/web/assets/{chunk-NETBCI7D-CeJ3XBZ2.js → chunk-NETBCI7D-CpUUK6rh.js} +1 -1
  55. package/dist/web/assets/{chunk-O7XYJQB3-BH2gESvO.js → chunk-O7XYJQB3-BNx_V4Oi.js} +1 -1
  56. package/dist/web/assets/{chunk-UA2S7LBM-BWr0xCux.js → chunk-UA2S7LBM-D3tMiIOY.js} +1 -1
  57. package/dist/web/assets/{chunk-WEXAMYUT-B4QwUZPM.js → chunk-WEXAMYUT-CC-3C32l.js} +1 -1
  58. package/dist/web/assets/{chunk-Z7XXMR3K-BxcA-y5B.js → chunk-Z7XXMR3K-BzhxKQUc.js} +1 -1
  59. package/dist/web/assets/{chunk-ZIGJFQKS-BZYvP63G.js → chunk-ZIGJFQKS-D4tBHzxg.js} +1 -1
  60. package/dist/web/assets/{classDiagram-v2-NBCMYWYE-BS3P_NXb.js → classDiagram-v2-NBCMYWYE-BbtyanXR.js} +1 -1
  61. package/dist/web/assets/{cynefin-OW5HDTMX-BALD4Pve.js → cynefin-OW5HDTMX-BIArb8W1.js} +1 -1
  62. package/dist/web/assets/{cynefinDiagram-VND7K2PF-BM2y4W6d.js → cynefinDiagram-VND7K2PF-BrAcfkXL.js} +1 -1
  63. package/dist/web/assets/{dagre-6A5THRUB-PTfOrIdF.js → dagre-6A5THRUB-BcHXRl4s.js} +1 -1
  64. package/dist/web/assets/{diagram-22UHCM2B-CpXEHhUl.js → diagram-22UHCM2B-Dx9tSCdE.js} +1 -1
  65. package/dist/web/assets/{diagram-3UASUU5V-DPHfXzr6.js → diagram-3UASUU5V-CLLDP9yH.js} +1 -1
  66. package/dist/web/assets/{diagram-ATOU4E4O-DMBNXvAC.js → diagram-ATOU4E4O-B46H9iPt.js} +1 -1
  67. package/dist/web/assets/{diagram-CDSNMT55-CDLe1M7G.js → diagram-CDSNMT55-CYtvB6aG.js} +1 -1
  68. package/dist/web/assets/{diagram-MLGK6HIB-D6L8oE7j.js → diagram-MLGK6HIB-Dar7ktoX.js} +1 -1
  69. package/dist/web/assets/{diagram-MPIPVDR6-CP-S7rrQ.js → diagram-MPIPVDR6-C-DljnYN.js} +1 -1
  70. package/dist/web/assets/{ebnfDiagram-ZINNZB2B-CkUc63TK.js → ebnfDiagram-ZINNZB2B-Dv_3jWnh.js} +1 -1
  71. package/dist/web/assets/{elk-276RUBZZ-C1CAJLH_.js → elk-276RUBZZ-DnHciE9k.js} +1 -1
  72. package/dist/web/assets/{erDiagram-OPXOYQCR-DXBnaTHm.js → erDiagram-OPXOYQCR-Bn46KrHz.js} +1 -1
  73. package/dist/web/assets/eventmodeling-NTZA5JFV-DYwoptMd.js +1 -0
  74. package/dist/web/assets/flowDiagram-KWPJA3E3-y4rS0gIB.js +1 -0
  75. package/dist/web/assets/{ganttDiagram-FUAMR5RP-BVm8SiGg.js → ganttDiagram-FUAMR5RP-DOjjJtqz.js} +1 -1
  76. package/dist/web/assets/{gitGraph-4MIJSDKK-Dm7xBrW0.js → gitGraph-4MIJSDKK-BIoMXJRQ.js} +1 -1
  77. package/dist/web/assets/{gitGraphDiagram-X574FWY7-D_PIKKhx.js → gitGraphDiagram-X574FWY7-BsJ01R0v.js} +1 -1
  78. package/dist/web/assets/{index-CeOIBpu2.js → index-Cen0jOXj.js} +5 -4
  79. package/dist/web/assets/{index-DKE3ojTe.css → index-WwRY6n68.css} +1 -1
  80. package/dist/web/assets/{info-A6RAGUB7-CLGrx8pn.js → info-A6RAGUB7-BmlXzRWj.js} +1 -1
  81. package/dist/web/assets/{infoDiagram-VRGFBTTK-BlBjaKm7.js → infoDiagram-VRGFBTTK-CYPJPmBP.js} +1 -1
  82. package/dist/web/assets/{ishikawaDiagram-OU5B5YK6-Kxe7GGS3.js → ishikawaDiagram-OU5B5YK6-YN96geky.js} +1 -1
  83. package/dist/web/assets/{journeyDiagram-ZHPQQLJL-wCMoHK4M.js → journeyDiagram-ZHPQQLJL-20juojKY.js} +1 -1
  84. package/dist/web/assets/{kanban-definition-PNTS6WVX-BxdCz9Ko.js → kanban-definition-PNTS6WVX-BhCKIEbP.js} +1 -1
  85. package/dist/web/assets/{line-Zf11FnWF.js → line-BERsMFG6.js} +1 -1
  86. package/dist/web/assets/{mermaid-parser.core-BvFFklev.js → mermaid-parser.core-Bis_wTB-.js} +3 -3
  87. package/dist/web/assets/{mermaid.core-Cd_Ssti9.js → mermaid.core-DMsM3ZX7.js} +4 -4
  88. package/dist/web/assets/{mindmap-definition-NLK3R4M7-BGPQl-GY.js → mindmap-definition-NLK3R4M7-BkcGdOfv.js} +1 -1
  89. package/dist/web/assets/{packet-AYTQ26CC-6lI3cEX_.js → packet-AYTQ26CC-Bh30-JJX.js} +1 -1
  90. package/dist/web/assets/{pegDiagram-GJSIUBJH-BPIjlSAj.js → pegDiagram-GJSIUBJH-DxnIo9RF.js} +1 -1
  91. package/dist/web/assets/{pie-WAS4IAKB-D6Dzj3Ja.js → pie-WAS4IAKB-ChaTr-GD.js} +1 -1
  92. package/dist/web/assets/{pieDiagram-5QR66LMP-DtA-vZmv.js → pieDiagram-5QR66LMP-CzAp78FM.js} +1 -1
  93. package/dist/web/assets/{quadrantDiagram-O4NWA36T-EettyqQn.js → quadrantDiagram-O4NWA36T-BDSE-cfY.js} +1 -1
  94. package/dist/web/assets/{radar-RG4KPBEZ-xmRc3Dl8.js → radar-RG4KPBEZ-DgJ-o_dq.js} +1 -1
  95. package/dist/web/assets/{railroad-74A4TZTK-BLB7dhOn.js → railroad-74A4TZTK-C8MmcBKz.js} +1 -1
  96. package/dist/web/assets/railroad-abnf-HS5TGJTU-CTLXjcdP.js +1 -0
  97. package/dist/web/assets/railroad-ebnf-LZEXJU2U-ggWsTTL0.js +1 -0
  98. package/dist/web/assets/railroad-peg-WCYAUIDC-D1mCX705.js +1 -0
  99. package/dist/web/assets/{railroadDiagram-XR7U4H2S-PBw4We6b.js → railroadDiagram-XR7U4H2S-DfbcWRNh.js} +1 -1
  100. package/dist/web/assets/{requirementDiagram-PLB6GJNP-DjQpaUFA.js → requirementDiagram-PLB6GJNP-DM3nksxs.js} +1 -1
  101. package/dist/web/assets/{sankeyDiagram-IPEJSGJF-CBW-_AoF.js → sankeyDiagram-IPEJSGJF-DthUpiiC.js} +1 -1
  102. package/dist/web/assets/{sequenceDiagram-PO4LG4MO-DEoPYqY9.js → sequenceDiagram-PO4LG4MO-DLA3nuvA.js} +1 -1
  103. package/dist/web/assets/{stateDiagram-v2-GCMORJYK-UZq5rPud.js → stateDiagram-v2-GCMORJYK-B0X6ihBW.js} +1 -1
  104. package/dist/web/assets/{swimlanes-2SLR337P-CACfuXJR.js → swimlanes-2SLR337P-B4qWe6vE.js} +1 -1
  105. package/dist/web/assets/swimlanesDiagram-TC7HE7FX-ClIk3e7S.js +8 -0
  106. package/dist/web/assets/{timeline-definition-EJHVYXUP-CYJl7mP-.js → timeline-definition-EJHVYXUP-F-cDzYrj.js} +1 -1
  107. package/dist/web/assets/{treeView-Q6P3EWNA-DtZ5nkPQ.js → treeView-Q6P3EWNA-BaI30nLZ.js} +1 -1
  108. package/dist/web/assets/{treemap-WGGIJYW6-m49GDM-M.js → treemap-WGGIJYW6-D2jGGoMl.js} +1 -1
  109. package/dist/web/assets/{usecaseDiagram-POWQR4AR-C2Vg20UK.js → usecaseDiagram-POWQR4AR-B9qoAQCy.js} +1 -1
  110. package/dist/web/assets/{vennDiagram-UO4OBE2U-C07v5OGI.js → vennDiagram-UO4OBE2U-DGVNOaKO.js} +1 -1
  111. package/dist/web/assets/{wardley-WFR3VGLG-C9Z7EZtz.js → wardley-WFR3VGLG-DbKqhNAh.js} +1 -1
  112. package/dist/web/assets/{wardleyDiagram-VNRHLVJA-DdA8CcSC.js → wardleyDiagram-VNRHLVJA-BgZ1gprw.js} +1 -1
  113. package/dist/web/assets/{xychartDiagram-PMCCYNJV-C9EZw07b.js → xychartDiagram-PMCCYNJV-D73RYid1.js} +1 -1
  114. package/dist/web/index.html +2 -2
  115. package/package.json +1 -1
  116. package/dist/chunk-CXUTYCZX.js +0 -238
  117. package/dist/web/assets/architecture-7GRP2DOG-DyxkwYiW.js +0 -1
  118. package/dist/web/assets/channel-BvDD7AMO.js +0 -1
  119. package/dist/web/assets/eventmodeling-NTZA5JFV-cLIzvgDp.js +0 -1
  120. package/dist/web/assets/flowDiagram-KWPJA3E3-D7Zq63VQ.js +0 -1
  121. package/dist/web/assets/railroad-abnf-HS5TGJTU-DBFym6g8.js +0 -1
  122. package/dist/web/assets/railroad-ebnf-LZEXJU2U-CkG28ig8.js +0 -1
  123. package/dist/web/assets/railroad-peg-WCYAUIDC-Df_Ifaad.js +0 -1
  124. package/dist/web/assets/swimlanesDiagram-TC7HE7FX-CDSrqdgx.js +0 -8
@@ -0,0 +1,108 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ CONTEXT_MEMORY_LIMIT,
4
+ documentSections,
5
+ listMemory,
6
+ recall,
7
+ selectContext
8
+ } from "./chunk-TDNZ2RYA.js";
9
+ import {
10
+ projectSession
11
+ } from "./chunk-WVQC2EGO.js";
12
+ import {
13
+ analyzeProject
14
+ } from "./chunk-MPG3IEGB.js";
15
+ import {
16
+ GRAPH_FILE,
17
+ buildGraph,
18
+ saveGraph
19
+ } from "./chunk-SVTEJYMS.js";
20
+ import {
21
+ KNOWLEDGE_DOCS
22
+ } from "./chunk-FQEGEVLY.js";
23
+ import {
24
+ athenaDir
25
+ } from "./chunk-2DY4PUR4.js";
26
+ import {
27
+ readTextIfExists
28
+ } from "./chunk-IQQBAWSM.js";
29
+ import {
30
+ AthenaError
31
+ } from "./chunk-AD4OZCU2.js";
32
+
33
+ // src/services/context.ts
34
+ import path from "path";
35
+ async function refreshGraph(root, opts = {}) {
36
+ const session = projectSession(root);
37
+ const st = await session.state();
38
+ const analysis = await analyzeProject(root, { signal: opts.signal });
39
+ const files = analysis.files.map((f) => f.path);
40
+ const graph = await buildGraph(analysis.model, {
41
+ files,
42
+ signal: opts.signal,
43
+ read: async (rel) => readTextIfExists(path.join(root, rel)).catch(() => null)
44
+ });
45
+ await saveGraph(root, graph);
46
+ await session.remember(GRAPH_FILE, graph);
47
+ return graph;
48
+ }
49
+ async function getGraph(root, opts = {}) {
50
+ const existing = await projectSession(root).graph();
51
+ if (existing) return existing;
52
+ return opts.build ? refreshGraph(root, { signal: opts.signal }) : null;
53
+ }
54
+ async function getRelevantContext(root, task, opts = {}) {
55
+ if (!task.trim()) throw new AthenaError("Describe the task to get relevant context.", 'For example: athena context "add refunds to the payments API"');
56
+ const dir = athenaDir(root);
57
+ const documents = [];
58
+ for (const d of KNOWLEDGE_DOCS) {
59
+ if (d.id === "rules") continue;
60
+ const text = await readTextIfExists(path.join(dir, d.file));
61
+ if (text) documents.push({ id: d.id, file: d.file, sections: documentSections(text) });
62
+ }
63
+ if (!documents.length) throw new AthenaError("No knowledge documents found.", "Run `athena init` first.", 3);
64
+ return selectContext({
65
+ task,
66
+ documents,
67
+ rulesMarkdown: await readTextIfExists(path.join(dir, "rules.md")),
68
+ graph: await getGraph(root, { build: opts.buildGraph, signal: opts.signal }),
69
+ maxChars: opts.maxChars,
70
+ memories: await memoriesFor(root, task)
71
+ });
72
+ }
73
+ async function memoriesFor(root, task, files = []) {
74
+ let hits;
75
+ try {
76
+ hits = recall(await listMemory(root), { task, files, limit: CONTEXT_MEMORY_LIMIT * 2 });
77
+ } catch {
78
+ return [];
79
+ }
80
+ const rank = (s) => s === "confirmed" ? 0 : 1;
81
+ return hits.map((h, i) => ({ h, i })).sort((a, b) => rank(a.h.entry.status) - rank(b.h.entry.status) || a.i - b.i).slice(0, CONTEXT_MEMORY_LIMIT).map(({ h: { entry: e, why } }) => ({
82
+ id: e.id,
83
+ kind: e.kind,
84
+ status: e.status === "confirmed" ? "confirmed" : "unreviewed",
85
+ label: e.label,
86
+ stale: e.stale,
87
+ changedFiles: e.changedFiles,
88
+ source: e.source,
89
+ title: e.title,
90
+ details: e.details,
91
+ files: e.files,
92
+ evidence: e.evidence,
93
+ why
94
+ }));
95
+ }
96
+ async function graphSummary(root) {
97
+ const session = projectSession(root);
98
+ const [graph, hasModel] = await Promise.all([session.graph(), session.hasModel()]);
99
+ return { built: Boolean(graph), builtAt: graph?.builtAt ?? null, stats: graph?.stats ?? null, model: { hasModel } };
100
+ }
101
+
102
+ export {
103
+ refreshGraph,
104
+ getGraph,
105
+ getRelevantContext,
106
+ graphSummary
107
+ };
108
+ //# sourceMappingURL=chunk-UAZLPNVC.js.map
@@ -0,0 +1,166 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ SCAN_FILE,
4
+ SecurityScan
5
+ } from "./chunk-MPG3IEGB.js";
6
+ import {
7
+ GRAPH_FILE,
8
+ ProjectGraph
9
+ } from "./chunk-SVTEJYMS.js";
10
+ import {
11
+ ProjectModel
12
+ } from "./chunk-QCC4VJUH.js";
13
+ import {
14
+ athenaDir,
15
+ readState
16
+ } from "./chunk-2DY4PUR4.js";
17
+ import {
18
+ AthenaError
19
+ } from "./chunk-AD4OZCU2.js";
20
+
21
+ // src/services/project-session.ts
22
+ import { promises as fs } from "fs";
23
+ import path from "path";
24
+ var fileKey = (st) => `${st.ino}:${st.size}:${st.mtimeNs}`;
25
+ var ProjectSession = class {
26
+ constructor(root) {
27
+ this.root = root;
28
+ }
29
+ root;
30
+ cache = /* @__PURE__ */ new Map();
31
+ inflight = /* @__PURE__ */ new Map();
32
+ stateEntry = null;
33
+ get dir() {
34
+ return athenaDir(this.root);
35
+ }
36
+ /** model.json, or why it can't be used. */
37
+ readModel() {
38
+ return this.read("model.json", ProjectModel);
39
+ }
40
+ /** The parsed model, or null when missing or unusable. */
41
+ async model() {
42
+ const r = await this.readModel();
43
+ return r.kind === "ok" ? r.value : null;
44
+ }
45
+ /** The parsed model; throws an AthenaError with a hint when it is missing or corrupted. */
46
+ async requireModel() {
47
+ const r = await this.readModel();
48
+ if (r.kind === "ok") return r.value;
49
+ if (r.kind === "missing") throw new AthenaError("model.json is missing.", "Run `athena analyze` (or re-analyze from the overview) first.");
50
+ throw new AthenaError(`model.json is corrupted (${r.reason}).`, "Run `athena analyze` to rebuild it.");
51
+ }
52
+ /** Cheap existence check (a stat, no parsing). */
53
+ async hasModel() {
54
+ return this.exists("model.json");
55
+ }
56
+ readGraph() {
57
+ return this.read(GRAPH_FILE, ProjectGraph);
58
+ }
59
+ async graph() {
60
+ const r = await this.readGraph();
61
+ return r.kind === "ok" ? r.value : null;
62
+ }
63
+ readScan() {
64
+ return this.read(SCAN_FILE, SecurityScan);
65
+ }
66
+ async scan() {
67
+ const r = await this.readScan();
68
+ return r.kind === "ok" ? r.value : null;
69
+ }
70
+ /** state.json via `readState`, memoized like the other artifacts. */
71
+ async state() {
72
+ const file = path.join(this.dir, "state.json");
73
+ const st = await fs.stat(file, { bigint: true }).catch(() => null);
74
+ if (!st) return readState(this.dir);
75
+ const key = fileKey(st);
76
+ if (this.stateEntry?.key === key) return this.stateEntry.state;
77
+ const state = await readState(this.dir);
78
+ const after = await fs.stat(file, { bigint: true }).catch(() => null);
79
+ if (after && fileKey(after) === key) this.stateEntry = { key, state };
80
+ return state;
81
+ }
82
+ /**
83
+ * Record a value this process just wrote to `.athena/<name>`, so the next
84
+ * read doesn't parse it again. The file must already be on disk.
85
+ */
86
+ async remember(name, value) {
87
+ const st = await fs.stat(path.join(this.dir, name), { bigint: true }).catch(() => null);
88
+ if (st) this.cache.set(name, { key: fileKey(st), result: { kind: "ok", value } });
89
+ else this.cache.delete(name);
90
+ }
91
+ /** Drop memoized results (all, or one file). */
92
+ invalidate(name) {
93
+ if (!name || name === "state.json") this.stateEntry = null;
94
+ if (name) this.cache.delete(name);
95
+ else this.cache.clear();
96
+ }
97
+ async exists(name) {
98
+ const st = await fs.stat(path.join(this.dir, name)).catch(() => null);
99
+ return Boolean(st?.isFile());
100
+ }
101
+ read(name, schema) {
102
+ const running = this.inflight.get(name);
103
+ if (running) return running;
104
+ const p = this.load(name, schema).finally(() => this.inflight.delete(name));
105
+ this.inflight.set(name, p);
106
+ return p;
107
+ }
108
+ async load(name, schema) {
109
+ const file = path.join(this.dir, name);
110
+ let st;
111
+ try {
112
+ st = await fs.stat(file, { bigint: true });
113
+ } catch (err) {
114
+ const code = err.code;
115
+ this.cache.delete(name);
116
+ if (code === "ENOENT" || code === "ENOTDIR") return { kind: "missing" };
117
+ return { kind: "corrupted", reason: `unreadable (${code})` };
118
+ }
119
+ const key = fileKey(st);
120
+ const hit = this.cache.get(name);
121
+ if (hit?.key === key) return hit.result;
122
+ let raw;
123
+ try {
124
+ raw = await fs.readFile(file, "utf8");
125
+ } catch (err) {
126
+ const code = err.code;
127
+ if (code === "ENOENT") return { kind: "missing" };
128
+ return { kind: "corrupted", reason: `unreadable (${code})` };
129
+ }
130
+ const result = parseArtifact(raw, schema);
131
+ const after = await fs.stat(file, { bigint: true }).catch(() => null);
132
+ if (after && fileKey(after) === key) this.cache.set(name, { key, result });
133
+ return result;
134
+ }
135
+ };
136
+ function parseArtifact(raw, schema) {
137
+ let json;
138
+ try {
139
+ json = JSON.parse(raw);
140
+ } catch {
141
+ return { kind: "corrupted", reason: "invalid JSON" };
142
+ }
143
+ const parsed = schema.safeParse(json);
144
+ if (parsed.success) return { kind: "ok", value: parsed.data };
145
+ const issue = parsed.error.issues[0];
146
+ return { kind: "corrupted", reason: `schema mismatch at ${issue?.path.map(String).join(".") || "(root)"}: ${issue?.message}` };
147
+ }
148
+ var sessions = /* @__PURE__ */ new Map();
149
+ function projectSession(root) {
150
+ const key = path.resolve(root);
151
+ let s = sessions.get(key);
152
+ if (!s) {
153
+ s = new ProjectSession(key);
154
+ sessions.set(key, s);
155
+ }
156
+ return s;
157
+ }
158
+ function releaseProjectSession(root) {
159
+ sessions.delete(path.resolve(root));
160
+ }
161
+
162
+ export {
163
+ projectSession,
164
+ releaseProjectSession
165
+ };
166
+ //# sourceMappingURL=chunk-WVQC2EGO.js.map
@@ -33,11 +33,11 @@ import {
33
33
  } from "./chunk-XFN7UZCS.js";
34
34
  import {
35
35
  runPipeline
36
- } from "./chunk-SJOOXO34.js";
36
+ } from "./chunk-GGXPG6OE.js";
37
37
  import {
38
38
  ADAPTERS,
39
39
  resolveAdapters
40
- } from "./chunk-2RS6TA3D.js";
40
+ } from "./chunk-YRIS7ZS6.js";
41
41
  import {
42
42
  KNOWLEDGE_DOCS
43
43
  } from "./chunk-FQEGEVLY.js";
@@ -433,4 +433,4 @@ export {
433
433
  printSummary,
434
434
  summarize
435
435
  };
436
- //# sourceMappingURL=chunk-DOQMAZL5.js.map
436
+ //# sourceMappingURL=chunk-XDCKZ5TV.js.map
@@ -12,6 +12,13 @@ import {
12
12
  removeJsonHooks,
13
13
  stripMcpServers
14
14
  } from "./chunk-GHFRQAYT.js";
15
+ import {
16
+ CLAUDE_HOOK_EVENTS,
17
+ CODEX_HOOK_EVENTS,
18
+ COPILOT_HOOK_EVENTS,
19
+ CURSOR_HOOK_EVENTS,
20
+ GEMINI_HOOK_EVENTS
21
+ } from "./chunk-INT3IGMQ.js";
15
22
  import {
16
23
  INTEGRATION_END,
17
24
  INTEGRATION_START,
@@ -27,13 +34,6 @@ import {
27
34
  readTextIfExists,
28
35
  writeFileAtomic
29
36
  } from "./chunk-IQQBAWSM.js";
30
- import {
31
- CLAUDE_HOOK_EVENTS,
32
- CODEX_HOOK_EVENTS,
33
- COPILOT_HOOK_EVENTS,
34
- CURSOR_HOOK_EVENTS,
35
- GEMINI_HOOK_EVENTS
36
- } from "./chunk-INT3IGMQ.js";
37
37
  import {
38
38
  resolveInside
39
39
  } from "./chunk-XW3MLHI2.js";
@@ -49,14 +49,16 @@ import path2 from "path";
49
49
  function workflowSteps() {
50
50
  return [
51
51
  "1. Read `.athena/rules.md` and follow every enabled rule (lines marked `[disabled]` do not apply).",
52
- "2. Classify the task and read only the relevant Athena documents (see the relevance map below).",
53
- "3. Identify the affected modules and architecture boundaries.",
54
- "4. Check security implications (`.athena/security.md`, `.athena/auth.md`) when touching input handling, auth, data access or secrets.",
55
- "5. Check database and API implications when the change touches schema, queries or endpoints.",
56
- "6. For non-trivial work, state a short implementation plan before editing.",
57
- "7. Implement only the required changes.",
58
- "8. Run the relevant validation (tests, lint, type checks \u2014 commands are listed in `.athena/project.md` and `.athena/testing.md`).",
59
- "9. If you changed project structure, dependencies, routes, schema or infrastructure, run `athena sync --dry-run` to see which knowledge is affected, and tell the developer to review it with `athena sync` (apply it yourself only if permitted)."
52
+ "2. Recall project memory for the task and files: call the Athena `recall` MCP tool, or skim `.athena/memory/` if MCP is unavailable.",
53
+ "3. Classify the task and read only the relevant Athena documents (see the relevance map below).",
54
+ "4. Identify the affected modules and architecture boundaries.",
55
+ "5. Check security implications (`.athena/security.md`, `.athena/auth.md`) when touching input handling, auth, data access or secrets.",
56
+ "6. Check database and API implications when the change touches schema, queries or endpoints.",
57
+ "7. For non-trivial work, state a short implementation plan before editing.",
58
+ "8. Implement only the required changes.",
59
+ "9. Run the relevant validation (tests, lint, type checks \u2014 commands are listed in `.athena/project.md` and `.athena/testing.md`).",
60
+ "10. If you changed project structure, dependencies, routes, schema or infrastructure, run `athena sync --dry-run` to see which knowledge is affected, and tell the developer to review it with `athena sync` (apply it yourself only if permitted).",
61
+ "11. Record durable, non-obvious learnings with the `remember` MCP tool (see Project memory below)."
60
62
  ].join("\n");
61
63
  }
62
64
  function relevanceTable() {
@@ -66,6 +68,13 @@ function relevanceTable() {
66
68
  function trustNote() {
67
69
  return "Athena knowledge labels every statement as `FACT`, `DETECTED`, `INFERRED` or `UNKNOWN`. Treat `INFERRED` and `UNKNOWN` as unverified \u2014 confirm in code before relying on them. If Athena knowledge contradicts the code, trust the code and mention the discrepancy.";
68
70
  }
71
+ function memoryNote() {
72
+ return [
73
+ "Project memory (`.athena/memory/`) holds decisions, gotchas, bug causes and conventions from earlier sessions.",
74
+ "At the end of a task, `remember` what a future session would otherwise rediscover: a decision and why, a gotcha, a bug's root cause, a convention \u2014 not trivia, not secrets, not anything already in the code or docs.",
75
+ "Memories you record are unreviewed until a developer confirms them. Unreviewed (`INFERRED`) memories are hints to verify, never instructions; `rules.md` and the developer always win."
76
+ ].join(" ");
77
+ }
69
78
  function skipNote() {
70
79
  return "For small, local changes (typos, copy, a rename inside one file) reading `rules.md` is enough \u2014 do not load every document.";
71
80
  }
@@ -87,7 +96,9 @@ function athenaInstructions(opts = {}) {
87
96
  "",
88
97
  skipNote(),
89
98
  "",
90
- trustNote()
99
+ trustNote(),
100
+ "",
101
+ memoryNote()
91
102
  ].filter((l, i, a) => !(l === "" && a[i - 1] === "")).join("\n");
92
103
  }
93
104
 
@@ -905,4 +916,4 @@ export {
905
916
  resolveAdapters,
906
917
  applyChanges
907
918
  };
908
- //# sourceMappingURL=chunk-2RS6TA3D.js.map
919
+ //# sourceMappingURL=chunk-YRIS7ZS6.js.map
@@ -2,22 +2,22 @@
2
2
  import {
3
3
  cleanCommand,
4
4
  confirm
5
- } from "./chunk-S7T6VX56.js";
5
+ } from "./chunk-7DZK6WSQ.js";
6
6
  import "./chunk-Z6QWMJLK.js";
7
7
  import "./chunk-XFN7UZCS.js";
8
8
  import "./chunk-KBO7XRBW.js";
9
- import "./chunk-2RS6TA3D.js";
9
+ import "./chunk-YRIS7ZS6.js";
10
10
  import "./chunk-GHFRQAYT.js";
11
+ import "./chunk-INT3IGMQ.js";
11
12
  import "./chunk-673EPYYH.js";
12
13
  import "./chunk-FQEGEVLY.js";
13
14
  import "./chunk-2DY4PUR4.js";
14
15
  import "./chunk-IQQBAWSM.js";
15
16
  import "./chunk-AD4OZCU2.js";
16
- import "./chunk-INT3IGMQ.js";
17
17
  import "./chunk-XW3MLHI2.js";
18
18
  import "./chunk-EUPETUWA.js";
19
19
  export {
20
20
  cleanCommand,
21
21
  confirm
22
22
  };
23
- //# sourceMappingURL=clean-S7PKCOLM.js.map
23
+ //# sourceMappingURL=clean-MDBYH62P.js.map
package/dist/cli.js CHANGED
@@ -21,7 +21,7 @@ function eventFailed(err) {
21
21
  return true;
22
22
  }
23
23
  if (process.argv[2] !== "event" || !await runEvent(process.argv.slice(3)).catch(eventFailed)) {
24
- const { main } = await import("./program-V2USHGXN.js");
24
+ const { main } = await import("./program-CWJNGCTZ.js");
25
25
  await main();
26
26
  }
27
27
  //# sourceMappingURL=cli.js.map
@@ -1,10 +1,12 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
- formatContext,
4
3
  getRelevantContext,
5
4
  graphSummary,
6
5
  refreshGraph
7
- } from "./chunk-CXUTYCZX.js";
6
+ } from "./chunk-UAZLPNVC.js";
7
+ import {
8
+ formatContext
9
+ } from "./chunk-TDNZ2RYA.js";
8
10
  import "./chunk-3IS2X2Z7.js";
9
11
  import {
10
12
  bullet,
@@ -22,14 +24,16 @@ import {
22
24
  requireProjectRoot
23
25
  } from "./chunk-XFN7UZCS.js";
24
26
  import "./chunk-KBO7XRBW.js";
25
- import {
26
- loadGraph,
27
- neighbors
28
- } from "./chunk-PDFQ5BFG.js";
29
- import "./chunk-PANVPNYF.js";
27
+ import "./chunk-WVQC2EGO.js";
28
+ import "./chunk-MPG3IEGB.js";
30
29
  import "./chunk-ELKFRTZT.js";
31
30
  import "./chunk-PVCIGUIT.js";
32
31
  import "./chunk-OLPSEQS5.js";
32
+ import {
33
+ loadGraph,
34
+ neighbors
35
+ } from "./chunk-SVTEJYMS.js";
36
+ import "./chunk-QCC4VJUH.js";
33
37
  import "./chunk-JCGDR4UV.js";
34
38
  import "./chunk-673EPYYH.js";
35
39
  import "./chunk-FQEGEVLY.js";
@@ -70,11 +74,21 @@ async function contextCommand(task, opts) {
70
74
  for (const n of ctx.graphNodes.slice(0, 12)) line(` ${dim(`${n.kind}:`)} ${n.name}${n.path ? dim(` (${n.path})`) : ""}`);
71
75
  if (ctx.graphNodes.length > 12) line(dim(` +${ctx.graphNodes.length - 12} more`));
72
76
  }
77
+ if (ctx.memories.length) {
78
+ line();
79
+ heading("Project memory");
80
+ for (const m of ctx.memories) {
81
+ const label = m.label === "FACT" ? c.green(m.label) : c.yellow(m.label);
82
+ line(` ${label} ${m.title} ${dim(`(${m.id}, ${m.kind}${m.status === "unreviewed" ? ", unreviewed" : ""}${m.stale ? ", stale" : ""})`)}`);
83
+ line(dim(` ${m.why.join("; ")}`));
84
+ }
85
+ if (ctx.memories.some((m) => m.status === "unreviewed")) line(dim(" Unreviewed memories were written by an agent; confirm or forget them with `athena memory`."));
86
+ }
73
87
  line();
74
88
  heading("Sections selected");
75
89
  for (const s of ctx.sections) line(` ${dim(`${s.file} \u2192`)} ${s.section}`);
76
90
  line();
77
- line(dim(`${ctx.sections.length} sections \xB7 ~${ctx.approxChars} characters \xB7 ${ctx.rules.length} rules${ctx.truncated ? " \xB7 some sections omitted for budget" : ""}`));
91
+ line(dim(`${ctx.sections.length} sections \xB7 ${ctx.memories.length} memories \xB7 ~${ctx.approxChars} characters \xB7 ${ctx.rules.length} rules${ctx.truncated ? " \xB7 some content omitted for budget" : ""}`));
78
92
  line(dim("Use --full to print the context an agent would read, or --json for tooling."));
79
93
  }
80
94
  async function graphCommand(opts) {
@@ -144,4 +158,4 @@ export {
144
158
  contextCommand,
145
159
  graphCommand
146
160
  };
147
- //# sourceMappingURL=context-AH5MFHRG.js.map
161
+ //# sourceMappingURL=context-PLPCAPCO.js.map
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  runDoctor
4
- } from "./chunk-PR53DT7I.js";
4
+ } from "./chunk-3XSDI5WF.js";
5
5
  import "./chunk-RXNRMIZP.js";
6
6
  import "./chunk-VSYBC3VY.js";
7
- import "./chunk-3IS2X2Z7.js";
8
7
  import "./chunk-65TSRDQ3.js";
8
+ import "./chunk-3IS2X2Z7.js";
9
9
  import {
10
10
  c,
11
11
  dim,
@@ -23,21 +23,28 @@ import "./chunk-2R6PXY6Z.js";
23
23
  import "./chunk-PVCIGUIT.js";
24
24
  import "./chunk-OLPSEQS5.js";
25
25
  import "./chunk-JCGDR4UV.js";
26
- import "./chunk-2RS6TA3D.js";
26
+ import "./chunk-YRIS7ZS6.js";
27
27
  import "./chunk-GHFRQAYT.js";
28
+ import "./chunk-INT3IGMQ.js";
28
29
  import "./chunk-673EPYYH.js";
29
30
  import "./chunk-FQEGEVLY.js";
30
31
  import "./chunk-2DY4PUR4.js";
31
32
  import "./chunk-IQQBAWSM.js";
32
33
  import "./chunk-AD4OZCU2.js";
33
- import "./chunk-INT3IGMQ.js";
34
34
  import "./chunk-XW3MLHI2.js";
35
35
  import "./chunk-EUPETUWA.js";
36
36
 
37
37
  // src/cli/commands/doctor.ts
38
38
  async function doctorCommand(opts) {
39
39
  const cwd = await resolveCwd(opts);
40
- const { checks } = await runDoctor(cwd);
40
+ const { checks, root } = await runDoctor(cwd);
41
+ if (root) {
42
+ const m = await (await import("./memory-VSVNLEJC.js")).memorySummary(root);
43
+ if (m?.total) {
44
+ const pending = [m.unreviewed ? `${m.unreviewed} unreviewed` : "", m.stale ? `${m.stale} stale` : ""].filter(Boolean);
45
+ checks.push({ area: "Memory", level: "info", message: `${m.total} project memory ${m.total === 1 ? "entry" : "entries"}${pending.length ? ` (${pending.join(", ")})` : ""}`, hint: pending.length ? "Review with `athena memory review` and `athena memory stale`." : void 0 });
46
+ }
47
+ }
41
48
  const errors = checks.filter((c2) => c2.level === "error").length;
42
49
  if (isJson()) {
43
50
  json({ ok: errors === 0, checks });
@@ -59,4 +66,4 @@ async function doctorCommand(opts) {
59
66
  export {
60
67
  doctorCommand
61
68
  };
62
- //# sourceMappingURL=doctor-RSJMLE2P.js.map
69
+ //# sourceMappingURL=doctor-BX677KRE.js.map
@@ -5,26 +5,27 @@ import {
5
5
  printSummary,
6
6
  runWithProgress,
7
7
  summarize
8
- } from "./chunk-DOQMAZL5.js";
8
+ } from "./chunk-XDCKZ5TV.js";
9
9
  import "./chunk-SHKXELUX.js";
10
10
  import "./chunk-Z6QWMJLK.js";
11
11
  import "./chunk-XFN7UZCS.js";
12
12
  import "./chunk-KBO7XRBW.js";
13
- import "./chunk-SJOOXO34.js";
14
- import "./chunk-PANVPNYF.js";
13
+ import "./chunk-GGXPG6OE.js";
14
+ import "./chunk-MPG3IEGB.js";
15
15
  import "./chunk-ELKFRTZT.js";
16
16
  import "./chunk-2R6PXY6Z.js";
17
17
  import "./chunk-PVCIGUIT.js";
18
18
  import "./chunk-OLPSEQS5.js";
19
+ import "./chunk-QCC4VJUH.js";
19
20
  import "./chunk-JCGDR4UV.js";
20
- import "./chunk-2RS6TA3D.js";
21
+ import "./chunk-YRIS7ZS6.js";
21
22
  import "./chunk-GHFRQAYT.js";
23
+ import "./chunk-INT3IGMQ.js";
22
24
  import "./chunk-673EPYYH.js";
23
25
  import "./chunk-FQEGEVLY.js";
24
26
  import "./chunk-2DY4PUR4.js";
25
27
  import "./chunk-IQQBAWSM.js";
26
28
  import "./chunk-AD4OZCU2.js";
27
- import "./chunk-INT3IGMQ.js";
28
29
  import "./chunk-XW3MLHI2.js";
29
30
  import "./chunk-EUPETUWA.js";
30
31
  export {
@@ -34,4 +35,4 @@ export {
34
35
  runWithProgress,
35
36
  summarize
36
37
  };
37
- //# sourceMappingURL=init-2V34DVRQ.js.map
38
+ //# sourceMappingURL=init-WQCAOJ2R.js.map