snapfail 0.0.22 → 0.0.24

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/dist/index.js CHANGED
@@ -1938,9 +1938,7 @@ ${r2}
1938
1938
  }).prompt();
1939
1939
 
1940
1940
  // src/skill.ts
1941
- function generateSkillMd(config, framework) {
1942
- return `# snapfail
1943
-
1941
+ var SKILL_BODY = `
1944
1942
  snapfail captures browser error context (stack, console, network, replay timeline)
1945
1943
  and stores it so you can diagnose root causes. Evidence is structured for LLM reasoning.
1946
1944
 
@@ -1952,14 +1950,18 @@ When the user reports an error or unexpected behavior in their app, run:
1952
1950
  snapfail incidents --json
1953
1951
  \`\`\`
1954
1952
 
1955
- Then drill into a specific incident:
1953
+ Then get full structured context for a specific incident:
1956
1954
 
1957
1955
  \`\`\`
1958
- snapfail incident <id> --json
1956
+ snapfail explain <id>
1959
1957
  \`\`\`
1960
1958
 
1961
- **Always use \`--json\` when querying from the LLM** \u2014 it returns structured data
1962
- without ANSI color codes.
1959
+ \`snapfail explain\` outputs all captured evidence (stack, console, network, timeline, device,
1960
+ multiple samples) formatted as structured text. **Read it and reason about the root cause
1961
+ yourself** \u2014 do not delegate this to another model.
1962
+
1963
+ **Always use \`--json\` when querying from the LLM** for \`incidents\` and \`incident\` \u2014
1964
+ it returns structured data without ANSI color codes.
1963
1965
 
1964
1966
  ## Commands
1965
1967
 
@@ -1968,34 +1970,47 @@ snapfail incidents [--status=unresolved|resolved|ignored] [--json]
1968
1970
  List incident groups. Default status: unresolved.
1969
1971
 
1970
1972
  snapfail incident <id> [--sample <n>] [--json]
1971
- Show incident detail: group summary + most recent sample (stack, console, network, timeline).
1972
- Use --sample <n> (0-indexed) to compare different occurrences of the same error.
1973
+ Group summary + one sample (stack, console, network, timeline).
1974
+ Use --sample <n> (0-indexed) to compare different occurrences.
1973
1975
 
1974
1976
  snapfail explain <id>
1975
- AI diagnosis: root cause, plain summary, fix prompt. (requires @snapfail/ai)
1977
+ Outputs structured evidence for up to 3 samples. Read and diagnose directly.
1976
1978
  \`\`\`
1977
1979
 
1980
+ All commands accept \`--pk <project_key>\` to override the project key from \`.env\`.
1981
+
1978
1982
  ## Interpreting an incident
1979
1983
 
1980
- Key fields from \`snapfail incident <id> --json\`:
1984
+ Key fields:
1981
1985
 
1982
1986
  - \`group.title\` \u2014 normalized error message (dynamic values replaced with [uuid], [id], etc.)
1983
- - \`group.count\` \u2014 total occurrences
1984
- - \`group.environments\` \u2014 where it happened: "dev" | "prod"
1987
+ - \`group.count\` \u2014 total occurrences (\u2260 number of groups)
1988
+ - \`group.environments\` \u2014 "dev" | "prod"
1985
1989
  - \`group.severity\` \u2014 "critical" | "error" | "warning"
1986
1990
  - \`sample.stackFrames\` \u2014 call stack at the time of the error
1987
- - \`sample.consoleEntries\` \u2014 last ~15s of console output before the error
1988
- - \`sample.networkEntries\` \u2014 last ~15s of network requests (scrubbed)
1989
- - \`sample.timeline\` \u2014 derived user interaction sequence (clicks, navigation, mutations)
1991
+ - \`sample.consoleEntries\` \u2014 console output before the error
1992
+ - \`sample.networkEntries\` \u2014 network requests (auth headers scrubbed)
1993
+ - \`sample.timeline\` \u2014 user interaction sequence (clicks, navigation, mutations)
1994
+ - \`sample.device.userAgent\` \u2014 browser/OS \u2014 critical for mobile/in-app browser bugs
1990
1995
  - \`sample.url\` / \`sample.route\` \u2014 where the error occurred
1991
-
1996
+ `;
1997
+ function generateSkillMd(config, framework) {
1998
+ return `# snapfail
1999
+ ${SKILL_BODY}
1992
2000
  ## Config
1993
2001
 
1994
2002
  Project key: \`${config.projectKey}\`
1995
2003
  Endpoint: \`${config.endpoint}\`
1996
- ${framework ? `Framework: ${framework}
1997
- ` : ""}
1998
- Config file: \`.snapfail.json\` (gitignored)
2004
+ ${framework ? `Framework: \`${framework}\`
2005
+ ` : ""}`;
2006
+ }
2007
+ function generateGlobalSkillMd() {
2008
+ return `# snapfail
2009
+ ${SKILL_BODY}
2010
+ ## Project key
2011
+
2012
+ The project key is read automatically from \`SNAPFAIL_PROJECT_KEY\` in \`.env\` or the shell.
2013
+ Pass \`--pk <key>\` to override when querying a specific project.
1999
2014
  `;
2000
2015
  }
