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 CHANGED
@@ -1,13 +1,8 @@
1
1
  # agentwaste-core
2
2
 
3
- Shared scanner/report engine used by the `agentmess` focused CLI tools.
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
- - `agentmess`
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.0",
3
+ "version": "0.1.1",
4
4
  "type": "module",
5
- "description": "Shared local coding-agent scanner powering agentmess and the tiny gremlin CLI squad.",
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 { buildReport, calculationGuide } from "./report.js";
4
- import { scanAgentWaste } from "./scanner.js";
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
- const elapsedMs = Date.now() - startedAt;
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, config) {
51
+ function parseArgs(argv) {
106
52
  const args = argv.slice(2);
107
53
  const options = {
108
- command: config.defaultCommand,
54
+ command: "scan",
109
55
  homeDir: undefined,
110
56
  projectDir: process.cwd(),
111
- days: 365,
112
- maxFiles: Number.MAX_SAFE_INTEGER,
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 rawCommand = args.shift();
119
- if (!config.commands.has(rawCommand)) throw new Error(`unknown command ${rawCommand}`);
120
- options.command = config.aliases.get(rawCommand) ?? rawCommand;
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 = Number.MAX_SAFE_INTEGER;
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 = Number.MAX_SAFE_INTEGER;
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.emoji} ${config.npc}: ${config.tagline}
151
+ ${config.tagline}
220
152
 
221
153
  Usage:
222
- ${config.binName} [scan] [options]
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: 365)
234
- --all Scan all available sessions (same as --days all)
235
- --max-files <number> Maximum session files per source (default: unlimited)
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
- Try:
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 messages = spinnerMessages(toolId);
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 message = messages[Math.floor(index / 8) % messages.length];
294
- process.stdout.write(`\r${ansi(options.color, "38;2;147;197;253", frame)} ${ansi(options.color, "38;2;148;163;184", message)} `);
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, 80);
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 spinnerMessages(toolId) {
310
- switch (toolId) {
311
- case "suckytraces":
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 { runAgentmessCli, runToolCli } from "./cli.js";
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";