@cluesmith/codev 2.0.3 → 2.0.6
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/dashboard/dist/assets/index-B-s8BA2l.js +135 -0
- package/dashboard/dist/assets/index-B-s8BA2l.js.map +1 -0
- package/dashboard/dist/assets/index-DB2AxRP7.css +32 -0
- package/dashboard/dist/index.html +2 -2
- package/dist/agent-farm/cli.d.ts.map +1 -1
- package/dist/agent-farm/cli.js +31 -13
- package/dist/agent-farm/cli.js.map +1 -1
- package/dist/agent-farm/commands/attach.d.ts +19 -0
- package/dist/agent-farm/commands/attach.d.ts.map +1 -1
- package/dist/agent-farm/commands/attach.js +172 -12
- package/dist/agent-farm/commands/attach.js.map +1 -1
- package/dist/agent-farm/commands/send.d.ts +22 -2
- package/dist/agent-farm/commands/send.d.ts.map +1 -1
- package/dist/agent-farm/commands/send.js +97 -178
- package/dist/agent-farm/commands/send.js.map +1 -1
- package/dist/agent-farm/commands/spawn-roles.d.ts +3 -9
- package/dist/agent-farm/commands/spawn-roles.d.ts.map +1 -1
- package/dist/agent-farm/commands/spawn-roles.js +14 -53
- package/dist/agent-farm/commands/spawn-roles.js.map +1 -1
- package/dist/agent-farm/commands/spawn-worktree.d.ts +10 -16
- package/dist/agent-farm/commands/spawn-worktree.d.ts.map +1 -1
- package/dist/agent-farm/commands/spawn-worktree.js +24 -5
- package/dist/agent-farm/commands/spawn-worktree.js.map +1 -1
- package/dist/agent-farm/commands/spawn.d.ts +8 -6
- package/dist/agent-farm/commands/spawn.d.ts.map +1 -1
- package/dist/agent-farm/commands/spawn.js +180 -66
- package/dist/agent-farm/commands/spawn.js.map +1 -1
- package/dist/agent-farm/commands/status.d.ts.map +1 -1
- package/dist/agent-farm/commands/status.js +1 -12
- package/dist/agent-farm/commands/status.js.map +1 -1
- package/dist/agent-farm/lib/tower-client.d.ts +16 -6
- package/dist/agent-farm/lib/tower-client.d.ts.map +1 -1
- package/dist/agent-farm/lib/tower-client.js +25 -0
- package/dist/agent-farm/lib/tower-client.js.map +1 -1
- package/dist/agent-farm/servers/overview.d.ts +111 -0
- package/dist/agent-farm/servers/overview.d.ts.map +1 -0
- package/dist/agent-farm/servers/overview.js +385 -0
- package/dist/agent-farm/servers/overview.js.map +1 -0
- package/dist/agent-farm/servers/tower-instances.d.ts +1 -3
- package/dist/agent-farm/servers/tower-instances.d.ts.map +1 -1
- package/dist/agent-farm/servers/tower-instances.js +10 -13
- package/dist/agent-farm/servers/tower-instances.js.map +1 -1
- package/dist/agent-farm/servers/tower-messages.d.ts +87 -0
- package/dist/agent-farm/servers/tower-messages.d.ts.map +1 -0
- package/dist/agent-farm/servers/tower-messages.js +202 -0
- package/dist/agent-farm/servers/tower-messages.js.map +1 -0
- package/dist/agent-farm/servers/tower-routes.d.ts.map +1 -1
- package/dist/agent-farm/servers/tower-routes.js +164 -17
- package/dist/agent-farm/servers/tower-routes.js.map +1 -1
- package/dist/agent-farm/servers/tower-server.js +27 -2
- package/dist/agent-farm/servers/tower-server.js.map +1 -1
- package/dist/agent-farm/servers/tower-terminals.d.ts +8 -2
- package/dist/agent-farm/servers/tower-terminals.d.ts.map +1 -1
- package/dist/agent-farm/servers/tower-terminals.js +125 -80
- package/dist/agent-farm/servers/tower-terminals.js.map +1 -1
- package/dist/agent-farm/servers/tower-types.d.ts +0 -2
- package/dist/agent-farm/servers/tower-types.d.ts.map +1 -1
- package/dist/agent-farm/servers/tower-websocket.d.ts.map +1 -1
- package/dist/agent-farm/servers/tower-websocket.js +25 -4
- package/dist/agent-farm/servers/tower-websocket.js.map +1 -1
- package/dist/agent-farm/types.d.ts +3 -4
- package/dist/agent-farm/types.d.ts.map +1 -1
- package/dist/agent-farm/utils/agent-names.d.ts +85 -0
- package/dist/agent-farm/utils/agent-names.d.ts.map +1 -0
- package/dist/agent-farm/utils/agent-names.js +140 -0
- package/dist/agent-farm/utils/agent-names.js.map +1 -0
- package/dist/agent-farm/utils/message-format.d.ts +17 -0
- package/dist/agent-farm/utils/message-format.d.ts.map +1 -0
- package/dist/agent-farm/utils/message-format.js +41 -0
- package/dist/agent-farm/utils/message-format.js.map +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +26 -1
- package/dist/cli.js.map +1 -1
- package/dist/commands/adopt.d.ts.map +1 -1
- package/dist/commands/adopt.js +1 -13
- package/dist/commands/adopt.js.map +1 -1
- package/dist/commands/consult/index.d.ts +25 -1
- package/dist/commands/consult/index.d.ts.map +1 -1
- package/dist/commands/consult/index.js +251 -39
- package/dist/commands/consult/index.js.map +1 -1
- package/dist/commands/consult/metrics.d.ts +90 -0
- package/dist/commands/consult/metrics.d.ts.map +1 -0
- package/dist/commands/consult/metrics.js +203 -0
- package/dist/commands/consult/metrics.js.map +1 -0
- package/dist/commands/consult/stats.d.ts +18 -0
- package/dist/commands/consult/stats.d.ts.map +1 -0
- package/dist/commands/consult/stats.js +150 -0
- package/dist/commands/consult/stats.js.map +1 -0
- package/dist/commands/consult/usage-extractor.d.ts +38 -0
- package/dist/commands/consult/usage-extractor.d.ts.map +1 -0
- package/dist/commands/consult/usage-extractor.js +99 -0
- package/dist/commands/consult/usage-extractor.js.map +1 -0
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +5 -3
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +1 -13
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/porch/next.d.ts.map +1 -1
- package/dist/commands/porch/next.js +53 -62
- package/dist/commands/porch/next.js.map +1 -1
- package/dist/commands/porch/prompts.d.ts +10 -1
- package/dist/commands/porch/prompts.d.ts.map +1 -1
- package/dist/commands/porch/prompts.js +50 -26
- package/dist/commands/porch/prompts.js.map +1 -1
- package/dist/commands/porch/protocol.js +2 -2
- package/dist/commands/porch/state.d.ts.map +1 -1
- package/dist/commands/porch/state.js +3 -1
- package/dist/commands/porch/state.js.map +1 -1
- package/dist/commands/update.d.ts.map +1 -1
- package/dist/commands/update.js +0 -10
- package/dist/commands/update.js.map +1 -1
- package/dist/lib/github.d.ts +81 -0
- package/dist/lib/github.d.ts.map +1 -0
- package/dist/lib/github.js +141 -0
- package/dist/lib/github.js.map +1 -0
- package/dist/lib/scaffold.d.ts +0 -21
- package/dist/lib/scaffold.d.ts.map +1 -1
- package/dist/lib/scaffold.js +0 -57
- package/dist/lib/scaffold.js.map +1 -1
- package/dist/terminal/index.d.ts +14 -0
- package/dist/terminal/index.d.ts.map +1 -1
- package/dist/terminal/index.js +12 -0
- package/dist/terminal/index.js.map +1 -1
- package/dist/terminal/pty-manager.d.ts.map +1 -1
- package/dist/terminal/pty-manager.js +7 -4
- package/dist/terminal/pty-manager.js.map +1 -1
- package/dist/terminal/pty-session.js +3 -3
- package/dist/terminal/pty-session.js.map +1 -1
- package/dist/terminal/session-manager.d.ts +64 -0
- package/dist/terminal/session-manager.d.ts.map +1 -1
- package/dist/terminal/session-manager.js +299 -10
- package/dist/terminal/session-manager.js.map +1 -1
- package/dist/terminal/shellper-client.d.ts +2 -1
- package/dist/terminal/shellper-client.d.ts.map +1 -1
- package/dist/terminal/shellper-client.js +4 -2
- package/dist/terminal/shellper-client.js.map +1 -1
- package/dist/terminal/shellper-main.js +33 -4
- package/dist/terminal/shellper-main.js.map +1 -1
- package/dist/terminal/shellper-process.d.ts +24 -7
- package/dist/terminal/shellper-process.d.ts.map +1 -1
- package/dist/terminal/shellper-process.js +139 -36
- package/dist/terminal/shellper-process.js.map +1 -1
- package/dist/terminal/shellper-protocol.d.ts +1 -0
- package/dist/terminal/shellper-protocol.d.ts.map +1 -1
- package/dist/terminal/shellper-protocol.js.map +1 -1
- package/package.json +4 -1
- package/skeleton/.claude/skills/af/SKILL.md +7 -7
- package/skeleton/.claude/skills/consult/SKILL.md +1 -1
- package/skeleton/builders.md +2 -2
- package/skeleton/maintain/.gitkeep +1 -1
- package/skeleton/porch/prompts/specify.md +1 -1
- package/skeleton/protocols/bugfix/prompts/pr.md +15 -4
- package/skeleton/protocols/experiment/protocol.md +17 -17
- package/skeleton/protocols/maintain/prompts/audit.md +2 -2
- package/skeleton/protocols/maintain/prompts/sync.md +1 -1
- package/skeleton/protocols/maintain/prompts/verify.md +1 -1
- package/skeleton/protocols/maintain/protocol.md +8 -9
- package/skeleton/protocols/maintain/templates/maintenance-run.md +2 -2
- package/skeleton/protocols/spir/protocol.json +5 -5
- package/skeleton/protocols/spir/protocol.md +8 -8
- package/skeleton/protocols/tick/protocol.md +31 -31
- package/skeleton/resources/commands/agent-farm.md +14 -14
- package/skeleton/resources/commands/codev.md +0 -1
- package/skeleton/resources/commands/consult.md +3 -3
- package/skeleton/resources/spikes.md +3 -3
- package/skeleton/resources/workflow-reference.md +14 -14
- package/skeleton/roles/architect.md +25 -25
- package/skeleton/roles/builder.md +1 -1
- package/skeleton/roles/consultant.md +6 -0
- package/skeleton/templates/AGENTS.md +5 -5
- package/skeleton/templates/CLAUDE.md +5 -5
- package/skeleton/templates/lifecycle.md +9 -9
- package/templates/open.html +6 -3
- package/templates/tower.html +1 -41
- package/dashboard/dist/assets/index-4n9zpWLY.css +0 -32
- package/dashboard/dist/assets/index-UsH9ixz1.js +0 -136
- package/dashboard/dist/assets/index-UsH9ixz1.js.map +0 -1
- package/dist/agent-farm/utils/gate-status.d.ts +0 -16
- package/dist/agent-farm/utils/gate-status.d.ts.map +0 -1
- package/dist/agent-farm/utils/gate-status.js +0 -79
- package/dist/agent-farm/utils/gate-status.js.map +0 -1
- package/skeleton/templates/projectlist-archive.md +0 -21
- package/skeleton/templates/projectlist.md +0 -147
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metrics.d.ts","sourceRoot":"","sources":["../../../src/commands/consult/metrics.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Consultation metrics database
|
|
3
|
+
*
|
|
4
|
+
* Stores per-invocation metrics (duration, tokens, cost) in a global
|
|
5
|
+
* SQLite database at ~/.codev/metrics.db. Uses WAL mode and busy_timeout
|
|
6
|
+
* for safe concurrent writes from 3-way parallel consultations.
|
|
7
|
+
*/
|
|
8
|
+
import Database from 'better-sqlite3';
|
|
9
|
+
import { existsSync, mkdirSync } from 'node:fs';
|
|
10
|
+
import { homedir } from 'node:os';
|
|
11
|
+
import { join, dirname } from 'node:path';
|
|
12
|
+
const CODEV_DIR = join(homedir(), '.codev');
|
|
13
|
+
const DB_PATH = join(CODEV_DIR, 'metrics.db');
|
|
14
|
+
const CREATE_TABLE = `
|
|
15
|
+
CREATE TABLE IF NOT EXISTS consultation_metrics (
|
|
16
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
17
|
+
timestamp TEXT NOT NULL,
|
|
18
|
+
model TEXT NOT NULL,
|
|
19
|
+
review_type TEXT,
|
|
20
|
+
subcommand TEXT NOT NULL,
|
|
21
|
+
protocol TEXT,
|
|
22
|
+
project_id TEXT,
|
|
23
|
+
duration_seconds REAL NOT NULL,
|
|
24
|
+
input_tokens INTEGER,
|
|
25
|
+
cached_input_tokens INTEGER,
|
|
26
|
+
output_tokens INTEGER,
|
|
27
|
+
cost_usd REAL,
|
|
28
|
+
exit_code INTEGER NOT NULL,
|
|
29
|
+
workspace_path TEXT NOT NULL,
|
|
30
|
+
error_message TEXT
|
|
31
|
+
)`;
|
|
32
|
+
const INSERT_ROW = `
|
|
33
|
+
INSERT INTO consultation_metrics (
|
|
34
|
+
timestamp, model, review_type, subcommand, protocol, project_id,
|
|
35
|
+
duration_seconds, input_tokens, cached_input_tokens, output_tokens,
|
|
36
|
+
cost_usd, exit_code, workspace_path, error_message
|
|
37
|
+
) VALUES (
|
|
38
|
+
@timestamp, @model, @reviewType, @subcommand, @protocol, @projectId,
|
|
39
|
+
@durationSeconds, @inputTokens, @cachedInputTokens, @outputTokens,
|
|
40
|
+
@costUsd, @exitCode, @workspacePath, @errorMessage
|
|
41
|
+
)`;
|
|
42
|
+
function buildWhereClause(filters) {
|
|
43
|
+
const conditions = [];
|
|
44
|
+
const params = {};
|
|
45
|
+
if (filters.days) {
|
|
46
|
+
conditions.push("datetime(timestamp) >= datetime('now', @daysOffset)");
|
|
47
|
+
params.daysOffset = `-${filters.days} days`;
|
|
48
|
+
}
|
|
49
|
+
if (filters.model) {
|
|
50
|
+
conditions.push('model = @filterModel');
|
|
51
|
+
params.filterModel = filters.model;
|
|
52
|
+
}
|
|
53
|
+
if (filters.type) {
|
|
54
|
+
conditions.push('review_type = @filterType');
|
|
55
|
+
params.filterType = filters.type;
|
|
56
|
+
}
|
|
57
|
+
if (filters.protocol) {
|
|
58
|
+
conditions.push('protocol = @filterProtocol');
|
|
59
|
+
params.filterProtocol = filters.protocol;
|
|
60
|
+
}
|
|
61
|
+
if (filters.project) {
|
|
62
|
+
conditions.push('project_id = @filterProject');
|
|
63
|
+
params.filterProject = filters.project;
|
|
64
|
+
}
|
|
65
|
+
const where = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';
|
|
66
|
+
return { where, params };
|
|
67
|
+
}
|
|
68
|
+
export class MetricsDB {
|
|
69
|
+
db;
|
|
70
|
+
constructor(dbPath) {
|
|
71
|
+
const path = dbPath ?? DB_PATH;
|
|
72
|
+
const dir = dirname(path);
|
|
73
|
+
if (!existsSync(dir)) {
|
|
74
|
+
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
75
|
+
}
|
|
76
|
+
this.db = new Database(path);
|
|
77
|
+
const journalMode = this.db.pragma('journal_mode = WAL', { simple: true });
|
|
78
|
+
if (journalMode !== 'wal') {
|
|
79
|
+
console.error('[warn] WAL mode unavailable for metrics database');
|
|
80
|
+
}
|
|
81
|
+
this.db.pragma('busy_timeout = 5000');
|
|
82
|
+
this.db.exec(CREATE_TABLE);
|
|
83
|
+
}
|
|
84
|
+
record(entry) {
|
|
85
|
+
try {
|
|
86
|
+
this.db.prepare(INSERT_ROW).run({
|
|
87
|
+
timestamp: entry.timestamp,
|
|
88
|
+
model: entry.model,
|
|
89
|
+
reviewType: entry.reviewType,
|
|
90
|
+
subcommand: entry.subcommand,
|
|
91
|
+
protocol: entry.protocol,
|
|
92
|
+
projectId: entry.projectId,
|
|
93
|
+
durationSeconds: entry.durationSeconds,
|
|
94
|
+
inputTokens: entry.inputTokens,
|
|
95
|
+
cachedInputTokens: entry.cachedInputTokens,
|
|
96
|
+
outputTokens: entry.outputTokens,
|
|
97
|
+
costUsd: entry.costUsd,
|
|
98
|
+
exitCode: entry.exitCode,
|
|
99
|
+
workspacePath: entry.workspacePath,
|
|
100
|
+
errorMessage: entry.errorMessage,
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
catch (err) {
|
|
104
|
+
console.error(`[warn] Failed to write metrics: ${err instanceof Error ? err.message : String(err)}`);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
query(filters) {
|
|
108
|
+
const { where, params } = buildWhereClause(filters);
|
|
109
|
+
let sql = `SELECT * FROM consultation_metrics ${where} ORDER BY timestamp DESC`;
|
|
110
|
+
if (filters.last) {
|
|
111
|
+
sql += ' LIMIT @limit';
|
|
112
|
+
params.limit = filters.last;
|
|
113
|
+
}
|
|
114
|
+
return this.db.prepare(sql).all(params);
|
|
115
|
+
}
|
|
116
|
+
summary(filters) {
|
|
117
|
+
const { where, params } = buildWhereClause(filters);
|
|
118
|
+
// Overall totals
|
|
119
|
+
const totals = this.db.prepare(`
|
|
120
|
+
SELECT
|
|
121
|
+
COUNT(*) as total_count,
|
|
122
|
+
COALESCE(SUM(duration_seconds), 0) as total_duration,
|
|
123
|
+
SUM(CASE WHEN cost_usd IS NOT NULL THEN cost_usd ELSE 0 END) as total_cost,
|
|
124
|
+
SUM(CASE WHEN cost_usd IS NOT NULL THEN 1 ELSE 0 END) as cost_count,
|
|
125
|
+
SUM(CASE WHEN exit_code = 0 THEN 1 ELSE 0 END) as success_count
|
|
126
|
+
FROM consultation_metrics ${where}
|
|
127
|
+
`).get(params);
|
|
128
|
+
// By model
|
|
129
|
+
const byModel = this.db.prepare(`
|
|
130
|
+
SELECT
|
|
131
|
+
model,
|
|
132
|
+
COUNT(*) as count,
|
|
133
|
+
AVG(duration_seconds) as avg_duration,
|
|
134
|
+
SUM(CASE WHEN cost_usd IS NOT NULL THEN cost_usd ELSE 0 END) as total_cost,
|
|
135
|
+
SUM(CASE WHEN cost_usd IS NOT NULL THEN 1 ELSE 0 END) as cost_count,
|
|
136
|
+
SUM(CASE WHEN exit_code = 0 THEN 1 ELSE 0 END) as success_count
|
|
137
|
+
FROM consultation_metrics ${where}
|
|
138
|
+
GROUP BY model
|
|
139
|
+
ORDER BY count DESC
|
|
140
|
+
`).all(params);
|
|
141
|
+
// By review type
|
|
142
|
+
const byType = this.db.prepare(`
|
|
143
|
+
SELECT
|
|
144
|
+
review_type,
|
|
145
|
+
COUNT(*) as count,
|
|
146
|
+
AVG(duration_seconds) as avg_duration,
|
|
147
|
+
SUM(CASE WHEN cost_usd IS NOT NULL THEN cost_usd ELSE 0 END) as total_cost,
|
|
148
|
+
SUM(CASE WHEN cost_usd IS NOT NULL THEN 1 ELSE 0 END) as cost_count
|
|
149
|
+
FROM consultation_metrics ${where} AND review_type IS NOT NULL
|
|
150
|
+
GROUP BY review_type
|
|
151
|
+
ORDER BY count DESC
|
|
152
|
+
`.replace('AND review_type IS NOT NULL', where ? 'AND review_type IS NOT NULL' : 'WHERE review_type IS NOT NULL'))
|
|
153
|
+
.all(params);
|
|
154
|
+
// By protocol
|
|
155
|
+
const byProtocol = this.db.prepare(`
|
|
156
|
+
SELECT
|
|
157
|
+
protocol,
|
|
158
|
+
COUNT(*) as count,
|
|
159
|
+
SUM(CASE WHEN cost_usd IS NOT NULL THEN cost_usd ELSE 0 END) as total_cost,
|
|
160
|
+
SUM(CASE WHEN cost_usd IS NOT NULL THEN 1 ELSE 0 END) as cost_count
|
|
161
|
+
FROM consultation_metrics ${where} AND protocol IS NOT NULL
|
|
162
|
+
GROUP BY protocol
|
|
163
|
+
ORDER BY count DESC
|
|
164
|
+
`.replace('AND protocol IS NOT NULL', where ? 'AND protocol IS NOT NULL' : 'WHERE protocol IS NOT NULL'))
|
|
165
|
+
.all(params);
|
|
166
|
+
return {
|
|
167
|
+
totalCount: totals.total_count,
|
|
168
|
+
totalDuration: totals.total_duration,
|
|
169
|
+
totalCost: totals.cost_count > 0 ? totals.total_cost : null,
|
|
170
|
+
costCount: totals.cost_count,
|
|
171
|
+
successCount: totals.success_count,
|
|
172
|
+
byModel: byModel.map(r => ({
|
|
173
|
+
model: r.model,
|
|
174
|
+
count: r.count,
|
|
175
|
+
avgDuration: r.avg_duration,
|
|
176
|
+
totalCost: r.cost_count > 0 ? r.total_cost : null,
|
|
177
|
+
costCount: r.cost_count,
|
|
178
|
+
successRate: r.count > 0 ? (r.success_count / r.count) * 100 : 0,
|
|
179
|
+
successCount: r.success_count,
|
|
180
|
+
})),
|
|
181
|
+
byType: byType.map(r => ({
|
|
182
|
+
reviewType: r.review_type,
|
|
183
|
+
count: r.count,
|
|
184
|
+
avgDuration: r.avg_duration,
|
|
185
|
+
totalCost: r.cost_count > 0 ? r.total_cost : null,
|
|
186
|
+
costCount: r.cost_count,
|
|
187
|
+
})),
|
|
188
|
+
byProtocol: byProtocol.map(r => ({
|
|
189
|
+
protocol: r.protocol,
|
|
190
|
+
count: r.count,
|
|
191
|
+
totalCost: r.cost_count > 0 ? r.total_cost : null,
|
|
192
|
+
costCount: r.cost_count,
|
|
193
|
+
})),
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
close() {
|
|
197
|
+
this.db.close();
|
|
198
|
+
}
|
|
199
|
+
static get defaultPath() {
|
|
200
|
+
return DB_PATH;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
//# sourceMappingURL=metrics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metrics.js","sourceRoot":"","sources":["../../../src/commands/consult/metrics.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* consult stats - Display consultation metrics summary
|
|
3
|
+
*
|
|
4
|
+
* Queries ~/.codev/metrics.db and displays aggregated statistics
|
|
5
|
+
* or individual invocation history.
|
|
6
|
+
*/
|
|
7
|
+
interface StatsOptions {
|
|
8
|
+
days?: string;
|
|
9
|
+
model?: string;
|
|
10
|
+
type?: string;
|
|
11
|
+
protocol?: string;
|
|
12
|
+
project?: string;
|
|
13
|
+
last?: string;
|
|
14
|
+
json?: boolean;
|
|
15
|
+
}
|
|
16
|
+
export declare function handleStats(_args: string[], options: StatsOptions): Promise<void>;
|
|
17
|
+
export {};
|
|
18
|
+
//# sourceMappingURL=stats.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stats.d.ts","sourceRoot":"","sources":["../../../src/commands/consult/stats.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,UAAU,YAAY;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAyFD,wBAAsB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CA0DvF"}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* consult stats - Display consultation metrics summary
|
|
3
|
+
*
|
|
4
|
+
* Queries ~/.codev/metrics.db and displays aggregated statistics
|
|
5
|
+
* or individual invocation history.
|
|
6
|
+
*/
|
|
7
|
+
import { existsSync } from 'node:fs';
|
|
8
|
+
import { MetricsDB } from './metrics.js';
|
|
9
|
+
function formatDuration(seconds) {
|
|
10
|
+
if (seconds >= 3600) {
|
|
11
|
+
return `${(seconds / 3600).toFixed(1)} hours`;
|
|
12
|
+
}
|
|
13
|
+
if (seconds >= 60) {
|
|
14
|
+
return `${(seconds / 60).toFixed(1)} min`;
|
|
15
|
+
}
|
|
16
|
+
return `${seconds.toFixed(1)}s`;
|
|
17
|
+
}
|
|
18
|
+
function formatCost(cost) {
|
|
19
|
+
if (cost === null)
|
|
20
|
+
return 'N/A';
|
|
21
|
+
return `$${cost.toFixed(2)}`;
|
|
22
|
+
}
|
|
23
|
+
function padRight(str, len) {
|
|
24
|
+
return str + ' '.repeat(Math.max(0, len - str.length));
|
|
25
|
+
}
|
|
26
|
+
function padLeft(str, len) {
|
|
27
|
+
return ' '.repeat(Math.max(0, len - str.length)) + str;
|
|
28
|
+
}
|
|
29
|
+
function printSummary(summary, days) {
|
|
30
|
+
const successRate = summary.totalCount > 0
|
|
31
|
+
? ((summary.successCount / summary.totalCount) * 100).toFixed(1)
|
|
32
|
+
: '0.0';
|
|
33
|
+
const costStr = summary.totalCost !== null
|
|
34
|
+
? `$${summary.totalCost.toFixed(2)} (${summary.costCount} of ${summary.totalCount} with cost data)`
|
|
35
|
+
: 'N/A';
|
|
36
|
+
console.log(`Consultation Metrics (last ${days} days)`);
|
|
37
|
+
console.log('='.repeat(40));
|
|
38
|
+
console.log('');
|
|
39
|
+
console.log(`Total invocations: ${summary.totalCount}`);
|
|
40
|
+
console.log(`Total duration: ${formatDuration(summary.totalDuration)}`);
|
|
41
|
+
console.log(`Total cost: ${costStr}`);
|
|
42
|
+
console.log(`Success rate: ${successRate}% (${summary.successCount}/${summary.totalCount})`);
|
|
43
|
+
if (summary.byModel.length > 0) {
|
|
44
|
+
console.log('');
|
|
45
|
+
console.log('By Model:');
|
|
46
|
+
for (const m of summary.byModel) {
|
|
47
|
+
const avgDur = `avg ${m.avgDuration.toFixed(0)}s`;
|
|
48
|
+
const cost = formatCost(m.totalCost);
|
|
49
|
+
const success = `${m.successRate.toFixed(0)}% success`;
|
|
50
|
+
console.log(` ${padRight(m.model, 8)} ${padLeft(String(m.count), 3)} calls ${padLeft(avgDur, 8)} ${padLeft(cost, 8)} ${success}`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
if (summary.byType.length > 0) {
|
|
54
|
+
console.log('');
|
|
55
|
+
console.log('By Review Type:');
|
|
56
|
+
for (const t of summary.byType) {
|
|
57
|
+
const avgDur = `avg ${t.avgDuration.toFixed(0)}s`;
|
|
58
|
+
const cost = formatCost(t.totalCost);
|
|
59
|
+
console.log(` ${padRight(t.reviewType, 20)} ${padLeft(String(t.count), 3)} calls ${padLeft(avgDur, 8)} ${padLeft(cost, 8)}`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
if (summary.byProtocol.length > 0) {
|
|
63
|
+
console.log('');
|
|
64
|
+
console.log('By Protocol:');
|
|
65
|
+
for (const p of summary.byProtocol) {
|
|
66
|
+
const cost = formatCost(p.totalCost);
|
|
67
|
+
console.log(` ${padRight(p.protocol, 8)} ${padLeft(String(p.count), 3)} calls ${padLeft(cost, 8)}`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
function printLastN(rows) {
|
|
72
|
+
console.log(`Last ${rows.length} consultations:`);
|
|
73
|
+
console.log(`${padRight('TIMESTAMP', 20)} ${padRight('MODEL', 8)} ${padRight('TYPE', 20)} ${padRight('DURATION', 10)} ${padRight('COST', 10)} ${padRight('EXIT', 5)} PROJECT`);
|
|
74
|
+
for (const row of rows) {
|
|
75
|
+
const ts = new Date(row.timestamp).toLocaleString('sv-SE', { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit' }).replace(',', '');
|
|
76
|
+
const model = row.model;
|
|
77
|
+
const type = row.review_type ?? '';
|
|
78
|
+
const duration = `${row.duration_seconds.toFixed(1)}s`;
|
|
79
|
+
const cost = row.cost_usd !== null ? `$${row.cost_usd.toFixed(2)}` : 'N/A';
|
|
80
|
+
const exit = String(row.exit_code);
|
|
81
|
+
const project = row.project_id ?? '';
|
|
82
|
+
console.log(`${padRight(ts, 20)} ${padRight(model, 8)} ${padRight(type, 20)} ${padLeft(duration, 10)} ${padLeft(cost, 10)} ${padLeft(exit, 5)} ${project}`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
export async function handleStats(_args, options) {
|
|
86
|
+
// Cold start: check if database exists
|
|
87
|
+
if (!existsSync(MetricsDB.defaultPath)) {
|
|
88
|
+
console.log('No metrics data found. Run a consultation first.');
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
const filters = {};
|
|
92
|
+
if (options.days) {
|
|
93
|
+
filters.days = parseInt(options.days, 10);
|
|
94
|
+
if (isNaN(filters.days) || filters.days <= 0) {
|
|
95
|
+
throw new Error(`Invalid --days value: ${options.days}`);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
filters.days = 30; // Default to last 30 days
|
|
100
|
+
}
|
|
101
|
+
if (options.model)
|
|
102
|
+
filters.model = options.model;
|
|
103
|
+
if (options.type)
|
|
104
|
+
filters.type = options.type;
|
|
105
|
+
if (options.protocol)
|
|
106
|
+
filters.protocol = options.protocol;
|
|
107
|
+
if (options.project)
|
|
108
|
+
filters.project = options.project;
|
|
109
|
+
if (options.last) {
|
|
110
|
+
filters.last = parseInt(options.last, 10);
|
|
111
|
+
if (isNaN(filters.last) || filters.last <= 0) {
|
|
112
|
+
throw new Error(`Invalid --last value: ${options.last}`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
const db = new MetricsDB();
|
|
116
|
+
try {
|
|
117
|
+
if (options.json) {
|
|
118
|
+
if (options.last) {
|
|
119
|
+
const rows = db.query(filters);
|
|
120
|
+
console.log(JSON.stringify(rows, null, 2));
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
const summary = db.summary(filters);
|
|
124
|
+
console.log(JSON.stringify(summary, null, 2));
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
else if (options.last) {
|
|
128
|
+
const rows = db.query(filters);
|
|
129
|
+
if (rows.length === 0) {
|
|
130
|
+
console.log('No consultations found matching the filters.');
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
printLastN(rows);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
const summary = db.summary(filters);
|
|
138
|
+
if (summary.totalCount === 0) {
|
|
139
|
+
console.log('No consultations found matching the filters.');
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
printSummary(summary, filters.days);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
finally {
|
|
147
|
+
db.close();
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
//# sourceMappingURL=stats.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stats.js","sourceRoot":"","sources":["../../../src/commands/consult/stats.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Usage extraction from structured model output
|
|
3
|
+
*
|
|
4
|
+
* Extracts token counts, cost, and review text from Claude SDK results
|
|
5
|
+
* and Gemini JSON output. All parsing is wrapped in try/catch — returns
|
|
6
|
+
* null on failure, never throws.
|
|
7
|
+
*
|
|
8
|
+
* Codex usage and review text are captured directly from SDK events in
|
|
9
|
+
* runCodexConsultation() — no JSONL parsing needed.
|
|
10
|
+
*/
|
|
11
|
+
export interface UsageData {
|
|
12
|
+
inputTokens: number | null;
|
|
13
|
+
cachedInputTokens: number | null;
|
|
14
|
+
outputTokens: number | null;
|
|
15
|
+
costUsd: number | null;
|
|
16
|
+
}
|
|
17
|
+
export interface SDKResultLike {
|
|
18
|
+
type: 'result';
|
|
19
|
+
subtype: string;
|
|
20
|
+
total_cost_usd?: number;
|
|
21
|
+
usage?: {
|
|
22
|
+
input_tokens?: number;
|
|
23
|
+
output_tokens?: number;
|
|
24
|
+
cache_read_input_tokens?: number;
|
|
25
|
+
cache_creation_input_tokens?: number;
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Extract token counts and cost from structured model output.
|
|
30
|
+
* Returns null if extraction fails entirely (logs warning to stderr).
|
|
31
|
+
*/
|
|
32
|
+
export declare function extractUsage(model: string, output: string, sdkResult?: SDKResultLike): UsageData | null;
|
|
33
|
+
/**
|
|
34
|
+
* Extract plain-text review content from structured model output.
|
|
35
|
+
* Returns null if extraction fails (caller should fall back to raw output).
|
|
36
|
+
*/
|
|
37
|
+
export declare function extractReviewText(model: string, output: string): string | null;
|
|
38
|
+
//# sourceMappingURL=usage-extractor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usage-extractor.d.ts","sourceRoot":"","sources":["../../../src/commands/consult/usage-extractor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAWH,MAAM,WAAW,SAAS;IACxB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AAGD,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,QAAQ,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,KAAK,CAAC,EAAE;QACN,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,uBAAuB,CAAC,EAAE,MAAM,CAAC;QACjC,2BAA2B,CAAC,EAAE,MAAM,CAAC;KACtC,CAAC;CACH;AAyDD;;;GAGG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,aAAa,GAAG,SAAS,GAAG,IAAI,CAcvG;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAgB9E"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Usage extraction from structured model output
|
|
3
|
+
*
|
|
4
|
+
* Extracts token counts, cost, and review text from Claude SDK results
|
|
5
|
+
* and Gemini JSON output. All parsing is wrapped in try/catch — returns
|
|
6
|
+
* null on failure, never throws.
|
|
7
|
+
*
|
|
8
|
+
* Codex usage and review text are captured directly from SDK events in
|
|
9
|
+
* runCodexConsultation() — no JSONL parsing needed.
|
|
10
|
+
*/
|
|
11
|
+
// Static pricing for subprocess models (Claude and Codex provide cost via SDK)
|
|
12
|
+
const SUBPROCESS_MODEL_PRICING = {
|
|
13
|
+
gemini: { inputPer1M: 1.25, cachedInputPer1M: 0.315, outputPer1M: 10.00 },
|
|
14
|
+
};
|
|
15
|
+
function computeCost(model, inputTokens, cachedInputTokens, outputTokens) {
|
|
16
|
+
if (inputTokens === null || cachedInputTokens === null || outputTokens === null) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
const pricing = SUBPROCESS_MODEL_PRICING[model];
|
|
20
|
+
if (!pricing)
|
|
21
|
+
return null;
|
|
22
|
+
const uncachedInput = inputTokens - cachedInputTokens;
|
|
23
|
+
return ((uncachedInput / 1_000_000) * pricing.inputPer1M +
|
|
24
|
+
(cachedInputTokens / 1_000_000) * pricing.cachedInputPer1M +
|
|
25
|
+
(outputTokens / 1_000_000) * pricing.outputPer1M);
|
|
26
|
+
}
|
|
27
|
+
function extractClaudeUsage(sdkResult) {
|
|
28
|
+
const usage = sdkResult.usage;
|
|
29
|
+
return {
|
|
30
|
+
inputTokens: usage?.input_tokens ?? null,
|
|
31
|
+
cachedInputTokens: usage?.cache_read_input_tokens ?? null,
|
|
32
|
+
outputTokens: usage?.output_tokens ?? null,
|
|
33
|
+
costUsd: sdkResult.total_cost_usd ?? null,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
function extractGeminiUsage(output) {
|
|
37
|
+
const parsed = JSON.parse(output);
|
|
38
|
+
const models = parsed?.stats?.models;
|
|
39
|
+
if (!models || typeof models !== 'object')
|
|
40
|
+
return null;
|
|
41
|
+
// Take the first (and typically only) model entry
|
|
42
|
+
const modelKeys = Object.keys(models);
|
|
43
|
+
if (modelKeys.length === 0)
|
|
44
|
+
return null;
|
|
45
|
+
const tokens = models[modelKeys[0]]?.tokens;
|
|
46
|
+
if (!tokens)
|
|
47
|
+
return null;
|
|
48
|
+
const inputTokens = typeof tokens.prompt === 'number' ? tokens.prompt : null;
|
|
49
|
+
const cachedInputTokens = typeof tokens.cached === 'number' ? tokens.cached : null;
|
|
50
|
+
const outputTokens = typeof tokens.candidates === 'number' ? tokens.candidates : null;
|
|
51
|
+
return {
|
|
52
|
+
inputTokens,
|
|
53
|
+
cachedInputTokens,
|
|
54
|
+
outputTokens,
|
|
55
|
+
costUsd: computeCost('gemini', inputTokens, cachedInputTokens, outputTokens),
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Extract token counts and cost from structured model output.
|
|
60
|
+
* Returns null if extraction fails entirely (logs warning to stderr).
|
|
61
|
+
*/
|
|
62
|
+
export function extractUsage(model, output, sdkResult) {
|
|
63
|
+
try {
|
|
64
|
+
if (model === 'claude' && sdkResult) {
|
|
65
|
+
return extractClaudeUsage(sdkResult);
|
|
66
|
+
}
|
|
67
|
+
if (model === 'gemini') {
|
|
68
|
+
return extractGeminiUsage(output);
|
|
69
|
+
}
|
|
70
|
+
// Codex usage is captured directly from SDK events in runCodexConsultation()
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
catch (err) {
|
|
74
|
+
console.error(`[warn] Failed to extract usage for ${model}: ${err instanceof Error ? err.message : String(err)}`);
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Extract plain-text review content from structured model output.
|
|
80
|
+
* Returns null if extraction fails (caller should fall back to raw output).
|
|
81
|
+
*/
|
|
82
|
+
export function extractReviewText(model, output) {
|
|
83
|
+
try {
|
|
84
|
+
if (model === 'gemini') {
|
|
85
|
+
const parsed = JSON.parse(output);
|
|
86
|
+
if (typeof parsed?.response === 'string') {
|
|
87
|
+
return parsed.response;
|
|
88
|
+
}
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
// Claude and Codex use SDKs — text is captured directly by their streaming loops
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
catch (err) {
|
|
95
|
+
console.error(`[warn] Failed to extract review text for ${model}: ${err instanceof Error ? err.message : String(err)}`);
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=usage-extractor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usage-extractor.js","sourceRoot":"","sources":["../../../src/commands/consult/usage-extractor.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AAAA;;;;GAIG;
|
|
1
|
+
{"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAqeH;;GAEG;AACH,wBAAsB,MAAM,IAAI,OAAO,CAAC,MAAM,CAAC,CA2J9C"}
|
package/dist/commands/doctor.js
CHANGED
|
@@ -168,11 +168,13 @@ function checkDependency(dep) {
|
|
|
168
168
|
// Special case for gh auth status
|
|
169
169
|
if (dep.name === 'gh') {
|
|
170
170
|
try {
|
|
171
|
-
execSync('gh auth status', { stdio: 'pipe' });
|
|
172
|
-
|
|
171
|
+
const authOutput = execSync('gh auth status', { stdio: 'pipe', encoding: 'utf-8' });
|
|
172
|
+
const accountMatch = authOutput.match(/Logged in to .+ account (\S+)/);
|
|
173
|
+
const username = accountMatch ? accountMatch[1] : null;
|
|
174
|
+
return { status: 'ok', version: username ? `authenticated as ${username}` : 'authenticated' };
|
|
173
175
|
}
|
|
174
176
|
catch {
|
|
175
|
-
return { status: 'warn', version: 'not authenticated', note: 'gh auth login' };
|
|
177
|
+
return { status: 'warn', version: 'not authenticated', note: 'run: gh auth login' };
|
|
176
178
|
}
|
|
177
179
|
}
|
|
178
180
|
// Get version
|