2001
2016
 
@@ -2316,10 +2331,10 @@ async function runInit(cwd = process.cwd()) {
2316
2331
  writeProjectKey(selectedKey, cwd, "NEXT_PUBLIC_SNAPFAIL_PROJECT_KEY");
2317
2332
  addToGitignore(cwd, ".env");
2318
2333
  log.success("SNAPFAIL_PROJECT_KEY written to .env");
2319
- const skillDir = join2(cwd, ".agents", "skills", "snapfail");
2334
+ const skillDir = join2(cwd, ".claude", "skills", "snapfail");
2320
2335
  mkdirSync2(skillDir, { recursive: true });
2321
2336
  writeFileSync3(join2(skillDir, "SKILL.md"), generateSkillMd({ projectKey: selectedKey, endpoint: DEFAULT_ENDPOINT }, framework), "utf-8");
2322
- log.success("SKILL.md created at .agents/skills/snapfail/SKILL.md");
2337
+ log.success("SKILL.md created at .claude/skills/snapfail/SKILL.md");
2323
2338
  const pm = detectPackageManager(cwd);
2324
2339
  if (framework === "astro") {
2325
2340
  const cfg = findConfigFile(cwd, ["astro.config.ts", "astro.config.mjs", "astro.config.js"]);
@@ -2392,6 +2407,19 @@ async function runExplain(opts) {
2392
2407
  `);
2393
2408
  }
2394
2409
 
2410
+ // src/commands/skill.ts
2411
+ import { writeFileSync as writeFileSync4, mkdirSync as mkdirSync3, existsSync as existsSync4 } from "fs";
2412
+ import { join as join3 } from "path";
2413
+ import { homedir as homedir2 } from "os";
2414
+ var SKILL_DIR = join3(homedir2(), ".claude", "skills", "snapfail");
2415
+ var SKILL_FILE = join3(SKILL_DIR, "SKILL.md");
2416
+ async function runSkill() {
2417
+ mkdirSync3(SKILL_DIR, { recursive: true });
2418
+ const existed = existsSync4(SKILL_FILE);
2419
+ writeFileSync4(SKILL_FILE, generateGlobalSkillMd(), "utf-8");
2420
+ console.log(existed ? `Updated ${SKILL_FILE}` : `Created ${SKILL_FILE}`);
2421
+ }
2422
+
2395
2423
  // src/index.ts
2396
2424
  function parseArgs(argv) {
2397
2425
  const [, , rawCommand = "incidents", ...rest] = argv;
@@ -2426,6 +2454,10 @@ async function main() {
2426
2454
  await runInit();
2427
2455
  return;
2428
2456
  }
2457
+ if (command === "skill") {
2458
+ await runSkill();
2459
+ return;
2460
+ }
2429
2461
  if (command === "incidents") {
2430
2462
  await runIncidents({
2431
2463
  json,
@@ -2457,7 +2489,7 @@ async function main() {
2457
2489
  return;
2458
2490
  }
2459
2491
  console.error(`Unknown command: ${command}`);
2460
- console.error(`snapfail v${VERSION} \u2014 Usage: snapfail [incidents|incident|init|explain] [--version]`);
2492
+ console.error(`snapfail v${VERSION} \u2014 Usage: snapfail [incidents|incident|init|explain|skill] [--version]`);
2461
2493
  process.exit(1);
2462
2494
  } catch (err) {
2463
2495
  const message = err instanceof Error ? err.message : String(err);
package/package.json CHANGED
@@ -1,19 +1,13 @@
1
1
  {
2
2
  "name": "snapfail",
3
- "version": "0.0.22",
3
+ "version": "0.0.24",
4
4
  "type": "module",
5
5
  "description": "CLI for snapfail — project setup, incident inspection and AI diagnostics",
6
6
  "license": "MIT",
7
7
  "bin": {
8
- "snapfail": "./src/index.ts"
9
- },
10
- "main": "./src/index.ts",
11
- "publishConfig": {
12
- "bin": {
13
- "snapfail": "./dist/index.js"
14
- },
15
- "main": "./dist/index.js"
8
+ "snapfail": "./dist/index.js"
16
9
  },
10
+ "main": "./dist/index.js",
17
11
  "files": ["dist"],
18
12
  "scripts": {
19
13
  "build": "bun build src/index.ts --outdir dist --target bun --format esm --sourcemap=none",
package/src/index.ts DELETED
@@ -1,97 +0,0 @@
1
- #!/usr/bin/env bun
2
- import { runIncidents } from "./commands/incidents.ts";
3
- import { runIncident } from "./commands/incident.ts";
4
- import { runInit } from "./commands/init.ts";
5
- import { runExplain } from "./commands/explain.ts";
6
-
7
- function parseArgs(argv: string[]): {
8
- command: string;
9
- args: string[];
10
- flags: Record<string, string | boolean>;
11
- } {
12
- const [, , rawCommand = "incidents", ...rest] = argv;
13
- const command = rawCommand;
14
- const args: string[] = [];
15
- const flags: Record<string, string | boolean> = {};
16
-
17
- for (const token of rest) {
18
- if (token.startsWith("--")) {
19
- const eq = token.indexOf("=");
20
- if (eq !== -1) {
21
- flags[token.slice(2, eq)] = token.slice(eq + 1);
22
- } else {
23
- flags[token.slice(2)] = true;
24
- }
25
- } else {
26
- args.push(token);
27
- }
28
- }
29
-
30
- return { command, args, flags };
31
- }
32
-
33
- const VERSION = "0.0.18";
34
-
35
- async function main(): Promise<void> {
36
- const { command, args, flags } = parseArgs(process.argv);
37
- const json = flags["json"] === true;
38
- const pk = typeof flags["pk"] === "string" ? flags["pk"] : undefined;
39
-
40
- if (command === "--version" || command === "-v" || flags["version"] === true) {
41
- console.log(VERSION);
42
- return;
43
- }
44
-
45
- try {
46
- if (command === "init") {
47
- await runInit();
48
- return;
49
- }
50
-
51
- if (command === "incidents") {
52
- await runIncidents({
53
- json,
54
- pk,
55
- status: typeof flags["status"] === "string" ? flags["status"] : undefined,
56
- limit: typeof flags["limit"] === "string" ? parseInt(flags["limit"]) : undefined,
57
- offset: typeof flags["offset"] === "string" ? parseInt(flags["offset"]) : undefined,
58
- });
59
- return;
60
- }
61
-
62
- if (command === "incident") {
63
- const id = args[0];
64
- if (!id) {
65
- console.error("Usage: snapfail incident <id> [--sample <n>] [--json]");
66
- process.exit(1);
67
- }
68
- const sampleFlag = flags["sample"];
69
- const sample =
70
- typeof sampleFlag === "string" ? parseInt(sampleFlag) : undefined;
71
- await runIncident({ id, sample, json, pk, delete: flags["delete"] === true });
72
- return;
73
- }
74
-
75
- if (command === "explain") {
76
- const id = args[0];
77
- if (!id) {
78
- console.error("Usage: snapfail explain <id> [--force] [--json]");
79
- process.exit(1);
80
- }
81
- await runExplain({ id, json, pk });
82
- return;
83
- }
84
-
85
- console.error(`Unknown command: ${command}`);
86
- console.error(`snapfail v${VERSION} — Usage: snapfail [incidents|incident|init|explain] [--version]`);
87
- process.exit(1);
88
- } catch (err) {
89
- const message = err instanceof Error ? err.message : String(err);
90
- console.error(`Error: ${message}`);
91
- process.exit(1);
92
- }
93
- }
94
-
95
- if (import.meta.main) {
96
- main();
97
- }