project-athena 0.2.0 → 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.
- package/CHANGELOG.md +76 -0
- package/README.md +19 -11
- package/dist/activity-P4UUFHWV.js +77 -0
- package/dist/agents-3HTSQGL2.js +69 -0
- package/dist/ai-ASL4FFQ7.js +96 -0
- package/dist/analyze-F3YOILNL.js +49 -0
- package/dist/chunk-2DY4PUR4.js +465 -0
- package/dist/chunk-2R6PXY6Z.js +33 -0
- package/dist/chunk-2RS6TA3D.js +908 -0
- package/dist/chunk-32PRS2MG.js +169 -0
- package/dist/chunk-3IS2X2Z7.js +89 -0
- package/dist/chunk-65TSRDQ3.js +124 -0
- package/dist/chunk-673EPYYH.js +105 -0
- package/dist/chunk-AD4OZCU2.js +34 -0
- package/dist/chunk-CXUTYCZX.js +238 -0
- package/dist/chunk-DOQMAZL5.js +436 -0
- package/dist/chunk-EF6GHOIN.js +343 -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-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-JY6BFIJJ.js +95 -0
- package/dist/chunk-KBO7XRBW.js +26 -0
- package/dist/chunk-LEMPCNAY.js +209 -0
- package/dist/chunk-LMOFZNTQ.js +379 -0
- package/dist/chunk-OLPSEQS5.js +264 -0
- package/dist/chunk-PANVPNYF.js +2892 -0
- package/dist/chunk-PDFQ5BFG.js +378 -0
- package/dist/chunk-PR53DT7I.js +179 -0
- package/dist/chunk-PVCIGUIT.js +64 -0
- package/dist/chunk-RXNRMIZP.js +390 -0
- package/dist/chunk-S7T6VX56.js +61 -0
- package/dist/chunk-SHKXELUX.js +295 -0
- package/dist/chunk-SJOOXO34.js +904 -0
- package/dist/chunk-TGJUUB44.js +399 -0
- package/dist/chunk-VSYBC3VY.js +28 -0
- package/dist/chunk-XB66PZ6Z.js +182 -0
- package/dist/chunk-XFN7UZCS.js +35 -0
- package/dist/chunk-XW3MLHI2.js +32 -0
- package/dist/chunk-Z6QWMJLK.js +124 -0
- package/dist/chunk-ZB7LC6FP.js +221 -0
- package/dist/clean-S7PKCOLM.js +23 -0
- package/dist/cli.js +18 -9795
- package/dist/context-AH5MFHRG.js +147 -0
- package/dist/doctor-RSJMLE2P.js +62 -0
- package/dist/event-TNT6CQZR.js +101 -0
- package/dist/git-hook-YZNZGAAP.js +252 -0
- package/dist/init-2V34DVRQ.js +37 -0
- package/dist/mcp-T2GRTEX5.js +255 -0
- package/dist/open-2QSZKKUG.js +1259 -0
- package/dist/program-V2USHGXN.js +148 -0
- package/dist/review-R3R2J5BJ.js +115 -0
- package/dist/rules-4FXJUCXB.js +83 -0
- package/dist/security-PI4LXCOB.js +175 -0
- package/dist/staged-check-HHIBKKMR.js +500 -0
- package/dist/status-6M73WX5I.js +75 -0
- package/dist/sync-3ZNJDSSU.js +216 -0
- package/dist/watch-USN5CQIV.js +121 -0
- package/dist/web/assets/{Editor-CL6A82dQ.js → Editor-BI56-HX5.js} +1 -1
- package/dist/web/assets/{abnfDiagram-O67JEVCF-BuFfjTfx.js → abnfDiagram-O67JEVCF-y_9px2ob.js} +1 -1
- package/dist/web/assets/architecture-7GRP2DOG-DyxkwYiW.js +1 -0
- package/dist/web/assets/{architectureDiagram-NJMV4G6O-BTsv87pA.js → architectureDiagram-NJMV4G6O-lB6fcVzU.js} +1 -1
- package/dist/web/assets/{blockDiagram-BEXU5L5S-CNXqyKIx.js → blockDiagram-BEXU5L5S-DcM5pEjM.js} +1 -1
- package/dist/web/assets/{c4Diagram-YGBWAQC7-kksFXQoJ.js → c4Diagram-YGBWAQC7-CJgqxTY2.js} +1 -1
- package/dist/web/assets/channel-BvDD7AMO.js +1 -0
- package/dist/web/assets/{chunk-3FUC2YCW-BY99XYBs.js → chunk-3FUC2YCW-B8l_VuWR.js} +1 -1
- package/dist/web/assets/{chunk-5DYCD2WN-h-PRThMP.js → chunk-5DYCD2WN-CZecgNhf.js} +1 -1
- package/dist/web/assets/{chunk-742MDFTN-BIxfyBUj.js → chunk-742MDFTN-BeZ7P5jB.js} +1 -1
- package/dist/web/assets/{chunk-7INBJB4K-DZtctDdk.js → chunk-7INBJB4K-IKy0pr5m.js} +1 -1
- package/dist/web/assets/{chunk-7M6MHVWA-BX9fUUbL.js → chunk-7M6MHVWA-Dg_QqJEX.js} +1 -1
- package/dist/web/assets/{chunk-7PRAP22T-X1s3e81n.js → chunk-7PRAP22T-DqQNS8oq.js} +1 -1
- package/dist/web/assets/{chunk-GTNCS2PH-Bh8eluU-.js → chunk-GTNCS2PH-x4sM51nJ.js} +1 -1
- package/dist/web/assets/{chunk-GWA4HPMP-D1KATAi0.js → chunk-GWA4HPMP-CE5GcwVN.js} +1 -1
- package/dist/web/assets/{chunk-MBY4JIJT-CEErv5kP.js → chunk-MBY4JIJT-DA_D1hjF.js} +1 -1
- package/dist/web/assets/{chunk-NETBCI7D-BXiH4aPa.js → chunk-NETBCI7D-CeJ3XBZ2.js} +1 -1
- package/dist/web/assets/{chunk-O7XYJQB3-Dede62yi.js → chunk-O7XYJQB3-BH2gESvO.js} +1 -1
- package/dist/web/assets/{chunk-UA2S7LBM-KZ9aWRTa.js → chunk-UA2S7LBM-BWr0xCux.js} +1 -1
- package/dist/web/assets/{chunk-WEXAMYUT-xf-3L2zU.js → chunk-WEXAMYUT-B4QwUZPM.js} +1 -1
- package/dist/web/assets/{chunk-Z7XXMR3K-DLpRdZ8n.js → chunk-Z7XXMR3K-BxcA-y5B.js} +1 -1
- package/dist/web/assets/{chunk-ZIGJFQKS-BdJ0_J-U.js → chunk-ZIGJFQKS-BZYvP63G.js} +1 -1
- package/dist/web/assets/{classDiagram-v2-NBCMYWYE-C5VzGDGq.js → classDiagram-v2-NBCMYWYE-BS3P_NXb.js} +1 -1
- package/dist/web/assets/{cynefin-OW5HDTMX-BqOgbE7U.js → cynefin-OW5HDTMX-BALD4Pve.js} +1 -1
- package/dist/web/assets/{cynefinDiagram-VND7K2PF-CCC_feG5.js → cynefinDiagram-VND7K2PF-BM2y4W6d.js} +1 -1
- package/dist/web/assets/{dagre-6A5THRUB-SLP-94sd.js → dagre-6A5THRUB-PTfOrIdF.js} +1 -1
- package/dist/web/assets/{diagram-22UHCM2B-DpHwEBYM.js → diagram-22UHCM2B-CpXEHhUl.js} +1 -1
- package/dist/web/assets/{diagram-3UASUU5V-iGFwuMEk.js → diagram-3UASUU5V-DPHfXzr6.js} +1 -1
- package/dist/web/assets/{diagram-ATOU4E4O-Csx9hj0z.js → diagram-ATOU4E4O-DMBNXvAC.js} +1 -1
- package/dist/web/assets/{diagram-CDSNMT55-yGKrLRO5.js → diagram-CDSNMT55-CDLe1M7G.js} +1 -1
- package/dist/web/assets/{diagram-MLGK6HIB-mDpCormD.js → diagram-MLGK6HIB-D6L8oE7j.js} +1 -1
- package/dist/web/assets/{diagram-MPIPVDR6-BJHdatrF.js → diagram-MPIPVDR6-CP-S7rrQ.js} +1 -1
- package/dist/web/assets/{ebnfDiagram-ZINNZB2B-ClJbCBBu.js → ebnfDiagram-ZINNZB2B-CkUc63TK.js} +1 -1
- package/dist/web/assets/{elk-276RUBZZ-C5tFZMYm.js → elk-276RUBZZ-C1CAJLH_.js} +1 -1
- package/dist/web/assets/{erDiagram-OPXOYQCR-u7_UFZot.js → erDiagram-OPXOYQCR-DXBnaTHm.js} +1 -1
- package/dist/web/assets/eventmodeling-NTZA5JFV-cLIzvgDp.js +1 -0
- package/dist/web/assets/flowDiagram-KWPJA3E3-D7Zq63VQ.js +1 -0
- package/dist/web/assets/{ganttDiagram-FUAMR5RP-B4hrLcLf.js → ganttDiagram-FUAMR5RP-BVm8SiGg.js} +1 -1
- package/dist/web/assets/{gitGraph-4MIJSDKK-Dxx-Bl-U.js → gitGraph-4MIJSDKK-Dm7xBrW0.js} +1 -1
- package/dist/web/assets/{gitGraphDiagram-X574FWY7-DKjDV5Kr.js → gitGraphDiagram-X574FWY7-D_PIKKhx.js} +1 -1
- package/dist/web/assets/index-CeOIBpu2.js +45 -0
- package/dist/web/assets/{info-A6RAGUB7-CgqIdgQA.js → info-A6RAGUB7-CLGrx8pn.js} +1 -1
- package/dist/web/assets/{infoDiagram-VRGFBTTK-D-qjWkwy.js → infoDiagram-VRGFBTTK-BlBjaKm7.js} +1 -1
- package/dist/web/assets/{ishikawaDiagram-OU5B5YK6-CzpqV6WN.js → ishikawaDiagram-OU5B5YK6-Kxe7GGS3.js} +1 -1
- package/dist/web/assets/{journeyDiagram-ZHPQQLJL-BBnOUDzw.js → journeyDiagram-ZHPQQLJL-wCMoHK4M.js} +1 -1
- package/dist/web/assets/{kanban-definition-PNTS6WVX-Di9sTFB1.js → kanban-definition-PNTS6WVX-BxdCz9Ko.js} +1 -1
- package/dist/web/assets/{line-B8ehGiwF.js → line-Zf11FnWF.js} +1 -1
- package/dist/web/assets/{mermaid-parser.core-DWsT24e5.js → mermaid-parser.core-BvFFklev.js} +3 -3
- package/dist/web/assets/{mermaid.core-DzYpaVzI.js → mermaid.core-Cd_Ssti9.js} +4 -4
- package/dist/web/assets/{mindmap-definition-NLK3R4M7-CxagBsH3.js → mindmap-definition-NLK3R4M7-BGPQl-GY.js} +1 -1
- package/dist/web/assets/{packet-AYTQ26CC-CmxbS0qf.js → packet-AYTQ26CC-6lI3cEX_.js} +1 -1
- package/dist/web/assets/{pegDiagram-GJSIUBJH-_3jnD3q8.js → pegDiagram-GJSIUBJH-BPIjlSAj.js} +1 -1
- package/dist/web/assets/{pie-WAS4IAKB-DppCWOqP.js → pie-WAS4IAKB-D6Dzj3Ja.js} +1 -1
- package/dist/web/assets/{pieDiagram-5QR66LMP-DTVThTqz.js → pieDiagram-5QR66LMP-DtA-vZmv.js} +1 -1
- package/dist/web/assets/{quadrantDiagram-O4NWA36T-BJ_OFnht.js → quadrantDiagram-O4NWA36T-EettyqQn.js} +1 -1
- package/dist/web/assets/{radar-RG4KPBEZ-B6quSMjs.js → radar-RG4KPBEZ-xmRc3Dl8.js} +1 -1
- package/dist/web/assets/{railroad-74A4TZTK-CErU7RG3.js → railroad-74A4TZTK-BLB7dhOn.js} +1 -1
- package/dist/web/assets/railroad-abnf-HS5TGJTU-DBFym6g8.js +1 -0
- package/dist/web/assets/railroad-ebnf-LZEXJU2U-CkG28ig8.js +1 -0
- package/dist/web/assets/railroad-peg-WCYAUIDC-Df_Ifaad.js +1 -0
- package/dist/web/assets/{railroadDiagram-XR7U4H2S-Zu0N_D-D.js → railroadDiagram-XR7U4H2S-PBw4We6b.js} +1 -1
- package/dist/web/assets/{requirementDiagram-PLB6GJNP-Bl6CN3ul.js → requirementDiagram-PLB6GJNP-DjQpaUFA.js} +1 -1
- package/dist/web/assets/{sankeyDiagram-IPEJSGJF-DdpKzZV8.js → sankeyDiagram-IPEJSGJF-CBW-_AoF.js} +1 -1
- package/dist/web/assets/{sequenceDiagram-PO4LG4MO-BwUqrl9F.js → sequenceDiagram-PO4LG4MO-DEoPYqY9.js} +1 -1
- package/dist/web/assets/{stateDiagram-v2-GCMORJYK-C3vZGpAi.js → stateDiagram-v2-GCMORJYK-UZq5rPud.js} +1 -1
- package/dist/web/assets/{swimlanes-2SLR337P-BjoMa2HW.js → swimlanes-2SLR337P-CACfuXJR.js} +1 -1
- package/dist/web/assets/swimlanesDiagram-TC7HE7FX-CDSrqdgx.js +8 -0
- package/dist/web/assets/{timeline-definition-EJHVYXUP-0apcf2l2.js → timeline-definition-EJHVYXUP-CYJl7mP-.js} +1 -1
- package/dist/web/assets/{treeView-Q6P3EWNA-BOPWzyg3.js → treeView-Q6P3EWNA-DtZ5nkPQ.js} +1 -1
- package/dist/web/assets/{treemap-WGGIJYW6-CC6rU6dD.js → treemap-WGGIJYW6-m49GDM-M.js} +1 -1
- package/dist/web/assets/{usecaseDiagram-POWQR4AR-BFclVNBG.js → usecaseDiagram-POWQR4AR-C2Vg20UK.js} +1 -1
- package/dist/web/assets/{vennDiagram-UO4OBE2U-D2XPv-zb.js → vennDiagram-UO4OBE2U-C07v5OGI.js} +1 -1
- package/dist/web/assets/{wardley-WFR3VGLG-Btz6ID8P.js → wardley-WFR3VGLG-C9Z7EZtz.js} +1 -1
- package/dist/web/assets/{wardleyDiagram-VNRHLVJA-DFYPvGpS.js → wardleyDiagram-VNRHLVJA-DdA8CcSC.js} +1 -1
- package/dist/web/assets/{xychartDiagram-PMCCYNJV-DMkQD-sV.js → xychartDiagram-PMCCYNJV-C9EZw07b.js} +1 -1
- package/dist/web/index.html +1 -1
- package/package.json +5 -2
- package/dist/web/assets/architecture-7GRP2DOG-CGSEE8po.js +0 -1
- package/dist/web/assets/channel-Dneho6u-.js +0 -1
- package/dist/web/assets/eventmodeling-NTZA5JFV-CA-vzJb3.js +0 -1
- package/dist/web/assets/flowDiagram-KWPJA3E3-Ca_1cbbS.js +0 -1
- package/dist/web/assets/index-s6lwoj84.js +0 -45
- package/dist/web/assets/railroad-abnf-HS5TGJTU-CWsEvTRR.js +0 -1
- package/dist/web/assets/railroad-ebnf-LZEXJU2U-Cyq9ELNn.js +0 -1
- package/dist/web/assets/railroad-peg-WCYAUIDC-BX1hI1hV.js +0 -1
- package/dist/web/assets/swimlanesDiagram-TC7HE7FX-BGNz1HGG.js +0 -8
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
formatContext,
|
|
4
|
+
getRelevantContext,
|
|
5
|
+
graphSummary,
|
|
6
|
+
refreshGraph
|
|
7
|
+
} from "./chunk-CXUTYCZX.js";
|
|
8
|
+
import "./chunk-3IS2X2Z7.js";
|
|
9
|
+
import {
|
|
10
|
+
bullet,
|
|
11
|
+
c,
|
|
12
|
+
dim,
|
|
13
|
+
heading,
|
|
14
|
+
isJson,
|
|
15
|
+
json,
|
|
16
|
+
line,
|
|
17
|
+
relativeTime,
|
|
18
|
+
spinner,
|
|
19
|
+
sym
|
|
20
|
+
} from "./chunk-Z6QWMJLK.js";
|
|
21
|
+
import {
|
|
22
|
+
requireProjectRoot
|
|
23
|
+
} from "./chunk-XFN7UZCS.js";
|
|
24
|
+
import "./chunk-KBO7XRBW.js";
|
|
25
|
+
import {
|
|
26
|
+
loadGraph,
|
|
27
|
+
neighbors
|
|
28
|
+
} from "./chunk-PDFQ5BFG.js";
|
|
29
|
+
import "./chunk-PANVPNYF.js";
|
|
30
|
+
import "./chunk-ELKFRTZT.js";
|
|
31
|
+
import "./chunk-PVCIGUIT.js";
|
|
32
|
+
import "./chunk-OLPSEQS5.js";
|
|
33
|
+
import "./chunk-JCGDR4UV.js";
|
|
34
|
+
import "./chunk-673EPYYH.js";
|
|
35
|
+
import "./chunk-FQEGEVLY.js";
|
|
36
|
+
import "./chunk-2DY4PUR4.js";
|
|
37
|
+
import "./chunk-IQQBAWSM.js";
|
|
38
|
+
import {
|
|
39
|
+
AthenaError
|
|
40
|
+
} from "./chunk-AD4OZCU2.js";
|
|
41
|
+
import "./chunk-XW3MLHI2.js";
|
|
42
|
+
import "./chunk-EUPETUWA.js";
|
|
43
|
+
|
|
44
|
+
// src/cli/commands/context.ts
|
|
45
|
+
async function contextCommand(task, opts) {
|
|
46
|
+
const root = await requireProjectRoot(opts);
|
|
47
|
+
const maxChars = opts.maxChars ? Number(opts.maxChars) : void 0;
|
|
48
|
+
if (maxChars !== void 0 && (!Number.isInteger(maxChars) || maxChars < 500)) throw new AthenaError("--max-chars must be an integer of at least 500");
|
|
49
|
+
const ctx = await getRelevantContext(root, task, { maxChars, buildGraph: true, signal: opts.signal });
|
|
50
|
+
if (isJson()) {
|
|
51
|
+
json(ctx);
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
if (opts.full) {
|
|
55
|
+
line(formatContext(ctx));
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
heading(`Context for: ${task}`);
|
|
59
|
+
line();
|
|
60
|
+
heading("Documents to read");
|
|
61
|
+
for (const a of ctx.areas) bullet(`${c.bold(a.id)} ${dim(`\u2014 ${a.why.join("; ")}`)}`);
|
|
62
|
+
if (ctx.mentionedFiles.length) {
|
|
63
|
+
line();
|
|
64
|
+
heading("Files named in the task");
|
|
65
|
+
for (const f of ctx.mentionedFiles) line(` ${dim(f)}`);
|
|
66
|
+
}
|
|
67
|
+
if (ctx.graphNodes.length) {
|
|
68
|
+
line();
|
|
69
|
+
heading("Related code (project graph)");
|
|
70
|
+
for (const n of ctx.graphNodes.slice(0, 12)) line(` ${dim(`${n.kind}:`)} ${n.name}${n.path ? dim(` (${n.path})`) : ""}`);
|
|
71
|
+
if (ctx.graphNodes.length > 12) line(dim(` +${ctx.graphNodes.length - 12} more`));
|
|
72
|
+
}
|
|
73
|
+
line();
|
|
74
|
+
heading("Sections selected");
|
|
75
|
+
for (const s of ctx.sections) line(` ${dim(`${s.file} \u2192`)} ${s.section}`);
|
|
76
|
+
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" : ""}`));
|
|
78
|
+
line(dim("Use --full to print the context an agent would read, or --json for tooling."));
|
|
79
|
+
}
|
|
80
|
+
async function graphCommand(opts) {
|
|
81
|
+
const root = await requireProjectRoot(opts);
|
|
82
|
+
if (opts.build) {
|
|
83
|
+
const sp = spinner("Building project graph...");
|
|
84
|
+
try {
|
|
85
|
+
const graph2 = await refreshGraph(root, { signal: opts.signal });
|
|
86
|
+
sp.succeed(`Graph built: ${graph2.stats.nodes} nodes, ${graph2.stats.edges} relationships`);
|
|
87
|
+
} catch (err) {
|
|
88
|
+
sp.stop();
|
|
89
|
+
throw err;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
const graph = await loadGraph(root);
|
|
93
|
+
if (!graph) throw new AthenaError("No project graph yet.", "Run `athena graph --build`.");
|
|
94
|
+
if (opts.node) {
|
|
95
|
+
const hood = neighbors(graph, opts.node) ?? neighbors(graph, graph.nodes.find((n) => n.name === opts.node || n.path === opts.node)?.id ?? "");
|
|
96
|
+
if (!hood) throw new AthenaError(`No graph node matches "${opts.node}".`, "Use `athena graph --search <term>` to find one.");
|
|
97
|
+
if (isJson()) {
|
|
98
|
+
json(hood);
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
heading(`${hood.node.kind}: ${hood.node.name}`);
|
|
102
|
+
if (hood.node.path) line(dim(hood.node.path));
|
|
103
|
+
line();
|
|
104
|
+
for (const e of hood.edges) line(` ${e.direction === "out" ? sym.arrow : "\u2190"} ${dim(e.edge.kind)} ${e.other.kind}: ${e.other.name}${e.other.path ? dim(` (${e.other.path})`) : ""}`);
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
const q = opts.search?.toLowerCase();
|
|
108
|
+
const nodes = graph.nodes.filter((n) => (!opts.kind || n.kind === opts.kind) && (!q || `${n.name} ${n.path ?? ""}`.toLowerCase().includes(q)));
|
|
109
|
+
if (isJson()) {
|
|
110
|
+
json({ stats: graph.stats, builtAt: graph.builtAt, nodes: nodes.slice(0, 200) });
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
heading("Project graph");
|
|
114
|
+
line(dim(`Built ${relativeTime(graph.builtAt)} \xB7 ${graph.stats.nodes} nodes \xB7 ${graph.stats.edges} relationships`));
|
|
115
|
+
line();
|
|
116
|
+
for (const [kind, count] of Object.entries(graph.stats.byKind).sort((a, b) => b[1] - a[1])) line(` ${String(count).padStart(5)} ${kind}`);
|
|
117
|
+
if (q || opts.kind) {
|
|
118
|
+
line();
|
|
119
|
+
heading(`Matching nodes (${nodes.length})`);
|
|
120
|
+
for (const n of nodes.slice(0, 30)) line(` ${dim(`${n.kind}:`)} ${n.name}${n.path ? dim(` (${n.path})`) : ""}`);
|
|
121
|
+
if (nodes.length > 30) line(dim(` +${nodes.length - 30} more`));
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
async function architectureCommand(opts) {
|
|
125
|
+
const root = await requireProjectRoot(opts);
|
|
126
|
+
const summary = await graphSummary(root);
|
|
127
|
+
if (isJson()) {
|
|
128
|
+
json(summary);
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
if (!summary.built) {
|
|
132
|
+
line(dim("No project graph yet. Run `athena graph --build`."));
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
heading("Architecture (from the project graph)");
|
|
136
|
+
line(dim(`Built ${relativeTime(summary.builtAt)}`));
|
|
137
|
+
line();
|
|
138
|
+
for (const [kind, count] of Object.entries(summary.stats.byKind).sort((a, b) => b[1] - a[1])) line(` ${String(count).padStart(5)} ${kind}`);
|
|
139
|
+
line();
|
|
140
|
+
line(dim("See .athena/architecture.md for the written architecture, and `athena graph --search <term>` to explore."));
|
|
141
|
+
}
|
|
142
|
+
export {
|
|
143
|
+
architectureCommand,
|
|
144
|
+
contextCommand,
|
|
145
|
+
graphCommand
|
|
146
|
+
};
|
|
147
|
+
//# sourceMappingURL=context-AH5MFHRG.js.map
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
runDoctor
|
|
4
|
+
} from "./chunk-PR53DT7I.js";
|
|
5
|
+
import "./chunk-RXNRMIZP.js";
|
|
6
|
+
import "./chunk-VSYBC3VY.js";
|
|
7
|
+
import "./chunk-3IS2X2Z7.js";
|
|
8
|
+
import "./chunk-65TSRDQ3.js";
|
|
9
|
+
import {
|
|
10
|
+
c,
|
|
11
|
+
dim,
|
|
12
|
+
heading,
|
|
13
|
+
isJson,
|
|
14
|
+
json,
|
|
15
|
+
line,
|
|
16
|
+
sym
|
|
17
|
+
} from "./chunk-Z6QWMJLK.js";
|
|
18
|
+
import {
|
|
19
|
+
resolveCwd
|
|
20
|
+
} from "./chunk-XFN7UZCS.js";
|
|
21
|
+
import "./chunk-KBO7XRBW.js";
|
|
22
|
+
import "./chunk-2R6PXY6Z.js";
|
|
23
|
+
import "./chunk-PVCIGUIT.js";
|
|
24
|
+
import "./chunk-OLPSEQS5.js";
|
|
25
|
+
import "./chunk-JCGDR4UV.js";
|
|
26
|
+
import "./chunk-2RS6TA3D.js";
|
|
27
|
+
import "./chunk-GHFRQAYT.js";
|
|
28
|
+
import "./chunk-673EPYYH.js";
|
|
29
|
+
import "./chunk-FQEGEVLY.js";
|
|
30
|
+
import "./chunk-2DY4PUR4.js";
|
|
31
|
+
import "./chunk-IQQBAWSM.js";
|
|
32
|
+
import "./chunk-AD4OZCU2.js";
|
|
33
|
+
import "./chunk-INT3IGMQ.js";
|
|
34
|
+
import "./chunk-XW3MLHI2.js";
|
|
35
|
+
import "./chunk-EUPETUWA.js";
|
|
36
|
+
|
|
37
|
+
// src/cli/commands/doctor.ts
|
|
38
|
+
async function doctorCommand(opts) {
|
|
39
|
+
const cwd = await resolveCwd(opts);
|
|
40
|
+
const { checks } = await runDoctor(cwd);
|
|
41
|
+
const errors = checks.filter((c2) => c2.level === "error").length;
|
|
42
|
+
if (isJson()) {
|
|
43
|
+
json({ ok: errors === 0, checks });
|
|
44
|
+
return errors ? 1 : 0;
|
|
45
|
+
}
|
|
46
|
+
heading("Athena Doctor");
|
|
47
|
+
line();
|
|
48
|
+
for (const c2 of checks) {
|
|
49
|
+
const icon = c2.level === "ok" ? c.green(sym.ok) : c2.level === "warn" ? c.yellow(sym.warn) : c2.level === "error" ? c.red(sym.err) : c.dim(sym.ring);
|
|
50
|
+
line(`${icon} ${c.bold(c2.area)} ${dim("\u2014")} ${c2.message}`);
|
|
51
|
+
if (c2.hint) line(` ${dim(c2.hint)}`);
|
|
52
|
+
}
|
|
53
|
+
line();
|
|
54
|
+
const warns = checks.filter((c2) => c2.level === "warn").length;
|
|
55
|
+
if (errors) line(c.red(`${errors} problem${errors === 1 ? "" : "s"} found.`));
|
|
56
|
+
else line(c.green(`Athena is ready.${warns ? dim(` (${warns} warning${warns === 1 ? "" : "s"})`) : ""}`));
|
|
57
|
+
return errors ? 1 : 0;
|
|
58
|
+
}
|
|
59
|
+
export {
|
|
60
|
+
doctorCommand
|
|
61
|
+
};
|
|
62
|
+
//# sourceMappingURL=doctor-RSJMLE2P.js.map
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
appendEvent
|
|
4
|
+
} from "./chunk-65TSRDQ3.js";
|
|
5
|
+
import {
|
|
6
|
+
findProjectRoot
|
|
7
|
+
} from "./chunk-KBO7XRBW.js";
|
|
8
|
+
import "./chunk-JCGDR4UV.js";
|
|
9
|
+
import {
|
|
10
|
+
normalizeHookEvent
|
|
11
|
+
} from "./chunk-INT3IGMQ.js";
|
|
12
|
+
import "./chunk-XW3MLHI2.js";
|
|
13
|
+
import "./chunk-EUPETUWA.js";
|
|
14
|
+
|
|
15
|
+
// src/cli/commands/event.ts
|
|
16
|
+
import path from "path";
|
|
17
|
+
function parseEventArgs(args) {
|
|
18
|
+
const opts = {};
|
|
19
|
+
const valued = { "--agent": "agent", "--hook": "hook", "--cwd": "cwd", "-C": "cwd" };
|
|
20
|
+
const flags = /* @__PURE__ */ new Set(["--athena-hook", "--verbose-errors", "--json", "--quiet", "-q", "--no-color"]);
|
|
21
|
+
for (let i = 0; i < args.length; i++) {
|
|
22
|
+
const a = args[i];
|
|
23
|
+
const eq = a.startsWith("--") ? a.indexOf("=") : -1;
|
|
24
|
+
const name = eq > 0 ? a.slice(0, eq) : a;
|
|
25
|
+
const key = valued[name];
|
|
26
|
+
if (key) {
|
|
27
|
+
const value = eq > 0 ? a.slice(eq + 1) : args[++i];
|
|
28
|
+
if (value === void 0) return null;
|
|
29
|
+
opts[key] = value;
|
|
30
|
+
} else if (a.startsWith("-C") && a.length > 2) {
|
|
31
|
+
opts.cwd = a.slice(2);
|
|
32
|
+
} else if (flags.has(a)) {
|
|
33
|
+
if (a === "--verbose-errors") opts.verbose = true;
|
|
34
|
+
} else {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return opts;
|
|
39
|
+
}
|
|
40
|
+
var STDIN_TIMEOUT_MS = 2e3;
|
|
41
|
+
var MAX_PAYLOAD_BYTES = 256 * 1024;
|
|
42
|
+
async function readStdin() {
|
|
43
|
+
if (process.stdin.isTTY) return "";
|
|
44
|
+
return new Promise((resolve) => {
|
|
45
|
+
let data = "";
|
|
46
|
+
let done = false;
|
|
47
|
+
const finish = () => {
|
|
48
|
+
if (done) return;
|
|
49
|
+
done = true;
|
|
50
|
+
process.stdin.removeAllListeners();
|
|
51
|
+
resolve(data);
|
|
52
|
+
};
|
|
53
|
+
const timer = setTimeout(finish, STDIN_TIMEOUT_MS);
|
|
54
|
+
timer.unref();
|
|
55
|
+
process.stdin.setEncoding("utf8");
|
|
56
|
+
process.stdin.on("data", (chunk) => {
|
|
57
|
+
data += chunk;
|
|
58
|
+
if (data.length > MAX_PAYLOAD_BYTES) finish();
|
|
59
|
+
});
|
|
60
|
+
process.stdin.on("end", () => {
|
|
61
|
+
clearTimeout(timer);
|
|
62
|
+
finish();
|
|
63
|
+
});
|
|
64
|
+
process.stdin.on("error", () => {
|
|
65
|
+
clearTimeout(timer);
|
|
66
|
+
finish();
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
async function eventCommand(opts) {
|
|
71
|
+
try {
|
|
72
|
+
const raw = await readStdin();
|
|
73
|
+
let payload = {};
|
|
74
|
+
if (raw.trim().startsWith("{")) {
|
|
75
|
+
try {
|
|
76
|
+
payload = JSON.parse(raw);
|
|
77
|
+
} catch {
|
|
78
|
+
payload = {};
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
const cwdCandidates = [opts.cwd, typeof payload.cwd === "string" ? payload.cwd : void 0, Array.isArray(payload.workspace_roots) ? payload.workspace_roots.find((x) => typeof x === "string") : void 0, process.cwd()];
|
|
82
|
+
let root = null;
|
|
83
|
+
for (const c of cwdCandidates) {
|
|
84
|
+
if (!c) continue;
|
|
85
|
+
root = await findProjectRoot(path.resolve(c));
|
|
86
|
+
if (root) break;
|
|
87
|
+
}
|
|
88
|
+
if (!root) return;
|
|
89
|
+
const event = normalizeHookEvent(opts.agent ?? "unknown", opts.hook ?? "", payload);
|
|
90
|
+
if (!event) return;
|
|
91
|
+
await appendEvent(root, event);
|
|
92
|
+
} catch (err) {
|
|
93
|
+
if (opts.verbose) process.stderr.write(`athena event: ${err.message}
|
|
94
|
+
`);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
export {
|
|
98
|
+
eventCommand,
|
|
99
|
+
parseEventArgs
|
|
100
|
+
};
|
|
101
|
+
//# sourceMappingURL=event-TNT6CQZR.js.map
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
dim,
|
|
4
|
+
info,
|
|
5
|
+
isJson,
|
|
6
|
+
isQuiet,
|
|
7
|
+
json,
|
|
8
|
+
line,
|
|
9
|
+
ok,
|
|
10
|
+
warn
|
|
11
|
+
} from "./chunk-Z6QWMJLK.js";
|
|
12
|
+
import {
|
|
13
|
+
requireProjectRoot
|
|
14
|
+
} from "./chunk-XFN7UZCS.js";
|
|
15
|
+
import "./chunk-KBO7XRBW.js";
|
|
16
|
+
import {
|
|
17
|
+
git
|
|
18
|
+
} from "./chunk-OLPSEQS5.js";
|
|
19
|
+
import {
|
|
20
|
+
hookCommand
|
|
21
|
+
} from "./chunk-GHFRQAYT.js";
|
|
22
|
+
import {
|
|
23
|
+
readTextIfExists
|
|
24
|
+
} from "./chunk-IQQBAWSM.js";
|
|
25
|
+
import {
|
|
26
|
+
AthenaError,
|
|
27
|
+
EXIT,
|
|
28
|
+
conflict
|
|
29
|
+
} from "./chunk-AD4OZCU2.js";
|
|
30
|
+
import "./chunk-EUPETUWA.js";
|
|
31
|
+
|
|
32
|
+
// src/cli/commands/git-hook.ts
|
|
33
|
+
import path2 from "path";
|
|
34
|
+
|
|
35
|
+
// src/services/git-hook.ts
|
|
36
|
+
import { promises as fs } from "fs";
|
|
37
|
+
import path from "path";
|
|
38
|
+
var HOOK_START = "# athena:start";
|
|
39
|
+
var HOOK_END = "# athena:end";
|
|
40
|
+
var HOOK_MANAGER_COMMAND = "npx --no-install athena sync --check --staged";
|
|
41
|
+
var SHELL_SHEBANG = /^#!\s*(?:\/usr\/bin\/env\s+)?(?:\/usr\/local\/bin\/|\/usr\/bin\/|\/bin\/)?(?:sh|bash|dash|zsh|ksh)(?:\s|$)/;
|
|
42
|
+
var HOOK_MANAGERS = [
|
|
43
|
+
{ name: "husky", pattern: /husky/i },
|
|
44
|
+
{ name: "lefthook", pattern: /lefthook/i },
|
|
45
|
+
{ name: "pre-commit", pattern: /pre-commit\.com|INSTALL_PYTHON|pre_commit/ },
|
|
46
|
+
{ name: "simple-git-hooks", pattern: /simple-git-hooks/i },
|
|
47
|
+
{ name: "overcommit", pattern: /overcommit/i }
|
|
48
|
+
];
|
|
49
|
+
async function locateHook(projectRoot) {
|
|
50
|
+
const top = await git(projectRoot, ["rev-parse", "--show-toplevel"]);
|
|
51
|
+
if (!top.ok || !top.stdout.trim()) throw new AthenaError("`athena git-hook` needs a Git repository.", "Run `git init` first, or use `athena sync --check` in your own tooling.");
|
|
52
|
+
const topLevel = await fs.realpath(top.stdout.trim());
|
|
53
|
+
const hooks = await git(topLevel, ["rev-parse", "--git-path", "hooks"]);
|
|
54
|
+
if (!hooks.ok || !hooks.stdout.trim()) throw new AthenaError("Could not find the Git hooks directory.");
|
|
55
|
+
const hooksDir = path.resolve(topLevel, hooks.stdout.trim());
|
|
56
|
+
const projectPrefix = path.relative(topLevel, await fs.realpath(projectRoot)).split(path.sep).join("/");
|
|
57
|
+
return { topLevel, hooksDir, hookFile: path.join(hooksDir, "pre-commit"), projectPrefix };
|
|
58
|
+
}
|
|
59
|
+
function shQuote(s) {
|
|
60
|
+
return `'${s.replace(/'/g, `'\\''`)}'`;
|
|
61
|
+
}
|
|
62
|
+
function renderHookBlock(opts) {
|
|
63
|
+
const cmd = opts.command ?? hookCommand();
|
|
64
|
+
const probe = cmd.split(/\s+/)[0];
|
|
65
|
+
const cwdArg = opts.projectPrefix ? ` -C ${shQuote(opts.projectPrefix)}` : "";
|
|
66
|
+
const athena = `${cmd} --no-color${cwdArg}`;
|
|
67
|
+
const lines = [
|
|
68
|
+
`${HOOK_START} (added by \`athena git-hook install\`; remove with \`athena git-hook uninstall\`)`,
|
|
69
|
+
`if command -v ${probe} >/dev/null 2>&1; then`,
|
|
70
|
+
" athena_rc=0",
|
|
71
|
+
` athena_out=$(${athena} sync --check --staged --quiet 2>&1) || athena_rc=$?`,
|
|
72
|
+
' if [ "$athena_rc" -eq 3 ]; then',
|
|
73
|
+
" echo 'athena: no Athena knowledge to check (not initialized, or .athena/ is not committed); skipping the knowledge check.' >&2",
|
|
74
|
+
' elif [ "$athena_rc" -ne 0 ]; then',
|
|
75
|
+
` printf '%s\\n' "$athena_out" >&2`,
|
|
76
|
+
" echo 'athena: commit blocked: staged .athena/ knowledge is out of date. Run `athena sync`, stage .athena/ and commit again (or skip once with `git commit --no-verify`).' >&2",
|
|
77
|
+
" exit 1",
|
|
78
|
+
" fi"
|
|
79
|
+
];
|
|
80
|
+
if (opts.review) {
|
|
81
|
+
lines.push(
|
|
82
|
+
" athena_rc=0",
|
|
83
|
+
` athena_out=$(${athena} review --staged --no-sync 2>&1) || athena_rc=$?`,
|
|
84
|
+
' if [ "$athena_rc" -eq 1 ]; then',
|
|
85
|
+
` printf '%s\\n' "$athena_out" >&2`,
|
|
86
|
+
" echo 'athena: commit blocked: `athena review` found blockers (possible secrets or env files). Fix them, or skip once with `git commit --no-verify`.' >&2",
|
|
87
|
+
" exit 1",
|
|
88
|
+
' elif [ "$athena_rc" -ne 0 ] && [ "$athena_rc" -ne 3 ]; then',
|
|
89
|
+
` printf '%s\\n' "$athena_out" >&2`,
|
|
90
|
+
" echo 'athena: commit blocked: `athena review` could not check the staged changes. Fix the error above, or skip once with `git commit --no-verify`.' >&2",
|
|
91
|
+
" exit 1",
|
|
92
|
+
" fi"
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
lines.push("else", ` echo 'athena: \`${probe}\` not found on PATH; skipping Athena pre-commit checks.' >&2`, "fi", HOOK_END);
|
|
96
|
+
return `${lines.join("\n")}
|
|
97
|
+
`;
|
|
98
|
+
}
|
|
99
|
+
function parseHook(text) {
|
|
100
|
+
const start = text.indexOf(`${HOOK_START}`);
|
|
101
|
+
if (start < 0) return null;
|
|
102
|
+
const lineStart = text.lastIndexOf("\n", start) + 1;
|
|
103
|
+
const endIdx = text.indexOf(HOOK_END, start);
|
|
104
|
+
if (endIdx < 0) return null;
|
|
105
|
+
let blockEnd = endIdx + HOOK_END.length;
|
|
106
|
+
if (text[blockEnd] === "\n") blockEnd++;
|
|
107
|
+
return { before: text.slice(0, lineStart), block: text.slice(lineStart, blockEnd), after: text.slice(blockEnd) };
|
|
108
|
+
}
|
|
109
|
+
function detectManager(loc, text) {
|
|
110
|
+
const rel2 = path.relative(loc.topLevel, loc.hooksDir).split(path.sep);
|
|
111
|
+
if (rel2.includes(".husky")) return "husky";
|
|
112
|
+
if (text) {
|
|
113
|
+
for (const m of HOOK_MANAGERS) if (m.pattern.test(text)) return m.name;
|
|
114
|
+
}
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
var NEW_FILE_HEADER = "#!/bin/sh\n";
|
|
118
|
+
async function hookStatus(projectRoot) {
|
|
119
|
+
const loc = await locateHook(projectRoot);
|
|
120
|
+
const text = await readTextIfExists(loc.hookFile);
|
|
121
|
+
const parsed = text ? parseHook(text) : null;
|
|
122
|
+
return {
|
|
123
|
+
...loc,
|
|
124
|
+
installed: Boolean(parsed),
|
|
125
|
+
review: Boolean(parsed?.block.includes(" review ")),
|
|
126
|
+
staged: Boolean(parsed?.block.includes(" sync --check --staged")),
|
|
127
|
+
ownsFile: Boolean(parsed && `${parsed.before}${parsed.after}`.trim() === NEW_FILE_HEADER.trim()),
|
|
128
|
+
manager: detectManager(loc, text && parsed ? `${parsed.before}${parsed.after}` : text)
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
async function installHook(projectRoot, opts = {}) {
|
|
132
|
+
const loc = await locateHook(projectRoot);
|
|
133
|
+
const block = renderHookBlock({ projectPrefix: loc.projectPrefix, review: Boolean(opts.review) });
|
|
134
|
+
const text = await readTextIfExists(loc.hookFile);
|
|
135
|
+
let next;
|
|
136
|
+
let action;
|
|
137
|
+
const parsed = text ? parseHook(text) : null;
|
|
138
|
+
if (text === null) {
|
|
139
|
+
const manager = detectManager(loc, null);
|
|
140
|
+
if (manager) throw managedError(manager);
|
|
141
|
+
next = `${NEW_FILE_HEADER}
|
|
142
|
+
${block}`;
|
|
143
|
+
action = "created";
|
|
144
|
+
} else if (parsed) {
|
|
145
|
+
next = `${parsed.before}${block}${parsed.after}`;
|
|
146
|
+
action = next === text ? "unchanged" : "updated";
|
|
147
|
+
} else {
|
|
148
|
+
const manager = detectManager(loc, text);
|
|
149
|
+
if (manager) throw managedError(manager);
|
|
150
|
+
const firstLine = text.split("\n", 1)[0];
|
|
151
|
+
if (!SHELL_SHEBANG.test(firstLine)) {
|
|
152
|
+
throw conflict(
|
|
153
|
+
`${path.relative(loc.topLevel, loc.hookFile) || loc.hookFile} already exists and is not a shell script, so Athena will not modify it.`,
|
|
154
|
+
`Add this command to your pre-commit hook yourself: ${HOOK_MANAGER_COMMAND}`
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
const rest = text.slice(firstLine.length + 1);
|
|
158
|
+
next = `${firstLine}
|
|
159
|
+
${block}
|
|
160
|
+
${rest}`;
|
|
161
|
+
action = "added-to-existing";
|
|
162
|
+
}
|
|
163
|
+
if (action !== "unchanged") {
|
|
164
|
+
await fs.mkdir(loc.hooksDir, { recursive: true });
|
|
165
|
+
await fs.writeFile(loc.hookFile, next, "utf8");
|
|
166
|
+
}
|
|
167
|
+
await fs.chmod(loc.hookFile, 493);
|
|
168
|
+
return { action, status: await hookStatus(projectRoot) };
|
|
169
|
+
}
|
|
170
|
+
async function uninstallHook(projectRoot) {
|
|
171
|
+
const loc = await locateHook(projectRoot);
|
|
172
|
+
const text = await readTextIfExists(loc.hookFile);
|
|
173
|
+
const parsed = text ? parseHook(text) : null;
|
|
174
|
+
if (!parsed) return { removed: false, deletedFile: false, status: await hookStatus(projectRoot) };
|
|
175
|
+
let rest = parsed.after;
|
|
176
|
+
if (rest.startsWith("\n")) rest = rest.slice(1);
|
|
177
|
+
const remaining = `${parsed.before}${rest}`;
|
|
178
|
+
let deletedFile = false;
|
|
179
|
+
if (!remaining.trim() || remaining.trim() === NEW_FILE_HEADER.trim()) {
|
|
180
|
+
await fs.rm(loc.hookFile, { force: true });
|
|
181
|
+
deletedFile = true;
|
|
182
|
+
} else {
|
|
183
|
+
await fs.writeFile(loc.hookFile, remaining, "utf8");
|
|
184
|
+
}
|
|
185
|
+
return { removed: true, deletedFile, status: await hookStatus(projectRoot) };
|
|
186
|
+
}
|
|
187
|
+
function managedError(manager) {
|
|
188
|
+
return conflict(
|
|
189
|
+
`Git hooks in this repository are managed by ${manager}, so Athena will not write a hook file.`,
|
|
190
|
+
`Add this line to your ${manager} pre-commit configuration instead: ${HOOK_MANAGER_COMMAND}`
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// src/cli/commands/git-hook.ts
|
|
195
|
+
var rel = (s) => path2.relative(s.topLevel, s.hookFile).split(path2.sep).join("/") || s.hookFile;
|
|
196
|
+
function managerTip() {
|
|
197
|
+
line(dim(`Using husky, lefthook or pre-commit? Add \`${HOOK_MANAGER_COMMAND}\` to its pre-commit config instead.`));
|
|
198
|
+
}
|
|
199
|
+
async function gitHookInstallCommand(opts) {
|
|
200
|
+
const root = await requireProjectRoot(opts);
|
|
201
|
+
const { action, status } = await installHook(root, { review: opts.review });
|
|
202
|
+
if (isJson()) {
|
|
203
|
+
json({ action, ...status });
|
|
204
|
+
return EXIT.OK;
|
|
205
|
+
}
|
|
206
|
+
const what = status.review ? "knowledge check + review" : "knowledge check";
|
|
207
|
+
const message = {
|
|
208
|
+
created: `Installed the pre-commit hook (${what}) at ${rel(status)}`,
|
|
209
|
+
updated: `Updated Athena's block in ${rel(status)} (${what})`,
|
|
210
|
+
unchanged: `Pre-commit hook already installed at ${rel(status)} (${what})`,
|
|
211
|
+
"added-to-existing": `Added Athena's block to your existing ${rel(status)} (${what}); the rest of the hook is unchanged`
|
|
212
|
+
};
|
|
213
|
+
ok(message[action]);
|
|
214
|
+
info(dim("Commits are blocked when the staged .athena/ knowledge is out of date for the staged code (untracked and unstaged files are ignored). Teammates without Athena installed are not blocked."));
|
|
215
|
+
if (!isQuiet()) managerTip();
|
|
216
|
+
return EXIT.OK;
|
|
217
|
+
}
|
|
218
|
+
async function gitHookUninstallCommand(opts) {
|
|
219
|
+
const root = await requireProjectRoot(opts);
|
|
220
|
+
const r = await uninstallHook(root);
|
|
221
|
+
if (isJson()) {
|
|
222
|
+
json({ removed: r.removed, deletedFile: r.deletedFile, ...r.status });
|
|
223
|
+
return EXIT.OK;
|
|
224
|
+
}
|
|
225
|
+
if (!r.removed) line(`No Athena pre-commit hook found in ${rel(r.status)}.`);
|
|
226
|
+
else if (r.deletedFile) ok(`Removed ${rel(r.status)}`);
|
|
227
|
+
else ok(`Removed Athena's block from ${rel(r.status)}; the rest of the hook is unchanged`);
|
|
228
|
+
return EXIT.OK;
|
|
229
|
+
}
|
|
230
|
+
async function gitHookStatusCommand(opts) {
|
|
231
|
+
const root = await requireProjectRoot(opts);
|
|
232
|
+
const s = await hookStatus(root);
|
|
233
|
+
if (isJson()) {
|
|
234
|
+
json(s);
|
|
235
|
+
return EXIT.OK;
|
|
236
|
+
}
|
|
237
|
+
if (s.installed) {
|
|
238
|
+
ok(`Installed in ${rel(s)} (${s.review ? "knowledge check + review" : "knowledge check"}${s.ownsFile ? "" : "; shared with your own hook"})`);
|
|
239
|
+
if (!s.staged) warn("This hook checks the working tree, so untracked or unstaged files can block commits. Run `athena git-hook install` to check only what is staged.");
|
|
240
|
+
} else {
|
|
241
|
+
line(`Not installed ${dim(`(${rel(s)})`)}`);
|
|
242
|
+
if (s.manager) line(dim(`Hooks here are managed by ${s.manager}: add \`${HOOK_MANAGER_COMMAND}\` to its pre-commit config.`));
|
|
243
|
+
else line(dim("Run `athena git-hook install` (add `--review` to also block commits with secrets or env files)."));
|
|
244
|
+
}
|
|
245
|
+
return EXIT.OK;
|
|
246
|
+
}
|
|
247
|
+
export {
|
|
248
|
+
gitHookInstallCommand,
|
|
249
|
+
gitHookStatusCommand,
|
|
250
|
+
gitHookUninstallCommand
|
|
251
|
+
};
|
|
252
|
+
//# sourceMappingURL=git-hook-YZNZGAAP.js.map
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
initCommand,
|
|
4
|
+
parseAgentsOption,
|
|
5
|
+
printSummary,
|
|
6
|
+
runWithProgress,
|
|
7
|
+
summarize
|
|
8
|
+
} from "./chunk-DOQMAZL5.js";
|
|
9
|
+
import "./chunk-SHKXELUX.js";
|
|
10
|
+
import "./chunk-Z6QWMJLK.js";
|
|
11
|
+
import "./chunk-XFN7UZCS.js";
|
|
12
|
+
import "./chunk-KBO7XRBW.js";
|
|
13
|
+
import "./chunk-SJOOXO34.js";
|
|
14
|
+
import "./chunk-PANVPNYF.js";
|
|
15
|
+
import "./chunk-ELKFRTZT.js";
|
|
16
|
+
import "./chunk-2R6PXY6Z.js";
|
|
17
|
+
import "./chunk-PVCIGUIT.js";
|
|
18
|
+
import "./chunk-OLPSEQS5.js";
|
|
19
|
+
import "./chunk-JCGDR4UV.js";
|
|
20
|
+
import "./chunk-2RS6TA3D.js";
|
|
21
|
+
import "./chunk-GHFRQAYT.js";
|
|
22
|
+
import "./chunk-673EPYYH.js";
|
|
23
|
+
import "./chunk-FQEGEVLY.js";
|
|
24
|
+
import "./chunk-2DY4PUR4.js";
|
|
25
|
+
import "./chunk-IQQBAWSM.js";
|
|
26
|
+
import "./chunk-AD4OZCU2.js";
|
|
27
|
+
import "./chunk-INT3IGMQ.js";
|
|
28
|
+
import "./chunk-XW3MLHI2.js";
|
|
29
|
+
import "./chunk-EUPETUWA.js";
|
|
30
|
+
export {
|
|
31
|
+
initCommand,
|
|
32
|
+
parseAgentsOption,
|
|
33
|
+
printSummary,
|
|
34
|
+
runWithProgress,
|
|
35
|
+
summarize
|
|
36
|
+
};
|
|
37
|
+
//# sourceMappingURL=init-2V34DVRQ.js.map
|