litmus-cli 1.4.1 → 1.4.2

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 (40) hide show
  1. package/dist/commands/doctor.d.ts +136 -0
  2. package/dist/commands/doctor.d.ts.map +1 -0
  3. package/dist/commands/doctor.js +1055 -0
  4. package/dist/commands/doctor.js.map +1 -0
  5. package/dist/commands/init.d.ts +1 -0
  6. package/dist/commands/init.d.ts.map +1 -1
  7. package/dist/commands/init.js +8 -2
  8. package/dist/commands/init.js.map +1 -1
  9. package/dist/commands/status.d.ts.map +1 -1
  10. package/dist/commands/status.js +5 -1
  11. package/dist/commands/status.js.map +1 -1
  12. package/dist/index.js +25 -0
  13. package/dist/index.js.map +1 -1
  14. package/dist/lib/ai-tracking.d.ts +35 -0
  15. package/dist/lib/ai-tracking.d.ts.map +1 -1
  16. package/dist/lib/ai-tracking.js +40 -10
  17. package/dist/lib/ai-tracking.js.map +1 -1
  18. package/dist/lib/api.d.ts +14 -0
  19. package/dist/lib/api.d.ts.map +1 -1
  20. package/dist/lib/api.js +40 -0
  21. package/dist/lib/api.js.map +1 -1
  22. package/dist/lib/backfill.d.ts +106 -0
  23. package/dist/lib/backfill.d.ts.map +1 -0
  24. package/dist/lib/backfill.js +356 -0
  25. package/dist/lib/backfill.js.map +1 -0
  26. package/dist/lib/chain.d.ts +42 -0
  27. package/dist/lib/chain.d.ts.map +1 -0
  28. package/dist/lib/chain.js +98 -0
  29. package/dist/lib/chain.js.map +1 -0
  30. package/dist/lib/errors.d.ts +19 -0
  31. package/dist/lib/errors.d.ts.map +1 -1
  32. package/dist/lib/errors.js +9 -1
  33. package/dist/lib/errors.js.map +1 -1
  34. package/dist/lib/tracker.d.ts +16 -0
  35. package/dist/lib/tracker.d.ts.map +1 -1
  36. package/dist/lib/tracker.js +23 -0
  37. package/dist/lib/tracker.js.map +1 -1
  38. package/dist/lib/watcher.js +110 -5
  39. package/dist/lib/watcher.js.map +1 -1
  40. package/package.json +1 -1
