agentix-cli 0.13.0 → 0.14.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/README.md +50 -493
- package/dist/{agent-5KIMJI3F.js → agent-DW3NYIIL.js} +2 -2
- package/dist/board-dashboard-6TKE6NMV.js +1435 -0
- package/dist/board-dashboard-6TKE6NMV.js.map +1 -0
- package/dist/chunk-6U2XOQHU.js +7 -0
- package/dist/chunk-6U2XOQHU.js.map +1 -0
- package/dist/chunk-DYOBFJLX.js +11 -0
- package/dist/chunk-DYOBFJLX.js.map +1 -0
- package/dist/chunk-ITZEVXZ4.js +2 -0
- package/dist/chunk-ITZEVXZ4.js.map +1 -0
- package/dist/chunk-M33CB2H4.js +6 -0
- package/dist/chunk-M33CB2H4.js.map +1 -0
- package/dist/chunk-NJR5WF5E.js +5 -0
- package/dist/chunk-NJR5WF5E.js.map +1 -0
- package/dist/chunk-O72LPMBR.js +12 -0
- package/dist/chunk-O72LPMBR.js.map +1 -0
- package/dist/chunk-RB73FZXJ.js +133 -0
- package/dist/chunk-RB73FZXJ.js.map +1 -0
- package/dist/{chunk-VH23CDHL.js → chunk-UPT2UMF6.js} +42 -40
- package/dist/chunk-UPT2UMF6.js.map +1 -0
- package/dist/{chunk-D6EDMQRV.js → chunk-XVYMZ4M7.js} +3 -3
- package/dist/cli.js +54 -48
- package/dist/cli.js.map +1 -1
- package/dist/config-7QJ2QJIC.js +2 -0
- package/dist/config-mutator-GAEVGHDD.js +2 -0
- package/dist/index.d.ts +670 -69
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/registry-YVAG4EO5.js +2 -0
- package/dist/registry-YVAG4EO5.js.map +1 -0
- package/dist/{usage-dashboard-2TJQBFSH.js → usage-dashboard-M7AFIGMJ.js} +2 -2
- package/package.json +9 -1
- package/dist/chunk-34UAFPK4.js +0 -10
- package/dist/chunk-34UAFPK4.js.map +0 -1
- package/dist/chunk-CJ45Y2IR.js +0 -12
- package/dist/chunk-CJ45Y2IR.js.map +0 -1
- package/dist/chunk-T25UEXVK.js +0 -126
- package/dist/chunk-T25UEXVK.js.map +0 -1
- package/dist/chunk-VH23CDHL.js.map +0 -1
- package/dist/chunk-WJ6ZF6EZ.js +0 -6
- package/dist/chunk-WJ6ZF6EZ.js.map +0 -1
- package/dist/config-HAD5E4YX.js +0 -2
- package/dist/registry-CDWY7CLL.js +0 -2
- /package/dist/{agent-5KIMJI3F.js.map → agent-DW3NYIIL.js.map} +0 -0
- /package/dist/{chunk-D6EDMQRV.js.map → chunk-XVYMZ4M7.js.map} +0 -0
- /package/dist/{config-HAD5E4YX.js.map → config-7QJ2QJIC.js.map} +0 -0
- /package/dist/{registry-CDWY7CLL.js.map → config-mutator-GAEVGHDD.js.map} +0 -0
- /package/dist/{usage-dashboard-2TJQBFSH.js.map → usage-dashboard-M7AFIGMJ.js.map} +0 -0
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{g as a,h as b,i as c}from"./chunk-UPT2UMF6.js";import"./chunk-HI24KAEY.js";import"./chunk-DYOBFJLX.js";import"./chunk-ZRYBSI5G.js";import"./chunk-QOYAX2FT.js";import"./chunk-4YCH6IZV.js";export{c as AgentRegistry,b as getGlobalRegistry,a as setGlobalRegistry};
|
|
2
|
+
//# sourceMappingURL=registry-YVAG4EO5.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{a as p}from"./chunk-
|
|
1
|
+
import{a as p}from"./chunk-DYOBFJLX.js";import"./chunk-4YCH6IZV.js";import{createServer as b}from"http";import{readdirSync as v}from"fs";function y(s=4201){let n=new p;b(async(i,e)=>{let t=new URL(i.url||"/",`http://localhost:${s}`),o=t.pathname;if(e.setHeader("Access-Control-Allow-Origin","*"),o==="/api/usage"){let c=t.searchParams.get("from")||"",r=t.searchParams.get("to")||"",l=w(n,c,r);e.writeHead(200,{"Content-Type":"application/json"}),e.end(JSON.stringify(l));return}e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(C())}).listen(s,()=>{console.log(`
|
|
2
2
|
Usage dashboard: http://localhost:${s}
|
|
3
3
|
`)})}function w(s,n,d){let i=s.dir,e=[];try{for(let t of v(i)){if(!t.endsWith(".json"))continue;let o=t.replace(".json","");n&&o<n||d&&o>d||e.push(o)}}catch{return[]}return e.sort(),e.map(t=>{let o=s.getDate(t);if(!o)return null;let c=0,r=0,l=0,h=0,u=0,f=0,x={};for(let[g,a]of Object.entries(o.agents)){let m=p.calculateCost(a);c+=a.tasks,r+=a.inputTokens||0,l+=a.outputTokens||0,h+=a.cacheReadTokens||0,u+=a.cacheCreateTokens||0,f+=m,x[g]={tasks:a.tasks,cost:m,input:a.inputTokens||0,output:a.outputTokens||0,cacheRead:a.cacheReadTokens||0,cacheCreate:a.cacheCreateTokens||0,model:a.model}}return{date:t,tasks:c,input:r,output:l,cacheRead:h,cacheCreate:u,cost:f,agents:x}}).filter(t=>t!==null&&t.tasks>0)}function C(){return`<!DOCTYPE html>
|
|
4
4
|
<html lang="en">
|
|
@@ -401,4 +401,4 @@ function renderTable() {
|
|
|
401
401
|
// Auto-load last 30 days
|
|
402
402
|
setRange(30);
|
|
403
403
|
`,O=y;export{O as default,y as startUsageDashboard};
|
|
404
|
-
//# sourceMappingURL=usage-dashboard-
|
|
404
|
+
//# sourceMappingURL=usage-dashboard-M7AFIGMJ.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agentix-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.0",
|
|
4
4
|
"description": "Self-hosted multi-agent orchestrator — routes Telegram, WhatsApp, crons, and A2A mesh tasks to Claude Code, OpenAI, or any LLM provider",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": {
|
|
@@ -55,6 +55,9 @@
|
|
|
55
55
|
"eval": "vitest run test/eval/",
|
|
56
56
|
"eval:track": "TRACK_SCORES=1 vitest run test/eval/real-data-eval.test.ts",
|
|
57
57
|
"usage:track": "tsx src/scripts/track-usage.ts",
|
|
58
|
+
"docs:dev": "vitepress dev docs",
|
|
59
|
+
"docs:build": "vitepress build docs",
|
|
60
|
+
"docs:preview": "vitepress preview docs",
|
|
58
61
|
"prepublishOnly": "npm run build"
|
|
59
62
|
},
|
|
60
63
|
"dependencies": {
|
|
@@ -62,6 +65,7 @@
|
|
|
62
65
|
"chalk": "5.2.0",
|
|
63
66
|
"commander": "^10.0.0",
|
|
64
67
|
"cosmiconfig": "^8.1.3",
|
|
68
|
+
"cronstrue": "^3.14.0",
|
|
65
69
|
"execa": "^7.0.0",
|
|
66
70
|
"fast-glob": "^3.3.2",
|
|
67
71
|
"fs-extra": "^11.2.0",
|
|
@@ -74,12 +78,16 @@
|
|
|
74
78
|
"devDependencies": {
|
|
75
79
|
"@types/fs-extra": "^11.0.1",
|
|
76
80
|
"@types/prompts": "^2.4.2",
|
|
81
|
+
"lucide-static": "^1.8.0",
|
|
82
|
+
"mermaid": "^11.14.0",
|
|
77
83
|
"prettier": "^3.0.0",
|
|
78
84
|
"rimraf": "^4.1.3",
|
|
79
85
|
"tsup": "^6.6.3",
|
|
80
86
|
"type-fest": "^3.8.0",
|
|
81
87
|
"typescript": "^4.9.3",
|
|
82
88
|
"vite-tsconfig-paths": "^4.3.1",
|
|
89
|
+
"vitepress": "^1.6.4",
|
|
90
|
+
"vitepress-plugin-mermaid": "^2.0.17",
|
|
83
91
|
"vitest": "^1.2.2"
|
|
84
92
|
},
|
|
85
93
|
"engines": {
|
package/dist/chunk-34UAFPK4.js
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import{readFileSync as R,writeFileSync as D,appendFileSync as S,existsSync as C,mkdirSync as _}from"fs";import{resolve as T}from"path";var y={"claude-opus":{input:15,output:75,cacheRead:1.5,cacheCreate:18.75},"claude-sonnet":{input:3,output:15,cacheRead:.3,cacheCreate:3.75},"claude-haiku":{input:.25,output:1.25,cacheRead:.025,cacheCreate:.3125}};function v(O){let t=O.toLowerCase();return t.includes("opus")?"claude-opus":t.includes("haiku")?"claude-haiku":"claude-sonnet"}var b=class{dir;cache=null;constructor(t=T(process.cwd(),".agentx/usage")){this.dir=t,_(this.dir,{recursive:!0})}static calculateCost(t){let o=v(t.model||"claude-sonnet"),n=y[o]||y["claude-sonnet"];return(t.inputTokens||0)/1e6*n.input+(t.outputTokens||0)/1e6*n.output+(t.cacheReadTokens||0)/1e6*n.cacheRead+(t.cacheCreateTokens||0)/1e6*n.cacheCreate}record(t,o,n,c,s,i,l){let e=this.today(),a=e.agents[t]||{tasks:0,inputTokens:0,outputTokens:0,cacheReadTokens:0,cacheCreateTokens:0,totalDuration:0,errors:0};a.tasks++,a.totalDuration+=o,l&&(a.model=l),n?(a.inputTokens+=n.inputTokens,a.outputTokens+=n.outputTokens,a.cacheReadTokens+=n.cacheReadTokens,a.cacheCreateTokens+=n.cacheCreateTokens):c!==void 0&&s!==void 0&&(a.inputTokens+=Math.ceil(c/4),a.outputTokens+=Math.ceil(s/4)),i&&a.errors++,e.agents[t]=a,this.save(e)}today(){let t=new Date().toISOString().slice(0,10);if(this.cache?.date===t)return this.cache;let o=this.filePath(t);if(C(o))try{return this.cache=JSON.parse(R(o,"utf-8")),this.cache}catch{}return this.cache={date:t,agents:{}},this.cache}getDate(t){let o=this.filePath(t);if(!C(o))return null;try{return JSON.parse(R(o,"utf-8"))}catch{return null}}generateDailyReport(t){let o=t||new Date().toISOString().slice(0,10),n=this.getDate(o);if(!n)return null;let c=0,s=0,i=0,l=0,e=0,a=0,g="",m=0,p={};for(let[k,h]of Object.entries(n.agents)){let d=b.calculateCost(h);p[k]=d,c+=h.tasks,s+=h.inputTokens||0,i+=h.outputTokens||0,l+=h.cacheReadTokens||0,e+=h.cacheCreateTokens||0,a+=d,d>m&&(m=d,g=k)}return{date:o,totalTasks:c,totalInput:s,totalOutput:i,totalCacheRead:l,totalCacheCreate:e,totalCost:a,topAgent:g,topCost:m,agentCosts:p}}appendToTokenCosts(t,o){let n=o||T(process.cwd(),".agentx/TOKEN_COSTS.md"),c=e=>e<.01?e.toFixed(4):e.toFixed(2),s=e=>e>=1e6?`${(e/1e6).toFixed(1)}M`:e>=1e3?`${(e/1e3).toFixed(0)}K`:String(e),i=Object.entries(t.agentCosts).sort(([,e],[,a])=>a-e).map(([e,a])=>`${e}: $${c(a)}`).join(", "),l=`| ${t.date} | ${t.totalTasks} | ${s(t.totalInput)} | ${s(t.totalOutput)} | ${s(t.totalCacheRead)} | ${s(t.totalCacheCreate)} | $${c(t.totalCost)} | ${i} |`;C(n)?S(n,l+`
|
|
2
|
-
`):D(n,`# Token Costs
|
|
3
|
-
|
|
4
|
-
Daily token cost tracking. Auto-appended at midnight (Africa/Tunis).
|
|
5
|
-
|
|
6
|
-
| Date | Tasks | Input | Output | Cache R | Cache W | Cost | Per Agent |
|
|
7
|
-
|------|-------|-------|--------|---------|---------|------|-----------|
|
|
8
|
-
`+l+`
|
|
9
|
-
`)}summary(t=7){let o=0,n=0,c=0,s=0,i=0,l=0,e=0,a={};for(let p=0;p<t;p++){let k=new Date(Date.now()-p*864e5).toISOString().slice(0,10),h=this.getDate(k);if(h)for(let[d,u]of Object.entries(h.agents)){let f=b.calculateCost(u);o+=u.tasks,n+=u.inputTokens||0,c+=u.outputTokens||0,s+=u.cacheReadTokens||0,i+=u.cacheCreateTokens||0,l+=u.errors,e+=f;let r=a[d]||{tasks:0,input:0,output:0,cacheRead:0,cacheCreate:0,total:0,avgDuration:0,totalDuration:0,cost:0};r.tasks+=u.tasks,r.input+=u.inputTokens||0,r.output+=u.outputTokens||0,r.cacheRead+=u.cacheReadTokens||0,r.cacheCreate+=u.cacheCreateTokens||0,r.total=r.input+r.output+r.cacheRead+r.cacheCreate,r.totalDuration+=u.totalDuration,r.avgDuration=r.totalDuration/r.tasks,r.cost+=f,u.model&&(r.model=u.model),a[d]=r}}let g=n+c+s+i,m=s+i>0?s/(s+i):0;return{totalTasks:o,totalTokens:g,totalInput:n,totalOutput:c,totalCacheRead:s,totalCacheCreate:i,cacheHitRatio:m,totalErrors:l,totalCost:e,byAgent:a}}filePath(t){return T(this.dir,`${t}.json`)}save(t){try{D(this.filePath(t.date),JSON.stringify(t,null,2))}catch{}}};export{b as a};
|
|
10
|
-
//# sourceMappingURL=chunk-34UAFPK4.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/daemon/token-tracker.ts"],"sourcesContent":["import { readFileSync, writeFileSync, appendFileSync, existsSync, mkdirSync } from \"fs\"\nimport { resolve } from \"path\"\n\n// --- Token usage tracker ---\n// Tracks token usage per agent per day with cache-aware cost calculation.\n// Persisted to .agentx/usage/{YYYY-MM-DD}.json\n\n// Anthropic pricing per million tokens (as of April 2026)\nexport const CACHE_AWARE_PRICING: Record<string, { input: number; output: number; cacheRead: number; cacheCreate: number }> = {\n \"claude-opus\": { input: 15, output: 75, cacheRead: 1.5, cacheCreate: 18.75 },\n \"claude-sonnet\": { input: 3, output: 15, cacheRead: 0.3, cacheCreate: 3.75 },\n \"claude-haiku\": { input: 0.25, output: 1.25, cacheRead: 0.025, cacheCreate: 0.3125 },\n}\n\nexport function getModelFamily(model: string): string {\n const lower = model.toLowerCase()\n if (lower.includes(\"opus\")) return \"claude-opus\"\n if (lower.includes(\"haiku\")) return \"claude-haiku\"\n return \"claude-sonnet\"\n}\n\nexport interface DailyUsage {\n date: string\n agents: Record<string, AgentUsage>\n}\n\nexport interface AgentUsage {\n tasks: number\n inputTokens: number\n outputTokens: number\n cacheReadTokens: number\n cacheCreateTokens: number\n totalDuration: number\n errors: number\n model?: string\n}\n\nexport interface DailyReport {\n date: string\n totalTasks: number\n totalInput: number\n totalOutput: number\n totalCacheRead: number\n totalCacheCreate: number\n totalCost: number\n topAgent: string\n topCost: number\n agentCosts: Record<string, number>\n}\n\nexport class TokenTracker {\n private dir: string\n private cache: DailyUsage | null = null\n\n constructor(baseDir: string = resolve(process.cwd(), \".agentx/usage\")) {\n this.dir = baseDir\n mkdirSync(this.dir, { recursive: true })\n }\n\n /**\n * Calculate cost for an agent's usage with cache-aware pricing.\n */\n static calculateCost(usage: AgentUsage): number {\n const family = getModelFamily(usage.model || \"claude-sonnet\")\n const pricing = CACHE_AWARE_PRICING[family] || CACHE_AWARE_PRICING[\"claude-sonnet\"]\n\n return (\n ((usage.inputTokens || 0) / 1_000_000) * pricing.input +\n ((usage.outputTokens || 0) / 1_000_000) * pricing.output +\n ((usage.cacheReadTokens || 0) / 1_000_000) * pricing.cacheRead +\n ((usage.cacheCreateTokens || 0) / 1_000_000) * pricing.cacheCreate\n )\n }\n\n /**\n * Record a task execution with real or estimated token counts.\n */\n record(\n agentId: string,\n duration: number,\n realUsage?: { inputTokens: number; outputTokens: number; cacheReadTokens: number; cacheCreateTokens: number },\n messageLength?: number,\n responseLength?: number,\n error?: boolean,\n model?: string,\n ): void {\n const daily = this.today()\n const agent = daily.agents[agentId] || {\n tasks: 0, inputTokens: 0, outputTokens: 0,\n cacheReadTokens: 0, cacheCreateTokens: 0, totalDuration: 0, errors: 0,\n }\n\n agent.tasks++\n agent.totalDuration += duration\n if (model) agent.model = model\n\n if (realUsage) {\n agent.inputTokens += realUsage.inputTokens\n agent.outputTokens += realUsage.outputTokens\n agent.cacheReadTokens += realUsage.cacheReadTokens\n agent.cacheCreateTokens += realUsage.cacheCreateTokens\n } else if (messageLength !== undefined && responseLength !== undefined) {\n agent.inputTokens += Math.ceil(messageLength / 4)\n agent.outputTokens += Math.ceil(responseLength / 4)\n }\n\n if (error) agent.errors++\n\n daily.agents[agentId] = agent\n this.save(daily)\n }\n\n /**\n * Get today's usage summary.\n */\n today(): DailyUsage {\n const date = new Date().toISOString().slice(0, 10)\n\n if (this.cache?.date === date) return this.cache\n\n const path = this.filePath(date)\n if (existsSync(path)) {\n try {\n this.cache = JSON.parse(readFileSync(path, \"utf-8\"))\n return this.cache!\n } catch {}\n }\n\n this.cache = { date, agents: {} }\n return this.cache\n }\n\n /**\n * Get usage for a specific date.\n */\n getDate(date: string): DailyUsage | null {\n const path = this.filePath(date)\n if (!existsSync(path)) return null\n try {\n return JSON.parse(readFileSync(path, \"utf-8\"))\n } catch {\n return null\n }\n }\n\n /**\n * Generate a daily cost report for a given date.\n */\n generateDailyReport(date?: string): DailyReport | null {\n const targetDate = date || new Date().toISOString().slice(0, 10)\n const usage = this.getDate(targetDate)\n if (!usage) return null\n\n let totalTasks = 0, totalInput = 0, totalOutput = 0\n let totalCacheRead = 0, totalCacheCreate = 0, totalCost = 0\n let topAgent = \"\", topCost = 0\n const agentCosts: Record<string, number> = {}\n\n for (const [id, agent] of Object.entries(usage.agents)) {\n const cost = TokenTracker.calculateCost(agent)\n agentCosts[id] = cost\n totalTasks += agent.tasks\n totalInput += agent.inputTokens || 0\n totalOutput += agent.outputTokens || 0\n totalCacheRead += agent.cacheReadTokens || 0\n totalCacheCreate += agent.cacheCreateTokens || 0\n totalCost += cost\n if (cost > topCost) { topCost = cost; topAgent = id }\n }\n\n return {\n date: targetDate, totalTasks, totalInput, totalOutput,\n totalCacheRead, totalCacheCreate, totalCost, topAgent, topCost, agentCosts,\n }\n }\n\n /**\n * Append a daily report row to TOKEN_COSTS.md.\n */\n appendToTokenCosts(report: DailyReport, filePath?: string): void {\n const file = filePath || resolve(process.cwd(), \".agentx/TOKEN_COSTS.md\")\n const fmt = (n: number) => n < 0.01 ? n.toFixed(4) : n.toFixed(2)\n const fmtTok = (n: number) =>\n n >= 1_000_000 ? `${(n / 1_000_000).toFixed(1)}M` :\n n >= 1_000 ? `${(n / 1_000).toFixed(0)}K` :\n String(n)\n\n const agentBreakdown = Object.entries(report.agentCosts)\n .sort(([, a], [, b]) => b - a)\n .map(([id, cost]) => `${id}: $${fmt(cost)}`)\n .join(\", \")\n\n const row = `| ${report.date} | ${report.totalTasks} | ${fmtTok(report.totalInput)} | ${fmtTok(report.totalOutput)} | ${fmtTok(report.totalCacheRead)} | ${fmtTok(report.totalCacheCreate)} | $${fmt(report.totalCost)} | ${agentBreakdown} |`\n\n if (!existsSync(file)) {\n const header =\n \"# Token Costs\\n\\n\" +\n \"Daily token cost tracking. Auto-appended at midnight (Africa/Tunis).\\n\\n\" +\n \"| Date | Tasks | Input | Output | Cache R | Cache W | Cost | Per Agent |\\n\" +\n \"|------|-------|-------|--------|---------|---------|------|-----------|\\n\"\n writeFileSync(file, header + row + \"\\n\")\n } else {\n appendFileSync(file, row + \"\\n\")\n }\n }\n\n /**\n * Get summary across last N days.\n */\n summary(days: number = 7): {\n totalTasks: number\n totalTokens: number\n totalInput: number\n totalOutput: number\n totalCacheRead: number\n totalCacheCreate: number\n cacheHitRatio: number\n totalErrors: number\n totalCost: number\n byAgent: Record<string, { tasks: number; input: number; output: number; cacheRead: number; cacheCreate: number; total: number; avgDuration: number; cost: number }>\n } {\n let totalTasks = 0\n let totalInput = 0\n let totalOutput = 0\n let totalCacheRead = 0\n let totalCacheCreate = 0\n let totalErrors = 0\n let totalCost = 0\n const byAgent: Record<string, { tasks: number; input: number; output: number; cacheRead: number; cacheCreate: number; total: number; avgDuration: number; totalDuration: number; cost: number; model?: string }> = {}\n\n for (let i = 0; i < days; i++) {\n const date = new Date(Date.now() - i * 86400_000).toISOString().slice(0, 10)\n const usage = this.getDate(date)\n if (!usage) continue\n\n for (const [id, agent] of Object.entries(usage.agents)) {\n const cost = TokenTracker.calculateCost(agent)\n totalTasks += agent.tasks\n totalInput += agent.inputTokens || 0\n totalOutput += agent.outputTokens || 0\n totalCacheRead += agent.cacheReadTokens || 0\n totalCacheCreate += agent.cacheCreateTokens || 0\n totalErrors += agent.errors\n totalCost += cost\n\n const existing = byAgent[id] || { tasks: 0, input: 0, output: 0, cacheRead: 0, cacheCreate: 0, total: 0, avgDuration: 0, totalDuration: 0, cost: 0 }\n existing.tasks += agent.tasks\n existing.input += agent.inputTokens || 0\n existing.output += agent.outputTokens || 0\n existing.cacheRead += agent.cacheReadTokens || 0\n existing.cacheCreate += agent.cacheCreateTokens || 0\n existing.total = existing.input + existing.output + existing.cacheRead + existing.cacheCreate\n existing.totalDuration += agent.totalDuration\n existing.avgDuration = existing.totalDuration / existing.tasks\n existing.cost += cost\n if (agent.model) existing.model = agent.model\n byAgent[id] = existing\n }\n }\n\n const totalTokens = totalInput + totalOutput + totalCacheRead + totalCacheCreate\n const cacheHitRatio = (totalCacheRead + totalCacheCreate) > 0\n ? totalCacheRead / (totalCacheRead + totalCacheCreate)\n : 0\n\n return { totalTasks, totalTokens, totalInput, totalOutput, totalCacheRead, totalCacheCreate, cacheHitRatio, totalErrors, totalCost, byAgent }\n }\n\n private filePath(date: string): string {\n return resolve(this.dir, `${date}.json`)\n }\n\n private save(usage: DailyUsage): void {\n try {\n writeFileSync(this.filePath(usage.date), JSON.stringify(usage, null, 2))\n } catch {}\n }\n}\n"],"mappings":"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","names":["readFileSync","writeFileSync","appendFileSync","existsSync","mkdirSync","resolve","CACHE_AWARE_PRICING","getModelFamily","model","lower","TokenTracker","baseDir","usage","family","pricing","agentId","duration","realUsage","messageLength","responseLength","error","daily","agent","date","path","targetDate","totalTasks","totalInput","totalOutput","totalCacheRead","totalCacheCreate","totalCost","topAgent","topCost","agentCosts","id","cost","report","filePath","file","fmt","n","fmtTok","agentBreakdown","a","b","row","days","totalErrors","byAgent","i","existing","totalTokens","cacheHitRatio"]}
|
package/dist/chunk-CJ45Y2IR.js
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import{a as c,b,d as w}from"./chunk-M7HKBG3V.js";import{e as m}from"./chunk-DSYKYZMT.js";import{z as l}from"zod";var d=["pre:generate","post:generate","pre:file-write","post:file-write","pre:prompt","post:response","pre:command","on:error","pre:tool-call","post:tool-call","pre:channel-message","post:channel-message","pre:a2a-task","pre:cron-run","post:cron-run"],H=["pre:generate","pre:file-write","pre:prompt","post:response","pre:command","pre:tool-call","pre:channel-message","post:channel-message","pre:a2a-task","pre:cron-run"],v=l.object({name:l.string(),type:l.enum(["command","prompt","script"]),command:l.string().optional(),prompt:l.string().optional(),provider:l.enum(["claude-code","claude","openai","ollama","custom"]).optional(),model:l.string().optional(),script:l.string().optional(),priority:l.number().default(100),enabled:l.boolean().default(!0)});var x={"claude-sonnet":{input:3,output:15},"claude-opus":{input:15,output:75},"claude-haiku":{input:.25,output:1.25}};function T(i){let o=i.toLowerCase();return o.includes("opus")?"claude-opus":o.includes("haiku")?"claude-haiku":"claude-sonnet"}var h=class{steps=[];models=new Map;recordStep(o,e,t,r){let n=T(e),s=x[n]||x["claude-sonnet"],p=t/1e6*s.input+r/1e6*s.output;this.steps.push({step:o,model:e,inputTokens:t,outputTokens:r,cost:p,timestamp:Date.now()});let a=this.models.get(e)||{inputTokens:0,outputTokens:0,cost:0,steps:0};a.inputTokens+=t,a.outputTokens+=r,a.cost+=p,a.steps++,this.models.set(e,a)}getSummary(){let o=0,e=0,t=0;for(let n of this.steps)o+=n.inputTokens,e+=n.outputTokens,t+=n.cost;let r={};for(let[n,s]of this.models)r[n]={...s};return{totalInputTokens:o,totalOutputTokens:e,totalTokens:o+e,totalCost:t,steps:[...this.steps],models:r}}reset(){this.steps=[],this.models.clear()}},E=new h;function C(i,o){let e=[];if(e.push(`# Session: ${i.id}`),e.push(""),e.push(`- **Created**: ${i.createdAt}`),e.push(`- **Updated**: ${i.updatedAt}`),e.push(`- **CWD**: ${i.cwd}`),e.push(`- **Messages**: ${i.messages.length}`),e.push(`- **Tokens**: ${i.tokensUsed.toLocaleString()}`),e.push(""),i.filesGenerated.length){e.push("## Files Generated"),e.push("");for(let t of i.filesGenerated)e.push(`- \`${t}\``);e.push("")}if(i.messages.length){e.push("## Conversation"),e.push("");for(let t of i.messages){if(t.role==="system")continue;let r=t.role==="user"?"**User**":"**Assistant**";e.push(`### ${r}`),e.push(""),t.role,e.push(t.content),e.push("")}}if(o){if(e.push("## Cost Summary"),e.push(""),e.push(`- **Total tokens**: ${o.totalTokens.toLocaleString()}`),e.push(` - Input: ${o.totalInputTokens.toLocaleString()}`),e.push(` - Output: ${o.totalOutputTokens.toLocaleString()}`),e.push(`- **Total cost**: $${o.totalCost.toFixed(4)}`),e.push(""),Object.keys(o.models).length){e.push("### Per Model"),e.push(""),e.push("| Model | Input | Output | Cost | Steps |"),e.push("|-------|-------|--------|------|-------|");for(let[t,r]of Object.entries(o.models))e.push(`| ${t} | ${r.inputTokens.toLocaleString()} | ${r.outputTokens.toLocaleString()} | $${r.cost.toFixed(4)} | ${r.steps} |`);e.push("")}if(o.steps.length){e.push("### Per Step"),e.push(""),e.push("| Step | Model | Input | Output | Cost |"),e.push("|------|-------|-------|--------|------|");for(let t of o.steps)e.push(`| ${t.step} | ${t.model} | ${t.inputTokens.toLocaleString()} | ${t.outputTokens.toLocaleString()} | $${t.cost.toFixed(4)} |`);e.push("")}}return e.join(`
|
|
2
|
-
`)}import{execa as O}from"execa";var k=class{hooks=new Map;register(o,e){if(!e.enabled)return;let t=this.createHandler(e),r={event:o,definition:e,handler:t},n=this.hooks.get(o)||[];n.push(r),n.sort((s,p)=>s.definition.priority-p.definition.priority),this.hooks.set(o,n)}async execute(o,e){let t=this.hooks.get(o);if(!t?.length)return{};let r=H.includes(o),n={};for(let s of t){let p=Date.now();try{let a=await s.handler({...e,...n}),u=Date.now()-p;if(a.modified&&(n={...n,...a.modified}),r&&a.blocked)return m.hook(s.definition.name,u,"blocked"),{blocked:!0,message:a.message||`Blocked by hook: ${s.definition.name}`,modified:n};m.hook(s.definition.name,u,"ok")}catch(a){let u=Date.now()-p;if(m.hook(s.definition.name,u,`error: ${a.message}`),c.warn(`Hook "${s.definition.name}" failed: ${a.message}`),r)return{blocked:!0,message:`Hook "${s.definition.name}" errored: ${a.message}`}}}return{modified:Object.keys(n).length?n:void 0}}has(o){return!!this.hooks.get(o)?.length}clear(){this.hooks.clear()}createHandler(o){switch(o.type){case"command":return this.createCommandHandler(o);case"script":return this.createScriptHandler(o);case"prompt":return this.createPromptHandler(o);default:throw new Error(`Unknown hook type: ${o.type}`)}}createCommandHandler(o){return async e=>{if(!o.command)return{};let t=o.command;t=t.replace(/\{\{(\w+)\}\}/g,(n,s)=>String(e[s]??""));let r=await O("sh",["-c",t],{cwd:e.cwd||process.cwd(),reject:!1,timeout:6e4,env:process.env});return r.exitCode!==0?{blocked:!0,message:r.stderr||r.stdout||`Command hook "${o.name}" failed`}:{}}}createScriptHandler(o){return async e=>{if(!o.script)return{};let r=await import(o.script.startsWith("/")?o.script:`${e.cwd||process.cwd()}/${o.script}`),n=r.default||r.handler||r;return typeof n=="function"?await n(e):{}}}createPromptHandler(o){return async e=>{if(!o.prompt)return{};let t=o.provider||b()?.provider||"claude-code",r=w();if(!r&&t!=="claude-code")return c.warn(`Prompt hook "${o.name}" skipped: no credentials available for provider "${t}"`),{};try{let{createProvider:n}=await import("./providers-G3WZ4RVJ.js"),s=n(t,r?.token),p=o.prompt;p=p.replace(/\{\{(\w+)\}\}/g,(M,$)=>String(e[$]??""));let a=`You are a hook validator for agentx. Analyze the following context and respond with ONLY a JSON object (no markdown, no code fences).
|
|
3
|
-
|
|
4
|
-
Response format:
|
|
5
|
-
{"action": "allow", "message": "optional explanation"}
|
|
6
|
-
OR
|
|
7
|
-
{"action": "block", "message": "reason for blocking"}
|
|
8
|
-
OR
|
|
9
|
-
{"action": "allow", "message": "optional", "modified": {"key": "new value"}}
|
|
10
|
-
|
|
11
|
-
The "modified" field is optional and can contain updated values to pass forward.`,y=(await s.generate([{role:"system",content:a},{role:"user",content:p}],{model:o.model,maxTokens:1024})).content.trim().match(/\{[\s\S]*\}/);if(!y)return c.warn(`Prompt hook "${o.name}": LLM response was not valid JSON, allowing`),{};let f=JSON.parse(y[0]);return f.action==="block"?{blocked:!0,message:f.message||`Blocked by prompt hook: ${o.name}`}:f.modified?{modified:f.modified}:{}}catch(n){return c.warn(`Prompt hook "${o.name}" failed: ${n.message}`),{}}}}};import{existsSync as S,readFileSync as R,readdirSync as D}from"fs";import g from"path";function U(i,o){j(i,o),N(i,o)}function j(i,o){let e=g.join(i,"agentx.config.json");if(S(e))try{let t=JSON.parse(R(e,"utf8"));if(!t.hooks)return;for(let[r,n]of Object.entries(t.hooks)){if(!d.includes(r)){c.warn(`Unknown hook event in config: ${r}`);continue}let s=r;if(Array.isArray(n))for(let p of n)try{let a=v.parse(p);o.register(s,a)}catch(a){c.warn(`Invalid hook definition for ${s}: ${a.message}`)}}}catch(t){c.warn(`Failed to load hooks from config: ${t.message}`)}}function N(i,o){let e=g.join(i,".agentx","hooks");if(S(e))try{let t=D(e).filter(r=>r.endsWith(".ts")||r.endsWith(".js")||r.endsWith(".mjs"));for(let r of t){let n=r.replace(/\.(ts|js|mjs)$/,"").split(".");if(n.length<2){c.warn(`Hook file "${r}" should be named <event>.<name>.<ext>`);continue}let s=n[0],p=n.slice(1).join("."),a=s.replace(/-/g,":");if(!d.includes(a)){let u=s.replace("-",":");if(!d.includes(u)){c.warn(`Unknown hook event in filename: ${r}`);continue}o.register(u,{name:p,type:"script",script:g.join(e,r),priority:100,enabled:!0});continue}o.register(a,{name:p,type:"script",script:g.join(e,r),priority:100,enabled:!0})}}catch(t){c.warn(`Failed to load hooks from directory: ${t.message}`)}}var se=new k;export{d as a,H as b,h as c,E as d,C as e,k as f,U as g,se as h};
|
|
12
|
-
//# sourceMappingURL=chunk-CJ45Y2IR.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/hooks/types.ts","../src/observability/tracker.ts","../src/observability/export.ts","../src/hooks/registry.ts","../src/hooks/loader.ts","../src/hooks/index.ts"],"sourcesContent":["import { z } from \"zod\"\n\n// --- Hook system types ---\n\nexport const HOOK_EVENTS = [\n \"pre:generate\",\n \"post:generate\",\n \"pre:file-write\",\n \"post:file-write\",\n \"pre:prompt\",\n \"post:response\",\n \"pre:command\",\n \"on:error\",\n \"pre:tool-call\",\n \"post:tool-call\",\n // Daemon events\n \"pre:channel-message\",\n \"post:channel-message\",\n \"pre:a2a-task\",\n \"pre:cron-run\",\n \"post:cron-run\",\n] as const\n\nexport type HookEvent = (typeof HOOK_EVENTS)[number]\n\n// Which hooks can block (return { blocked: true } to cancel the operation)\nexport const BLOCKING_EVENTS: HookEvent[] = [\n \"pre:generate\",\n \"pre:file-write\",\n \"pre:prompt\",\n \"post:response\",\n \"pre:command\",\n \"pre:tool-call\",\n // Daemon blocking events\n \"pre:channel-message\",\n \"post:channel-message\",\n \"pre:a2a-task\",\n \"pre:cron-run\",\n]\n\nexport type HookType = \"command\" | \"prompt\" | \"script\"\n\nexport const hookDefinitionSchema = z.object({\n name: z.string(),\n type: z.enum([\"command\", \"prompt\", \"script\"]),\n // For \"command\" type: shell command with {{variable}} interpolation\n command: z.string().optional(),\n // For \"prompt\" type: LLM prompt template\n prompt: z.string().optional(),\n // For \"prompt\" type: override provider/model for this hook\n provider: z.enum([\"claude-code\", \"claude\", \"openai\", \"ollama\", \"custom\"]).optional(),\n model: z.string().optional(),\n // For \"script\" type: path to JS/TS file exporting a handler\n script: z.string().optional(),\n // Hook priority (lower runs first, default 100)\n priority: z.number().default(100),\n // Whether this hook is enabled\n enabled: z.boolean().default(true),\n})\n\nexport type HookDefinition = z.infer<typeof hookDefinitionSchema>\n\nexport interface HookContext {\n event: HookEvent\n // Data varies by event\n task?: string\n file?: string\n fileContent?: string\n content?: string\n command?: string\n error?: Error\n cwd?: string\n [key: string]: unknown\n}\n\nexport interface HookResult {\n // If true, the operation is blocked/cancelled\n blocked?: boolean\n // Optional message explaining why it was blocked\n message?: string\n // Modified data to pass forward (e.g., modified file content)\n modified?: Record<string, unknown>\n}\n\nexport type HookHandler = (context: HookContext) => Promise<HookResult>\n","// --- Usage tracking: tokens, cost, per-step and per-model breakdown ---\n\nexport interface StepUsage {\n step: number\n model: string\n inputTokens: number\n outputTokens: number\n cost: number\n timestamp: number\n}\n\nexport interface ModelUsage {\n inputTokens: number\n outputTokens: number\n cost: number\n steps: number\n}\n\nexport interface UsageSummary {\n totalInputTokens: number\n totalOutputTokens: number\n totalTokens: number\n totalCost: number\n steps: StepUsage[]\n models: Record<string, ModelUsage>\n}\n\n// Cost per million tokens (input / output)\nconst MODEL_PRICING: Record<string, { input: number; output: number }> = {\n \"claude-sonnet\": { input: 3, output: 15 },\n \"claude-opus\": { input: 15, output: 75 },\n \"claude-haiku\": { input: 0.25, output: 1.25 },\n}\n\nfunction getModelFamily(model: string): string {\n const lower = model.toLowerCase()\n if (lower.includes(\"opus\")) return \"claude-opus\"\n if (lower.includes(\"haiku\")) return \"claude-haiku\"\n return \"claude-sonnet\" // default\n}\n\nexport class UsageTracker {\n private steps: StepUsage[] = []\n private models: Map<string, ModelUsage> = new Map()\n\n recordStep(\n step: number,\n model: string,\n inputTokens: number,\n outputTokens: number\n ): void {\n const family = getModelFamily(model)\n const pricing = MODEL_PRICING[family] || MODEL_PRICING[\"claude-sonnet\"]\n const cost =\n (inputTokens / 1_000_000) * pricing.input +\n (outputTokens / 1_000_000) * pricing.output\n\n this.steps.push({\n step,\n model,\n inputTokens,\n outputTokens,\n cost,\n timestamp: Date.now(),\n })\n\n const existing = this.models.get(model) || {\n inputTokens: 0,\n outputTokens: 0,\n cost: 0,\n steps: 0,\n }\n existing.inputTokens += inputTokens\n existing.outputTokens += outputTokens\n existing.cost += cost\n existing.steps++\n this.models.set(model, existing)\n }\n\n getSummary(): UsageSummary {\n let totalInputTokens = 0\n let totalOutputTokens = 0\n let totalCost = 0\n\n for (const step of this.steps) {\n totalInputTokens += step.inputTokens\n totalOutputTokens += step.outputTokens\n totalCost += step.cost\n }\n\n const models: Record<string, ModelUsage> = {}\n for (const [name, usage] of this.models) {\n models[name] = { ...usage }\n }\n\n return {\n totalInputTokens,\n totalOutputTokens,\n totalTokens: totalInputTokens + totalOutputTokens,\n totalCost,\n steps: [...this.steps],\n models,\n }\n }\n\n reset(): void {\n this.steps = []\n this.models.clear()\n }\n}\n\nexport const globalTracker = new UsageTracker()\n","// --- Session export: convert a session to readable markdown ---\n\nimport type { Session } from \"@/repl/session\"\nimport type { UsageSummary } from \"./tracker\"\n\nexport function exportSession(session: Session, usage?: UsageSummary): string {\n const lines: string[] = []\n\n // Header\n lines.push(`# Session: ${session.id}`)\n lines.push(\"\")\n lines.push(`- **Created**: ${session.createdAt}`)\n lines.push(`- **Updated**: ${session.updatedAt}`)\n lines.push(`- **CWD**: ${session.cwd}`)\n lines.push(`- **Messages**: ${session.messages.length}`)\n lines.push(`- **Tokens**: ${session.tokensUsed.toLocaleString()}`)\n lines.push(\"\")\n\n // Files generated\n if (session.filesGenerated.length) {\n lines.push(\"## Files Generated\")\n lines.push(\"\")\n for (const file of session.filesGenerated) {\n lines.push(`- \\`${file}\\``)\n }\n lines.push(\"\")\n }\n\n // Conversation\n if (session.messages.length) {\n lines.push(\"## Conversation\")\n lines.push(\"\")\n for (const msg of session.messages) {\n if (msg.role === \"system\") continue\n const label = msg.role === \"user\" ? \"**User**\" : \"**Assistant**\"\n lines.push(`### ${label}`)\n lines.push(\"\")\n if (msg.role === \"assistant\") {\n lines.push(msg.content)\n } else {\n lines.push(msg.content)\n }\n lines.push(\"\")\n }\n }\n\n // Cost summary\n if (usage) {\n lines.push(\"## Cost Summary\")\n lines.push(\"\")\n lines.push(`- **Total tokens**: ${usage.totalTokens.toLocaleString()}`)\n lines.push(` - Input: ${usage.totalInputTokens.toLocaleString()}`)\n lines.push(` - Output: ${usage.totalOutputTokens.toLocaleString()}`)\n lines.push(`- **Total cost**: $${usage.totalCost.toFixed(4)}`)\n lines.push(\"\")\n\n if (Object.keys(usage.models).length) {\n lines.push(\"### Per Model\")\n lines.push(\"\")\n lines.push(\"| Model | Input | Output | Cost | Steps |\")\n lines.push(\"|-------|-------|--------|------|-------|\")\n for (const [model, mu] of Object.entries(usage.models)) {\n lines.push(\n `| ${model} | ${mu.inputTokens.toLocaleString()} | ${mu.outputTokens.toLocaleString()} | $${mu.cost.toFixed(4)} | ${mu.steps} |`\n )\n }\n lines.push(\"\")\n }\n\n if (usage.steps.length) {\n lines.push(\"### Per Step\")\n lines.push(\"\")\n lines.push(\"| Step | Model | Input | Output | Cost |\")\n lines.push(\"|------|-------|-------|--------|------|\")\n for (const step of usage.steps) {\n lines.push(\n `| ${step.step} | ${step.model} | ${step.inputTokens.toLocaleString()} | ${step.outputTokens.toLocaleString()} | $${step.cost.toFixed(4)} |`\n )\n }\n lines.push(\"\")\n }\n }\n\n return lines.join(\"\\n\")\n}\n","import { execa } from \"execa\"\nimport type { HookEvent, HookDefinition, HookContext, HookResult, HookHandler } from \"./types\"\nimport { BLOCKING_EVENTS } from \"./types\"\nimport { logger } from \"@/utils/logger\"\nimport { debug } from \"@/observability\"\nimport { loadAuthConfig, resolveToken } from \"@/utils/auth-store\"\n\n// --- Hook Registry: registration, priority ordering, execution ---\n\ninterface RegisteredHook {\n event: HookEvent\n definition: HookDefinition\n handler: HookHandler\n}\n\nexport class HookRegistry {\n private hooks: Map<HookEvent, RegisteredHook[]> = new Map()\n\n /**\n * Register a hook for an event.\n */\n register(event: HookEvent, definition: HookDefinition): void {\n if (!definition.enabled) return\n\n const handler = this.createHandler(definition)\n const entry: RegisteredHook = { event, definition, handler }\n\n const existing = this.hooks.get(event) || []\n existing.push(entry)\n // Sort by priority (lower number = runs first)\n existing.sort((a, b) => a.definition.priority - b.definition.priority)\n this.hooks.set(event, existing)\n }\n\n /**\n * Execute all hooks for an event. Returns combined result.\n * For blocking events, stops at the first hook that returns { blocked: true }.\n */\n async execute(event: HookEvent, context: HookContext): Promise<HookResult> {\n const registered = this.hooks.get(event)\n if (!registered?.length) {\n return {}\n }\n\n const canBlock = BLOCKING_EVENTS.includes(event)\n let combinedModified: Record<string, unknown> = {}\n\n for (const hook of registered) {\n const start = Date.now()\n try {\n const result = await hook.handler({ ...context, ...combinedModified })\n const duration = Date.now() - start\n\n if (result.modified) {\n combinedModified = { ...combinedModified, ...result.modified }\n }\n\n if (canBlock && result.blocked) {\n debug.hook(hook.definition.name, duration, \"blocked\")\n return {\n blocked: true,\n message: result.message || `Blocked by hook: ${hook.definition.name}`,\n modified: combinedModified,\n }\n }\n\n debug.hook(hook.definition.name, duration, \"ok\")\n } catch (error: any) {\n const duration = Date.now() - start\n debug.hook(hook.definition.name, duration, `error: ${error.message}`)\n logger.warn(`Hook \"${hook.definition.name}\" failed: ${error.message}`)\n // Non-blocking hooks swallow errors; blocking hooks propagate\n if (canBlock) {\n return {\n blocked: true,\n message: `Hook \"${hook.definition.name}\" errored: ${error.message}`,\n }\n }\n }\n }\n\n return { modified: Object.keys(combinedModified).length ? combinedModified : undefined }\n }\n\n /**\n * Check if any hooks are registered for an event.\n */\n has(event: HookEvent): boolean {\n const registered = this.hooks.get(event)\n return !!registered?.length\n }\n\n /**\n * Clear all hooks (useful for testing).\n */\n clear(): void {\n this.hooks.clear()\n }\n\n /**\n * Create a HookHandler from a HookDefinition.\n */\n private createHandler(definition: HookDefinition): HookHandler {\n switch (definition.type) {\n case \"command\":\n return this.createCommandHandler(definition)\n case \"script\":\n return this.createScriptHandler(definition)\n case \"prompt\":\n return this.createPromptHandler(definition)\n default:\n throw new Error(`Unknown hook type: ${definition.type}`)\n }\n }\n\n /**\n * Command hook: runs a shell command with {{variable}} interpolation.\n * Exit code 0 = success, non-zero = blocked (for blocking events).\n */\n private createCommandHandler(definition: HookDefinition): HookHandler {\n return async (context: HookContext): Promise<HookResult> => {\n if (!definition.command) {\n return {}\n }\n\n // Interpolate {{variable}} placeholders\n let cmd = definition.command\n cmd = cmd.replace(/\\{\\{(\\w+)\\}\\}/g, (_match, key) => {\n return String(context[key] ?? \"\")\n })\n\n const result = await execa(\"sh\", [\"-c\", cmd], {\n cwd: context.cwd || process.cwd(),\n reject: false,\n timeout: 60_000,\n env: process.env,\n })\n\n if (result.exitCode !== 0) {\n return {\n blocked: true,\n message: result.stderr || result.stdout || `Command hook \"${definition.name}\" failed`,\n }\n }\n\n return {}\n }\n }\n\n /**\n * Script hook: imports and runs a JS/TS module that exports a handler function.\n */\n private createScriptHandler(definition: HookDefinition): HookHandler {\n return async (context: HookContext): Promise<HookResult> => {\n if (!definition.script) {\n return {}\n }\n\n const scriptPath = definition.script.startsWith(\"/\")\n ? definition.script\n : `${context.cwd || process.cwd()}/${definition.script}`\n\n const mod = await import(scriptPath)\n const handler = mod.default || mod.handler || mod\n\n if (typeof handler === \"function\") {\n return await handler(context)\n }\n\n return {}\n }\n }\n\n /**\n * Prompt hook: single-turn LLM call that can block or modify the operation.\n * The prompt template supports {{variable}} interpolation from hook context.\n * The LLM must respond with JSON: { \"action\": \"allow\"|\"block\", \"message\": \"...\", \"modified\": {...} }\n */\n private createPromptHandler(definition: HookDefinition): HookHandler {\n return async (context: HookContext): Promise<HookResult> => {\n if (!definition.prompt) {\n return {}\n }\n\n // Check credentials are available (don't prompt interactively)\n const providerName = definition.provider || loadAuthConfig()?.provider || \"claude-code\"\n const resolved = resolveToken()\n if (!resolved && providerName !== \"claude-code\") {\n logger.warn(\n `Prompt hook \"${definition.name}\" skipped: no credentials available for provider \"${providerName}\"`\n )\n return {}\n }\n\n try {\n // Lazy import to avoid circular deps\n const { createProvider } = await import(\"@/agent/providers\")\n const provider = createProvider(providerName as any, resolved?.token)\n\n // Interpolate {{variable}} placeholders in the prompt template\n let prompt = definition.prompt\n prompt = prompt.replace(/\\{\\{(\\w+)\\}\\}/g, (_match, key) => {\n return String(context[key] ?? \"\")\n })\n\n const systemPrompt = `You are a hook validator for agentx. Analyze the following context and respond with ONLY a JSON object (no markdown, no code fences).\n\nResponse format:\n{\"action\": \"allow\", \"message\": \"optional explanation\"}\nOR\n{\"action\": \"block\", \"message\": \"reason for blocking\"}\nOR\n{\"action\": \"allow\", \"message\": \"optional\", \"modified\": {\"key\": \"new value\"}}\n\nThe \"modified\" field is optional and can contain updated values to pass forward.`\n\n const result = await provider.generate(\n [\n { role: \"system\", content: systemPrompt },\n { role: \"user\", content: prompt },\n ],\n {\n model: definition.model,\n maxTokens: 1024,\n }\n )\n\n // Parse the LLM response as JSON\n const content = result.content.trim()\n // Try to extract JSON from the response (handle markdown fences)\n const jsonMatch = content.match(/\\{[\\s\\S]*\\}/)\n if (!jsonMatch) {\n logger.warn(`Prompt hook \"${definition.name}\": LLM response was not valid JSON, allowing`)\n return {}\n }\n\n const parsed = JSON.parse(jsonMatch[0])\n\n if (parsed.action === \"block\") {\n return {\n blocked: true,\n message: parsed.message || `Blocked by prompt hook: ${definition.name}`,\n }\n }\n\n if (parsed.modified) {\n return { modified: parsed.modified }\n }\n\n return {}\n } catch (error: any) {\n // Don't block on hook failures — log and continue\n logger.warn(`Prompt hook \"${definition.name}\" failed: ${error.message}`)\n return {}\n }\n }\n }\n}\n","import { existsSync, readFileSync, readdirSync } from \"fs\"\nimport path from \"path\"\nimport type { HookEvent, HookDefinition } from \"./types\"\nimport { HOOK_EVENTS, hookDefinitionSchema } from \"./types\"\nimport { HookRegistry } from \"./registry\"\nimport { logger } from \"@/utils/logger\"\n\n// --- Hook Loader: load hooks from config and .agentx/hooks/ ---\n\ninterface HooksConfig {\n hooks?: Partial<Record<HookEvent, HookDefinition[]>>\n}\n\n/**\n * Load hooks from agentx.config.json and .agentx/hooks/ directory.\n */\nexport function loadHooks(cwd: string, registry: HookRegistry): void {\n loadHooksFromConfig(cwd, registry)\n loadHooksFromDirectory(cwd, registry)\n}\n\n/**\n * Load hook definitions from agentx.config.json.\n */\nfunction loadHooksFromConfig(cwd: string, registry: HookRegistry): void {\n const configPath = path.join(cwd, \"agentx.config.json\")\n if (!existsSync(configPath)) return\n\n try {\n const raw = JSON.parse(readFileSync(configPath, \"utf8\")) as HooksConfig\n if (!raw.hooks) return\n\n for (const [eventName, definitions] of Object.entries(raw.hooks)) {\n if (!HOOK_EVENTS.includes(eventName as HookEvent)) {\n logger.warn(`Unknown hook event in config: ${eventName}`)\n continue\n }\n\n const event = eventName as HookEvent\n if (!Array.isArray(definitions)) continue\n\n for (const def of definitions) {\n try {\n const parsed = hookDefinitionSchema.parse(def)\n registry.register(event, parsed)\n } catch (error: any) {\n logger.warn(`Invalid hook definition for ${event}: ${error.message}`)\n }\n }\n }\n } catch (error: any) {\n logger.warn(`Failed to load hooks from config: ${error.message}`)\n }\n}\n\n/**\n * Load hook scripts from .agentx/hooks/ directory.\n * Files are named <event>.<name>.ts (e.g., pre-file-write.format.ts).\n */\nfunction loadHooksFromDirectory(cwd: string, registry: HookRegistry): void {\n const hooksDir = path.join(cwd, \".agentx\", \"hooks\")\n if (!existsSync(hooksDir)) return\n\n try {\n const files = readdirSync(hooksDir).filter(\n (f) => f.endsWith(\".ts\") || f.endsWith(\".js\") || f.endsWith(\".mjs\")\n )\n\n for (const file of files) {\n // Parse filename: <event>.<name>.<ext>\n // Event uses dashes in filename: pre-file-write → pre:file-write\n const parts = file.replace(/\\.(ts|js|mjs)$/, \"\").split(\".\")\n if (parts.length < 2) {\n logger.warn(`Hook file \"${file}\" should be named <event>.<name>.<ext>`)\n continue\n }\n\n const eventSlug = parts[0]\n const name = parts.slice(1).join(\".\")\n\n // Convert slug to event name: pre-file-write → pre:file-write\n const eventName = eventSlug.replace(/-/g, \":\") as HookEvent\n if (!HOOK_EVENTS.includes(eventName)) {\n // Try replacing first dash only: pre-generate → pre:generate\n const altEvent = eventSlug.replace(\"-\", \":\") as HookEvent\n if (!HOOK_EVENTS.includes(altEvent)) {\n logger.warn(`Unknown hook event in filename: ${file}`)\n continue\n }\n registry.register(altEvent, {\n name,\n type: \"script\",\n script: path.join(hooksDir, file),\n priority: 100,\n enabled: true,\n })\n continue\n }\n\n registry.register(eventName, {\n name,\n type: \"script\",\n script: path.join(hooksDir, file),\n priority: 100,\n enabled: true,\n })\n }\n } catch (error: any) {\n logger.warn(`Failed to load hooks from directory: ${error.message}`)\n }\n}\n","export { HookRegistry } from \"./registry\"\nexport { loadHooks } from \"./loader\"\nexport type { HookEvent, HookDefinition, HookContext, HookResult, HookHandler } from \"./types\"\nexport { HOOK_EVENTS, BLOCKING_EVENTS } from \"./types\"\n\nimport { HookRegistry } from \"./registry\"\n\n// Singleton hook registry for the CLI process\nexport const globalHooks = new HookRegistry()\n"],"mappings":"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","names":["z","HOOK_EVENTS","BLOCKING_EVENTS","hookDefinitionSchema","MODEL_PRICING","getModelFamily","model","lower","UsageTracker","step","inputTokens","outputTokens","family","pricing","cost","existing","totalInputTokens","totalOutputTokens","totalCost","models","name","usage","globalTracker","exportSession","session","usage","lines","file","msg","label","model","mu","step","execa","HookRegistry","event","definition","handler","entry","existing","a","b","context","registered","canBlock","BLOCKING_EVENTS","combinedModified","hook","start","result","duration","debug","error","logger","cmd","_match","key","execa","mod","providerName","loadAuthConfig","resolved","resolveToken","createProvider","provider","prompt","systemPrompt","jsonMatch","parsed","existsSync","readFileSync","readdirSync","path","loadHooks","cwd","registry","loadHooksFromConfig","loadHooksFromDirectory","configPath","path","existsSync","raw","readFileSync","eventName","definitions","HOOK_EVENTS","logger","event","def","parsed","hookDefinitionSchema","error","hooksDir","files","readdirSync","f","file","parts","eventSlug","name","altEvent","globalHooks","HookRegistry"]}
|