project-athena 0.2.1 → 0.3.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 (147) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/README.md +15 -8
  3. package/dist/activity-P4UUFHWV.js +77 -0
  4. package/dist/agents-3HTSQGL2.js +69 -0
  5. package/dist/ai-ASL4FFQ7.js +96 -0
  6. package/dist/analyze-F3YOILNL.js +49 -0
  7. package/dist/chunk-2DY4PUR4.js +465 -0
  8. package/dist/chunk-2R6PXY6Z.js +33 -0
  9. package/dist/chunk-2RS6TA3D.js +908 -0
  10. package/dist/chunk-32PRS2MG.js +169 -0
  11. package/dist/chunk-3IS2X2Z7.js +89 -0
  12. package/dist/chunk-65TSRDQ3.js +124 -0
  13. package/dist/chunk-673EPYYH.js +105 -0
  14. package/dist/chunk-AD4OZCU2.js +34 -0
  15. package/dist/chunk-CXUTYCZX.js +238 -0
  16. package/dist/chunk-DOQMAZL5.js +436 -0
  17. package/dist/chunk-EF6GHOIN.js +343 -0
  18. package/dist/chunk-ELKFRTZT.js +221 -0
  19. package/dist/chunk-EUPETUWA.js +14 -0
  20. package/dist/chunk-FQEGEVLY.js +38 -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-JY6BFIJJ.js +95 -0
  27. package/dist/chunk-KBO7XRBW.js +26 -0
  28. package/dist/chunk-LEMPCNAY.js +209 -0
  29. package/dist/chunk-LMOFZNTQ.js +379 -0
  30. package/dist/chunk-OLPSEQS5.js +264 -0
  31. package/dist/chunk-PANVPNYF.js +2892 -0
  32. package/dist/chunk-PDFQ5BFG.js +378 -0
  33. package/dist/chunk-PR53DT7I.js +179 -0
  34. package/dist/chunk-PVCIGUIT.js +64 -0
  35. package/dist/chunk-RXNRMIZP.js +390 -0
  36. package/dist/chunk-S7T6VX56.js +61 -0
  37. package/dist/chunk-SHKXELUX.js +295 -0
  38. package/dist/chunk-SJOOXO34.js +904 -0
  39. package/dist/chunk-TGJUUB44.js +399 -0
  40. package/dist/chunk-VSYBC3VY.js +28 -0
  41. package/dist/chunk-XB66PZ6Z.js +182 -0
  42. package/dist/chunk-XFN7UZCS.js +35 -0
  43. package/dist/chunk-XW3MLHI2.js +32 -0
  44. package/dist/chunk-Z6QWMJLK.js +124 -0
  45. package/dist/chunk-ZB7LC6FP.js +221 -0
  46. package/dist/clean-S7PKCOLM.js +23 -0
  47. package/dist/cli.js +18 -10716
  48. package/dist/context-AH5MFHRG.js +147 -0
  49. package/dist/doctor-RSJMLE2P.js +62 -0
  50. package/dist/event-TNT6CQZR.js +101 -0
  51. package/dist/git-hook-YZNZGAAP.js +252 -0
  52. package/dist/init-2V34DVRQ.js +37 -0
  53. package/dist/mcp-T2GRTEX5.js +255 -0
  54. package/dist/open-2QSZKKUG.js +1259 -0
  55. package/dist/program-V2USHGXN.js +148 -0
  56. package/dist/review-R3R2J5BJ.js +115 -0
  57. package/dist/rules-4FXJUCXB.js +83 -0
  58. package/dist/security-PI4LXCOB.js +175 -0
  59. package/dist/staged-check-HHIBKKMR.js +500 -0
  60. package/dist/status-6M73WX5I.js +75 -0
  61. package/dist/sync-3ZNJDSSU.js +216 -0
  62. package/dist/watch-USN5CQIV.js +121 -0
  63. package/dist/web/assets/{Editor-DAXvniWB.js → Editor-BI56-HX5.js} +1 -1
  64. package/dist/web/assets/{abnfDiagram-O67JEVCF-Az7EW1BC.js → abnfDiagram-O67JEVCF-y_9px2ob.js} +1 -1
  65. package/dist/web/assets/architecture-7GRP2DOG-DyxkwYiW.js +1 -0
  66. package/dist/web/assets/{architectureDiagram-NJMV4G6O-BxeXqSTn.js → architectureDiagram-NJMV4G6O-lB6fcVzU.js} +1 -1
  67. package/dist/web/assets/{blockDiagram-BEXU5L5S-aeKZl9lJ.js → blockDiagram-BEXU5L5S-DcM5pEjM.js} +1 -1
  68. package/dist/web/assets/{c4Diagram-YGBWAQC7-CgmntYsG.js → c4Diagram-YGBWAQC7-CJgqxTY2.js} +1 -1
  69. package/dist/web/assets/channel-BvDD7AMO.js +1 -0
  70. package/dist/web/assets/{chunk-3FUC2YCW-BpmRD2yo.js → chunk-3FUC2YCW-B8l_VuWR.js} +1 -1
  71. package/dist/web/assets/{chunk-5DYCD2WN-CRIFDwod.js → chunk-5DYCD2WN-CZecgNhf.js} +1 -1
  72. package/dist/web/assets/{chunk-742MDFTN-hRW9VeNV.js → chunk-742MDFTN-BeZ7P5jB.js} +1 -1
  73. package/dist/web/assets/{chunk-7INBJB4K-C6VEpT0Y.js → chunk-7INBJB4K-IKy0pr5m.js} +1 -1
  74. package/dist/web/assets/{chunk-7M6MHVWA-Dnajov2w.js → chunk-7M6MHVWA-Dg_QqJEX.js} +1 -1
  75. package/dist/web/assets/{chunk-7PRAP22T-DSAc0_CZ.js → chunk-7PRAP22T-DqQNS8oq.js} +1 -1
  76. package/dist/web/assets/{chunk-GTNCS2PH-CefpYUjb.js → chunk-GTNCS2PH-x4sM51nJ.js} +1 -1
  77. package/dist/web/assets/{chunk-GWA4HPMP-MLNflMmF.js → chunk-GWA4HPMP-CE5GcwVN.js} +1 -1
  78. package/dist/web/assets/{chunk-MBY4JIJT-D3GmmEiU.js → chunk-MBY4JIJT-DA_D1hjF.js} +1 -1
  79. package/dist/web/assets/{chunk-NETBCI7D-DzTj6xVk.js → chunk-NETBCI7D-CeJ3XBZ2.js} +1 -1
  80. package/dist/web/assets/{chunk-O7XYJQB3-D1d0hCko.js → chunk-O7XYJQB3-BH2gESvO.js} +1 -1
  81. package/dist/web/assets/{chunk-UA2S7LBM-C9hIFeWR.js → chunk-UA2S7LBM-BWr0xCux.js} +1 -1
  82. package/dist/web/assets/{chunk-WEXAMYUT-BFGtcjsi.js → chunk-WEXAMYUT-B4QwUZPM.js} +1 -1
  83. package/dist/web/assets/{chunk-Z7XXMR3K-BRZ8_wtE.js → chunk-Z7XXMR3K-BxcA-y5B.js} +1 -1
  84. package/dist/web/assets/{chunk-ZIGJFQKS-CTKOioal.js → chunk-ZIGJFQKS-BZYvP63G.js} +1 -1
  85. package/dist/web/assets/{classDiagram-v2-NBCMYWYE-DJGKtWJv.js → classDiagram-v2-NBCMYWYE-BS3P_NXb.js} +1 -1
  86. package/dist/web/assets/{cynefin-OW5HDTMX-hNq1kGmA.js → cynefin-OW5HDTMX-BALD4Pve.js} +1 -1
  87. package/dist/web/assets/{cynefinDiagram-VND7K2PF-sODQM_ZZ.js → cynefinDiagram-VND7K2PF-BM2y4W6d.js} +1 -1
  88. package/dist/web/assets/{dagre-6A5THRUB-DEzTThIf.js → dagre-6A5THRUB-PTfOrIdF.js} +1 -1
  89. package/dist/web/assets/{diagram-22UHCM2B-s_eellsa.js → diagram-22UHCM2B-CpXEHhUl.js} +1 -1
  90. package/dist/web/assets/{diagram-3UASUU5V-B2onY_Xw.js → diagram-3UASUU5V-DPHfXzr6.js} +1 -1
  91. package/dist/web/assets/{diagram-ATOU4E4O-B8V6s13s.js → diagram-ATOU4E4O-DMBNXvAC.js} +1 -1
  92. package/dist/web/assets/{diagram-CDSNMT55-CJxiE6mf.js → diagram-CDSNMT55-CDLe1M7G.js} +1 -1
  93. package/dist/web/assets/{diagram-MLGK6HIB-m5OHPLAp.js → diagram-MLGK6HIB-D6L8oE7j.js} +1 -1
  94. package/dist/web/assets/{diagram-MPIPVDR6-Buvvrk_A.js → diagram-MPIPVDR6-CP-S7rrQ.js} +1 -1
  95. package/dist/web/assets/{ebnfDiagram-ZINNZB2B-CpL7Wt3R.js → ebnfDiagram-ZINNZB2B-CkUc63TK.js} +1 -1
  96. package/dist/web/assets/{elk-276RUBZZ-CwYhbsXa.js → elk-276RUBZZ-C1CAJLH_.js} +1 -1
  97. package/dist/web/assets/{erDiagram-OPXOYQCR-DNikci2r.js → erDiagram-OPXOYQCR-DXBnaTHm.js} +1 -1
  98. package/dist/web/assets/eventmodeling-NTZA5JFV-cLIzvgDp.js +1 -0
  99. package/dist/web/assets/flowDiagram-KWPJA3E3-D7Zq63VQ.js +1 -0
  100. package/dist/web/assets/{ganttDiagram-FUAMR5RP-d-ynDlvJ.js → ganttDiagram-FUAMR5RP-BVm8SiGg.js} +1 -1
  101. package/dist/web/assets/{gitGraph-4MIJSDKK-DwIeBI91.js → gitGraph-4MIJSDKK-Dm7xBrW0.js} +1 -1
  102. package/dist/web/assets/{gitGraphDiagram-X574FWY7-04RZccu6.js → gitGraphDiagram-X574FWY7-D_PIKKhx.js} +1 -1
  103. package/dist/web/assets/{index-C3-8uYXr.js → index-CeOIBpu2.js} +3 -3
  104. package/dist/web/assets/{info-A6RAGUB7-xf4Nzgv-.js → info-A6RAGUB7-CLGrx8pn.js} +1 -1
  105. package/dist/web/assets/{infoDiagram-VRGFBTTK-BYjw0eiK.js → infoDiagram-VRGFBTTK-BlBjaKm7.js} +1 -1
  106. package/dist/web/assets/{ishikawaDiagram-OU5B5YK6-Bx9s4nPM.js → ishikawaDiagram-OU5B5YK6-Kxe7GGS3.js} +1 -1
  107. package/dist/web/assets/{journeyDiagram-ZHPQQLJL-DrdHs7B-.js → journeyDiagram-ZHPQQLJL-wCMoHK4M.js} +1 -1
  108. package/dist/web/assets/{kanban-definition-PNTS6WVX-CVd8v2Te.js → kanban-definition-PNTS6WVX-BxdCz9Ko.js} +1 -1
  109. package/dist/web/assets/{line-V_WrJ-6y.js → line-Zf11FnWF.js} +1 -1
  110. package/dist/web/assets/{mermaid-parser.core-B-ilyEpO.js → mermaid-parser.core-BvFFklev.js} +3 -3
  111. package/dist/web/assets/{mermaid.core-Bnyaa0nF.js → mermaid.core-Cd_Ssti9.js} +4 -4
  112. package/dist/web/assets/{mindmap-definition-NLK3R4M7-B3AbvHPR.js → mindmap-definition-NLK3R4M7-BGPQl-GY.js} +1 -1
  113. package/dist/web/assets/{packet-AYTQ26CC-CBAIUXIc.js → packet-AYTQ26CC-6lI3cEX_.js} +1 -1
  114. package/dist/web/assets/{pegDiagram-GJSIUBJH-DIdeELUM.js → pegDiagram-GJSIUBJH-BPIjlSAj.js} +1 -1
  115. package/dist/web/assets/{pie-WAS4IAKB-a1r3tzPR.js → pie-WAS4IAKB-D6Dzj3Ja.js} +1 -1
  116. package/dist/web/assets/{pieDiagram-5QR66LMP-pQBEio0x.js → pieDiagram-5QR66LMP-DtA-vZmv.js} +1 -1
  117. package/dist/web/assets/{quadrantDiagram-O4NWA36T-CkJK5Y03.js → quadrantDiagram-O4NWA36T-EettyqQn.js} +1 -1
  118. package/dist/web/assets/{radar-RG4KPBEZ-BZfLYjx5.js → radar-RG4KPBEZ-xmRc3Dl8.js} +1 -1
  119. package/dist/web/assets/{railroad-74A4TZTK-CuIW1ZAU.js → railroad-74A4TZTK-BLB7dhOn.js} +1 -1
  120. package/dist/web/assets/railroad-abnf-HS5TGJTU-DBFym6g8.js +1 -0
  121. package/dist/web/assets/railroad-ebnf-LZEXJU2U-CkG28ig8.js +1 -0
  122. package/dist/web/assets/railroad-peg-WCYAUIDC-Df_Ifaad.js +1 -0
  123. package/dist/web/assets/{railroadDiagram-XR7U4H2S-_BpGE8aJ.js → railroadDiagram-XR7U4H2S-PBw4We6b.js} +1 -1
  124. package/dist/web/assets/{requirementDiagram-PLB6GJNP-CnzF90GS.js → requirementDiagram-PLB6GJNP-DjQpaUFA.js} +1 -1
  125. package/dist/web/assets/{sankeyDiagram-IPEJSGJF-DYeisDj_.js → sankeyDiagram-IPEJSGJF-CBW-_AoF.js} +1 -1
  126. package/dist/web/assets/{sequenceDiagram-PO4LG4MO-ll9cBvca.js → sequenceDiagram-PO4LG4MO-DEoPYqY9.js} +1 -1
  127. package/dist/web/assets/{stateDiagram-v2-GCMORJYK-CdKcOIKQ.js → stateDiagram-v2-GCMORJYK-UZq5rPud.js} +1 -1
  128. package/dist/web/assets/{swimlanes-2SLR337P-y6piTWEW.js → swimlanes-2SLR337P-CACfuXJR.js} +1 -1
  129. package/dist/web/assets/swimlanesDiagram-TC7HE7FX-CDSrqdgx.js +8 -0
  130. package/dist/web/assets/{timeline-definition-EJHVYXUP-DuC_4xK0.js → timeline-definition-EJHVYXUP-CYJl7mP-.js} +1 -1
  131. package/dist/web/assets/{treeView-Q6P3EWNA-gCQFmND0.js → treeView-Q6P3EWNA-DtZ5nkPQ.js} +1 -1
  132. package/dist/web/assets/{treemap-WGGIJYW6-BQ2010OY.js → treemap-WGGIJYW6-m49GDM-M.js} +1 -1
  133. package/dist/web/assets/{usecaseDiagram-POWQR4AR-CCTqzHz6.js → usecaseDiagram-POWQR4AR-C2Vg20UK.js} +1 -1
  134. package/dist/web/assets/{vennDiagram-UO4OBE2U-0_O7guNq.js → vennDiagram-UO4OBE2U-C07v5OGI.js} +1 -1
  135. package/dist/web/assets/{wardley-WFR3VGLG-SsX7uMDs.js → wardley-WFR3VGLG-C9Z7EZtz.js} +1 -1
  136. package/dist/web/assets/{wardleyDiagram-VNRHLVJA-DlqH6Hox.js → wardleyDiagram-VNRHLVJA-DdA8CcSC.js} +1 -1
  137. package/dist/web/assets/{xychartDiagram-PMCCYNJV-nr4UYDtd.js → xychartDiagram-PMCCYNJV-C9EZw07b.js} +1 -1
  138. package/dist/web/index.html +1 -1
  139. package/package.json +4 -2
  140. package/dist/web/assets/architecture-7GRP2DOG-blXBarB2.js +0 -1
  141. package/dist/web/assets/channel-f4QzewnN.js +0 -1
  142. package/dist/web/assets/eventmodeling-NTZA5JFV-CA_ZFPZ2.js +0 -1
  143. package/dist/web/assets/flowDiagram-KWPJA3E3-DObsBuWT.js +0 -1
  144. package/dist/web/assets/railroad-abnf-HS5TGJTU-6B4Ffbxn.js +0 -1
  145. package/dist/web/assets/railroad-ebnf-LZEXJU2U-BGL9lIQc.js +0 -1
  146. package/dist/web/assets/railroad-peg-WCYAUIDC-DcqxTem7.js +0 -1
  147. package/dist/web/assets/swimlanesDiagram-TC7HE7FX-DFS8a3jO.js +0 -8
