@axplusb/kepler 0.0.1 → 1.0.1
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 +82 -0
- package/package.json +36 -4
- package/pulse/app/activity/page.tsx +190 -0
- package/pulse/app/api/activity/route.ts +138 -0
- package/pulse/app/api/costs/route.ts +88 -0
- package/pulse/app/api/export/route.ts +77 -0
- package/pulse/app/api/history/route.ts +11 -0
- package/pulse/app/api/import/route.ts +31 -0
- package/pulse/app/api/memory/route.ts +52 -0
- package/pulse/app/api/plans/route.ts +9 -0
- package/pulse/app/api/projects/[slug]/route.ts +96 -0
- package/pulse/app/api/projects/route.ts +121 -0
- package/pulse/app/api/sessions/[id]/replay/route.ts +20 -0
- package/pulse/app/api/sessions/[id]/route.ts +31 -0
- package/pulse/app/api/sessions/route.ts +112 -0
- package/pulse/app/api/settings/route.ts +14 -0
- package/pulse/app/api/stats/route.ts +143 -0
- package/pulse/app/api/todos/route.ts +9 -0
- package/pulse/app/api/tools/route.ts +160 -0
- package/pulse/app/costs/page.tsx +179 -0
- package/pulse/app/export/page.tsx +465 -0
- package/pulse/app/favicon.ico +0 -0
- package/pulse/app/globals.css +263 -0
- package/pulse/app/help/page.tsx +142 -0
- package/pulse/app/history/page.tsx +157 -0
- package/pulse/app/layout.tsx +46 -0
- package/pulse/app/memory/page.tsx +365 -0
- package/pulse/app/overview-client.tsx +393 -0
- package/pulse/app/page.tsx +14 -0
- package/pulse/app/plans/page.tsx +308 -0
- package/pulse/app/projects/[slug]/page.tsx +390 -0
- package/pulse/app/projects/page.tsx +110 -0
- package/pulse/app/sessions/[id]/page.tsx +243 -0
- package/pulse/app/sessions/page.tsx +39 -0
- package/pulse/app/settings/page.tsx +188 -0
- package/pulse/app/todos/page.tsx +211 -0
- package/pulse/app/tools/page.tsx +249 -0
- package/pulse/cli.js +159 -0
- package/pulse/components/activity/day-of-week-chart.tsx +35 -0
- package/pulse/components/activity/streak-card.tsx +36 -0
- package/pulse/components/costs/cache-efficiency-panel.tsx +76 -0
- package/pulse/components/costs/cost-by-project-chart.tsx +48 -0
- package/pulse/components/costs/cost-over-time-chart.tsx +95 -0
- package/pulse/components/costs/model-token-table.tsx +60 -0
- package/pulse/components/global-search.tsx +193 -0
- package/pulse/components/keyboard-nav-provider.tsx +23 -0
- package/pulse/components/layout/bottom-nav.tsx +52 -0
- package/pulse/components/layout/client-layout.tsx +31 -0
- package/pulse/components/layout/sidebar-context.tsx +50 -0
- package/pulse/components/layout/sidebar.tsx +182 -0
- package/pulse/components/layout/top-bar.tsx +121 -0
- package/pulse/components/overview/activity-heatmap.tsx +107 -0
- package/pulse/components/overview/conversation-table.tsx +148 -0
- package/pulse/components/overview/model-breakdown-donut.tsx +95 -0
- package/pulse/components/overview/peak-hours-chart.tsx +87 -0
- package/pulse/components/overview/project-activity-donut.tsx +96 -0
- package/pulse/components/overview/stat-card.tsx +102 -0
- package/pulse/components/overview/usage-over-time-chart.tsx +166 -0
- package/pulse/components/projects/project-card.tsx +175 -0
- package/pulse/components/sessions/replay/assistant-markdown.tsx +94 -0
- package/pulse/components/sessions/replay/compaction-card.tsx +25 -0
- package/pulse/components/sessions/replay/session-sidebar.tsx +231 -0
- package/pulse/components/sessions/replay/token-accumulation-chart.tsx +98 -0
- package/pulse/components/sessions/replay/tool-call-badge.tsx +127 -0
- package/pulse/components/sessions/replay/turn-cards.tsx +220 -0
- package/pulse/components/sessions/replay/user-tool-result.tsx +158 -0
- package/pulse/components/sessions/session-badges.tsx +49 -0
- package/pulse/components/sessions/session-table.tsx +299 -0
- package/pulse/components/theme-provider.tsx +44 -0
- package/pulse/components/tools/feature-adoption-table.tsx +58 -0
- package/pulse/components/tools/mcp-server-panel.tsx +45 -0
- package/pulse/components/tools/tool-ranking-chart.tsx +57 -0
- package/pulse/components/tools/version-history-table.tsx +32 -0
- package/pulse/components/ui/alert.tsx +66 -0
- package/pulse/components/ui/badge.tsx +48 -0
- package/pulse/components/ui/breadcrumb.tsx +109 -0
- package/pulse/components/ui/button.tsx +64 -0
- package/pulse/components/ui/calendar.tsx +220 -0
- package/pulse/components/ui/card.tsx +92 -0
- package/pulse/components/ui/command.tsx +158 -0
- package/pulse/components/ui/dialog.tsx +158 -0
- package/pulse/components/ui/input.tsx +21 -0
- package/pulse/components/ui/popover.tsx +89 -0
- package/pulse/components/ui/progress.tsx +31 -0
- package/pulse/components/ui/select.tsx +190 -0
- package/pulse/components/ui/separator.tsx +28 -0
- package/pulse/components/ui/sheet.tsx +143 -0
- package/pulse/components/ui/skeleton.tsx +13 -0
- package/pulse/components/ui/table.tsx +116 -0
- package/pulse/components/ui/tabs.tsx +91 -0
- package/pulse/components/ui/tooltip.tsx +57 -0
- package/pulse/components/use-global-keyboard-nav.ts +79 -0
- package/pulse/components.json +23 -0
- package/pulse/eslint.config.mjs +18 -0
- package/pulse/lib/claude-reader.ts +594 -0
- package/pulse/lib/decode.ts +129 -0
- package/pulse/lib/pricing.ts +102 -0
- package/pulse/lib/replay-parser.ts +165 -0
- package/pulse/lib/tool-categories.ts +127 -0
- package/pulse/lib/utils.ts +6 -0
- package/pulse/next-env.d.ts +6 -0
- package/pulse/next.config.ts +16 -0
- package/pulse/package.json +45 -0
- package/pulse/postcss.config.mjs +7 -0
- package/pulse/public/activity.png +0 -0
- package/pulse/public/cc-lens.png +0 -0
- package/pulse/public/command-k.png +0 -0
- package/pulse/public/costs.png +0 -0
- package/pulse/public/dashboard-dark.png +0 -0
- package/pulse/public/dashboard-white.png +0 -0
- package/pulse/public/export.png +0 -0
- package/pulse/public/file.svg +1 -0
- package/pulse/public/globe.svg +1 -0
- package/pulse/public/next.svg +1 -0
- package/pulse/public/projects.png +0 -0
- package/pulse/public/session-chat.png +0 -0
- package/pulse/public/todos.png +0 -0
- package/pulse/public/tools.png +0 -0
- package/pulse/public/vercel.svg +1 -0
- package/pulse/public/window.svg +1 -0
- package/pulse/tsconfig.json +34 -0
- package/pulse/types/claude.ts +294 -0
- package/src/agents/loader.mjs +89 -0
- package/src/agents/parser.mjs +98 -0
- package/src/agents/teams.mjs +123 -0
- package/src/auth/oauth.mjs +220 -0
- package/src/auth/tarang-auth.mjs +277 -0
- package/src/config/cli-args.mjs +173 -0
- package/src/config/env.mjs +263 -0
- package/src/config/settings.mjs +132 -0
- package/src/context/ast-parser.mjs +298 -0
- package/src/context/bm25.mjs +85 -0
- package/src/context/retriever.mjs +270 -0
- package/src/context/skeleton.mjs +134 -0
- package/src/core/agent-loop.mjs +480 -0
- package/src/core/approval.mjs +273 -0
- package/src/core/backend-url.mjs +57 -0
- package/src/core/cache.mjs +105 -0
- package/src/core/callback-client.mjs +149 -0
- package/src/core/checkpoints.mjs +142 -0
- package/src/core/context-manager.mjs +198 -0
- package/src/core/headless.mjs +168 -0
- package/src/core/hooks-manager.mjs +87 -0
- package/src/core/jsonl-writer.mjs +351 -0
- package/src/core/local-agent.mjs +429 -0
- package/src/core/local-store.mjs +325 -0
- package/src/core/mode-selector.mjs +51 -0
- package/src/core/output-filter.mjs +177 -0
- package/src/core/paths.mjs +101 -0
- package/src/core/pricing.mjs +314 -0
- package/src/core/providers.mjs +219 -0
- package/src/core/rate-limiter.mjs +119 -0
- package/src/core/safety.mjs +200 -0
- package/src/core/scheduler.mjs +173 -0
- package/src/core/session-manager.mjs +317 -0
- package/src/core/session.mjs +143 -0
- package/src/core/settings-sync.mjs +85 -0
- package/src/core/stagnation.mjs +57 -0
- package/src/core/stream-client.mjs +367 -0
- package/src/core/streaming.mjs +182 -0
- package/src/core/system-prompt.mjs +135 -0
- package/src/core/tool-executor.mjs +725 -0
- package/src/hooks/engine.mjs +162 -0
- package/src/index.mjs +370 -0
- package/src/mcp/client.mjs +253 -0
- package/src/mcp/transport-shttp.mjs +130 -0
- package/src/mcp/transport-sse.mjs +131 -0
- package/src/mcp/transport-ws.mjs +134 -0
- package/src/permissions/checker.mjs +57 -0
- package/src/permissions/command-classifier.mjs +573 -0
- package/src/permissions/injection-check.mjs +60 -0
- package/src/permissions/path-check.mjs +102 -0
- package/src/permissions/prompt.mjs +73 -0
- package/src/permissions/sandbox.mjs +112 -0
- package/src/plugins/loader.mjs +138 -0
- package/src/skills/loader.mjs +147 -0
- package/src/skills/runner.mjs +55 -0
- package/src/telemetry/index.mjs +96 -0
- package/src/terminal/agents.mjs +177 -0
- package/src/terminal/analytics.mjs +292 -0
- package/src/terminal/ansi.mjs +421 -0
- package/src/terminal/main.mjs +150 -0
- package/src/terminal/repl.mjs +1484 -0
- package/src/terminal/tool-display.mjs +58 -0
- package/src/tools/agent.mjs +137 -0
- package/src/tools/ask-user.mjs +61 -0
- package/src/tools/bash.mjs +148 -0
- package/src/tools/cron-create.mjs +120 -0
- package/src/tools/cron-delete.mjs +49 -0
- package/src/tools/cron-list.mjs +37 -0
- package/src/tools/edit.mjs +82 -0
- package/src/tools/enter-worktree.mjs +69 -0
- package/src/tools/exit-worktree.mjs +57 -0
- package/src/tools/glob.mjs +117 -0
- package/src/tools/grep.mjs +129 -0
- package/src/tools/lint.mjs +71 -0
- package/src/tools/ls.mjs +58 -0
- package/src/tools/lsp.mjs +115 -0
- package/src/tools/multi-edit.mjs +94 -0
- package/src/tools/notebook-edit.mjs +96 -0
- package/src/tools/read-mcp-resource.mjs +57 -0
- package/src/tools/read.mjs +138 -0
- package/src/tools/registry.mjs +132 -0
- package/src/tools/remote-trigger.mjs +84 -0
- package/src/tools/send-message.mjs +64 -0
- package/src/tools/skill.mjs +52 -0
- package/src/tools/test-runner.mjs +49 -0
- package/src/tools/todo-write.mjs +68 -0
- package/src/tools/tool-search.mjs +77 -0
- package/src/tools/web-fetch.mjs +65 -0
- package/src/tools/web-search.mjs +89 -0
- package/src/tools/write.mjs +55 -0
- package/src/ui/banner.mjs +237 -0
- package/src/ui/commands.mjs +499 -0
- package/src/ui/formatter.mjs +379 -0
- package/src/ui/markdown.mjs +278 -0
- package/src/ui/slash-commands.mjs +258 -0
- package/index.js +0 -1
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2017",
|
|
4
|
+
"lib": ["dom", "dom.iterable", "esnext"],
|
|
5
|
+
"allowJs": true,
|
|
6
|
+
"skipLibCheck": true,
|
|
7
|
+
"strict": true,
|
|
8
|
+
"noEmit": true,
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"module": "esnext",
|
|
11
|
+
"moduleResolution": "bundler",
|
|
12
|
+
"resolveJsonModule": true,
|
|
13
|
+
"isolatedModules": true,
|
|
14
|
+
"jsx": "react-jsx",
|
|
15
|
+
"incremental": true,
|
|
16
|
+
"plugins": [
|
|
17
|
+
{
|
|
18
|
+
"name": "next"
|
|
19
|
+
}
|
|
20
|
+
],
|
|
21
|
+
"paths": {
|
|
22
|
+
"@/*": ["./*"]
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"include": [
|
|
26
|
+
"next-env.d.ts",
|
|
27
|
+
"**/*.ts",
|
|
28
|
+
"**/*.tsx",
|
|
29
|
+
".next/types/**/*.ts",
|
|
30
|
+
".next/dev/types/**/*.ts",
|
|
31
|
+
"**/*.mts"
|
|
32
|
+
],
|
|
33
|
+
"exclude": ["node_modules"]
|
|
34
|
+
}
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
// ─── Stats Cache ─────────────────────────────────────────────────────────────
|
|
2
|
+
|
|
3
|
+
export interface DailyActivity {
|
|
4
|
+
date: string
|
|
5
|
+
messageCount: number
|
|
6
|
+
sessionCount: number
|
|
7
|
+
toolCallCount: number
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface DailyTokens {
|
|
11
|
+
date: string
|
|
12
|
+
tokensByModel: Record<string, number>
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface ModelUsage {
|
|
16
|
+
inputTokens: number
|
|
17
|
+
outputTokens: number
|
|
18
|
+
cacheReadInputTokens: number
|
|
19
|
+
cacheCreationInputTokens: number
|
|
20
|
+
costUSD: number
|
|
21
|
+
webSearchRequests: number
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface LongestSession {
|
|
25
|
+
sessionId: string
|
|
26
|
+
duration: number
|
|
27
|
+
messageCount: number
|
|
28
|
+
timestamp: string
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface StatsCache {
|
|
32
|
+
version: number
|
|
33
|
+
lastComputedDate: string
|
|
34
|
+
dailyActivity: DailyActivity[]
|
|
35
|
+
tokensByDate: DailyTokens[]
|
|
36
|
+
dailyModelTokens?: DailyTokens[]
|
|
37
|
+
modelUsage: Record<string, ModelUsage>
|
|
38
|
+
totalSessions: number
|
|
39
|
+
totalMessages: number
|
|
40
|
+
longestSession: LongestSession
|
|
41
|
+
firstSessionDate: string
|
|
42
|
+
hourCounts: Record<string, number>
|
|
43
|
+
totalSpeculationTimeSavedMs: number
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// ─── Session Meta ─────────────────────────────────────────────────────────────
|
|
47
|
+
|
|
48
|
+
export interface SessionMeta {
|
|
49
|
+
session_id: string
|
|
50
|
+
project_path: string
|
|
51
|
+
start_time: string
|
|
52
|
+
duration_minutes: number
|
|
53
|
+
user_message_count: number
|
|
54
|
+
assistant_message_count: number
|
|
55
|
+
tool_counts: Record<string, number>
|
|
56
|
+
languages: Record<string, number>
|
|
57
|
+
git_commits: number
|
|
58
|
+
git_pushes: number
|
|
59
|
+
input_tokens: number
|
|
60
|
+
output_tokens: number
|
|
61
|
+
cache_creation_input_tokens?: number
|
|
62
|
+
cache_read_input_tokens?: number
|
|
63
|
+
first_prompt: string
|
|
64
|
+
user_interruptions: number
|
|
65
|
+
user_response_times: number[]
|
|
66
|
+
tool_errors: number
|
|
67
|
+
tool_error_categories: Record<string, number>
|
|
68
|
+
uses_task_agent: boolean
|
|
69
|
+
uses_mcp: boolean
|
|
70
|
+
uses_web_search: boolean
|
|
71
|
+
uses_web_fetch: boolean
|
|
72
|
+
lines_added: number
|
|
73
|
+
lines_removed: number
|
|
74
|
+
files_modified: number
|
|
75
|
+
message_hours: number[]
|
|
76
|
+
user_message_timestamps: string[]
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// ─── Facets ──────────────────────────────────────────────────────────────────
|
|
80
|
+
|
|
81
|
+
export interface Facet {
|
|
82
|
+
session_id: string
|
|
83
|
+
underlying_goal: string
|
|
84
|
+
goal_categories: Record<string, number>
|
|
85
|
+
outcome: string
|
|
86
|
+
user_satisfaction_counts: Record<string, number>
|
|
87
|
+
claude_helpfulness: string
|
|
88
|
+
session_type: string
|
|
89
|
+
friction_counts: Record<string, number>
|
|
90
|
+
friction_detail: string
|
|
91
|
+
primary_success: string
|
|
92
|
+
brief_summary: string
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// ─── Session with Facet joined ───────────────────────────────────────────────
|
|
96
|
+
|
|
97
|
+
export interface SessionWithFacet extends SessionMeta {
|
|
98
|
+
facet?: Facet
|
|
99
|
+
estimated_cost: number
|
|
100
|
+
slug?: string
|
|
101
|
+
version?: string
|
|
102
|
+
git_branch?: string
|
|
103
|
+
has_compaction?: boolean
|
|
104
|
+
has_thinking?: boolean
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// ─── Replay / JSONL ──────────────────────────────────────────────────────────
|
|
108
|
+
|
|
109
|
+
export interface TurnUsage {
|
|
110
|
+
input_tokens: number
|
|
111
|
+
output_tokens: number
|
|
112
|
+
cache_creation_input_tokens: number
|
|
113
|
+
cache_read_input_tokens: number
|
|
114
|
+
cache_creation?: {
|
|
115
|
+
ephemeral_5m_input_tokens: number
|
|
116
|
+
ephemeral_1h_input_tokens: number
|
|
117
|
+
}
|
|
118
|
+
service_tier?: string
|
|
119
|
+
inference_geo?: string
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export interface ToolCall {
|
|
123
|
+
id: string
|
|
124
|
+
name: string
|
|
125
|
+
input: Record<string, unknown>
|
|
126
|
+
result?: string
|
|
127
|
+
is_error?: boolean
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export interface ReplayTurn {
|
|
131
|
+
uuid: string
|
|
132
|
+
parentUuid: string | null
|
|
133
|
+
type: 'user' | 'assistant'
|
|
134
|
+
timestamp: string
|
|
135
|
+
model?: string
|
|
136
|
+
usage?: TurnUsage
|
|
137
|
+
text?: string
|
|
138
|
+
tool_calls?: ToolCall[]
|
|
139
|
+
tool_results?: Array<{ tool_use_id: string; content: string; is_error: boolean }>
|
|
140
|
+
has_thinking?: boolean
|
|
141
|
+
thinking_text?: string
|
|
142
|
+
estimated_cost?: number
|
|
143
|
+
turn_duration_ms?: number
|
|
144
|
+
response_time_s?: number
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export interface CompactionEvent {
|
|
148
|
+
uuid: string
|
|
149
|
+
timestamp: string
|
|
150
|
+
trigger: 'auto' | 'manual'
|
|
151
|
+
pre_tokens: number
|
|
152
|
+
summary?: string
|
|
153
|
+
turn_index: number
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export interface SummaryEvent {
|
|
157
|
+
uuid: string
|
|
158
|
+
summary: string
|
|
159
|
+
leaf_uuid: string
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export interface ReplayData {
|
|
163
|
+
session_id: string
|
|
164
|
+
slug?: string
|
|
165
|
+
version?: string
|
|
166
|
+
git_branch?: string
|
|
167
|
+
turns: ReplayTurn[]
|
|
168
|
+
compactions: CompactionEvent[]
|
|
169
|
+
summaries: SummaryEvent[]
|
|
170
|
+
total_cost: number
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// ─── Project Summary ──────────────────────────────────────────────────────────
|
|
174
|
+
|
|
175
|
+
export interface ProjectSummary {
|
|
176
|
+
slug: string
|
|
177
|
+
project_path: string
|
|
178
|
+
display_name: string
|
|
179
|
+
session_count: number
|
|
180
|
+
total_messages: number
|
|
181
|
+
total_duration_minutes: number
|
|
182
|
+
total_lines_added: number
|
|
183
|
+
total_lines_removed: number
|
|
184
|
+
total_files_modified: number
|
|
185
|
+
git_commits: number
|
|
186
|
+
git_pushes: number
|
|
187
|
+
estimated_cost: number
|
|
188
|
+
input_tokens: number
|
|
189
|
+
output_tokens: number
|
|
190
|
+
languages: Record<string, number>
|
|
191
|
+
tool_counts: Record<string, number>
|
|
192
|
+
last_active: string
|
|
193
|
+
first_active: string
|
|
194
|
+
uses_mcp: boolean
|
|
195
|
+
uses_task_agent: boolean
|
|
196
|
+
branches: string[]
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// ─── Tool Analytics ───────────────────────────────────────────────────────────
|
|
200
|
+
|
|
201
|
+
export interface ToolSummary {
|
|
202
|
+
name: string
|
|
203
|
+
category: string
|
|
204
|
+
total_calls: number
|
|
205
|
+
session_count: number
|
|
206
|
+
error_count: number
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
export interface McpServerSummary {
|
|
210
|
+
server_name: string
|
|
211
|
+
tools: Array<{ name: string; calls: number }>
|
|
212
|
+
total_calls: number
|
|
213
|
+
session_count: number
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
export interface VersionRecord {
|
|
217
|
+
version: string
|
|
218
|
+
session_count: number
|
|
219
|
+
first_seen: string
|
|
220
|
+
last_seen: string
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
export interface ToolsAnalytics {
|
|
224
|
+
tools: ToolSummary[]
|
|
225
|
+
mcp_servers: McpServerSummary[]
|
|
226
|
+
feature_adoption: Record<string, { sessions: number; pct: number }>
|
|
227
|
+
versions: VersionRecord[]
|
|
228
|
+
branches: Array<{ branch: string; turns: number }>
|
|
229
|
+
error_categories: Record<string, number>
|
|
230
|
+
total_tool_calls: number
|
|
231
|
+
total_errors: number
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// ─── Cost Analytics ───────────────────────────────────────────────────────────
|
|
235
|
+
|
|
236
|
+
export interface ModelCostBreakdown {
|
|
237
|
+
model: string
|
|
238
|
+
input_tokens: number
|
|
239
|
+
output_tokens: number
|
|
240
|
+
cache_write_tokens: number
|
|
241
|
+
cache_read_tokens: number
|
|
242
|
+
estimated_cost: number
|
|
243
|
+
cache_savings: number
|
|
244
|
+
cache_hit_rate: number
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
export interface DailyCost {
|
|
248
|
+
date: string
|
|
249
|
+
costs: Record<string, number>
|
|
250
|
+
total: number
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
export interface ProjectCost {
|
|
254
|
+
slug: string
|
|
255
|
+
display_name: string
|
|
256
|
+
estimated_cost: number
|
|
257
|
+
input_tokens: number
|
|
258
|
+
output_tokens: number
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
export interface CostAnalytics {
|
|
262
|
+
total_cost: number
|
|
263
|
+
total_savings: number
|
|
264
|
+
models: ModelCostBreakdown[]
|
|
265
|
+
daily: DailyCost[]
|
|
266
|
+
by_project: ProjectCost[]
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// ─── History ──────────────────────────────────────────────────────────────────
|
|
270
|
+
|
|
271
|
+
export interface HistoryEntry {
|
|
272
|
+
display: string
|
|
273
|
+
timestamp: number
|
|
274
|
+
project: string
|
|
275
|
+
sessionId?: string
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// ─── Export ──────────────────────────────────────────────────────────────────
|
|
279
|
+
|
|
280
|
+
export interface ExportPayload {
|
|
281
|
+
exportedAt: string
|
|
282
|
+
version: string
|
|
283
|
+
stats: StatsCache | null
|
|
284
|
+
sessions: SessionMeta[]
|
|
285
|
+
facets: Facet[]
|
|
286
|
+
history: HistoryEntry[]
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
export interface ImportDiff {
|
|
290
|
+
total_in_export: number
|
|
291
|
+
already_present: number
|
|
292
|
+
new_sessions: number
|
|
293
|
+
sessions_to_add: SessionMeta[]
|
|
294
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Loader — loads custom agent definitions from .claude/agents/
|
|
3
|
+
*
|
|
4
|
+
* Supports two formats:
|
|
5
|
+
* - JSON: .claude/agents/*.json
|
|
6
|
+
* - Markdown with YAML frontmatter: .claude/agents/*.md
|
|
7
|
+
*
|
|
8
|
+
* Agent definitions specify: name, description, model, tools, hooks, prompt.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import fs from 'fs';
|
|
12
|
+
import path from 'path';
|
|
13
|
+
import { parseAgentDefinition } from './parser.mjs';
|
|
14
|
+
|
|
15
|
+
export class AgentLoader {
|
|
16
|
+
constructor() {
|
|
17
|
+
this.agents = new Map();
|
|
18
|
+
this.searchPaths = [];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Load agents from standard directories.
|
|
23
|
+
* @param {string} [cwd] - project working directory
|
|
24
|
+
*/
|
|
25
|
+
load(cwd = process.cwd()) {
|
|
26
|
+
this.searchPaths = [
|
|
27
|
+
path.join(cwd, '.claude', 'agents'),
|
|
28
|
+
path.join(process.env.HOME || '', '.claude', 'agents'),
|
|
29
|
+
];
|
|
30
|
+
|
|
31
|
+
for (const dir of this.searchPaths) {
|
|
32
|
+
this._loadFromDir(dir);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return this;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
_loadFromDir(dir) {
|
|
39
|
+
try {
|
|
40
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
41
|
+
for (const entry of entries) {
|
|
42
|
+
if (!entry.isFile()) continue;
|
|
43
|
+
const ext = path.extname(entry.name);
|
|
44
|
+
if (ext !== '.json' && ext !== '.md') continue;
|
|
45
|
+
|
|
46
|
+
const filePath = path.join(dir, entry.name);
|
|
47
|
+
try {
|
|
48
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
49
|
+
const agent = parseAgentDefinition(content, ext);
|
|
50
|
+
if (agent && agent.name) {
|
|
51
|
+
this.agents.set(agent.name, { ...agent, source: filePath });
|
|
52
|
+
}
|
|
53
|
+
} catch (err) {
|
|
54
|
+
if (process.env.DEBUG) {
|
|
55
|
+
console.error(`Failed to load agent ${filePath}: ${err.message}`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
} catch {
|
|
60
|
+
// Directory does not exist
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Get an agent definition by name.
|
|
66
|
+
* @param {string} name
|
|
67
|
+
* @returns {object|null}
|
|
68
|
+
*/
|
|
69
|
+
get(name) {
|
|
70
|
+
return this.agents.get(name) || null;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* List all loaded agents.
|
|
75
|
+
* @returns {Array<object>}
|
|
76
|
+
*/
|
|
77
|
+
list() {
|
|
78
|
+
return [...this.agents.values()];
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Check if an agent exists.
|
|
83
|
+
* @param {string} name
|
|
84
|
+
* @returns {boolean}
|
|
85
|
+
*/
|
|
86
|
+
has(name) {
|
|
87
|
+
return this.agents.has(name);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Parser — parses agent definitions from JSON and Markdown formats.
|
|
3
|
+
*
|
|
4
|
+
* JSON format:
|
|
5
|
+
* {
|
|
6
|
+
* "name": "my-agent",
|
|
7
|
+
* "description": "Does things",
|
|
8
|
+
* "model": "claude-sonnet-4-6",
|
|
9
|
+
* "tools": ["Bash", "Read", "Write"],
|
|
10
|
+
* "hooks": { ... },
|
|
11
|
+
* "prompt": "You are a specialized agent..."
|
|
12
|
+
* }
|
|
13
|
+
*
|
|
14
|
+
* Markdown format (YAML frontmatter):
|
|
15
|
+
* ---
|
|
16
|
+
* name: my-agent
|
|
17
|
+
* description: Does things
|
|
18
|
+
* model: claude-sonnet-4-6
|
|
19
|
+
* tools: [Bash, Read, Write]
|
|
20
|
+
* ---
|
|
21
|
+
* You are a specialized agent...
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Parse an agent definition from file content.
|
|
26
|
+
* @param {string} content - file content
|
|
27
|
+
* @param {string} ext - file extension (.json or .md)
|
|
28
|
+
* @returns {object} agent definition
|
|
29
|
+
*/
|
|
30
|
+
export function parseAgentDefinition(content, ext) {
|
|
31
|
+
if (ext === '.json') {
|
|
32
|
+
return parseJsonAgent(content);
|
|
33
|
+
}
|
|
34
|
+
if (ext === '.md') {
|
|
35
|
+
return parseMarkdownAgent(content);
|
|
36
|
+
}
|
|
37
|
+
throw new Error(`Unsupported agent format: ${ext}`);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function parseJsonAgent(content) {
|
|
41
|
+
const data = JSON.parse(content);
|
|
42
|
+
return normalizeAgent(data);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function parseMarkdownAgent(content) {
|
|
46
|
+
const { frontmatter, body } = parseFrontmatter(content);
|
|
47
|
+
return normalizeAgent({ ...frontmatter, prompt: body });
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Parse YAML-like frontmatter from markdown.
|
|
52
|
+
* Simple key-value parser (no full YAML dependency).
|
|
53
|
+
*/
|
|
54
|
+
function parseFrontmatter(content) {
|
|
55
|
+
const match = content.match(/^---\s*\n([\s\S]*?)\n---\s*\n([\s\S]*)$/);
|
|
56
|
+
if (!match) {
|
|
57
|
+
return { frontmatter: {}, body: content };
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const yamlBlock = match[1];
|
|
61
|
+
const body = match[2].trim();
|
|
62
|
+
const frontmatter = {};
|
|
63
|
+
|
|
64
|
+
for (const line of yamlBlock.split('\n')) {
|
|
65
|
+
const colonIdx = line.indexOf(':');
|
|
66
|
+
if (colonIdx === -1) continue;
|
|
67
|
+
|
|
68
|
+
const key = line.slice(0, colonIdx).trim();
|
|
69
|
+
let value = line.slice(colonIdx + 1).trim();
|
|
70
|
+
|
|
71
|
+
// Parse arrays: [a, b, c]
|
|
72
|
+
if (value.startsWith('[') && value.endsWith(']')) {
|
|
73
|
+
value = value.slice(1, -1).split(',').map(s => s.trim()).filter(Boolean);
|
|
74
|
+
}
|
|
75
|
+
// Parse booleans
|
|
76
|
+
else if (value === 'true') value = true;
|
|
77
|
+
else if (value === 'false') value = false;
|
|
78
|
+
// Parse numbers
|
|
79
|
+
else if (/^\d+$/.test(value)) value = parseInt(value, 10);
|
|
80
|
+
|
|
81
|
+
frontmatter[key] = value;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return { frontmatter, body };
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function normalizeAgent(data) {
|
|
88
|
+
return {
|
|
89
|
+
name: data.name || 'unnamed',
|
|
90
|
+
description: data.description || '',
|
|
91
|
+
model: data.model || null,
|
|
92
|
+
tools: Array.isArray(data.tools) ? data.tools : [],
|
|
93
|
+
hooks: data.hooks || {},
|
|
94
|
+
prompt: data.prompt || '',
|
|
95
|
+
maxTurns: data.maxTurns || data.max_turns || 10,
|
|
96
|
+
temperature: data.temperature || undefined,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Teams — multi-agent coordination.
|
|
3
|
+
*
|
|
4
|
+
* Allows registering named agents that can communicate via messages.
|
|
5
|
+
* Each teammate is an agent loop that can be invoked with a prompt.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export class AgentTeams {
|
|
9
|
+
constructor() {
|
|
10
|
+
/** @type {Map<string, { loop: object, role?: string, status: string }>} */
|
|
11
|
+
this.teammates = new Map();
|
|
12
|
+
this.messageLog = [];
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Register a named agent.
|
|
17
|
+
* @param {string} name - unique agent name
|
|
18
|
+
* @param {object} agentLoop - agent loop with .run() async generator
|
|
19
|
+
* @param {object} [options]
|
|
20
|
+
* @param {string} [options.role] - agent role description
|
|
21
|
+
*/
|
|
22
|
+
register(name, agentLoop, options = {}) {
|
|
23
|
+
if (this.teammates.has(name)) {
|
|
24
|
+
throw new Error(`Agent "${name}" is already registered`);
|
|
25
|
+
}
|
|
26
|
+
this.teammates.set(name, {
|
|
27
|
+
loop: agentLoop,
|
|
28
|
+
role: options.role || 'general',
|
|
29
|
+
status: 'idle',
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Unregister an agent.
|
|
35
|
+
* @param {string} name
|
|
36
|
+
* @returns {boolean}
|
|
37
|
+
*/
|
|
38
|
+
unregister(name) {
|
|
39
|
+
return this.teammates.delete(name);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Send a message to a teammate and collect all events.
|
|
44
|
+
* @param {string} to - target agent name
|
|
45
|
+
* @param {string} message - prompt to send
|
|
46
|
+
* @returns {Promise<Array<object>>} collected events
|
|
47
|
+
*/
|
|
48
|
+
async sendMessage(to, message) {
|
|
49
|
+
const agent = this.teammates.get(to);
|
|
50
|
+
if (!agent) throw new Error(`Unknown teammate: ${to}`);
|
|
51
|
+
|
|
52
|
+
agent.status = 'running';
|
|
53
|
+
const results = [];
|
|
54
|
+
|
|
55
|
+
try {
|
|
56
|
+
for await (const event of agent.loop.run(message)) {
|
|
57
|
+
results.push(event);
|
|
58
|
+
}
|
|
59
|
+
} finally {
|
|
60
|
+
agent.status = 'idle';
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
this.messageLog.push({
|
|
64
|
+
to,
|
|
65
|
+
message: message.substring(0, 100),
|
|
66
|
+
resultCount: results.length,
|
|
67
|
+
timestamp: new Date().toISOString(),
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
return results;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Broadcast a message to all teammates.
|
|
75
|
+
* @param {string} message
|
|
76
|
+
* @returns {Promise<Map<string, Array<object>>>} results per agent
|
|
77
|
+
*/
|
|
78
|
+
async broadcast(message) {
|
|
79
|
+
const results = new Map();
|
|
80
|
+
const promises = [];
|
|
81
|
+
|
|
82
|
+
for (const [name] of this.teammates) {
|
|
83
|
+
promises.push(
|
|
84
|
+
this.sendMessage(name, message)
|
|
85
|
+
.then(events => results.set(name, events))
|
|
86
|
+
.catch(err => results.set(name, [{ type: 'error', message: err.message }]))
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
await Promise.all(promises);
|
|
91
|
+
return results;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* List all registered teammates.
|
|
96
|
+
* @returns {Array<{ name: string, role: string, status: string }>}
|
|
97
|
+
*/
|
|
98
|
+
list() {
|
|
99
|
+
return [...this.teammates.entries()].map(([name, info]) => ({
|
|
100
|
+
name,
|
|
101
|
+
role: info.role,
|
|
102
|
+
status: info.status,
|
|
103
|
+
}));
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Get the message log.
|
|
108
|
+
* @param {number} [limit] - max entries to return
|
|
109
|
+
* @returns {Array<object>}
|
|
110
|
+
*/
|
|
111
|
+
getMessageLog(limit) {
|
|
112
|
+
if (limit) return this.messageLog.slice(-limit);
|
|
113
|
+
return [...this.messageLog];
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Get count of registered teammates.
|
|
118
|
+
* @returns {number}
|
|
119
|
+
*/
|
|
120
|
+
size() {
|
|
121
|
+
return this.teammates.size;
|
|
122
|
+
}
|
|
123
|
+
}
|