claude-inspect 0.5.1 → 0.7.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.de.md +28 -2
- package/README.md +6 -2
- package/dist/app/server/cli/demo.js +2 -0
- package/dist/app/server/cli.js +5 -2
- package/dist/app/server/config.js +2 -0
- package/dist/app/server/cpu-monitor.js +23 -3
- package/dist/app/server/history/aggregator.js +7 -3
- package/dist/app/server/http.js +57 -1
- package/dist/app/server/inspector.js +102 -7
- package/dist/app/server/model/cpu.js +1 -1
- package/dist/app/server/review/digest.js +362 -0
- package/dist/app/server/review/runner.js +249 -0
- package/dist/app/server/run.js +1 -1
- package/dist/app/server/sources/plan.js +23 -0
- package/dist/app/server/sources/spawns.js +25 -6
- package/dist/app/shared/budget.js +18 -0
- package/dist/app/shared/review.js +57 -0
- package/dist/app/shared/types.js +0 -2
- package/dist/web/assets/index-BH5nprTU.js +19 -0
- package/dist/web/assets/index-BNso7xYj.css +1 -0
- package/dist/web/index.html +2 -2
- package/package.json +2 -1
- package/dist/web/assets/index-CpYuiE4Y.js +0 -16
- package/dist/web/assets/index-Jv_qFlIw.css +0 -1
|
@@ -132,8 +132,10 @@ export class SpawnIndex {
|
|
|
132
132
|
links = new Map();
|
|
133
133
|
/** Neue Zeilen aller Transcripts nach claude-Aufrufen durchsuchen (inkrementell). */
|
|
134
134
|
async refresh(transcripts, processes, full) {
|
|
135
|
+
let changed = full;
|
|
135
136
|
for (const f of transcripts) {
|
|
136
|
-
await this.scanFile(f.path, f.size, f.sessionId)
|
|
137
|
+
if (await this.scanFile(f.path, f.size, f.sessionId))
|
|
138
|
+
changed = true;
|
|
137
139
|
// Subagenten können ebenfalls claude-Aufrufe machen. Nach dem ersten
|
|
138
140
|
// Durchlauf nur noch bei kürzlich aktiven Sessions nachsehen.
|
|
139
141
|
if (!full && Date.now() - f.mtime > 3600_000)
|
|
@@ -152,7 +154,8 @@ export class SpawnIndex {
|
|
|
152
154
|
continue;
|
|
153
155
|
const path = join(dir, n);
|
|
154
156
|
try {
|
|
155
|
-
await this.scanFile(path, (await stat(path)).size, f.sessionId, m[1])
|
|
157
|
+
if (await this.scanFile(path, (await stat(path)).size, f.sessionId, m[1]))
|
|
158
|
+
changed = true;
|
|
156
159
|
}
|
|
157
160
|
catch {
|
|
158
161
|
/* gelöscht */
|
|
@@ -160,13 +163,26 @@ export class SpawnIndex {
|
|
|
160
163
|
}
|
|
161
164
|
}
|
|
162
165
|
for (const f of transcripts)
|
|
163
|
-
await this.readChild(f)
|
|
166
|
+
if (await this.readChild(f))
|
|
167
|
+
changed = true;
|
|
168
|
+
// Zuordnen ist teuer (alle Aufrufe × alle Kinder) – nur bei neuen Daten oder geänderten Prozessen
|
|
169
|
+
const procKey = processes
|
|
170
|
+
.filter((p) => p.alive)
|
|
171
|
+
.map((p) => `${p.pid}:${p.sessionId}:${p.parentPid ?? ''}`)
|
|
172
|
+
.sort()
|
|
173
|
+
.join(',');
|
|
174
|
+
if (!changed && procKey === this.procKey)
|
|
175
|
+
return;
|
|
176
|
+
this.procKey = procKey;
|
|
164
177
|
this.link(processes);
|
|
165
178
|
}
|
|
179
|
+
procKey = '';
|
|
180
|
+
/** true, wenn neue claude-Aufrufe dazugekommen sind */
|
|
166
181
|
async scanFile(path, size, sessionId, agentId) {
|
|
167
182
|
let st = this.files.get(path);
|
|
168
183
|
if (st && st.size === size)
|
|
169
|
-
return;
|
|
184
|
+
return false;
|
|
185
|
+
const before = st?.calls.length ?? -1;
|
|
170
186
|
if (!st || size < st.size) {
|
|
171
187
|
st = { size: 0, tail: new JsonlTail(path), calls: [] };
|
|
172
188
|
this.files.set(path, st);
|
|
@@ -192,12 +208,14 @@ export class SpawnIndex {
|
|
|
192
208
|
catch {
|
|
193
209
|
/* gelöscht */
|
|
194
210
|
}
|
|
211
|
+
return st.calls.length !== before;
|
|
195
212
|
}
|
|
196
213
|
/** Kopf eines Transcripts: Einstiegspunkt, erster Prompt, Startzeit, Agent. */
|
|
197
214
|
async readChild(f) {
|
|
198
215
|
const cached = this.children.get(f.sessionId);
|
|
199
|
-
|
|
200
|
-
|
|
216
|
+
// unveränderte Datei nicht erneut lesen (auch wenn noch kein Prompt gefunden wurde)
|
|
217
|
+
if (cached && (cached.size === f.size || (cached.info.prompt !== undefined && cached.size <= f.size)))
|
|
218
|
+
return false;
|
|
201
219
|
const info = { sessionId: f.sessionId };
|
|
202
220
|
try {
|
|
203
221
|
const { head } = await readHeadTail(f.path, 96 * 1024, 0);
|
|
@@ -228,6 +246,7 @@ export class SpawnIndex {
|
|
|
228
246
|
/* gelöscht */
|
|
229
247
|
}
|
|
230
248
|
this.children.set(f.sessionId, { size: f.size, info });
|
|
249
|
+
return JSON.stringify(cached?.info) !== JSON.stringify(info);
|
|
231
250
|
}
|
|
232
251
|
link(processes) {
|
|
233
252
|
const allCalls = [...this.files.values()].flatMap((f) => f.calls);
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export const BUDGET_CALIBRATED = '2026-10-13';
|
|
2
|
+
export const PLANS = {
|
|
3
|
+
max20x: { label: 'Max 20x', weekUSD: 2350, sessionUSD: 540, measured: true },
|
|
4
|
+
max5x: { label: 'Max 5x', weekUSD: 1500, sessionUSD: 120, measured: true },
|
|
5
|
+
pro: { label: 'Pro', weekUSD: 400, sessionUSD: 25, measured: false },
|
|
6
|
+
};
|
|
7
|
+
/** Tarif aus dem Rate-Limit-Tier in ~/.claude.json, z. B. "default_claude_max_20x". */
|
|
8
|
+
export function planFromTier(tier) {
|
|
9
|
+
if (!tier)
|
|
10
|
+
return undefined;
|
|
11
|
+
if (/max_20x/i.test(tier))
|
|
12
|
+
return 'max20x';
|
|
13
|
+
if (/max_5x/i.test(tier))
|
|
14
|
+
return 'max5x';
|
|
15
|
+
if (/pro/i.test(tier))
|
|
16
|
+
return 'pro';
|
|
17
|
+
return undefined;
|
|
18
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// Analyse einer Session durch Claude ("Analyze with Claude"): Prüfaspekte und Datentypen.
|
|
2
|
+
export const ASPECTS = [
|
|
3
|
+
{
|
|
4
|
+
key: 'outcome',
|
|
5
|
+
label: 'Task outcome',
|
|
6
|
+
hint: 'Did the agent do what was asked? Anything skipped, half-done or claimed without evidence?',
|
|
7
|
+
brief: 'Compare the user requests with what was actually done. Point out parts that were skipped, left unfinished or done differently than asked, and claims in the final answers that are not backed by the tool calls (e.g. "tests pass" without a test run).',
|
|
8
|
+
default: true,
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
key: 'efficiency',
|
|
12
|
+
label: 'Efficiency & cost',
|
|
13
|
+
hint: 'Wasted tokens and time: redundant reads, loops, oversized context, expensive model for simple work.',
|
|
14
|
+
brief: 'Find where time, tokens or money were wasted: files read repeatedly, searches that could have been one call, loops and retries, very large contexts, expensive models or subagents used for trivial work, long waits. Use the cost and context figures. Estimate what a leaner run would have looked like.',
|
|
15
|
+
default: true,
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
key: 'errors',
|
|
19
|
+
label: 'Errors & dead ends',
|
|
20
|
+
hint: 'Failed tool calls, retries and detours – what went wrong and how much it cost.',
|
|
21
|
+
brief: 'Go through failed tool calls, denied permissions, retries and abandoned approaches. For each relevant one: the cause, how the agent recovered (or did not), and how much time/cost the detour took.',
|
|
22
|
+
default: false,
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
key: 'privacy',
|
|
26
|
+
label: 'Privacy & data protection',
|
|
27
|
+
hint: 'Secrets or personal data read, printed or sent to external services.',
|
|
28
|
+
brief: 'Check whether sensitive data was touched: credentials, keys, tokens ([REDACTED] marks secrets that appeared in the original), .env files, SSH/cloud configs, personal data (names, emails, addresses, customer data). Did any of it end up in outputs, commits, logs or requests to external services (curl, WebFetch, MCP tools, git push)? Distinguish necessary access from unnecessary exposure.',
|
|
29
|
+
default: true,
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
key: 'security',
|
|
33
|
+
label: 'Security & risky actions',
|
|
34
|
+
hint: 'Destructive commands, force pushes, permission bypasses, untrusted code, prompt injection.',
|
|
35
|
+
brief: 'Look for risky actions: destructive or irreversible commands (rm -rf, reset --hard, force push, dropping data), sudo, disabled safety checks (--no-verify, bypass permissions), installing or running untrusted code (curl | sh, unknown packages), and signs of prompt injection from fetched web content or files that changed the agent\'s behaviour.',
|
|
36
|
+
default: false,
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
key: 'orchestration',
|
|
40
|
+
label: 'Agents & delegation',
|
|
41
|
+
hint: 'Subagents and spawned claude workers: sensible split, duplicate work, cost per agent.',
|
|
42
|
+
brief: 'Assess how work was split across subagents and spawned claude sessions: was delegation worth it, were prompts to subagents clear and complete, did agents duplicate work or wait on each other, which agent cost most relative to its contribution? If there were no subagents, say whether delegation would have helped.',
|
|
43
|
+
default: false,
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
key: 'improvements',
|
|
47
|
+
label: 'Setup improvements',
|
|
48
|
+
hint: 'What to change in prompt, CLAUDE.md, permissions or skills so the next run goes smoother.',
|
|
49
|
+
brief: 'Derive concrete improvements for next time: better phrasing of the request, rules or facts worth adding to CLAUDE.md, permission allow-rules that would have avoided prompts, hooks, skills or subagents that would fit. Give copy-pasteable snippets where possible.',
|
|
50
|
+
default: true,
|
|
51
|
+
},
|
|
52
|
+
];
|
|
53
|
+
export const REVIEW_MODELS = [
|
|
54
|
+
{ key: 'haiku', label: 'Haiku – fast, cheapest' },
|
|
55
|
+
{ key: 'sonnet', label: 'Sonnet – balanced' },
|
|
56
|
+
{ key: 'opus', label: 'Opus – most thorough' },
|
|
57
|
+
];
|
package/dist/app/shared/types.js
CHANGED