@@ -0,0 +1,136 @@
1
+ /**
2
+ * `litmus doctor` — candidate-run recovery for a live assessment.
3
+ *
4
+ * The background tracker `litmus init` starts is a detached process nothing
5
+ * supervises. Over a multi-day assessment the candidate's machine sleeps,
6
+ * crashes, and drops off Wi-Fi, and a tracker that dies stays dead silently;
7
+ * editor updates likewise clobber the AI-usage hooks. Doctor is the explicit
8
+ * repair command we point a candidate at when our monitoring sees their
9
+ * tracking go quiet: it diagnoses every piece of the local setup with
10
+ * pass/fail lines the candidate can paste back to us, repairs what it can
11
+ * through the SAME code paths init uses (tracker spawn, hook installers), and
12
+ * records what it did both locally (tracker.log, activity.jsonl) and
13
+ * server-side (a `doctor_run` activity event plus a CLI info event).
14
+ *
15
+ * Safety rules, in priority order:
16
+ * - Never destructive: activity.jsonl is never truncated or rewritten,
17
+ * events are uploaded verbatim, the flush cursor never moves backward,
18
+ * and a revived tracker resumes the existing tamper-evidence chain
19
+ * (see lib/chain.ts) instead of restarting it at genesis.
20
+ * - Idempotent: on a healthy setup every check passes and nothing changes.
21
+ * - No blind signals: doctor never SIGTERMs a pid it cannot verify is ours
22
+ * (a stale pid may have been recycled by an unrelated process); it asks
23
+ * the tracker to exit via the shutdown sentinel the tracker already polls.
24
+ *
25
+ * Exit code 0 when everything is healthy or was repaired; 1 when problems
26
+ * remain that need us (server unreachable, token rejected, restart failed).
27
+ */
28
+ type CheckStatus = "ok" | "fixed" | "warn" | "fail";
29
+ interface CheckResult {
30
+ /** Stable machine-readable name (goes into the uploaded doctor_run event). */
31
+ name: string;
32
+ status: CheckStatus;
33
+ /** Candidate-facing one-liner. */
34
+ detail: string;
35
+ /** Extra internals shown with --verbose (and always written to tracker.log). */
36
+ verbose?: string;
37
+ /**
38
+ * Don't print this line unless --verbose. For checks whose healthy/repaired
39
+ * states are our plumbing, not the candidate's business (capture internals,
40
+ * upload bookkeeping) — doctor should read like status/submit, not like a
41
+ * boot log. Quiet lines still land everywhere WE look: the doctor_run
42
+ * event, the diagnostic phone-home, and tracker.log. Never set on a line
43
+ * that asks the candidate to do something.
44
+ */
45
+ quiet?: boolean;
46
+ }
47
+ export declare const MAX_EVENTS_PER_BATCH = 500;
48
+ export declare const MAX_BATCH_BYTES = 2000000;
49
+ export interface ActivityScan {
50
+ totalBytes: number;
51
+ eventCount: number;
52
+ malformedCount: number;
53
+ aiPromptCount: number;
54
+ lastEventTs: string | null;
55
+ lastHeartbeatTs: string | null;
56
+ /**
57
+ * Timestamp of the newest LIVE-captured prompt (backfilled events excluded).
58
+ * This is where the automatic backfill window starts: everything before it
59
+ * was demonstrably captured by the live path, everything after it is the
60
+ * potential gap.
61
+ */
62
+ lastLiveAiPromptTs: string | null;
63
+ }
64
+ /** One pass over raw activity-log text: counts and latest timestamps. */
65
+ export declare function scanActivityLog(text: string): ActivityScan;
66
+ /**
67
+ * Byte offset of the first log line whose event timestamp is at or after
68
+ * `cutoffMs`. Lines without a parseable timestamp don't start the window.
69
+ * Returns the total byte length (i.e. "flush nothing") when no line qualifies.
70
+ */
71
+ export declare function offsetForFirstEventAtOrAfter(text: string, cutoffMs: number): number;
72
+ export interface FlushBatch {
73
+ events: unknown[];
74
+ /** Byte offset just past the last line included — the next cursor value. */
75
+ endOffset: number;
76
+ }
77
+ /**
78
+ * Slice the log from `startOffset` into upload batches. Events are passed
79
+ * through VERBATIM (chained watcher events stay verifiable); malformed lines
80
+ * are skipped but still advance the offset so they are never retried forever.
81
+ * `startOffset` must fall on a line boundary (it always does: every stored
82
+ * cursor value is a `FlushBatch.endOffset`); a mid-line offset skips the torn
83
+ * line rather than uploading half an event.
84
+ */
85
+ export declare function planFlushBatches(text: string, startOffset: number): FlushBatch[];
86
+ export declare function readUploadState(litmusDir: string): number | null;
87
+ export declare function writeUploadState(litmusDir: string, flushFromBytes: number): void;
88
+ /**
89
+ * Sanity-check the times the server sent before writing a rebuilt config.
90
+ * Returns a human-readable problem, or null when they are usable.
91
+ *
92
+ * The failure this guards against is real: the init route used to answer
93
+ * every re-fetch with `startedAt: now`, and a config rebuilt from that
94
+ * mid-session arms the client-side deadline (startedAt + timeLimit) hours
95
+ * late — the tracker then sleeps through the real cutoff. The route is fixed
96
+ * to return the candidate's true start, and this check refuses any regression
97
+ * of that class rather than writing a config that lies about time.
98
+ *
99
+ * A deadline already in the past is deliberately NOT refused: the deadline
100
+ * check reports it, and support flows still need the config on disk.
101
+ */
102
+ export declare function validateRebuiltTimes(meta: {
103
+ startedAt: string;
104
+ deadline: string | null;
105
+ timeLimit: number | null;
106
+ }, nowMs: number): string | null;
107
+ /**
108
+ * The forensic snapshot we cannot get server-side (R5). The single most
109
+ * important bit is `hooks.claudeUserScope`: submit is what uninstalls the
110
+ * user-scope hook, so on a live assessment it discriminates "hook install
111
+ * worked, something later deleted the config" (true) from "install failed or
112
+ * fell back to project scope at init" (false) — the two surviving causes of
113
+ * a zero-prompts session. The mtimes date the damage; the registry shows what
114
+ * the shared logger could still resolve.
115
+ */
116
+ export declare function collectDoctorDiagnostics(projectRoot: string, results: CheckResult[]): Record<string, unknown>;
117
+ export interface DoctorOptions {
118
+ verbose?: boolean;
119
+ /** Assessment token, for rebuilding a missing/corrupted config (R1). */
120
+ token?: string;
121
+ /**
122
+ * Force prompt recovery over the whole assessment window (R4). Without it,
123
+ * recovery still runs automatically — but only when this run proved capture
124
+ * was broken, and only from the last live-captured prompt onward.
125
+ */
126
+ backfillPrompts?: boolean;
127
+ /** Override the recovery window start. */
128
+ since?: string;
129
+ /** Scan every Claude Code session on the machine, not just this folder's. */
130
+ allSessions?: boolean;
131
+ /** commander maps --no-backfill to false; default true (opts out of automatic recovery). */
132
+ backfill?: boolean;
133
+ }
134
+ export declare function runDoctor(opts: DoctorOptions): Promise<void>;
135
+ export {};
136
+ //# sourceMappingURL=doctor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AAoBA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAIH,KAAK,WAAW,GAAG,IAAI,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,CAAA;AAEnD,UAAU,WAAW;IACnB,8EAA8E;IAC9E,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,WAAW,CAAA;IACnB,kCAAkC;IAClC,MAAM,EAAE,MAAM,CAAA;IACd,gFAAgF;IAChF,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB;;;;;;;OAOG;IACH,KAAK,CAAC,EAAE,OAAO,CAAA;CAChB;AAgCD,eAAO,MAAM,oBAAoB,MAAM,CAAA;AACvC,eAAO,MAAM,eAAe,UAAY,CAAA;AAKxC,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,MAAM,CAAA;IAClB,UAAU,EAAE,MAAM,CAAA;IAClB,cAAc,EAAE,MAAM,CAAA;IACtB,aAAa,EAAE,MAAM,CAAA;IACrB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,eAAe,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B;;;;;OAKG;IACH,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAA;CAClC;AAED,yEAAyE;AACzE,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,CAiC1D;AAED;;;;GAIG;AACH,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAgBnF;AAED,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,OAAO,EAAE,CAAA;IACjB,4EAA4E;IAC5E,SAAS,EAAE,MAAM,CAAA;CAClB;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,UAAU,EAAE,CAsChF;AAUD,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAOhE;AAED,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,IAAI,CAShF;AA4CD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,EAC9E,KAAK,EAAE,MAAM,GACZ,MAAM,GAAG,IAAI,CASf;AA2ID;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,CACtC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,WAAW,EAAE,GACrB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAyBzB;AAID,MAAM,WAAW,aAAa;IAC5B,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,wEAAwE;IACxE,KAAK,CAAC,EAAE,MAAM,CAAA;IACd;;;;OAIG;IACH,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,0CAA0C;IAC1C,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,6EAA6E;IAC7E,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,4FAA4F;IAC5F,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AAED,wBAAsB,SAAS,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAqnBlE"}