@@ -0,0 +1,238 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ listRules,
4
+ parseRules
5
+ } from "./chunk-3IS2X2Z7.js";
6
+ import {
7
+ GRAPH_FILE,
8
+ buildGraph,
9
+ expandFromFiles,
10
+ projectSession,
11
+ saveGraph
12
+ } from "./chunk-PDFQ5BFG.js";
13
+ import {
14
+ analyzeProject
15
+ } from "./chunk-PANVPNYF.js";
16
+ import {
17
+ parseBlocks
18
+ } from "./chunk-673EPYYH.js";
19
+ import {
20
+ KNOWLEDGE_DOCS,
21
+ RELEVANCE_MAP
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/core/context/context-engine.ts
34
+ var AREA_KEYWORDS = [
35
+ { id: "database", words: /\b(database|db|schema|migration|migrate|sql|query|queries|table|column|index|prisma|orm|entity|model|postgres|mysql|mongo|supabase)\b/i },
36
+ { id: "api", words: /\b(api|endpoint|route|router|controller|handler|rest|graphql|grpc|request|response|webhook|http|status code)\b/i },
37
+ { id: "auth", words: /\b(auth|authentication|authorization|login|logout|session|token|jwt|oauth|sso|permission|role|rbac|acl|password|mfa|2fa)\b/i },
38
+ { id: "security", words: /\b(security|secure|vulnerab|xss|csrf|ssrf|injection|sanitiz|escape|secret|credential|encrypt|audit|cors|rate limit)\b/i },
39
+ { id: "testing", words: /\b(test|tests|testing|spec|coverage|e2e|unit|integration|mock|fixture|vitest|jest|pytest|playwright|cypress)\b/i },
40
+ { id: "performance", words: /\b(performance|perf|slow|fast|latency|cache|caching|queue|worker|background job|optimi[sz]|n\+1|bottleneck|memory|profil)\b/i },
41
+ { id: "deployment", words: /\b(deploy|deployment|docker|container|kubernetes|k8s|ci|cd|pipeline|release|env var|environment variable|infra|terraform|vercel|hosting)\b/i },
42
+ { id: "debugging", words: /\b(bug|debug|error|exception|crash|stack trace|failing|broken|regression|log|logging|troubleshoot)\b/i },
43
+ { id: "architecture", words: /\b(architecture|structure|module|package|refactor|boundary|layer|service layer|dependency|monorepo|design)\b/i },
44
+ { id: "code-review", words: /\b(review|pull request|pr|merge|checklist|convention|style guide)\b/i },
45
+ { id: "project", words: /\b(setup|install|build|command|script|getting started|onboard|dependency|dependencies|tooling)\b/i }
46
+ ];
47
+ var UI_WORDS = /\b(ui|css|style|styling|layout|component|button|form|page|responsive|dark mode|design|frontend|tailwind)\b/i;
48
+ var SMALL_WORDS = /\b(typo|rename|comment|whitespace|format|wording|copy|spelling)\b/i;
49
+ var STOP = /* @__PURE__ */ new Set(["the", "and", "for", "with", "that", "this", "from", "into", "add", "new", "use", "using", "make", "need", "should", "when", "what", "where", "which", "must", "have", "has", "are", "was", "can", "will", "our", "their", "its", "not", "all", "any", "get", "set", "run"]);
50
+ function tokenize(task) {
51
+ return [...new Set(task.toLowerCase().match(/[a-z0-9_./-]{3,}/g) ?? [])].filter((w) => !STOP.has(w));
52
+ }
53
+ function mentionedFiles(task, knownFiles) {
54
+ const candidates = task.match(/[\w./-]+\.[a-z]{1,5}\b/gi) ?? [];
55
+ const out = [];
56
+ for (const c of candidates) {
57
+ const norm = c.replace(/^\.\//, "");
58
+ const exact = knownFiles.find((f) => f === norm || f.endsWith(`/${norm}`));
59
+ if (exact) out.push(exact);
60
+ }
61
+ return [...new Set(out)];
62
+ }
63
+ function selectContext(opts) {
64
+ const task = opts.task.trim();
65
+ const words = tokenize(task);
66
+ const maxChars = opts.maxChars ?? 12e3;
67
+ const areas = /* @__PURE__ */ new Map();
68
+ const bump = (id, score, why) => {
69
+ const cur = areas.get(id) ?? { id, score: 0, why: [] };
70
+ cur.score += score;
71
+ if (!cur.why.includes(why)) cur.why.push(why);
72
+ areas.set(id, cur);
73
+ };
74
+ for (const { id, words: re } of AREA_KEYWORDS) {
75
+ const hit = task.match(re);
76
+ if (hit) bump(id, 10, `task mentions "${hit[0]}"`);
77
+ }
78
+ if (UI_WORDS.test(task)) {
79
+ for (const id of ["project", "architecture"]) bump(id, 6, "frontend/UI task");
80
+ }
81
+ if (!areas.size && !SMALL_WORDS.test(task)) {
82
+ for (const id of RELEVANCE_MAP.find((r) => r.task.startsWith("New feature")).docs) bump(id, 3, "no specific area detected \u2014 using the broad feature set");
83
+ }
84
+ if (areas.has("database") || areas.has("api") || areas.has("auth")) {
85
+ bump("security", 4, "security implications of data/API changes");
86
+ bump("testing", 3, "tests for changed behavior");
87
+ }
88
+ const knownFiles = opts.graph?.nodes.filter((n) => n.path).map((n) => n.path) ?? [];
89
+ const files = mentionedFiles(task, knownFiles);
90
+ const graphNodes = opts.graph ? expandFromFiles(opts.graph, files, 1, 30) : [];
91
+ for (const n of graphNodes) {
92
+ if (n.kind === "route") bump("api", 5, `task touches route ${n.name}`);
93
+ if (n.kind === "entity") bump("database", 5, `task touches entity ${n.name}`);
94
+ }
95
+ if (opts.graph) {
96
+ for (const n of opts.graph.nodes) {
97
+ if (graphNodes.some((g) => g.id === n.id)) continue;
98
+ const hay = `${n.name} ${n.path ?? ""}`.toLowerCase();
99
+ if (words.some((w) => w.length > 3 && hay.includes(w))) {
100
+ graphNodes.push(n);
101
+ if (graphNodes.length >= 40) break;
102
+ }
103
+ }
104
+ }
105
+ const ranked = [...areas.values()].sort((a, b) => b.score - a.score);
106
+ const sections = [];
107
+ for (const area of ranked) {
108
+ const doc = opts.documents.find((d) => d.id === area.id);
109
+ if (!doc) continue;
110
+ for (const s of doc.sections) {
111
+ if (s.id === "about") continue;
112
+ const text = s.content.toLowerCase();
113
+ const matches = words.filter((w) => text.includes(w)).length;
114
+ const score = area.score + matches * 2;
115
+ sections.push({ doc: doc.id, file: doc.file, section: s.id, content: s.content, score });
116
+ }
117
+ }
118
+ sections.sort((a, b) => b.score - a.score);
119
+ let used = 0;
120
+ const kept = [];
121
+ let truncated = false;
122
+ for (const s of sections) {
123
+ if (used + s.content.length > maxChars) {
124
+ truncated = true;
125
+ continue;
126
+ }
127
+ kept.push(s);
128
+ used += s.content.length;
129
+ }
130
+ const rules = opts.rulesMarkdown ? listRules(parseRules(opts.rulesMarkdown)).filter((r) => r.enabled) : [];
131
+ return {
132
+ task,
133
+ areas: ranked,
134
+ sections: kept.sort((a, b) => a.doc.localeCompare(b.doc) || b.score - a.score),
135
+ rules,
136
+ graphNodes: graphNodes.slice(0, 40),
137
+ mentionedFiles: files,
138
+ truncated,
139
+ approxChars: used
140
+ };
141
+ }
142
+ function documentSections(markdown) {
143
+ const blocks = parseBlocks(markdown);
144
+ const sections = blocks.map((b) => ({ id: b.id, content: b.content }));
145
+ const last = blocks.at(-1);
146
+ const tail = last ? markdown.slice(last.end) : markdown;
147
+ const notes = tail.replace(/^#+ Developer Notes\s*/im, "").replace(/<!--[\s\S]*?-->/g, "").trim();
148
+ if (notes) sections.push({ id: "developer-notes", content: `## Developer Notes
149
+
150
+ ${notes}` });
151
+ return sections;
152
+ }
153
+ function formatContext(ctx) {
154
+ const out = [`# Athena context for: ${ctx.task}`, ""];
155
+ out.push("_Selected deterministically from this project's knowledge. Statements keep their FACT/DETECTED/INFERRED/UNKNOWN labels; verify anything not marked FACT or DETECTED._", "");
156
+ if (ctx.rules.length) {
157
+ out.push("## Project rules (always apply)", "");
158
+ for (const r of ctx.rules) out.push(`- [${r.section}] ${r.text}`);
159
+ out.push("");
160
+ }
161
+ if (ctx.areas.length) {
162
+ out.push(`## Why these documents`, "");
163
+ for (const a of ctx.areas) out.push(`- **${KNOWLEDGE_DOCS.find((d) => d.id === a.id).file}** \u2014 ${a.why.join("; ")}`);
164
+ out.push("");
165
+ }
166
+ if (ctx.mentionedFiles.length || ctx.graphNodes.length) {
167
+ out.push("## Related code (from the project graph)", "");
168
+ for (const f of ctx.mentionedFiles) out.push(`- file: \`${f}\` (named in the task)`);
169
+ for (const n of ctx.graphNodes.filter((n2) => !ctx.mentionedFiles.includes(n2.path ?? ""))) {
170
+ out.push(`- ${n.kind}: ${n.name}${n.path ? ` (\`${n.path}\`)` : ""}`);
171
+ }
172
+ out.push("");
173
+ }
174
+ let currentDoc = "";
175
+ for (const s of ctx.sections) {
176
+ if (s.doc !== currentDoc) {
177
+ currentDoc = s.doc;
178
+ out.push(`## From ${s.file}`, "");
179
+ }
180
+ out.push(s.content.trim(), "");
181
+ }
182
+ if (ctx.truncated) out.push("_Some lower-ranked sections were omitted to stay within the context budget._");
183
+ return out.join("\n");
184
+ }
185
+
186
+ // src/services/context.ts
187
+ import path from "path";
188
+ async function refreshGraph(root, opts = {}) {
189
+ const session = projectSession(root);
190
+ const st = await session.state();
191
+ const analysis = await analyzeProject(root, { signal: opts.signal });
192
+ const files = analysis.files.map((f) => f.path);
193
+ const graph = await buildGraph(analysis.model, {
194
+ files,
195
+ signal: opts.signal,
196
+ read: async (rel) => readTextIfExists(path.join(root, rel)).catch(() => null)
197
+ });
198
+ await saveGraph(root, graph);
199
+ await session.remember(GRAPH_FILE, graph);
200
+ return graph;
201
+ }
202
+ async function getGraph(root, opts = {}) {
203
+ const existing = await projectSession(root).graph();
204
+ if (existing) return existing;
205
+ return opts.build ? refreshGraph(root, { signal: opts.signal }) : null;
206
+ }
207
+ async function getRelevantContext(root, task, opts = {}) {
208
+ if (!task.trim()) throw new AthenaError("Describe the task to get relevant context.", 'For example: athena context "add refunds to the payments API"');
209
+ const dir = athenaDir(root);
210
+ const documents = [];
211
+ for (const d of KNOWLEDGE_DOCS) {
212
+ if (d.id === "rules") continue;
213
+ const text = await readTextIfExists(path.join(dir, d.file));
214
+ if (text) documents.push({ id: d.id, file: d.file, sections: documentSections(text) });
215
+ }
216
+ if (!documents.length) throw new AthenaError("No knowledge documents found.", "Run `athena init` first.", 3);
217
+ return selectContext({
218
+ task,
219
+ documents,
220
+ rulesMarkdown: await readTextIfExists(path.join(dir, "rules.md")),
221
+ graph: await getGraph(root, { build: opts.buildGraph, signal: opts.signal }),
222
+ maxChars: opts.maxChars
223
+ });
224
+ }
225
+ async function graphSummary(root) {
226
+ const session = projectSession(root);
227
+ const [graph, hasModel] = await Promise.all([session.graph(), session.hasModel()]);
228
+ return { built: Boolean(graph), builtAt: graph?.builtAt ?? null, stats: graph?.stats ?? null, model: { hasModel } };
229
+ }
230
+
231
+ export {
232
+ formatContext,
233
+ refreshGraph,
234
+ getGraph,
235
+ getRelevantContext,
236
+ graphSummary
237
+ };
238
+ //# sourceMappingURL=chunk-CXUTYCZX.js.map
@@ -0,0 +1,436 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ HR,
4
+ PALETTE,
5
+ box,
6
+ columns,
7
+ footer,
8
+ gradient,
9
+ mix,
10
+ padEnd,
11
+ paint,
12
+ printHeader,
13
+ termWidth,
14
+ truncate,
15
+ width
16
+ } from "./chunk-SHKXELUX.js";
17
+ import {
18
+ bullet,
19
+ c,
20
+ dim,
21
+ isJson,
22
+ isQuiet,
23
+ isTTY,
24
+ json,
25
+ line,
26
+ ok,
27
+ sym,
28
+ unicode,
29
+ warn
30
+ } from "./chunk-Z6QWMJLK.js";
31
+ import {
32
+ resolveCwd
33
+ } from "./chunk-XFN7UZCS.js";
34
+ import {
35
+ runPipeline
36
+ } from "./chunk-SJOOXO34.js";
37
+ import {
38
+ ADAPTERS,
39
+ resolveAdapters
40
+ } from "./chunk-2RS6TA3D.js";
41
+ import {
42
+ KNOWLEDGE_DOCS
43
+ } from "./chunk-FQEGEVLY.js";
44
+ import {
45
+ readState
46
+ } from "./chunk-2DY4PUR4.js";
47
+ import {
48
+ AthenaError
49
+ } from "./chunk-AD4OZCU2.js";
50
+
51
+ // src/cli/commands/init.ts
52
+ import path from "path";
53
+
54
+ // src/cli/ui/dashboard.ts
55
+ import pc from "picocolors";
56
+ var C = PALETTE;
57
+ var accent = (s) => paint(PALETTE.amber, s, true);
58
+ var warnText = (s) => paint(PALETTE.amber, s);
59
+ function sectionTitle(title) {
60
+ const total = termWidth();
61
+ const head = ` ${paint(PALETTE.violet, unicode ? "\u2726" : "*", true)} ${gradient(title, [PALETTE.cyan, PALETTE.violet], true)} `;
62
+ const rest = Math.max(0, total - width(head) - 2);
63
+ return [head + paint(PALETTE.blue, HR.repeat(rest))];
64
+ }
65
+ function rows(items) {
66
+ const labelW = Math.max(...items.map(([l]) => l.length)) + 2;
67
+ return (w) => items.map(([label, value]) => pc.dim(padEnd(label, labelW)) + padEnd(value ? paint(PALETTE.cyan, value) : pc.dim("Not detected"), w - labelW));
68
+ }
69
+ function fileTree(root, files) {
70
+ const nameW = Math.max(...files.map((f) => f.name.length)) + 2;
71
+ return (w) => [
72
+ pc.bold(root),
73
+ ...files.map((f, i) => {
74
+ const branch = unicode ? i === files.length - 1 ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 " : i === files.length - 1 ? "`-- " : "|-- ";
75
+ const name = f.highlight ? paint(PALETTE.amber, padEnd(f.name, nameW)) : padEnd(f.name, nameW);
76
+ return padEnd(pc.dim(branch) + name + pc.dim(f.note ? `# ${f.note}` : ""), w);
77
+ })
78
+ ];
79
+ }
80
+ function wrapCode(text, w) {
81
+ const out = [];
82
+ let cur = "";
83
+ for (const word of text.split(" ")) {
84
+ if (cur && cur.length + 1 + word.length > w) {
85
+ out.push(cur);
86
+ cur = word;
87
+ } else cur = cur ? `${cur} ${word}` : word;
88
+ }
89
+ if (cur) out.push(cur);
90
+ let inCode = false;
91
+ return out.map(
92
+ (l) => l.split("`").map((part, i) => {
93
+ if (i > 0) inCode = !inCode;
94
+ return inCode ? paint(PALETTE.cyan, part) : part;
95
+ }).join("")
96
+ );
97
+ }
98
+ function wrapLines(text, indent = 2) {
99
+ const w = Math.max(20, termWidth() - 1);
100
+ const out = [];
101
+ let cur = "";
102
+ for (const word of text.split(" ")) {
103
+ if (cur && cur.length + 1 + word.length > w) {
104
+ out.push(cur);
105
+ cur = " ".repeat(indent) + word;
106
+ } else cur = cur ? `${cur} ${word}` : word;
107
+ }
108
+ if (cur) out.push(cur);
109
+ return out;
110
+ }
111
+ function numbered(steps) {
112
+ return (w) => steps.flatMap((s, i) => {
113
+ const badge = paint(PALETTE.green, ` ${i + 1} `, true);
114
+ const [first = "", ...rest] = wrapCode(s, Math.max(10, w - 5));
115
+ return [`${badge} ${first}`, ...rest.map((r) => ` ${r}`)];
116
+ });
117
+ }
118
+ function quote(text) {
119
+ return (w) => {
120
+ const lines = wrapCode(`\u201C${text}\u201D`, Math.max(10, w - 6)).map((l) => pc.italic(l));
121
+ return box([...lines, paint(PALETTE.cyan, `\u2014 Sabarivasan`)], Math.min(w, Math.max(...lines.map(width)) + 6), { color: PALETTE.slate, padX: 2 });
122
+ };
123
+ }
124
+ function renderBody(body, w) {
125
+ const parts = Array.isArray(body) && body.length && typeof body[0] !== "string" ? body : [body];
126
+ return parts.flatMap((p) => typeof p === "function" ? p(w) : p);
127
+ }
128
+ function panels(list) {
129
+ const total = termWidth();
130
+ const title = (p) => `${paint(p.color, unicode ? p.icon : "*", true)} ${paint(p.color, p.title, true)}`;
131
+ if (total >= 120) {
132
+ const gap = 2;
133
+ const avail = total - gap * (list.length - 1) - 1;
134
+ const weights = [0.36, 0.32, 0.32];
135
+ const widths = list.map((_, i) => Math.floor(avail * (weights[i] ?? 1 / list.length)));
136
+ const bodies = list.map((p, i) => renderBody(p.body, widths[i] - 4));
137
+ const h = Math.max(...bodies.map((b) => b.length));
138
+ const boxes = list.map((p, i) => box([title(p), "", ...bodies[i], ...Array(h - bodies[i].length).fill("")], widths[i], { color: p.color, padX: 1 }));
139
+ return columns(boxes, widths, gap);
140
+ }
141
+ const w = Math.min(total - 1, 100);
142
+ return list.flatMap((p, i) => [...i ? [""] : [], ...box([title(p), "", ...renderBody(p.body, w - 4)], w, { color: p.color })]);
143
+ }
144
+
145
+ // src/cli/ui/stages.ts
146
+ import pc2 from "picocolors";
147
+ var STAGES = [
148
+ { id: "scan", label: "Scanning project structure" },
149
+ { id: "detect", label: "Detecting stack, database, API & auth" },
150
+ { id: "git", label: "Reading Git metadata" },
151
+ { id: "finalize", label: "Redacting secrets & validating" },
152
+ { id: "write", label: "Generating documentation" },
153
+ { id: "agents", label: "Configuring AI agents" }
154
+ ];
155
+ var STAGE_ALIASES = { analyze: "scan" };
156
+ var FRAMES = unicode ? ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"] : ["-", "\\", "|", "/"];
157
+ var BAR_STOPS = [PALETTE.green, PALETTE.cyan, PALETTE.blue, PALETTE.violet];
158
+ var StageBoard = class {
159
+ state = new Map(STAGES.map((s) => [s.id, "pending"]));
160
+ started = /* @__PURE__ */ new Map();
161
+ elapsed = /* @__PURE__ */ new Map();
162
+ results = /* @__PURE__ */ new Map();
163
+ current = null;
164
+ frame = 0;
165
+ drawn = 0;
166
+ timer = null;
167
+ live = isTTY && !isJson() && !isQuiet();
168
+ enabled = !isJson() && !isQuiet();
169
+ restoreCursor = () => process.stdout.write("\x1B[?25h");
170
+ start() {
171
+ if (!this.live) return;
172
+ process.stdout.write("\x1B[?25l");
173
+ process.once("exit", this.restoreCursor);
174
+ this.render();
175
+ this.timer = setInterval(() => {
176
+ this.frame++;
177
+ this.render();
178
+ }, 80);
179
+ this.timer.unref();
180
+ }
181
+ /** Accepts raw pipeline stage names; unknown names are ignored. */
182
+ enter(raw) {
183
+ const id = STAGE_ALIASES[raw] ?? raw;
184
+ if (!this.state.has(id) || this.current === id) return;
185
+ this.closeCurrent("done");
186
+ this.current = id;
187
+ this.state.set(id, "running");
188
+ this.started.set(id, performance.now());
189
+ }
190
+ finish(results) {
191
+ this.closeCurrent("done");
192
+ for (const [id, st] of this.state) if (st === "pending") this.state.set(id, "skipped");
193
+ for (const [id, r] of Object.entries(results)) this.results.set(id, r);
194
+ this.stop();
195
+ }
196
+ fail() {
197
+ this.closeCurrent("failed");
198
+ this.stop();
199
+ }
200
+ closeCurrent(to) {
201
+ if (!this.current) return;
202
+ this.state.set(this.current, to);
203
+ this.elapsed.set(this.current, performance.now() - this.started.get(this.current));
204
+ this.current = null;
205
+ }
206
+ stop() {
207
+ if (this.timer) clearInterval(this.timer);
208
+ this.timer = null;
209
+ if (!this.enabled) return;
210
+ if (this.live) {
211
+ this.render();
212
+ this.restoreCursor();
213
+ process.removeListener("exit", this.restoreCursor);
214
+ } else for (const l of this.lines()) line(l);
215
+ }
216
+ render() {
217
+ const rows2 = this.lines();
218
+ let s = this.drawn ? `\x1B[${this.drawn}F` : "";
219
+ for (const r of rows2) s += `\x1B[2K${r}
220
+ `;
221
+ process.stdout.write(s);
222
+ this.drawn = rows2.length;
223
+ }
224
+ lines() {
225
+ const total = termWidth();
226
+ const showBar = total >= 100;
227
+ const barW = total >= 130 ? 26 : 18;
228
+ return STAGES.map((s, i) => {
229
+ const st = this.state.get(s.id);
230
+ const icon = st === "done" ? paint(PALETTE.green, sym.ok, true) : st === "running" ? paint(PALETTE.cyan, FRAMES[this.frame % FRAMES.length]) : st === "failed" ? pc2.red(sym.err) : pc2.dim(st === "skipped" ? "\u2013" : sym.ring);
231
+ const label = st === "pending" || st === "skipped" ? pc2.dim(s.label) : s.label;
232
+ const ms = this.elapsed.get(s.id) ?? (st === "running" ? performance.now() - this.started.get(s.id) : void 0);
233
+ const time = st === "skipped" ? pc2.dim("skipped") : ms === void 0 ? "" : pc2.dim(ms < 1e3 ? `${Math.max(1, Math.round(ms))}ms` : `${(ms / 1e3).toFixed(1)}s`);
234
+ const r = this.results.get(s.id);
235
+ const result = r ? r.tone === "warn" ? paint(PALETTE.amber, `${sym.warn} ${r.text}`) : r.tone === "dim" ? pc2.dim(r.text) : `${paint(PALETTE.green, sym.ok)} ${r.text}` : "";
236
+ const bar = showBar ? `${this.bar(st, barW, i)} ` : "";
237
+ return truncate(` ${icon} ${padEnd(label, 40)}${bar}${padEnd(time, 8)}${result}`, total - 1);
238
+ });
239
+ }
240
+ bar(st, w, row) {
241
+ const fill = unicode ? "\u2501" : "#";
242
+ const track = unicode ? "\u2500" : "-";
243
+ if (st === "done") return paint(mix(BAR_STOPS, row / (STAGES.length - 1)), fill.repeat(w));
244
+ if (st === "failed") return pc2.red(fill.repeat(w));
245
+ if (st !== "running") return pc2.dim(track.repeat(w));
246
+ const seg = 6;
247
+ const span = w - seg;
248
+ const t = this.frame % (span * 2);
249
+ const pos = t <= span ? t : span * 2 - t;
250
+ return pc2.dim(track.repeat(pos)) + paint(PALETTE.cyan, fill.repeat(seg)) + pc2.dim(track.repeat(w - pos - seg));
251
+ }
252
+ };
253
+
254
+ // src/cli/commands/init.ts
255
+ function parseAgentsOption(value, disabled) {
256
+ if (disabled) return [];
257
+ if (value === void 0) return void 0;
258
+ if (value.trim().toLowerCase() === "all") return [...ADAPTERS];
259
+ if (value.trim().toLowerCase() === "none") return [];
260
+ try {
261
+ return resolveAdapters(value.split(","));
262
+ } catch (err) {
263
+ throw new AthenaError(err.message);
264
+ }
265
+ }
266
+ async function initCommand(opts) {
267
+ const root = await resolveCwd(opts);
268
+ const existing = await readState(path.join(root, ".athena"));
269
+ if (existing.kind === "ok") {
270
+ throw new AthenaError("Athena is already initialized in this project.", "Run `athena analyze` to refresh knowledge, or `athena clean` to start over.");
271
+ }
272
+ const agents = parseAgentsOption(opts.agents, opts.noAgents);
273
+ printHeader();
274
+ const result = await runWithProgress(root, { mode: "init", dryRun: opts.dryRun, agents, signal: opts.signal });
275
+ if (isJson()) {
276
+ json(summarize(result, root, Boolean(opts.dryRun)));
277
+ return;
278
+ }
279
+ printSummary(result, Boolean(opts.dryRun), "init");
280
+ }
281
+ async function runWithProgress(root, o) {
282
+ const board = new StageBoard();
283
+ board.start();
284
+ try {
285
+ const result = await runPipeline({
286
+ root,
287
+ mode: o.mode,
288
+ dryRun: o.dryRun,
289
+ force: o.force,
290
+ agents: o.agents,
291
+ signal: o.signal,
292
+ onStage: (stage) => board.enter(stage)
293
+ });
294
+ board.finish(stageResults(result, o.mode, Boolean(o.dryRun)));
295
+ return result;
296
+ } catch (err) {
297
+ board.fail();
298
+ throw err;
299
+ }
300
+ }
301
+ var plural = (n, word) => `${n} ${word}${n === 1 ? "" : "s"}`;
302
+ function stageResults(result, mode, dryRun) {
303
+ const m = result.analysis.model;
304
+ const skipped = m.stats.skippedBinary + m.stats.skippedLarge + m.stats.skippedUnreadable;
305
+ const found = [
306
+ m.frameworks.length && plural(new Set(m.frameworks.map((f) => f.name)).size, "framework"),
307
+ m.dbEntities.length && plural(m.dbEntities.length, "entity").replace("entitys", "entities"),
308
+ m.routes.length && plural(m.routes.length, "route"),
309
+ m.auth.length && "auth"
310
+ ].filter(Boolean);
311
+ const changed = result.docs.filter((d) => d.status !== "unchanged").length;
312
+ const agents = result.agentChanges.map((a) => a.adapter.displayName);
313
+ return {
314
+ scan: { text: `Found ${plural(m.stats.filesScanned, "file")}${skipped ? ` \xB7 ${skipped} skipped` : ""}` },
315
+ detect: found.length ? { text: found.join(" \xB7 ") } : { text: "No frameworks detected", tone: "dim" },
316
+ git: m.git.isRepo ? { text: `On ${m.git.branch ?? "detached HEAD"}${m.git.head ? ` @ ${m.git.head.slice(0, 7)}` : ""}` } : { text: m.git.available ? "Not a Git repository" : "Git not installed", tone: "dim" },
317
+ finalize: m.security.secrets.length ? { text: `${plural(m.security.secrets.length, "potential secret")} (values redacted)`, tone: "warn" } : { text: "No likely secrets found" },
318
+ write: dryRun ? { text: "Dry run \u2014 nothing written", tone: "dim" } : { text: mode === "init" ? `${plural(result.docs.length, "document")} generated` : changed ? `${changed} updated \xB7 ${result.docs.length - changed} unchanged` : "Already up to date" },
319
+ agents: agents.length ? { text: agents.join(", ") } : { text: "None configured", tone: "dim" }
320
+ };
321
+ }
322
+ var DOC_NOTES = {
323
+ "project.md": "Project overview",
324
+ "architecture.md": "System architecture",
325
+ "database.md": "Database schema",
326
+ "api.md": "API reference",
327
+ "auth.md": "Authentication flow",
328
+ "security.md": "Security analysis",
329
+ "testing.md": "Testing strategy",
330
+ "debugging.md": "Debugging guide",
331
+ "performance.md": "Performance notes",
332
+ "code-review.md": "Review checklist",
333
+ "deployment.md": "Deployment guide",
334
+ "rules.md": "Your project rules"
335
+ };
336
+ function printSummary(result, dryRun, mode) {
337
+ const m = result.analysis.model;
338
+ if (isQuiet()) {
339
+ for (const w of m.warnings) warn(w);
340
+ for (const n of result.notes) warn(n);
341
+ for (const d of result.docs.filter((x) => x.preservedModified.length)) warn(`${d.file}: kept your edits in ${d.preservedModified.join(", ")}`);
342
+ const changed = result.docs.filter((d) => d.status !== "unchanged").map((d) => d.file);
343
+ line(dryRun ? "Dry run: nothing written." : changed.length ? `Updated: ${changed.join(", ")}` : "Knowledge up to date.");
344
+ return;
345
+ }
346
+ const uniq = (xs) => [...new Set(xs)];
347
+ const list = (xs, n = 4) => uniq(xs).slice(0, n).join(" \xB7 ");
348
+ line();
349
+ for (const l of sectionTitle(dryRun ? "Dry Run Complete" : "Analysis Complete!")) line(l);
350
+ line(` Analyzed ${accent(String(m.stats.filesScanned))} files in ${accent(`${(result.analysis.durationMs / 1e3).toFixed(1)}s`)}`);
351
+ line();
352
+ const overview = [
353
+ ["Project", `${m.name}${m.languages[0] ? ` \xB7 ${list(m.languages.map((l) => l.name), 3)}` : ""}`],
354
+ ["Frameworks", list(m.frameworks.map((f) => f.name), 5)],
355
+ ["Workspace", m.workspace.isMonorepo ? `monorepo \xB7 ${plural(m.workspace.packages.length, "package")}` : ""],
356
+ ["Database", m.databases.length + m.dbEntities.length ? [list(m.databases.map((d) => d.name), 3), m.dbEntities.length ? plural(m.dbEntities.length, "entity").replace("entitys", "entities") : ""].filter(Boolean).join(" \xB7 ") : ""],
357
+ ["API", m.routes.length + m.apiSpecs.length ? [m.routes.length ? plural(m.routes.length, "route") : "", m.apiSpecs.length ? plural(m.apiSpecs.length, "spec") : ""].filter(Boolean).join(" \xB7 ") : ""],
358
+ ["Auth", list(m.auth.map((a) => a.name), 3)],
359
+ ["Testing", m.tests.frameworks.length + m.tests.testFileCount ? [list(m.tests.frameworks.map((f) => f.name), 3), plural(m.tests.testFileCount, "test file")].filter(Boolean).join(" \xB7 ") : ""],
360
+ ["Deployment", [m.containers.dockerfiles.length ? "Docker" : "", ...uniq(m.ci.map((j) => j.system)), ...uniq(m.infrastructure.filter((i) => i.kind === "hosting").map((i) => i.name))].filter(Boolean).slice(0, 4).join(" \xB7 ")],
361
+ ["Security", m.security.secrets.length ? warnText(`${plural(m.security.secrets.length, "potential secret")} \u2014 see security.md`) : "No likely secrets matched"]
362
+ ];
363
+ const files = dryRun ? ["Would create .athena/ with:", ...[...KNOWLEDGE_DOCS.map((d) => d.file), "model.json", "state.json"].map((f) => ` ${f}`)] : fileTree(
364
+ ".athena/",
365
+ result.docs.map((d) => ({ name: d.file, note: mode === "init" ? DOC_NOTES[d.file] ?? "" : d.status, highlight: mode === "analyze" && d.status !== "unchanged" }))
366
+ );
367
+ const configured = result.agentChanges.length > 0;
368
+ const steps = dryRun ? ["Run `athena init` without --dry-run to write the files"] : mode === "init" ? [
369
+ "Review `.athena/rules.md` and enable the rules that apply",
370
+ "Run `athena open` to browse and edit in the web UI",
371
+ configured ? "Your agents now read `.athena/` \u2014 watch with `athena activity`" : "Connect an agent: `athena agents add claude-code`",
372
+ "After code changes run `athena sync` to keep docs current",
373
+ "Guides and docs: https://athena.sabari.me \xB7 star us on GitHub \u2605"
374
+ ] : ["Review changes with `git diff .athena/`", "Run `athena open` to browse in the web UI", "Use `athena sync --watch` to stay current"];
375
+ for (const l of panels([
376
+ { title: "Project Overview", icon: "\u25C6", color: C.blue, body: rows(overview) },
377
+ { title: mode === "init" ? "Generated Files" : "Knowledge Files", icon: "\u25A4", color: C.violet, body: files },
378
+ { title: "Next Steps", icon: "\u279C", color: C.green, body: mode === "init" && !dryRun ? [numbered(steps), [""], quote("Better documentation leads to better software.")] : numbered(steps) }
379
+ ]))
380
+ line(l);
381
+ const preserved = result.docs.filter((d) => d.preservedModified.length);
382
+ const notes = [
383
+ ...m.warnings.slice(0, 5).map((w) => () => warn(c.yellow(w))),
384
+ ...m.warnings.length > 5 ? [() => line(dim(` +${m.warnings.length - 5} more warnings (see .athena/project.md)`))] : [],
385
+ ...preserved.map((d) => () => warn(`${d.file}: kept your edits in ${d.preservedModified.join(", ")} ${dim("(use --force to regenerate)")}`)),
386
+ ...(dryRun ? [] : result.agentChanges).map(({ adapter, changes }) => () => {
387
+ const touched = changes.filter((c2) => c2.action !== "unchanged").map((c2) => `${c2.path} (${c2.action})`);
388
+ ok(`${adapter.displayName} integration${dim(` \u2014 ${touched.length ? touched.join(", ") : changes.map((c2) => c2.path).join(", ") + " (unchanged)"}`)}`);
389
+ }),
390
+ ...mode === "init" && !dryRun ? (() => {
391
+ const unconfigured = ADAPTERS.filter((a) => !result.agentChanges.some((c2) => c2.adapter.id === a.id));
392
+ const text = `Not configured (not detected in this project): ${unconfigured.map((a) => a.id).join(", ")}. Add one with \`athena agents add <id>\`.`;
393
+ return unconfigured.length ? [() => wrapLines(text).forEach((l) => line(dim(l)))] : [];
394
+ })() : [],
395
+ ...dryRun ? result.agentChanges.flatMap(({ adapter, changes }) => changes.map((ch) => () => bullet(`${adapter.displayName}: would ${ch.action} ${ch.path}`))) : [],
396
+ ...result.notes.map((n) => () => warn(n))
397
+ ];
398
+ if (notes.length) {
399
+ line();
400
+ for (const print of notes) print();
401
+ }
402
+ line();
403
+ const lines = dryRun ? footer("Dry run \u2014 nothing was written.", "Re-run without --dry-run to create .athena/", "warn") : mode === "init" ? footer("Athena is ready!", `Your project intelligence is ready in ${accent(".athena/")}`) : footer("Analysis complete.", `Knowledge in ${accent(".athena/")} is up to date with your code`);
404
+ for (const l of lines) line(l);
405
+ }
406
+ function summarize(result, root, dryRun) {
407
+ const m = result.analysis.model;
408
+ return {
409
+ root,
410
+ dryRun,
411
+ project: m.name,
412
+ filesScanned: m.stats.filesScanned,
413
+ durationMs: result.analysis.durationMs,
414
+ languages: m.languages.slice(0, 5).map((l) => l.name),
415
+ frameworks: [...new Set(m.frameworks.map((f) => f.name))],
416
+ monorepo: m.workspace.isMonorepo,
417
+ databases: m.databases.map((d) => d.name),
418
+ entities: m.dbEntities.length,
419
+ routes: m.routes.length,
420
+ testFiles: m.tests.testFileCount,
421
+ potentialSecrets: m.security.secrets.length,
422
+ documents: result.docs.map((d) => ({ file: d.file, status: d.status, preservedModified: d.preservedModified })),
423
+ agents: result.agentChanges.map((a) => ({ id: a.adapter.id, files: a.changes.map((c2) => ({ path: c2.path, action: c2.action })) })),
424
+ warnings: m.warnings,
425
+ notes: result.notes
426
+ };
427
+ }
428
+
429
+ export {
430
+ parseAgentsOption,
431
+ initCommand,
432
+ runWithProgress,
433
+ printSummary,
434
+ summarize
435
+ };
436
+ //# sourceMappingURL=chunk-DOQMAZL5.js.map