agentwaste-core 0.1.0 → 0.1.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 +2 -7
- package/package.json +2 -2
- package/src/cli.js +50 -175
- package/src/index.js +1 -2
- package/src/report.js +0 -495
- package/src/scanner.js +133 -45
- package/src/tools.js +238 -577
package/README.md
CHANGED
|
@@ -1,13 +1,8 @@
|
|
|
1
1
|
# agentwaste-core
|
|
2
2
|
|
|
3
|
-
Shared scanner
|
|
3
|
+
Shared scanner engine used by the two focused local CLIs:
|
|
4
4
|
|
|
5
|
-
This package is meant as a dependency for:
|
|
6
|
-
|
|
7
|
-
- `suckytraces`
|
|
8
|
-
- `keybarf`
|
|
9
|
-
- `tokengoblin`
|
|
10
5
|
- `tooltantrum`
|
|
11
|
-
- `
|
|
6
|
+
- `suckytraces`
|
|
12
7
|
|
|
13
8
|
It has no public `npx` command of its own.
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agentwaste-core",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"description": "Shared local coding-agent scanner powering
|
|
5
|
+
"description": "Shared local coding-agent scanner powering tooltantrum and suckytraces.",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"ai",
|
|
8
8
|
"agents",
|
package/src/cli.js
CHANGED
|
@@ -1,69 +1,11 @@
|
|
|
1
1
|
import { resolve } from "node:path";
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { buildToolReport, explainTool, getToolConfig, listToolConfigs } from "./tools.js";
|
|
6
|
-
|
|
7
|
-
const DEFAULT_PACKAGE = { name: "agentmess", version: "0.1.0" };
|
|
8
|
-
|
|
9
|
-
export async function runAgentmessCli(argv, packageInfo = DEFAULT_PACKAGE) {
|
|
10
|
-
const parsed = parseArgs(argv, {
|
|
11
|
-
defaultCommand: "scan",
|
|
12
|
-
commands: new Set(["scan", "explain", "tools", "squad"]),
|
|
13
|
-
aliases: new Map([["list", "tools"]]),
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
if (parsed.help) {
|
|
17
|
-
console.log(agentmessHelp(packageInfo));
|
|
18
|
-
return;
|
|
19
|
-
}
|
|
20
|
-
if (parsed.version) {
|
|
21
|
-
console.log(packageInfo.version);
|
|
22
|
-
return;
|
|
23
|
-
}
|
|
24
|
-
if (parsed.options.command === "tools" || parsed.options.command === "squad") {
|
|
25
|
-
console.log(toolSquadText(packageInfo));
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
|
-
if (parsed.options.command === "explain") {
|
|
29
|
-
console.log(calculationGuide({ version: packageInfo.version, json: parsed.options.json }));
|
|
30
|
-
return;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
const startedAt = Date.now();
|
|
34
|
-
const spinner = startScanSpinner(parsed.options, "agentmess");
|
|
35
|
-
let stats;
|
|
36
|
-
try {
|
|
37
|
-
stats = await scanAgentWaste(parsed.options);
|
|
38
|
-
} finally {
|
|
39
|
-
spinner.stop();
|
|
40
|
-
}
|
|
41
|
-
const elapsedMs = Date.now() - startedAt;
|
|
42
|
-
const report = buildReport(stats, {
|
|
43
|
-
version: packageInfo.version,
|
|
44
|
-
elapsedMs,
|
|
45
|
-
color: parsed.options.color,
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
if (parsed.options.json) {
|
|
49
|
-
console.log(JSON.stringify(report.json, null, 2));
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
console.log(report.text);
|
|
54
|
-
}
|
|
3
|
+
import { SCAN_DEFAULTS, scanAgentWaste } from "./scanner.js";
|
|
4
|
+
import { buildToolReport, explainTool, getToolConfig } from "./tools.js";
|
|
55
5
|
|
|
56
6
|
export async function runToolCli(argv, toolId, packageInfo = { name: toolId, version: "0.1.0" }) {
|
|
57
7
|
const config = getToolConfig(toolId);
|
|
58
|
-
const parsed = parseArgs(argv
|
|
59
|
-
defaultCommand: "scan",
|
|
60
|
-
commands: new Set(["scan", "show", "sniff", "roast", "explain"]),
|
|
61
|
-
aliases: new Map([
|
|
62
|
-
["show", "scan"],
|
|
63
|
-
["sniff", "scan"],
|
|
64
|
-
["roast", "scan"],
|
|
65
|
-
]),
|
|
66
|
-
});
|
|
8
|
+
const parsed = parseArgs(argv);
|
|
67
9
|
|
|
68
10
|
if (parsed.help) {
|
|
69
11
|
console.log(toolHelp(config, packageInfo));
|
|
@@ -86,11 +28,11 @@ export async function runToolCli(argv, toolId, packageInfo = { name: toolId, ver
|
|
|
86
28
|
} finally {
|
|
87
29
|
spinner.stop();
|
|
88
30
|
}
|
|
89
|
-
|
|
31
|
+
|
|
90
32
|
const report = buildToolReport(stats, {
|
|
91
33
|
toolId,
|
|
92
34
|
version: packageInfo.version,
|
|
93
|
-
elapsedMs,
|
|
35
|
+
elapsedMs: Date.now() - startedAt,
|
|
94
36
|
color: parsed.options.color,
|
|
95
37
|
});
|
|
96
38
|
|
|
@@ -98,26 +40,37 @@ export async function runToolCli(argv, toolId, packageInfo = { name: toolId, ver
|
|
|
98
40
|
console.log(JSON.stringify(report.json, null, 2));
|
|
99
41
|
return;
|
|
100
42
|
}
|
|
43
|
+
if (parsed.options.share) {
|
|
44
|
+
console.log(report.share);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
101
47
|
|
|
102
48
|
console.log(report.text);
|
|
103
49
|
}
|
|
104
50
|
|
|
105
|
-
function parseArgs(argv
|
|
51
|
+
function parseArgs(argv) {
|
|
106
52
|
const args = argv.slice(2);
|
|
107
53
|
const options = {
|
|
108
|
-
command:
|
|
54
|
+
command: "scan",
|
|
109
55
|
homeDir: undefined,
|
|
110
56
|
projectDir: process.cwd(),
|
|
111
|
-
days:
|
|
112
|
-
maxFiles:
|
|
57
|
+
days: SCAN_DEFAULTS.days,
|
|
58
|
+
maxFiles: SCAN_DEFAULTS.maxFiles,
|
|
59
|
+
concurrency: SCAN_DEFAULTS.concurrency,
|
|
113
60
|
json: false,
|
|
61
|
+
share: false,
|
|
114
62
|
color: process.stdout.isTTY,
|
|
115
63
|
};
|
|
116
64
|
|
|
117
65
|
if (args[0] && !args[0].startsWith("-")) {
|
|
118
|
-
const
|
|
119
|
-
if (
|
|
120
|
-
|
|
66
|
+
const command = args.shift();
|
|
67
|
+
if (command === "explain") {
|
|
68
|
+
options.command = "explain";
|
|
69
|
+
} else if (["scan", "show", "sniff", "roast"].includes(command)) {
|
|
70
|
+
options.command = "scan";
|
|
71
|
+
} else {
|
|
72
|
+
throw new Error(`unknown command ${command}`);
|
|
73
|
+
}
|
|
121
74
|
}
|
|
122
75
|
|
|
123
76
|
let maxFilesExplicit = false;
|
|
@@ -130,13 +83,17 @@ function parseArgs(argv, config) {
|
|
|
130
83
|
options.json = true;
|
|
131
84
|
continue;
|
|
132
85
|
}
|
|
86
|
+
if (arg === "--share") {
|
|
87
|
+
options.share = true;
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
133
90
|
if (arg === "--no-color") {
|
|
134
91
|
options.color = false;
|
|
135
92
|
continue;
|
|
136
93
|
}
|
|
137
94
|
if (arg === "--all") {
|
|
138
95
|
options.days = "all";
|
|
139
|
-
if (!maxFilesExplicit) options.maxFiles =
|
|
96
|
+
if (!maxFilesExplicit) options.maxFiles = SCAN_DEFAULTS.exhaustiveMaxFiles;
|
|
140
97
|
continue;
|
|
141
98
|
}
|
|
142
99
|
if (arg === "--home") {
|
|
@@ -155,7 +112,7 @@ function parseArgs(argv, config) {
|
|
|
155
112
|
i += 1;
|
|
156
113
|
if (!args[i]) throw new Error("--days requires a number or all");
|
|
157
114
|
options.days = parseDays(args[i], "--days");
|
|
158
|
-
if (options.days === "all" && !maxFilesExplicit) options.maxFiles =
|
|
115
|
+
if (options.days === "all" && !maxFilesExplicit) options.maxFiles = SCAN_DEFAULTS.exhaustiveMaxFiles;
|
|
159
116
|
continue;
|
|
160
117
|
}
|
|
161
118
|
if (arg === "--max-files") {
|
|
@@ -165,6 +122,12 @@ function parseArgs(argv, config) {
|
|
|
165
122
|
options.maxFiles = parsePositiveInt(args[i], "--max-files");
|
|
166
123
|
continue;
|
|
167
124
|
}
|
|
125
|
+
if (arg === "--concurrency") {
|
|
126
|
+
i += 1;
|
|
127
|
+
if (!args[i]) throw new Error("--concurrency requires a number");
|
|
128
|
+
options.concurrency = parsePositiveInt(args[i], "--concurrency");
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
168
131
|
throw new Error(`unknown option ${arg}`);
|
|
169
132
|
}
|
|
170
133
|
|
|
@@ -182,121 +145,47 @@ function parsePositiveInt(value, flag) {
|
|
|
182
145
|
return parsed;
|
|
183
146
|
}
|
|
184
147
|
|
|
185
|
-
function agentmessHelp(packageInfo) {
|
|
186
|
-
return `agentmess v${packageInfo.version}
|
|
187
|
-
|
|
188
|
-
Usage:
|
|
189
|
-
agentmess [scan] [options]
|
|
190
|
-
agentmess explain [options]
|
|
191
|
-
agentmess tools
|
|
192
|
-
|
|
193
|
-
Commands:
|
|
194
|
-
scan Full local agent postmortem (default)
|
|
195
|
-
explain Explain every report formula without scanning logs
|
|
196
|
-
tools Show the focused npx CLIs
|
|
197
|
-
|
|
198
|
-
Options:
|
|
199
|
-
--home <path> Home directory to scan (default: current user's home)
|
|
200
|
-
--path <path> Project directory to scan (default: cwd)
|
|
201
|
-
--days <number|all> Lookback window in days (default: 365)
|
|
202
|
-
--all Scan all available sessions (same as --days all)
|
|
203
|
-
--max-files <number> Maximum session files per source (default: unlimited)
|
|
204
|
-
--json Print machine-readable JSON
|
|
205
|
-
--no-color Disable ANSI color
|
|
206
|
-
--version Print version
|
|
207
|
-
--help Show help
|
|
208
|
-
|
|
209
|
-
Focused tools:
|
|
210
|
-
${listToolConfigs().map((tool) => ` npx ${tool.binName.padEnd(16)} ${tool.emoji} ${tool.npc}`).join("\n")}
|
|
211
|
-
|
|
212
|
-
The scanner runs locally. It counts redacted fingerprints and aggregate metrics;
|
|
213
|
-
it does not upload transcripts or print raw secret values.`;
|
|
214
|
-
}
|
|
215
|
-
|
|
216
148
|
function toolHelp(config, packageInfo) {
|
|
217
149
|
return `${config.packageName} v${packageInfo.version}
|
|
218
150
|
|
|
219
|
-
${config.
|
|
151
|
+
${config.tagline}
|
|
220
152
|
|
|
221
153
|
Usage:
|
|
222
|
-
${config.binName} [
|
|
154
|
+
${config.binName} [options]
|
|
223
155
|
${config.binName} explain [options]
|
|
224
156
|
|
|
225
|
-
Aliases:
|
|
226
|
-
${config.binName} show
|
|
227
|
-
${config.binName} sniff
|
|
228
|
-
${config.binName} roast
|
|
229
|
-
|
|
230
157
|
Options:
|
|
231
158
|
--home <path> Home directory to scan (default: current user's home)
|
|
232
159
|
--path <path> Project directory to scan (default: cwd)
|
|
233
|
-
--days <number|all> Lookback window in days (default:
|
|
234
|
-
--all Scan all available sessions
|
|
235
|
-
--max-files <number> Maximum session files per source (default:
|
|
160
|
+
--days <number|all> Lookback window in days (default: ${SCAN_DEFAULTS.days})
|
|
161
|
+
--all Scan all available sessions
|
|
162
|
+
--max-files <number> Maximum session files per source (default: ${SCAN_DEFAULTS.maxFiles})
|
|
163
|
+
--concurrency <number> Session files to scan in parallel (default: ${SCAN_DEFAULTS.concurrency})
|
|
236
164
|
--json Print machine-readable JSON
|
|
165
|
+
--share Print a copy-pasteable summary card
|
|
237
166
|
--no-color Disable ANSI color
|
|
238
167
|
--version Print version
|
|
239
168
|
--help Show help
|
|
240
169
|
|
|
241
|
-
|
|
242
|
-
npx ${config.binName}
|
|
243
|
-
npx ${config.binName} --days 7
|
|
244
|
-
npx ${config.binName} --json`;
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
function toolSquadText(packageInfo) {
|
|
248
|
-
return [
|
|
249
|
-
`agentmess focused tools v${packageInfo.version}`,
|
|
250
|
-
"",
|
|
251
|
-
...listToolConfigs().map((tool) => `npx ${tool.binName.padEnd(16)} ${tool.emoji} ${tool.npc} — ${tool.tagline}`),
|
|
252
|
-
"",
|
|
253
|
-
"npx agentmess consolidated report for the focused checks",
|
|
254
|
-
].join("\n");
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
async function narrate(options, toolId) {
|
|
258
|
-
if (options.json || !process.stdout.isTTY) return;
|
|
259
|
-
for (const line of narrationMessages(toolId)) {
|
|
260
|
-
process.stdout.write(`${ansi(options.color, "38;2;148;163;184", ` ${line}`)}\n`);
|
|
261
|
-
await sleep(170);
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
function narrationMessages(toolId) {
|
|
266
|
-
switch (toolId) {
|
|
267
|
-
case "suckytraces":
|
|
268
|
-
return ["scanning session logs.", "computing trace coverage."];
|
|
269
|
-
case "keybarf":
|
|
270
|
-
return ["scanning logs and config for secret fingerprints.", "checking whether fingerprints appear in model-facing records."];
|
|
271
|
-
case "tokengoblin":
|
|
272
|
-
return ["reading token usage records.", "computing fresh input, cache hit rate, and excess context."];
|
|
273
|
-
case "tooltantrum":
|
|
274
|
-
return ["counting tool calls and failures.", "computing retry recovery and unresolved failures."];
|
|
275
|
-
default:
|
|
276
|
-
return ["scanned the agent logs.", "numbers first, feelings later."];
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
function sleep(ms) {
|
|
281
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
170
|
+
The scanner runs locally and prints aggregate metrics only.`;
|
|
282
171
|
}
|
|
283
172
|
|
|
284
173
|
function startScanSpinner(options, toolId) {
|
|
285
174
|
if (options.json || !process.stdout.isTTY) return { stop() {} };
|
|
286
175
|
|
|
287
176
|
const frames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
288
|
-
const
|
|
177
|
+
const startedAt = Date.now();
|
|
289
178
|
let index = 0;
|
|
290
179
|
|
|
291
180
|
const render = () => {
|
|
292
181
|
const frame = frames[index % frames.length];
|
|
293
|
-
const
|
|
294
|
-
process.stdout.write(`\r${ansi(options.color, "38;2;147;197;253", frame)} ${
|
|
182
|
+
const elapsed = formatSpinnerSeconds(Date.now() - startedAt);
|
|
183
|
+
process.stdout.write(`\r\x1b[2K${ansi(options.color, "38;2;147;197;253", frame)} ${toolId} scanning local sessions · ${elapsed}`);
|
|
295
184
|
index += 1;
|
|
296
185
|
};
|
|
297
186
|
|
|
298
187
|
render();
|
|
299
|
-
const timer = setInterval(render,
|
|
188
|
+
const timer = setInterval(render, 120);
|
|
300
189
|
|
|
301
190
|
return {
|
|
302
191
|
stop() {
|
|
@@ -306,26 +195,12 @@ function startScanSpinner(options, toolId) {
|
|
|
306
195
|
};
|
|
307
196
|
}
|
|
308
197
|
|
|
309
|
-
function
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
return ["scanning session logs...", "checking trace identifiers...", "computing trace coverage..."];
|
|
313
|
-
case "keybarf":
|
|
314
|
-
return ["scanning secret patterns...", "fingerprinting matches...", "checking model-facing records..."];
|
|
315
|
-
case "tokengoblin":
|
|
316
|
-
return ["reading token usage...", "computing fresh input...", "checking cache hit rate..."];
|
|
317
|
-
case "tooltantrum":
|
|
318
|
-
return ["counting tool calls...", "measuring failure rate...", "checking retry recovery..."];
|
|
319
|
-
default:
|
|
320
|
-
return ["scanning sessions...", "checking token usage...", "checking secrets...", "checking tool reliability...", "checking trace coverage..."];
|
|
321
|
-
}
|
|
198
|
+
function formatSpinnerSeconds(ms) {
|
|
199
|
+
const seconds = Math.max(0.1, Number(ms || 0) / 1000);
|
|
200
|
+
return `${seconds.toFixed(seconds >= 10 ? 0 : 1)}s`;
|
|
322
201
|
}
|
|
323
202
|
|
|
324
203
|
function ansi(enabled, code, value) {
|
|
325
204
|
if (!enabled) return value;
|
|
326
205
|
return `\x1b[${code}m${value}\x1b[0m`;
|
|
327
206
|
}
|
|
328
|
-
|
|
329
|
-
function color(code, value) {
|
|
330
|
-
return `\x1b[${code}m${value}\x1b[0m`;
|
|
331
|
-
}
|
package/src/index.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export { buildReport, calculationGuide, toReportJson } from "./report.js";
|
|
1
|
+
export { runToolCli } from "./cli.js";
|
|
3
2
|
export { scanAgentWaste } from "./scanner.js";
|
|
4
3
|
export { TOOL_IDS, buildToolReport, explainTool, getToolConfig, listToolConfigs } from "./tools.js";
|