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.
- package/CHANGELOG.md +63 -0
- package/README.md +61 -12
- package/dist/activity-BKW7G4I5.js +77 -0
- package/dist/agents-DFSNEOP5.js +69 -0
- package/dist/ai-ASL4FFQ7.js +96 -0
- package/dist/analyze-ZY3MXBOI.js +50 -0
- package/dist/chunk-2DY4PUR4.js +465 -0
- package/dist/chunk-2R6PXY6Z.js +33 -0
- package/dist/chunk-3IS2X2Z7.js +89 -0
- package/dist/chunk-3XSDI5WF.js +179 -0
- package/dist/chunk-65TSRDQ3.js +124 -0
- package/dist/chunk-673EPYYH.js +105 -0
- package/dist/chunk-7DZK6WSQ.js +65 -0
- package/dist/chunk-AD4OZCU2.js +34 -0
- package/dist/chunk-DZDI2HRT.js +169 -0
- package/dist/chunk-ELKFRTZT.js +221 -0
- package/dist/chunk-EUPETUWA.js +14 -0
- package/dist/chunk-FQEGEVLY.js +38 -0
- package/dist/chunk-FVCDMQUQ.js +343 -0
- package/dist/chunk-GGXPG6OE.js +904 -0
- package/dist/chunk-GHFRQAYT.js +112 -0
- package/dist/chunk-GR4DL2VM.js +47 -0
- package/dist/chunk-INT3IGMQ.js +111 -0
- package/dist/chunk-IQQBAWSM.js +90 -0
- package/dist/chunk-JCGDR4UV.js +182 -0
- package/dist/chunk-KBO7XRBW.js +26 -0
- package/dist/chunk-KHMBNT66.js +399 -0
- package/dist/chunk-LEMPCNAY.js +209 -0
- package/dist/chunk-MPG3IEGB.js +2691 -0
- package/dist/chunk-OLPSEQS5.js +264 -0
- package/dist/chunk-PVCIGUIT.js +64 -0
- package/dist/chunk-QCC4VJUH.js +217 -0
- package/dist/chunk-QLW657NT.js +95 -0
- package/dist/chunk-RVTNSNGK.js +182 -0
- package/dist/chunk-RXNRMIZP.js +390 -0
- package/dist/chunk-SHKXELUX.js +295 -0
- package/dist/chunk-SJ4DQFIJ.js +379 -0
- package/dist/chunk-SVTEJYMS.js +227 -0
- package/dist/chunk-TDNZ2RYA.js +702 -0
- package/dist/chunk-UAZLPNVC.js +108 -0
- package/dist/chunk-VSYBC3VY.js +28 -0
- package/dist/chunk-WVQC2EGO.js +166 -0
- package/dist/chunk-XDCKZ5TV.js +436 -0
- package/dist/chunk-XFN7UZCS.js +35 -0
- package/dist/chunk-XW3MLHI2.js +32 -0
- package/dist/chunk-YRIS7ZS6.js +919 -0
- package/dist/chunk-Z6QWMJLK.js +124 -0
- package/dist/chunk-ZB7LC6FP.js +221 -0
- package/dist/clean-MDBYH62P.js +23 -0
- package/dist/cli.js +18 -10716
- package/dist/context-PLPCAPCO.js +161 -0
- package/dist/doctor-BX677KRE.js +69 -0
- package/dist/event-TNT6CQZR.js +101 -0
- package/dist/git-hook-YZNZGAAP.js +252 -0
- package/dist/init-WQCAOJ2R.js +38 -0
- package/dist/mcp-U7EPH43L.js +393 -0
- package/dist/memory-VSVNLEJC.js +393 -0
- package/dist/open-UJZRYF4E.js +1450 -0
- package/dist/program-CWJNGCTZ.js +165 -0
- package/dist/review-OOKXSYMP.js +117 -0
- package/dist/rules-4FXJUCXB.js +83 -0
- package/dist/security-LME3XFL3.js +177 -0
- package/dist/staged-check-X24C3YRD.js +502 -0
- package/dist/status-RR57ZNGI.js +81 -0
- package/dist/sync-KFJANRXF.js +218 -0
- package/dist/watch-CY7QHIYN.js +123 -0
- package/dist/web/assets/{Editor-DAXvniWB.js → Editor-Bnilgch0.js} +1 -1
- package/dist/web/assets/{abnfDiagram-O67JEVCF-Az7EW1BC.js → abnfDiagram-O67JEVCF-DW9LWr8f.js} +1 -1
- package/dist/web/assets/architecture-7GRP2DOG-BWDZV2yn.js +1 -0
- package/dist/web/assets/{architectureDiagram-NJMV4G6O-BxeXqSTn.js → architectureDiagram-NJMV4G6O-0eKeQRhj.js} +1 -1
- package/dist/web/assets/{blockDiagram-BEXU5L5S-aeKZl9lJ.js → blockDiagram-BEXU5L5S-D5i3-ogI.js} +1 -1
- package/dist/web/assets/{c4Diagram-YGBWAQC7-CgmntYsG.js → c4Diagram-YGBWAQC7-BAWQZrEu.js} +1 -1
- package/dist/web/assets/channel-Bkh05NKd.js +1 -0
- package/dist/web/assets/{chunk-3FUC2YCW-BpmRD2yo.js → chunk-3FUC2YCW-fKRGOZF3.js} +1 -1
- package/dist/web/assets/{chunk-5DYCD2WN-CRIFDwod.js → chunk-5DYCD2WN-C5jOlx42.js} +1 -1
- package/dist/web/assets/{chunk-742MDFTN-hRW9VeNV.js → chunk-742MDFTN-urY4RP_A.js} +1 -1
- package/dist/web/assets/{chunk-7INBJB4K-C6VEpT0Y.js → chunk-7INBJB4K-nk48sKqZ.js} +1 -1
- package/dist/web/assets/{chunk-7M6MHVWA-Dnajov2w.js → chunk-7M6MHVWA-BfBD9X0F.js} +1 -1
- package/dist/web/assets/{chunk-7PRAP22T-DSAc0_CZ.js → chunk-7PRAP22T-jYf59QlI.js} +1 -1
- package/dist/web/assets/{chunk-GTNCS2PH-CefpYUjb.js → chunk-GTNCS2PH-BOCxryKf.js} +1 -1
- package/dist/web/assets/{chunk-GWA4HPMP-MLNflMmF.js → chunk-GWA4HPMP-CFpaW0ru.js} +1 -1
- package/dist/web/assets/{chunk-MBY4JIJT-D3GmmEiU.js → chunk-MBY4JIJT-BIB8HctN.js} +1 -1
- package/dist/web/assets/{chunk-NETBCI7D-DzTj6xVk.js → chunk-NETBCI7D-CpUUK6rh.js} +1 -1
- package/dist/web/assets/{chunk-O7XYJQB3-D1d0hCko.js → chunk-O7XYJQB3-BNx_V4Oi.js} +1 -1
- package/dist/web/assets/{chunk-UA2S7LBM-C9hIFeWR.js → chunk-UA2S7LBM-D3tMiIOY.js} +1 -1
- package/dist/web/assets/{chunk-WEXAMYUT-BFGtcjsi.js → chunk-WEXAMYUT-CC-3C32l.js} +1 -1
- package/dist/web/assets/{chunk-Z7XXMR3K-BRZ8_wtE.js → chunk-Z7XXMR3K-BzhxKQUc.js} +1 -1
- package/dist/web/assets/{chunk-ZIGJFQKS-CTKOioal.js → chunk-ZIGJFQKS-D4tBHzxg.js} +1 -1
- package/dist/web/assets/{classDiagram-v2-NBCMYWYE-DJGKtWJv.js → classDiagram-v2-NBCMYWYE-BbtyanXR.js} +1 -1
- package/dist/web/assets/{cynefin-OW5HDTMX-hNq1kGmA.js → cynefin-OW5HDTMX-BIArb8W1.js} +1 -1
- package/dist/web/assets/{cynefinDiagram-VND7K2PF-sODQM_ZZ.js → cynefinDiagram-VND7K2PF-BrAcfkXL.js} +1 -1
- package/dist/web/assets/{dagre-6A5THRUB-DEzTThIf.js → dagre-6A5THRUB-BcHXRl4s.js} +1 -1
- package/dist/web/assets/{diagram-22UHCM2B-s_eellsa.js → diagram-22UHCM2B-Dx9tSCdE.js} +1 -1
- package/dist/web/assets/{diagram-3UASUU5V-B2onY_Xw.js → diagram-3UASUU5V-CLLDP9yH.js} +1 -1
- package/dist/web/assets/{diagram-ATOU4E4O-B8V6s13s.js → diagram-ATOU4E4O-B46H9iPt.js} +1 -1
- package/dist/web/assets/{diagram-CDSNMT55-CJxiE6mf.js → diagram-CDSNMT55-CYtvB6aG.js} +1 -1
- package/dist/web/assets/{diagram-MLGK6HIB-m5OHPLAp.js → diagram-MLGK6HIB-Dar7ktoX.js} +1 -1
- package/dist/web/assets/{diagram-MPIPVDR6-Buvvrk_A.js → diagram-MPIPVDR6-C-DljnYN.js} +1 -1
- package/dist/web/assets/{ebnfDiagram-ZINNZB2B-CpL7Wt3R.js → ebnfDiagram-ZINNZB2B-Dv_3jWnh.js} +1 -1
- package/dist/web/assets/{elk-276RUBZZ-CwYhbsXa.js → elk-276RUBZZ-DnHciE9k.js} +1 -1
- package/dist/web/assets/{erDiagram-OPXOYQCR-DNikci2r.js → erDiagram-OPXOYQCR-Bn46KrHz.js} +1 -1
- package/dist/web/assets/eventmodeling-NTZA5JFV-DYwoptMd.js +1 -0
- package/dist/web/assets/flowDiagram-KWPJA3E3-y4rS0gIB.js +1 -0
- package/dist/web/assets/{ganttDiagram-FUAMR5RP-d-ynDlvJ.js → ganttDiagram-FUAMR5RP-DOjjJtqz.js} +1 -1
- package/dist/web/assets/{gitGraph-4MIJSDKK-DwIeBI91.js → gitGraph-4MIJSDKK-BIoMXJRQ.js} +1 -1
- package/dist/web/assets/{gitGraphDiagram-X574FWY7-04RZccu6.js → gitGraphDiagram-X574FWY7-BsJ01R0v.js} +1 -1
- package/dist/web/assets/{index-C3-8uYXr.js → index-Cen0jOXj.js} +5 -4
- package/dist/web/assets/{index-DKE3ojTe.css → index-WwRY6n68.css} +1 -1
- package/dist/web/assets/{info-A6RAGUB7-xf4Nzgv-.js → info-A6RAGUB7-BmlXzRWj.js} +1 -1
- package/dist/web/assets/{infoDiagram-VRGFBTTK-BYjw0eiK.js → infoDiagram-VRGFBTTK-CYPJPmBP.js} +1 -1
- package/dist/web/assets/{ishikawaDiagram-OU5B5YK6-Bx9s4nPM.js → ishikawaDiagram-OU5B5YK6-YN96geky.js} +1 -1
- package/dist/web/assets/{journeyDiagram-ZHPQQLJL-DrdHs7B-.js → journeyDiagram-ZHPQQLJL-20juojKY.js} +1 -1
- package/dist/web/assets/{kanban-definition-PNTS6WVX-CVd8v2Te.js → kanban-definition-PNTS6WVX-BhCKIEbP.js} +1 -1
- package/dist/web/assets/{line-V_WrJ-6y.js → line-BERsMFG6.js} +1 -1
- package/dist/web/assets/{mermaid-parser.core-B-ilyEpO.js → mermaid-parser.core-Bis_wTB-.js} +3 -3
- package/dist/web/assets/{mermaid.core-Bnyaa0nF.js → mermaid.core-DMsM3ZX7.js} +4 -4
- package/dist/web/assets/{mindmap-definition-NLK3R4M7-B3AbvHPR.js → mindmap-definition-NLK3R4M7-BkcGdOfv.js} +1 -1
- package/dist/web/assets/{packet-AYTQ26CC-CBAIUXIc.js → packet-AYTQ26CC-Bh30-JJX.js} +1 -1
- package/dist/web/assets/{pegDiagram-GJSIUBJH-DIdeELUM.js → pegDiagram-GJSIUBJH-DxnIo9RF.js} +1 -1
- package/dist/web/assets/{pie-WAS4IAKB-a1r3tzPR.js → pie-WAS4IAKB-ChaTr-GD.js} +1 -1
- package/dist/web/assets/{pieDiagram-5QR66LMP-pQBEio0x.js → pieDiagram-5QR66LMP-CzAp78FM.js} +1 -1
- package/dist/web/assets/{quadrantDiagram-O4NWA36T-CkJK5Y03.js → quadrantDiagram-O4NWA36T-BDSE-cfY.js} +1 -1
- package/dist/web/assets/{radar-RG4KPBEZ-BZfLYjx5.js → radar-RG4KPBEZ-DgJ-o_dq.js} +1 -1
- package/dist/web/assets/{railroad-74A4TZTK-CuIW1ZAU.js → railroad-74A4TZTK-C8MmcBKz.js} +1 -1
- package/dist/web/assets/railroad-abnf-HS5TGJTU-CTLXjcdP.js +1 -0
- package/dist/web/assets/railroad-ebnf-LZEXJU2U-ggWsTTL0.js +1 -0
- package/dist/web/assets/railroad-peg-WCYAUIDC-D1mCX705.js +1 -0
- package/dist/web/assets/{railroadDiagram-XR7U4H2S-_BpGE8aJ.js → railroadDiagram-XR7U4H2S-DfbcWRNh.js} +1 -1
- package/dist/web/assets/{requirementDiagram-PLB6GJNP-CnzF90GS.js → requirementDiagram-PLB6GJNP-DM3nksxs.js} +1 -1
- package/dist/web/assets/{sankeyDiagram-IPEJSGJF-DYeisDj_.js → sankeyDiagram-IPEJSGJF-DthUpiiC.js} +1 -1
- package/dist/web/assets/{sequenceDiagram-PO4LG4MO-ll9cBvca.js → sequenceDiagram-PO4LG4MO-DLA3nuvA.js} +1 -1
- package/dist/web/assets/{stateDiagram-v2-GCMORJYK-CdKcOIKQ.js → stateDiagram-v2-GCMORJYK-B0X6ihBW.js} +1 -1
- package/dist/web/assets/{swimlanes-2SLR337P-y6piTWEW.js → swimlanes-2SLR337P-B4qWe6vE.js} +1 -1
- package/dist/web/assets/swimlanesDiagram-TC7HE7FX-ClIk3e7S.js +8 -0
- package/dist/web/assets/{timeline-definition-EJHVYXUP-DuC_4xK0.js → timeline-definition-EJHVYXUP-F-cDzYrj.js} +1 -1
- package/dist/web/assets/{treeView-Q6P3EWNA-gCQFmND0.js → treeView-Q6P3EWNA-BaI30nLZ.js} +1 -1
- package/dist/web/assets/{treemap-WGGIJYW6-BQ2010OY.js → treemap-WGGIJYW6-D2jGGoMl.js} +1 -1
- package/dist/web/assets/{usecaseDiagram-POWQR4AR-CCTqzHz6.js → usecaseDiagram-POWQR4AR-B9qoAQCy.js} +1 -1
- package/dist/web/assets/{vennDiagram-UO4OBE2U-0_O7guNq.js → vennDiagram-UO4OBE2U-DGVNOaKO.js} +1 -1
- package/dist/web/assets/{wardley-WFR3VGLG-SsX7uMDs.js → wardley-WFR3VGLG-DbKqhNAh.js} +1 -1
- package/dist/web/assets/{wardleyDiagram-VNRHLVJA-DlqH6Hox.js → wardleyDiagram-VNRHLVJA-BgZ1gprw.js} +1 -1
- package/dist/web/assets/{xychartDiagram-PMCCYNJV-nr4UYDtd.js → xychartDiagram-PMCCYNJV-D73RYid1.js} +1 -1
- package/dist/web/index.html +2 -2
- package/package.json +4 -2
- package/dist/web/assets/architecture-7GRP2DOG-blXBarB2.js +0 -1
- package/dist/web/assets/channel-f4QzewnN.js +0 -1
- package/dist/web/assets/eventmodeling-NTZA5JFV-CA_ZFPZ2.js +0 -1
- package/dist/web/assets/flowDiagram-KWPJA3E3-DObsBuWT.js +0 -1
- package/dist/web/assets/railroad-abnf-HS5TGJTU-6B4Ffbxn.js +0 -1
- package/dist/web/assets/railroad-ebnf-LZEXJU2U-BGL9lIQc.js +0 -1
- package/dist/web/assets/railroad-peg-WCYAUIDC-DcqxTem7.js +0 -1
- package/dist/web/assets/swimlanesDiagram-TC7HE7FX-DFS8a3jO.js +0 -8
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
MEMORY_FILES,
|
|
4
|
+
MEMORY_KINDS,
|
|
5
|
+
MEMORY_STATUSES,
|
|
6
|
+
addMemory,
|
|
7
|
+
confirmMemory,
|
|
8
|
+
forgetMemory,
|
|
9
|
+
getMemory,
|
|
10
|
+
listMemory,
|
|
11
|
+
recallMemory,
|
|
12
|
+
searchMemory,
|
|
13
|
+
supersedeMemory,
|
|
14
|
+
updateMemory
|
|
15
|
+
} from "./chunk-TDNZ2RYA.js";
|
|
16
|
+
import "./chunk-3IS2X2Z7.js";
|
|
17
|
+
import {
|
|
18
|
+
c,
|
|
19
|
+
dim,
|
|
20
|
+
heading,
|
|
21
|
+
isJson,
|
|
22
|
+
json,
|
|
23
|
+
line,
|
|
24
|
+
ok,
|
|
25
|
+
relativeTime,
|
|
26
|
+
sym,
|
|
27
|
+
warn
|
|
28
|
+
} from "./chunk-Z6QWMJLK.js";
|
|
29
|
+
import {
|
|
30
|
+
requireProjectRoot
|
|
31
|
+
} from "./chunk-XFN7UZCS.js";
|
|
32
|
+
import "./chunk-KBO7XRBW.js";
|
|
33
|
+
import "./chunk-SVTEJYMS.js";
|
|
34
|
+
import "./chunk-QCC4VJUH.js";
|
|
35
|
+
import "./chunk-JCGDR4UV.js";
|
|
36
|
+
import "./chunk-673EPYYH.js";
|
|
37
|
+
import "./chunk-FQEGEVLY.js";
|
|
38
|
+
import "./chunk-2DY4PUR4.js";
|
|
39
|
+
import "./chunk-IQQBAWSM.js";
|
|
40
|
+
import {
|
|
41
|
+
AthenaError
|
|
42
|
+
} from "./chunk-AD4OZCU2.js";
|
|
43
|
+
import "./chunk-XW3MLHI2.js";
|
|
44
|
+
import "./chunk-EUPETUWA.js";
|
|
45
|
+
|
|
46
|
+
// src/cli/commands/memory.ts
|
|
47
|
+
import { createInterface } from "readline/promises";
|
|
48
|
+
var ID_RE = /^m-[a-z0-9]{4,16}$/;
|
|
49
|
+
function parseKind(k) {
|
|
50
|
+
if (k === void 0) return void 0;
|
|
51
|
+
if (!MEMORY_KINDS.includes(k)) throw new AthenaError(`Unknown memory kind: ${k}`, `Use one of: ${MEMORY_KINDS.join(", ")}`);
|
|
52
|
+
return k;
|
|
53
|
+
}
|
|
54
|
+
function parseStatus(s) {
|
|
55
|
+
if (s === void 0) return void 0;
|
|
56
|
+
if (!MEMORY_STATUSES.includes(s)) throw new AthenaError(`Unknown memory status: ${s}`, `Use one of: ${MEMORY_STATUSES.join(", ")}`);
|
|
57
|
+
return s;
|
|
58
|
+
}
|
|
59
|
+
function checkIds(ids) {
|
|
60
|
+
for (const id of ids) if (!ID_RE.test(id)) throw new AthenaError(`Invalid memory id: ${id}`, "Ids look like m-1a2b3c; list them with `athena memory list`.");
|
|
61
|
+
}
|
|
62
|
+
async function readStdin() {
|
|
63
|
+
if (process.stdin.isTTY) throw new AthenaError("`--details -` reads the details from stdin, but stdin is a terminal.", "Pipe the text in, e.g. `cat notes.txt | athena memory add \u2026 --details -`.");
|
|
64
|
+
const chunks = [];
|
|
65
|
+
for await (const chunk of process.stdin) chunks.push(chunk);
|
|
66
|
+
return Buffer.concat(chunks).toString("utf8");
|
|
67
|
+
}
|
|
68
|
+
var plural = (n, word, many = `${word}s`) => `${n} ${n === 1 ? word : many}`;
|
|
69
|
+
var trunc = (s, n) => s.length > n ? `${s.slice(0, n - 1)}\u2026` : s;
|
|
70
|
+
var pad = (s, n) => s + " ".repeat(Math.max(0, n - s.length));
|
|
71
|
+
function labelOf(v) {
|
|
72
|
+
if (v.status === "superseded") return dim(pad("history", 8));
|
|
73
|
+
return v.label === "FACT" ? c.green(pad("FACT", 8)) : c.yellow(pad("INFERRED", 8));
|
|
74
|
+
}
|
|
75
|
+
function statusOf(v) {
|
|
76
|
+
const s = pad(v.status, 10);
|
|
77
|
+
return v.status === "unreviewed" ? c.yellow(s) : v.status === "superseded" ? dim(s) : s;
|
|
78
|
+
}
|
|
79
|
+
function row(v) {
|
|
80
|
+
const markers = `${v.stale ? c.yellow("stale") : " "} ${v.flags.length ? c.red(sym.warn) : " "}`;
|
|
81
|
+
const title = v.status === "superseded" ? dim(trunc(v.title, 60)) : trunc(v.title, 60);
|
|
82
|
+
return `${c.bold(pad(v.id, 9))} ${pad(v.kind, 10)} ${labelOf(v)} ${statusOf(v)} ${markers} ${title} ${dim(`\xB7 ${v.source}`)}`;
|
|
83
|
+
}
|
|
84
|
+
function table(views) {
|
|
85
|
+
line(dim(`${pad("ID", 9)} ${pad("KIND", 10)} ${pad("LABEL", 8)} ${pad("STATUS", 10)} ${pad("", 7)} TITLE \xB7 SOURCE`));
|
|
86
|
+
for (const v of views) line(row(v));
|
|
87
|
+
}
|
|
88
|
+
function countMemory(views) {
|
|
89
|
+
return {
|
|
90
|
+
total: views.length,
|
|
91
|
+
unreviewed: views.filter((v) => v.status === "unreviewed").length,
|
|
92
|
+
confirmed: views.filter((v) => v.status === "confirmed").length,
|
|
93
|
+
superseded: views.filter((v) => v.status === "superseded").length,
|
|
94
|
+
stale: views.filter((v) => v.stale).length,
|
|
95
|
+
flagged: views.filter((v) => v.flags.length && v.status !== "superseded").length
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
async function memorySummary(root) {
|
|
99
|
+
try {
|
|
100
|
+
return countMemory(await listMemory(root));
|
|
101
|
+
} catch {
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
function countsLine(c2) {
|
|
106
|
+
const parts = [plural(c2.total, "entry", "entries"), `${c2.confirmed} confirmed`, `${c2.unreviewed} unreviewed`];
|
|
107
|
+
if (c2.superseded) parts.push(`${c2.superseded} superseded`);
|
|
108
|
+
if (c2.stale) parts.push(`${c2.stale} stale`);
|
|
109
|
+
if (c2.flagged) parts.push(`${c2.flagged} flagged`);
|
|
110
|
+
return parts.join(" \xB7 ");
|
|
111
|
+
}
|
|
112
|
+
function flagsBlock(v) {
|
|
113
|
+
if (!v.flags.length) return;
|
|
114
|
+
warn(c.red("Possible prompt injection \u2014 this entry addresses the agent instead of describing the project:"));
|
|
115
|
+
for (const f of v.flags) line(` ${dim("-")} ${f}`);
|
|
116
|
+
line(dim(" Flagged entries are never recalled automatically. Read it before confirming; forget it if it is not a real project fact."));
|
|
117
|
+
}
|
|
118
|
+
function detail(v) {
|
|
119
|
+
line(`${c.bold(v.id)} ${c.bold(v.title)}`);
|
|
120
|
+
line(`${dim("Kind:")} ${v.kind} ${dim(`(.athena/memory/${MEMORY_FILES[v.kind]})`)}`);
|
|
121
|
+
line(`${dim("Label:")} ${v.status === "superseded" ? dim("history (superseded)") : v.label === "FACT" ? c.green("FACT") : c.yellow("INFERRED")} ${dim(`\xB7 ${v.status}`)}`);
|
|
122
|
+
line(`${dim("Source:")} ${v.source}`);
|
|
123
|
+
line(`${dim("Created:")} ${v.createdAt} ${dim(`(${relativeTime(v.createdAt)})`)}`);
|
|
124
|
+
if (v.confirmedAt) line(`${dim("Confirmed:")} ${v.confirmedAt}`);
|
|
125
|
+
if (v.supersedes) line(`${dim("Replaces:")} ${v.supersedes}`);
|
|
126
|
+
if (v.supersededBy) line(`${dim("Superseded by:")} ${v.supersededBy}`);
|
|
127
|
+
if (v.tags.length) line(`${dim("Tags:")} ${v.tags.map((t) => `#${t}`).join(" ")}`);
|
|
128
|
+
if (v.evidence) line(`${dim("Evidence:")} ${v.evidence}`);
|
|
129
|
+
if (v.files.length) {
|
|
130
|
+
line(dim("Files:"));
|
|
131
|
+
for (const f of v.files) {
|
|
132
|
+
const state = v.changedFiles.includes(f) ? c.yellow("changed since recorded") : f in v.anchors ? c.green("unchanged") : dim("not anchored (file did not exist when recorded)");
|
|
133
|
+
line(` ${f} ${dim("\u2014")} ${state}`);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
if (v.details) {
|
|
137
|
+
line();
|
|
138
|
+
for (const l of v.details.split("\n")) line(` ${l}`);
|
|
139
|
+
}
|
|
140
|
+
if (v.stale) {
|
|
141
|
+
line();
|
|
142
|
+
warn(`Stale: ${v.changedFiles.join(", ")} changed since this was recorded.`);
|
|
143
|
+
}
|
|
144
|
+
if (v.flags.length) {
|
|
145
|
+
line();
|
|
146
|
+
flagsBlock(v);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
async function memoryListCommand(opts) {
|
|
150
|
+
const root = await requireProjectRoot(opts);
|
|
151
|
+
const kind = parseKind(opts.kind);
|
|
152
|
+
const status = parseStatus(opts.status);
|
|
153
|
+
const all = await listMemory(root);
|
|
154
|
+
const views = all.filter((v) => (!kind || v.kind === kind) && (!status || v.status === status) && (!opts.stale || v.stale));
|
|
155
|
+
const counts = countMemory(all);
|
|
156
|
+
if (isJson()) {
|
|
157
|
+
json({ entries: views, counts });
|
|
158
|
+
return 0;
|
|
159
|
+
}
|
|
160
|
+
if (!all.length) {
|
|
161
|
+
line(dim('No project memory yet. Record one with `athena memory add --kind decision --title "\u2026"`, or let your agent use the `remember` MCP tool.'));
|
|
162
|
+
return 0;
|
|
163
|
+
}
|
|
164
|
+
if (!views.length) line(dim("No entries match."));
|
|
165
|
+
else table(views);
|
|
166
|
+
line();
|
|
167
|
+
line(dim(`${countsLine(counts)} \xB7 source: .athena/memory/`));
|
|
168
|
+
if (counts.unreviewed) line(dim(`${plural(counts.unreviewed, "entry", "entries")} written by agents ${counts.unreviewed === 1 ? "is" : "are"} INFERRED until reviewed: run \`athena memory review\`.`));
|
|
169
|
+
if (counts.stale && !opts.stale) line(dim("Some entries are stale (their linked files changed): run `athena memory stale`."));
|
|
170
|
+
return 0;
|
|
171
|
+
}
|
|
172
|
+
async function memoryShowCommand(id, opts) {
|
|
173
|
+
checkIds([id]);
|
|
174
|
+
const root = await requireProjectRoot(opts);
|
|
175
|
+
const v = await getMemory(root, id);
|
|
176
|
+
if (isJson()) json(v);
|
|
177
|
+
else detail(v);
|
|
178
|
+
}
|
|
179
|
+
async function memoryAddCommand(opts) {
|
|
180
|
+
const root = await requireProjectRoot(opts);
|
|
181
|
+
if (!opts.kind) throw new AthenaError("Missing --kind.", `Use one of: ${MEMORY_KINDS.join(", ")}`);
|
|
182
|
+
const kind = parseKind(opts.kind);
|
|
183
|
+
if (!opts.title) throw new AthenaError("Missing --title.", 'A memory needs a short title, e.g. --title "Money is stored in cents".');
|
|
184
|
+
if (opts.supersedes) checkIds([opts.supersedes]);
|
|
185
|
+
const details = opts.details === "-" ? await readStdin() : opts.details;
|
|
186
|
+
const v = await addMemory(root, { kind, title: opts.title, details, files: opts.file, tags: opts.tag, evidence: opts.evidence, supersedes: opts.supersedes }, "developer");
|
|
187
|
+
if (isJson()) {
|
|
188
|
+
json({ ok: true, entry: v });
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
ok(`Recorded ${c.bold(v.id)} ${dim(`(${v.kind}, FACT) in .athena/memory/${MEMORY_FILES[v.kind]}`)}`);
|
|
192
|
+
if (v.supersedes) line(dim(` ${v.supersedes} is now superseded by ${v.id}.`));
|
|
193
|
+
const unanchored = v.files.filter((f) => !(f in v.anchors));
|
|
194
|
+
if (unanchored.length) warn(`Not found, so not tracked for staleness: ${unanchored.join(", ")}`);
|
|
195
|
+
if (v.flags.length) flagsBlock(v);
|
|
196
|
+
}
|
|
197
|
+
async function memorySearchCommand(query, opts) {
|
|
198
|
+
const root = await requireProjectRoot(opts);
|
|
199
|
+
const views = await searchMemory(root, query);
|
|
200
|
+
if (isJson()) {
|
|
201
|
+
json({ query, entries: views });
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
if (!views.length) {
|
|
205
|
+
line(dim(`No memory mentions "${query}".`));
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
table(views);
|
|
209
|
+
line();
|
|
210
|
+
line(dim(`${plural(views.length, "match", "matches")} \xB7 details: athena memory show <id>`));
|
|
211
|
+
}
|
|
212
|
+
async function memoryRecallCommand(task, opts) {
|
|
213
|
+
const root = await requireProjectRoot(opts);
|
|
214
|
+
const text = task.join(" ").trim();
|
|
215
|
+
const limit = opts.limit === void 0 ? void 0 : Number(opts.limit);
|
|
216
|
+
if (limit !== void 0 && (!Number.isInteger(limit) || limit < 1)) throw new AthenaError(`Invalid --limit: ${opts.limit}`);
|
|
217
|
+
const hits = await recallMemory(root, { task: text, files: opts.file, tags: opts.tag, limit });
|
|
218
|
+
if (isJson()) {
|
|
219
|
+
json({ task: text, files: opts.file ?? [], hits });
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
if (!hits.length) {
|
|
223
|
+
line(dim("No relevant memory for this task."));
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
heading(`Memory relevant to "${trunc(text, 60)}"`);
|
|
227
|
+
line();
|
|
228
|
+
hits.forEach((h, i) => {
|
|
229
|
+
const v = h.entry;
|
|
230
|
+
line(`${dim(`${String(i + 1).padStart(2)}.`)} ${c.bold(v.id)} ${labelOf(v)} ${v.kind} ${dim("\u2014")} ${v.title}`);
|
|
231
|
+
line(` ${dim(`score ${h.score} \xB7 ${h.why.join("; ")}`)}`);
|
|
232
|
+
});
|
|
233
|
+
line();
|
|
234
|
+
line(dim("Flagged (possible prompt-injection) and superseded entries are not recalled. Details: athena memory show <id>"));
|
|
235
|
+
}
|
|
236
|
+
async function memoryConfirmCommand(ids, opts) {
|
|
237
|
+
checkIds(ids);
|
|
238
|
+
const root = await requireProjectRoot(opts);
|
|
239
|
+
for (const id of ids) await getMemory(root, id);
|
|
240
|
+
const out = [];
|
|
241
|
+
for (const id of ids) out.push(await confirmMemory(root, id));
|
|
242
|
+
if (isJson()) {
|
|
243
|
+
json({ ok: true, entries: out });
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
for (const v of out) {
|
|
247
|
+
ok(`Confirmed ${c.bold(v.id)} ${dim(`\u2014 ${trunc(v.title, 60)} (now FACT${v.files.length ? ", re-anchored to current files" : ""})`)}`);
|
|
248
|
+
if (v.flags.length) flagsBlock(v);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
async function memorySupersedeCommand(id, opts) {
|
|
252
|
+
if (!opts.by) throw new AthenaError("Missing --by <id>.", "Name the newer memory that replaces this one: athena memory supersede <old-id> --by <new-id>");
|
|
253
|
+
checkIds([id, opts.by]);
|
|
254
|
+
const root = await requireProjectRoot(opts);
|
|
255
|
+
const v = await supersedeMemory(root, id, opts.by);
|
|
256
|
+
if (isJson()) json({ ok: true, entry: v });
|
|
257
|
+
else ok(`${c.bold(id)} is now superseded by ${c.bold(opts.by)} ${dim("(kept as history; no longer recalled)")}`);
|
|
258
|
+
}
|
|
259
|
+
async function ask(question) {
|
|
260
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
261
|
+
try {
|
|
262
|
+
return /^y(es)?$/i.test((await rl.question(`${question} ${dim("[y/N]")} `)).trim());
|
|
263
|
+
} finally {
|
|
264
|
+
rl.close();
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
async function memoryForgetCommand(ids, opts) {
|
|
268
|
+
checkIds(ids);
|
|
269
|
+
const root = await requireProjectRoot(opts);
|
|
270
|
+
const views = [];
|
|
271
|
+
for (const id of ids) views.push(await getMemory(root, id));
|
|
272
|
+
if (!opts.yes) {
|
|
273
|
+
if (!process.stdin.isTTY || isJson()) throw new AthenaError(`Refusing to forget ${plural(ids.length, "memory", "memories")} without confirmation.`, "Re-run with --yes in non-interactive environments.");
|
|
274
|
+
line("This permanently removes from .athena/memory/:");
|
|
275
|
+
for (const v of views) line(` ${c.bold(v.id)} ${v.kind} ${dim("\u2014")} ${v.title}`);
|
|
276
|
+
line(dim("If .athena/memory/ is committed to Git you can restore entries from history. To keep an outdated entry as history, use `athena memory supersede` instead."));
|
|
277
|
+
if (!await ask("Forget?")) {
|
|
278
|
+
line("Cancelled.");
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
for (const id of ids) await forgetMemory(root, id);
|
|
283
|
+
if (isJson()) json({ ok: true, forgotten: ids });
|
|
284
|
+
else for (const v of views) ok(`Forgot ${c.bold(v.id)} ${dim(`\u2014 ${trunc(v.title, 60)}`)}`);
|
|
285
|
+
}
|
|
286
|
+
async function memoryEditCommand(id, opts) {
|
|
287
|
+
checkIds([id]);
|
|
288
|
+
const root = await requireProjectRoot(opts);
|
|
289
|
+
const details = opts.details === "-" ? await readStdin() : opts.details;
|
|
290
|
+
const patch = { title: opts.title, details, files: opts.file, tags: opts.tag, evidence: opts.evidence };
|
|
291
|
+
if (Object.values(patch).every((v2) => v2 === void 0)) throw new AthenaError("Nothing to change.", "Pass at least one of --title, --details, --file, --tag, --evidence.");
|
|
292
|
+
const v = await updateMemory(root, id, patch);
|
|
293
|
+
if (isJson()) {
|
|
294
|
+
json({ ok: true, entry: v });
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
ok(`Updated ${c.bold(v.id)} ${dim(`\u2014 ${trunc(v.title, 60)}`)}`);
|
|
298
|
+
if (v.status === "unreviewed") line(dim(` Still INFERRED (unreviewed). Confirm it with \`athena memory confirm ${v.id}\`.`));
|
|
299
|
+
if (v.flags.length) flagsBlock(v);
|
|
300
|
+
}
|
|
301
|
+
async function memoryStaleCommand(opts) {
|
|
302
|
+
const root = await requireProjectRoot(opts);
|
|
303
|
+
const views = await listMemory(root, { stale: true });
|
|
304
|
+
if (isJson()) {
|
|
305
|
+
json({ entries: views });
|
|
306
|
+
return 0;
|
|
307
|
+
}
|
|
308
|
+
if (!views.length) {
|
|
309
|
+
ok("No stale memory: no linked file changed since its entry was recorded or confirmed.");
|
|
310
|
+
return 0;
|
|
311
|
+
}
|
|
312
|
+
heading(`${plural(views.length, "stale entry", "stale entries")}`);
|
|
313
|
+
line();
|
|
314
|
+
for (const v of views) {
|
|
315
|
+
line(`${c.bold(v.id)} ${labelOf(v)} ${v.kind} ${dim("\u2014")} ${v.title}`);
|
|
316
|
+
line(` ${c.yellow("changed:")} ${v.changedFiles.join(", ")}`);
|
|
317
|
+
}
|
|
318
|
+
line();
|
|
319
|
+
line(dim("For each: still true \u2192 `athena memory confirm <id>` (re-anchors to the current files);"));
|
|
320
|
+
line(dim("partly wrong \u2192 `athena memory edit <id> --details \u2026`; no longer true \u2192 `athena memory forget <id>`."));
|
|
321
|
+
return 0;
|
|
322
|
+
}
|
|
323
|
+
async function memoryReviewCommand(opts) {
|
|
324
|
+
const root = await requireProjectRoot(opts);
|
|
325
|
+
const pending = (await listMemory(root, { status: "unreviewed" })).sort((a, b) => a.createdAt.localeCompare(b.createdAt));
|
|
326
|
+
const interactive = Boolean(process.stdin.isTTY) && Boolean(process.stdout.isTTY) && !isJson();
|
|
327
|
+
if (!interactive) {
|
|
328
|
+
if (isJson()) json({ interactive: false, entries: pending });
|
|
329
|
+
else if (!pending.length) ok("Nothing to review: no unreviewed memory.");
|
|
330
|
+
else {
|
|
331
|
+
table(pending);
|
|
332
|
+
line();
|
|
333
|
+
line(dim(`${plural(pending.length, "unreviewed entry", "unreviewed entries")}. \`athena memory review\` is interactive in a terminal;`));
|
|
334
|
+
line(dim("here, use `athena memory confirm <id\u2026>` or `athena memory forget <id\u2026> --yes`."));
|
|
335
|
+
}
|
|
336
|
+
return 0;
|
|
337
|
+
}
|
|
338
|
+
if (!pending.length) {
|
|
339
|
+
ok("Nothing to review: no unreviewed memory.");
|
|
340
|
+
return 0;
|
|
341
|
+
}
|
|
342
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
343
|
+
const tally = { confirmed: 0, forgotten: 0, skipped: 0 };
|
|
344
|
+
try {
|
|
345
|
+
for (let i = 0; i < pending.length; i++) {
|
|
346
|
+
const v = pending[i];
|
|
347
|
+
line();
|
|
348
|
+
line(dim(`\u2500\u2500 ${i + 1}/${pending.length} \u2500\u2500`));
|
|
349
|
+
detail(v);
|
|
350
|
+
line();
|
|
351
|
+
let answer = "";
|
|
352
|
+
for (; ; ) {
|
|
353
|
+
answer = (await rl.question(`${c.bold("[c]")}onfirm ${c.bold("[e]")}dit later ${c.bold("[f]")}orget ${c.bold("[s]")}kip ${c.bold("[q]")}uit ${dim("\u203A")} `).catch(() => "q")).trim().toLowerCase();
|
|
354
|
+
if (/^[cefsq]/.test(answer)) break;
|
|
355
|
+
}
|
|
356
|
+
const a = answer[0];
|
|
357
|
+
if (a === "q") break;
|
|
358
|
+
if (a === "c") {
|
|
359
|
+
await confirmMemory(root, v.id);
|
|
360
|
+
tally.confirmed++;
|
|
361
|
+
ok(`Confirmed ${v.id} (now FACT)`);
|
|
362
|
+
} else if (a === "f") {
|
|
363
|
+
await forgetMemory(root, v.id);
|
|
364
|
+
tally.forgotten++;
|
|
365
|
+
ok(`Forgot ${v.id}`);
|
|
366
|
+
} else {
|
|
367
|
+
tally.skipped++;
|
|
368
|
+
if (a === "e") line(dim(` Skipped. Edit it with \`athena memory edit ${v.id} --title \u2026 --details \u2026\`, then confirm it.`));
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
} finally {
|
|
372
|
+
rl.close();
|
|
373
|
+
}
|
|
374
|
+
line();
|
|
375
|
+
line(`${tally.confirmed} confirmed \xB7 ${tally.forgotten} forgotten \xB7 ${tally.skipped} skipped`);
|
|
376
|
+
return 0;
|
|
377
|
+
}
|
|
378
|
+
export {
|
|
379
|
+
countMemory,
|
|
380
|
+
memoryAddCommand,
|
|
381
|
+
memoryConfirmCommand,
|
|
382
|
+
memoryEditCommand,
|
|
383
|
+
memoryForgetCommand,
|
|
384
|
+
memoryListCommand,
|
|
385
|
+
memoryRecallCommand,
|
|
386
|
+
memoryReviewCommand,
|
|
387
|
+
memorySearchCommand,
|
|
388
|
+
memoryShowCommand,
|
|
389
|
+
memoryStaleCommand,
|
|
390
|
+
memorySummary,
|
|
391
|
+
memorySupersedeCommand
|
|
392
|
+
};
|
|
393
|
+
//# sourceMappingURL=memory-VSVNLEJC.js.map
|