@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.
Files changed (184) hide show
  1. package/dashboard/dist/assets/index-B-s8BA2l.js +135 -0
  2. package/dashboard/dist/assets/index-B-s8BA2l.js.map +1 -0
  3. package/dashboard/dist/assets/index-DB2AxRP7.css +32 -0
  4. package/dashboard/dist/index.html +2 -2
  5. package/dist/agent-farm/cli.d.ts.map +1 -1
  6. package/dist/agent-farm/cli.js +31 -13
  7. package/dist/agent-farm/cli.js.map +1 -1
  8. package/dist/agent-farm/commands/attach.d.ts +19 -0
  9. package/dist/agent-farm/commands/attach.d.ts.map +1 -1
  10. package/dist/agent-farm/commands/attach.js +172 -12
  11. package/dist/agent-farm/commands/attach.js.map +1 -1
  12. package/dist/agent-farm/commands/send.d.ts +22 -2
  13. package/dist/agent-farm/commands/send.d.ts.map +1 -1
  14. package/dist/agent-farm/commands/send.js +97 -178
  15. package/dist/agent-farm/commands/send.js.map +1 -1
  16. package/dist/agent-farm/commands/spawn-roles.d.ts +3 -9
  17. package/dist/agent-farm/commands/spawn-roles.d.ts.map +1 -1
  18. package/dist/agent-farm/commands/spawn-roles.js +14 -53
  19. package/dist/agent-farm/commands/spawn-roles.js.map +1 -1
  20. package/dist/agent-farm/commands/spawn-worktree.d.ts +10 -16
  21. package/dist/agent-farm/commands/spawn-worktree.d.ts.map +1 -1
  22. package/dist/agent-farm/commands/spawn-worktree.js +24 -5
  23. package/dist/agent-farm/commands/spawn-worktree.js.map +1 -1
  24. package/dist/agent-farm/commands/spawn.d.ts +8 -6
  25. package/dist/agent-farm/commands/spawn.d.ts.map +1 -1
  26. package/dist/agent-farm/commands/spawn.js +180 -66
  27. package/dist/agent-farm/commands/spawn.js.map +1 -1
  28. package/dist/agent-farm/commands/status.d.ts.map +1 -1
  29. package/dist/agent-farm/commands/status.js +1 -12
  30. package/dist/agent-farm/commands/status.js.map +1 -1
  31. package/dist/agent-farm/lib/tower-client.d.ts +16 -6
  32. package/dist/agent-farm/lib/tower-client.d.ts.map +1 -1
  33. package/dist/agent-farm/lib/tower-client.js +25 -0
  34. package/dist/agent-farm/lib/tower-client.js.map +1 -1
  35. package/dist/agent-farm/servers/overview.d.ts +111 -0
  36. package/dist/agent-farm/servers/overview.d.ts.map +1 -0
  37. package/dist/agent-farm/servers/overview.js +385 -0
  38. package/dist/agent-farm/servers/overview.js.map +1 -0
  39. package/dist/agent-farm/servers/tower-instances.d.ts +1 -3
  40. package/dist/agent-farm/servers/tower-instances.d.ts.map +1 -1
  41. package/dist/agent-farm/servers/tower-instances.js +10 -13
  42. package/dist/agent-farm/servers/tower-instances.js.map +1 -1
  43. package/dist/agent-farm/servers/tower-messages.d.ts +87 -0
  44. package/dist/agent-farm/servers/tower-messages.d.ts.map +1 -0
  45. package/dist/agent-farm/servers/tower-messages.js +202 -0
  46. package/dist/agent-farm/servers/tower-messages.js.map +1 -0
  47. package/dist/agent-farm/servers/tower-routes.d.ts.map +1 -1
  48. package/dist/agent-farm/servers/tower-routes.js +164 -17
  49. package/dist/agent-farm/servers/tower-routes.js.map +1 -1
  50. package/dist/agent-farm/servers/tower-server.js +27 -2
  51. package/dist/agent-farm/servers/tower-server.js.map +1 -1
  52. package/dist/agent-farm/servers/tower-terminals.d.ts +8 -2
  53. package/dist/agent-farm/servers/tower-terminals.d.ts.map +1 -1
  54. package/dist/agent-farm/servers/tower-terminals.js +125 -80
  55. package/dist/agent-farm/servers/tower-terminals.js.map +1 -1
  56. package/dist/agent-farm/servers/tower-types.d.ts +0 -2
  57. package/dist/agent-farm/servers/tower-types.d.ts.map +1 -1
  58. package/dist/agent-farm/servers/tower-websocket.d.ts.map +1 -1
  59. package/dist/agent-farm/servers/tower-websocket.js +25 -4
  60. package/dist/agent-farm/servers/tower-websocket.js.map +1 -1
  61. package/dist/agent-farm/types.d.ts +3 -4
  62. package/dist/agent-farm/types.d.ts.map +1 -1
  63. package/dist/agent-farm/utils/agent-names.d.ts +85 -0
  64. package/dist/agent-farm/utils/agent-names.d.ts.map +1 -0
  65. package/dist/agent-farm/utils/agent-names.js +140 -0
  66. package/dist/agent-farm/utils/agent-names.js.map +1 -0
  67. package/dist/agent-farm/utils/message-format.d.ts +17 -0
  68. package/dist/agent-farm/utils/message-format.d.ts.map +1 -0
  69. package/dist/agent-farm/utils/message-format.js +41 -0
  70. package/dist/agent-farm/utils/message-format.js.map +1 -0
  71. package/dist/cli.d.ts.map +1 -1
  72. package/dist/cli.js +26 -1
  73. package/dist/cli.js.map +1 -1
  74. package/dist/commands/adopt.d.ts.map +1 -1
  75. package/dist/commands/adopt.js +1 -13
  76. package/dist/commands/adopt.js.map +1 -1
  77. package/dist/commands/consult/index.d.ts +25 -1
  78. package/dist/commands/consult/index.d.ts.map +1 -1
  79. package/dist/commands/consult/index.js +251 -39
  80. package/dist/commands/consult/index.js.map +1 -1
  81. package/dist/commands/consult/metrics.d.ts +90 -0
  82. package/dist/commands/consult/metrics.d.ts.map +1 -0
  83. package/dist/commands/consult/metrics.js +203 -0
  84. package/dist/commands/consult/metrics.js.map +1 -0
  85. package/dist/commands/consult/stats.d.ts +18 -0
  86. package/dist/commands/consult/stats.d.ts.map +1 -0
  87. package/dist/commands/consult/stats.js +150 -0
  88. package/dist/commands/consult/stats.js.map +1 -0
  89. package/dist/commands/consult/usage-extractor.d.ts +38 -0
  90. package/dist/commands/consult/usage-extractor.d.ts.map +1 -0
  91. package/dist/commands/consult/usage-extractor.js +99 -0
  92. package/dist/commands/consult/usage-extractor.js.map +1 -0
  93. package/dist/commands/doctor.d.ts.map +1 -1
  94. package/dist/commands/doctor.js +5 -3
  95. package/dist/commands/doctor.js.map +1 -1
  96. package/dist/commands/init.d.ts.map +1 -1
  97. package/dist/commands/init.js +1 -13
  98. package/dist/commands/init.js.map +1 -1
  99. package/dist/commands/porch/next.d.ts.map +1 -1
  100. package/dist/commands/porch/next.js +53 -62
  101. package/dist/commands/porch/next.js.map +1 -1
  102. package/dist/commands/porch/prompts.d.ts +10 -1
  103. package/dist/commands/porch/prompts.d.ts.map +1 -1
  104. package/dist/commands/porch/prompts.js +50 -26
  105. package/dist/commands/porch/prompts.js.map +1 -1
  106. package/dist/commands/porch/protocol.js +2 -2
  107. package/dist/commands/porch/state.d.ts.map +1 -1
  108. package/dist/commands/porch/state.js +3 -1
  109. package/dist/commands/porch/state.js.map +1 -1
  110. package/dist/commands/update.d.ts.map +1 -1
  111. package/dist/commands/update.js +0 -10
  112. package/dist/commands/update.js.map +1 -1
  113. package/dist/lib/github.d.ts +81 -0
  114. package/dist/lib/github.d.ts.map +1 -0
  115. package/dist/lib/github.js +141 -0
  116. package/dist/lib/github.js.map +1 -0
  117. package/dist/lib/scaffold.d.ts +0 -21
  118. package/dist/lib/scaffold.d.ts.map +1 -1
  119. package/dist/lib/scaffold.js +0 -57
  120. package/dist/lib/scaffold.js.map +1 -1
  121. package/dist/terminal/index.d.ts +14 -0
  122. package/dist/terminal/index.d.ts.map +1 -1
  123. package/dist/terminal/index.js +12 -0
  124. package/dist/terminal/index.js.map +1 -1
  125. package/dist/terminal/pty-manager.d.ts.map +1 -1
  126. package/dist/terminal/pty-manager.js +7 -4
  127. package/dist/terminal/pty-manager.js.map +1 -1
  128. package/dist/terminal/pty-session.js +3 -3
  129. package/dist/terminal/pty-session.js.map +1 -1
  130. package/dist/terminal/session-manager.d.ts +64 -0
  131. package/dist/terminal/session-manager.d.ts.map +1 -1
  132. package/dist/terminal/session-manager.js +299 -10
  133. package/dist/terminal/session-manager.js.map +1 -1
  134. package/dist/terminal/shellper-client.d.ts +2 -1
  135. package/dist/terminal/shellper-client.d.ts.map +1 -1
  136. package/dist/terminal/shellper-client.js +4 -2
  137. package/dist/terminal/shellper-client.js.map +1 -1
  138. package/dist/terminal/shellper-main.js +33 -4
  139. package/dist/terminal/shellper-main.js.map +1 -1
  140. package/dist/terminal/shellper-process.d.ts +24 -7
  141. package/dist/terminal/shellper-process.d.ts.map +1 -1
  142. package/dist/terminal/shellper-process.js +139 -36
  143. package/dist/terminal/shellper-process.js.map +1 -1
  144. package/dist/terminal/shellper-protocol.d.ts +1 -0
  145. package/dist/terminal/shellper-protocol.d.ts.map +1 -1
  146. package/dist/terminal/shellper-protocol.js.map +1 -1
  147. package/package.json +4 -1
  148. package/skeleton/.claude/skills/af/SKILL.md +7 -7
  149. package/skeleton/.claude/skills/consult/SKILL.md +1 -1
  150. package/skeleton/builders.md +2 -2
  151. package/skeleton/maintain/.gitkeep +1 -1
  152. package/skeleton/porch/prompts/specify.md +1 -1
  153. package/skeleton/protocols/bugfix/prompts/pr.md +15 -4
  154. package/skeleton/protocols/experiment/protocol.md +17 -17
  155. package/skeleton/protocols/maintain/prompts/audit.md +2 -2
  156. package/skeleton/protocols/maintain/prompts/sync.md +1 -1
  157. package/skeleton/protocols/maintain/prompts/verify.md +1 -1
  158. package/skeleton/protocols/maintain/protocol.md +8 -9
  159. package/skeleton/protocols/maintain/templates/maintenance-run.md +2 -2
  160. package/skeleton/protocols/spir/protocol.json +5 -5
  161. package/skeleton/protocols/spir/protocol.md +8 -8
  162. package/skeleton/protocols/tick/protocol.md +31 -31
  163. package/skeleton/resources/commands/agent-farm.md +14 -14
  164. package/skeleton/resources/commands/codev.md +0 -1
  165. package/skeleton/resources/commands/consult.md +3 -3
  166. package/skeleton/resources/spikes.md +3 -3
  167. package/skeleton/resources/workflow-reference.md +14 -14
  168. package/skeleton/roles/architect.md +25 -25
  169. package/skeleton/roles/builder.md +1 -1
  170. package/skeleton/roles/consultant.md +6 -0
  171. package/skeleton/templates/AGENTS.md +5 -5
  172. package/skeleton/templates/CLAUDE.md +5 -5
  173. package/skeleton/templates/lifecycle.md +9 -9
  174. package/templates/open.html +6 -3
  175. package/templates/tower.html +1 -41
  176. package/dashboard/dist/assets/index-4n9zpWLY.css +0 -32
  177. package/dashboard/dist/assets/index-UsH9ixz1.js +0 -136
  178. package/dashboard/dist/assets/index-UsH9ixz1.js.map +0 -1
  179. package/dist/agent-farm/utils/gate-status.d.ts +0 -16
  180. package/dist/agent-farm/utils/gate-status.d.ts.map +0 -1
  181. package/dist/agent-farm/utils/gate-status.js +0 -79
  182. package/dist/agent-farm/utils/gate-status.js.map +0 -1
  183. package/skeleton/templates/projectlist-archive.md +0 -21
  184. 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;AAmeH;;GAEG;AACH,wBAAsB,MAAM,IAAI,OAAO,CAAC,MAAM,CAAC,CA2J9C"}
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"}
@@ -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
- return { status: 'ok', version: 'authenticated' };
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