hacklab 0.22.2 → 26.921.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.
Files changed (259) hide show
  1. package/README.md +23 -430
  2. package/dist/index.js +132 -23
  3. package/package.json +20 -42
  4. package/LICENSE +0 -21
  5. package/dist/agent-handoff.d.ts +0 -51
  6. package/dist/agent-handoff.d.ts.map +0 -1
  7. package/dist/agent-handoff.js +0 -91
  8. package/dist/agent-handoff.js.map +0 -1
  9. package/dist/api-client.d.ts +0 -18
  10. package/dist/api-client.d.ts.map +0 -1
  11. package/dist/api-client.js +0 -40
  12. package/dist/api-client.js.map +0 -1
  13. package/dist/belt.d.ts +0 -25
  14. package/dist/belt.d.ts.map +0 -1
  15. package/dist/belt.js +0 -113
  16. package/dist/belt.js.map +0 -1
  17. package/dist/card.d.ts +0 -66
  18. package/dist/card.d.ts.map +0 -1
  19. package/dist/card.js +0 -151
  20. package/dist/card.js.map +0 -1
  21. package/dist/cli.d.ts +0 -2
  22. package/dist/cli.d.ts.map +0 -1
  23. package/dist/cli.js +0 -238
  24. package/dist/cli.js.map +0 -1
  25. package/dist/commands/book.d.ts +0 -14
  26. package/dist/commands/book.d.ts.map +0 -1
  27. package/dist/commands/book.js +0 -90
  28. package/dist/commands/book.js.map +0 -1
  29. package/dist/commands/chat.d.ts +0 -36
  30. package/dist/commands/chat.d.ts.map +0 -1
  31. package/dist/commands/chat.js +0 -642
  32. package/dist/commands/chat.js.map +0 -1
  33. package/dist/commands/config.d.ts +0 -2
  34. package/dist/commands/config.d.ts.map +0 -1
  35. package/dist/commands/config.js +0 -84
  36. package/dist/commands/config.js.map +0 -1
  37. package/dist/commands/daemon.d.ts +0 -19
  38. package/dist/commands/daemon.d.ts.map +0 -1
  39. package/dist/commands/daemon.js +0 -72
  40. package/dist/commands/daemon.js.map +0 -1
  41. package/dist/commands/drop.d.ts +0 -12
  42. package/dist/commands/drop.d.ts.map +0 -1
  43. package/dist/commands/drop.js +0 -103
  44. package/dist/commands/drop.js.map +0 -1
  45. package/dist/commands/drops.d.ts +0 -9
  46. package/dist/commands/drops.d.ts.map +0 -1
  47. package/dist/commands/drops.js +0 -96
  48. package/dist/commands/drops.js.map +0 -1
  49. package/dist/commands/essay.d.ts +0 -40
  50. package/dist/commands/essay.d.ts.map +0 -1
  51. package/dist/commands/essay.js +0 -651
  52. package/dist/commands/essay.js.map +0 -1
  53. package/dist/commands/hackathon.d.ts +0 -2
  54. package/dist/commands/hackathon.d.ts.map +0 -1
  55. package/dist/commands/hackathon.js +0 -893
  56. package/dist/commands/hackathon.js.map +0 -1
  57. package/dist/commands/hacker.d.ts +0 -2
  58. package/dist/commands/hacker.d.ts.map +0 -1
  59. package/dist/commands/hacker.js +0 -87
  60. package/dist/commands/hacker.js.map +0 -1
  61. package/dist/commands/jobs.d.ts +0 -18
  62. package/dist/commands/jobs.d.ts.map +0 -1
  63. package/dist/commands/jobs.js +0 -138
  64. package/dist/commands/jobs.js.map +0 -1
  65. package/dist/commands/keys.d.ts +0 -2
  66. package/dist/commands/keys.d.ts.map +0 -1
  67. package/dist/commands/keys.js +0 -138
  68. package/dist/commands/keys.js.map +0 -1
  69. package/dist/commands/login.d.ts +0 -83
  70. package/dist/commands/login.d.ts.map +0 -1
  71. package/dist/commands/login.js +0 -236
  72. package/dist/commands/login.js.map +0 -1
  73. package/dist/commands/logout.d.ts +0 -2
  74. package/dist/commands/logout.d.ts.map +0 -1
  75. package/dist/commands/logout.js +0 -22
  76. package/dist/commands/logout.js.map +0 -1
  77. package/dist/commands/org-jobs.d.ts +0 -50
  78. package/dist/commands/org-jobs.d.ts.map +0 -1
  79. package/dist/commands/org-jobs.js +0 -383
  80. package/dist/commands/org-jobs.js.map +0 -1
  81. package/dist/commands/org.d.ts +0 -67
  82. package/dist/commands/org.d.ts.map +0 -1
  83. package/dist/commands/org.js +0 -1244
  84. package/dist/commands/org.js.map +0 -1
  85. package/dist/commands/ping.d.ts +0 -2
  86. package/dist/commands/ping.d.ts.map +0 -1
  87. package/dist/commands/ping.js +0 -50
  88. package/dist/commands/ping.js.map +0 -1
  89. package/dist/commands/profile.d.ts +0 -72
  90. package/dist/commands/profile.d.ts.map +0 -1
  91. package/dist/commands/profile.js +0 -672
  92. package/dist/commands/profile.js.map +0 -1
  93. package/dist/commands/project.d.ts +0 -2
  94. package/dist/commands/project.d.ts.map +0 -1
  95. package/dist/commands/project.js +0 -583
  96. package/dist/commands/project.js.map +0 -1
  97. package/dist/commands/referral.d.ts +0 -6
  98. package/dist/commands/referral.d.ts.map +0 -1
  99. package/dist/commands/referral.js +0 -93
  100. package/dist/commands/referral.js.map +0 -1
  101. package/dist/commands/rtfm.d.ts +0 -9
  102. package/dist/commands/rtfm.d.ts.map +0 -1
  103. package/dist/commands/rtfm.js +0 -114
  104. package/dist/commands/rtfm.js.map +0 -1
  105. package/dist/commands/scan.d.ts +0 -13
  106. package/dist/commands/scan.d.ts.map +0 -1
  107. package/dist/commands/scan.js +0 -286
  108. package/dist/commands/scan.js.map +0 -1
  109. package/dist/commands/scout.d.ts +0 -18
  110. package/dist/commands/scout.d.ts.map +0 -1
  111. package/dist/commands/scout.js +0 -232
  112. package/dist/commands/scout.js.map +0 -1
  113. package/dist/commands/setup-rail.d.ts +0 -58
  114. package/dist/commands/setup-rail.d.ts.map +0 -1
  115. package/dist/commands/setup-rail.js +0 -135
  116. package/dist/commands/setup-rail.js.map +0 -1
  117. package/dist/commands/setup.d.ts +0 -29
  118. package/dist/commands/setup.d.ts.map +0 -1
  119. package/dist/commands/setup.js +0 -442
  120. package/dist/commands/setup.js.map +0 -1
  121. package/dist/commands/sync.d.ts +0 -9
  122. package/dist/commands/sync.d.ts.map +0 -1
  123. package/dist/commands/sync.js +0 -345
  124. package/dist/commands/sync.js.map +0 -1
  125. package/dist/commands/update.d.ts +0 -2
  126. package/dist/commands/update.d.ts.map +0 -1
  127. package/dist/commands/update.js +0 -92
  128. package/dist/commands/update.js.map +0 -1
  129. package/dist/commands/whoami.d.ts +0 -2
  130. package/dist/commands/whoami.d.ts.map +0 -1
  131. package/dist/commands/whoami.js +0 -41
  132. package/dist/commands/whoami.js.map +0 -1
  133. package/dist/config.d.ts +0 -78
  134. package/dist/config.d.ts.map +0 -1
  135. package/dist/config.js +0 -93
  136. package/dist/config.js.map +0 -1
  137. package/dist/daily-sync.d.ts +0 -150
  138. package/dist/daily-sync.d.ts.map +0 -1
  139. package/dist/daily-sync.js +0 -665
  140. package/dist/daily-sync.js.map +0 -1
  141. package/dist/dossier.d.ts +0 -73
  142. package/dist/dossier.d.ts.map +0 -1
  143. package/dist/dossier.js +0 -141
  144. package/dist/dossier.js.map +0 -1
  145. package/dist/field-normalize.d.ts +0 -4
  146. package/dist/field-normalize.d.ts.map +0 -1
  147. package/dist/field-normalize.js +0 -8
  148. package/dist/field-normalize.js.map +0 -1
  149. package/dist/index.d.ts +0 -3
  150. package/dist/index.d.ts.map +0 -1
  151. package/dist/index.js.map +0 -1
  152. package/dist/job-fields.d.ts +0 -47
  153. package/dist/job-fields.d.ts.map +0 -1
  154. package/dist/job-fields.js +0 -148
  155. package/dist/job-fields.js.map +0 -1
  156. package/dist/machine.d.ts +0 -15
  157. package/dist/machine.d.ts.map +0 -1
  158. package/dist/machine.js +0 -64
  159. package/dist/machine.js.map +0 -1
  160. package/dist/org-fields.d.ts +0 -57
  161. package/dist/org-fields.d.ts.map +0 -1
  162. package/dist/org-fields.js +0 -167
  163. package/dist/org-fields.js.map +0 -1
  164. package/dist/posthog.d.ts +0 -38
  165. package/dist/posthog.d.ts.map +0 -1
  166. package/dist/posthog.js +0 -224
  167. package/dist/posthog.js.map +0 -1
  168. package/dist/project-fields.d.ts +0 -40
  169. package/dist/project-fields.d.ts.map +0 -1
  170. package/dist/project-fields.js +0 -79
  171. package/dist/project-fields.js.map +0 -1
  172. package/dist/prompt-consent.d.ts +0 -73
  173. package/dist/prompt-consent.d.ts.map +0 -1
  174. package/dist/prompt-consent.js +0 -191
  175. package/dist/prompt-consent.js.map +0 -1
  176. package/dist/prompt-stats.d.ts +0 -226
  177. package/dist/prompt-stats.d.ts.map +0 -1
  178. package/dist/prompt-stats.js +0 -561
  179. package/dist/prompt-stats.js.map +0 -1
  180. package/dist/referral.d.ts +0 -14
  181. package/dist/referral.d.ts.map +0 -1
  182. package/dist/referral.js +0 -28
  183. package/dist/referral.js.map +0 -1
  184. package/dist/registry.d.ts +0 -15
  185. package/dist/registry.d.ts.map +0 -1
  186. package/dist/registry.js +0 -180
  187. package/dist/registry.js.map +0 -1
  188. package/dist/resolve-command.d.ts +0 -20
  189. package/dist/resolve-command.d.ts.map +0 -1
  190. package/dist/resolve-command.js +0 -21
  191. package/dist/resolve-command.js.map +0 -1
  192. package/dist/scanners/antigravity.d.ts +0 -41
  193. package/dist/scanners/antigravity.d.ts.map +0 -1
  194. package/dist/scanners/antigravity.js +0 -210
  195. package/dist/scanners/antigravity.js.map +0 -1
  196. package/dist/scanners/github-copilot-telemetry.d.ts +0 -23
  197. package/dist/scanners/github-copilot-telemetry.d.ts.map +0 -1
  198. package/dist/scanners/github-copilot-telemetry.js +0 -220
  199. package/dist/scanners/github-copilot-telemetry.js.map +0 -1
  200. package/dist/scanners/github-copilot.d.ts +0 -68
  201. package/dist/scanners/github-copilot.d.ts.map +0 -1
  202. package/dist/scanners/github-copilot.js +0 -262
  203. package/dist/scanners/github-copilot.js.map +0 -1
  204. package/dist/scanners/incremental.d.ts +0 -282
  205. package/dist/scanners/incremental.d.ts.map +0 -1
  206. package/dist/scanners/incremental.js +0 -788
  207. package/dist/scanners/incremental.js.map +0 -1
  208. package/dist/scanners/index.d.ts +0 -116
  209. package/dist/scanners/index.d.ts.map +0 -1
  210. package/dist/scanners/index.js +0 -726
  211. package/dist/scanners/index.js.map +0 -1
  212. package/dist/scanners/sqlite.d.ts +0 -18
  213. package/dist/scanners/sqlite.d.ts.map +0 -1
  214. package/dist/scanners/sqlite.js +0 -63
  215. package/dist/scanners/sqlite.js.map +0 -1
  216. package/dist/scanners/util.d.ts +0 -112
  217. package/dist/scanners/util.d.ts.map +0 -1
  218. package/dist/scanners/util.js +0 -167
  219. package/dist/scanners/util.js.map +0 -1
  220. package/dist/session.d.ts +0 -106
  221. package/dist/session.d.ts.map +0 -1
  222. package/dist/session.js +0 -191
  223. package/dist/session.js.map +0 -1
  224. package/dist/share-card-colors.d.ts +0 -19
  225. package/dist/share-card-colors.d.ts.map +0 -1
  226. package/dist/share-card-colors.js +0 -36
  227. package/dist/share-card-colors.js.map +0 -1
  228. package/dist/share-card.d.ts +0 -32
  229. package/dist/share-card.d.ts.map +0 -1
  230. package/dist/share-card.js +0 -420
  231. package/dist/share-card.js.map +0 -1
  232. package/dist/share.d.ts +0 -17
  233. package/dist/share.d.ts.map +0 -1
  234. package/dist/share.js +0 -77
  235. package/dist/share.js.map +0 -1
  236. package/dist/sync.d.ts +0 -100
  237. package/dist/sync.d.ts.map +0 -1
  238. package/dist/sync.js +0 -304
  239. package/dist/sync.js.map +0 -1
  240. package/dist/ui.d.ts +0 -33
  241. package/dist/ui.d.ts.map +0 -1
  242. package/dist/ui.js +0 -127
  243. package/dist/ui.js.map +0 -1
  244. package/dist/utils/npmGlobal.d.ts +0 -30
  245. package/dist/utils/npmGlobal.d.ts.map +0 -1
  246. package/dist/utils/npmGlobal.js +0 -69
  247. package/dist/utils/npmGlobal.js.map +0 -1
  248. package/dist/utils/openBrowser.d.ts +0 -14
  249. package/dist/utils/openBrowser.d.ts.map +0 -1
  250. package/dist/utils/openBrowser.js +0 -47
  251. package/dist/utils/openBrowser.js.map +0 -1
  252. package/dist/utils/updateCheck.d.ts +0 -16
  253. package/dist/utils/updateCheck.d.ts.map +0 -1
  254. package/dist/utils/updateCheck.js +0 -111
  255. package/dist/utils/updateCheck.js.map +0 -1
  256. package/dist/utils/waitForEnter.d.ts +0 -12
  257. package/dist/utils/waitForEnter.d.ts.map +0 -1
  258. package/dist/utils/waitForEnter.js +0 -43
  259. package/dist/utils/waitForEnter.js.map +0 -1
@@ -1,561 +0,0 @@
1
- import { execFile } from 'node:child_process';
2
- import { readFile, stat } from 'node:fs/promises';
3
- import { homedir } from 'node:os';
4
- import { dirname, join } from 'node:path';
5
- import { promisify } from 'node:util';
6
- import { antigravityTranscriptFiles, scanAntigravityPrompts, } from './scanners/antigravity.js';
7
- import { githubCopilotFiles, scanGitHubCopilotPrompts, } from './scanners/github-copilot.js';
8
- import { findFiles, toDateStr } from './scanners/util.js';
9
- /**
10
- * Prompt statistics, computed on this machine from supported local harness
11
- * transcripts and uploaded only under an explicit consent tier (see
12
- * prompt-consent.ts).
13
- *
14
- * Three things come out of a full scan:
15
- *
16
- * - a histogram of how long the user's own prompts are, in words — every
17
- * bucket an exact word count — plus the tail, which is where the prompts
18
- * longer than the axis are reported, and their only home
19
- * - a per-project prompt count, keyed by the project's git origin
20
- * - the prompt *activity* aggregate: per-session start/end/count and a
21
- * per-day prompt/word tally. That one is also what the minutely tick
22
- * accumulates incrementally (scanners/incremental.ts), so a full scan can
23
- * re-base the tick's state without either drifting from the other.
24
- *
25
- * and, under the `full` tier only, a sample of the raw prompt text so the
26
- * backend can score "how technical is this person's prompting". The backend
27
- * scores that sample and throws it away; it is never stored.
28
- *
29
- * Everything here is deliberately best-effort: an unreadable transcript, a
30
- * project that isn't a git repo, a missing `git` binary — each drops its own
31
- * contribution and the rest of the scan still uploads.
32
- */
33
- const execFileAsync = promisify(execFile);
34
- /** Buckets are `1..bucketMax`, so the axis stays readable at any prompt length. */
35
- export const PROMPT_LENGTH_BUCKET_MIN = 10;
36
- export const PROMPT_LENGTH_BUCKET_MAX = 100;
37
- /** The percentile that sets `bucketMax`; everything above it lands in `tail`. */
38
- export const PROMPT_LENGTH_AXIS_PERCENTILE = 0.9;
39
- /** The server's cap on `tail` entries; longer distributions are coarsened. */
40
- export const PROMPT_TAIL_MAX_ENTRIES = 400;
41
- /** Matches the backend's cap — anything longer is truncated before upload. */
42
- export const CONVERSATION_SAMPLE_MAX_CHARS = 20_000;
43
- /**
44
- * Which definition of "a prompt the user typed" produced this upload.
45
- *
46
- * Version 1 is implicit — every CLI shipped before this field existed counted
47
- * harness-generated `user` entries (subagent task notifications, skill bodies,
48
- * slash-command echoes, interrupt markers) as prompts, which inflated the
49
- * counts and blew out the word tallies. Version 2 is the scan with
50
- * `isHarnessNoise` in it.
51
- *
52
- * It rides on every sync as a top-level `scannerVersion`; the server ignores
53
- * `promptStats` / `promptActivity` from anything below 2, so an un-upgraded CLI
54
- * can't keep writing the old numbers into a table that was wiped to fix them.
55
- */
56
- export const PROMPT_SCANNER_VERSION = 2;
57
- /**
58
- * Prefixes that mark a `user` transcript entry as written by Claude Code
59
- * itself rather than typed by the person at the keyboard.
60
- *
61
- * These all arrive in exactly the shape a real prompt does — `type: 'user'`,
62
- * not a sidechain, content a plain string or `text` blocks — so nothing but the
63
- * text tells them apart. Measured over 194 local transcripts they were 39% of
64
- * everything the scan called a prompt and 65% of its words, because a machine's
65
- * report or an injected skill body is an order of magnitude longer than
66
- * anything a human types.
67
- *
68
- * Matched against the entry's text after `trimStart()`, and anchored to the
69
- * start on purpose: a prompt that *quotes* one of these tags mid-sentence
70
- * ("why does <command-name> show up twice?") is a real prompt and still counts.
71
- */
72
- const HARNESS_NOISE_PREFIXES = [
73
- // The body of a skill, injected when one is invoked. Up to ~11.5k words.
74
- 'Base directory for this skill:',
75
- // A background subagent's report, handed back as a user turn: ~400 words
76
- // each and the single largest source of fake prompts.
77
- '<task-notification>',
78
- // The wrapper around a slash command's expansion, its echo and its output.
79
- '<local-command-caveat>',
80
- '<command-name>',
81
- '<command-message>',
82
- '<command-args>',
83
- '<local-command-stdout>',
84
- // Context the harness injects into a turn. Nobody types it.
85
- '<system-reminder>',
86
- // Written when the user hits escape — the absence of a prompt, not one.
87
- '[Request interrupted',
88
- // `!`-prefixed bash mode: the command and whatever it printed.
89
- '<bash-input>',
90
- '<bash-stdout>',
91
- '<bash-stderr>',
92
- // Text a UserPromptSubmit hook appended to the turn.
93
- '<user-prompt-submit-hook>',
94
- ];
95
- /**
96
- * Is this entry text something the harness wrote rather than the user?
97
- *
98
- * Deliberately a prefix test and nothing more — no stripping of inline
99
- * `<system-reminder>` blocks out of otherwise-typed prompts. Those measured at
100
- * zero words of real contribution, and rewriting prompt text in place is a
101
- * bigger risk than the noise it would remove.
102
- */
103
- export function isHarnessNoise(text) {
104
- const start = text.trimStart();
105
- return HARNESS_NOISE_PREFIXES.some((prefix) => start.startsWith(prefix));
106
- }
107
- /** Prompt-only sources: no token estimates and no token harness registration. */
108
- export const IDE_PROMPT_SOURCES = [
109
- {
110
- id: 'antigravity',
111
- files: antigravityTranscriptFiles,
112
- scan: scanAntigravityPrompts,
113
- },
114
- {
115
- id: 'github_copilot',
116
- files: githubCopilotFiles,
117
- scan: scanGitHubCopilotPrompts,
118
- },
119
- ];
120
- export function mergePromptActivities(sources) {
121
- const merged = emptyPromptActivity();
122
- for (const source of sources) {
123
- for (const [id, session] of Object.entries(source.sessions)) {
124
- merged.sessions[id] = { ...session };
125
- }
126
- for (const [date, day] of Object.entries(source.daily)) {
127
- merged.daily[date] ??= { prompts: 0, words: 0 };
128
- const target = merged.daily[date];
129
- target.prompts += day.prompts;
130
- target.words += day.words;
131
- }
132
- }
133
- return merged;
134
- }
135
- /**
136
- * The user's own prompt text from one transcript line, or null when the line
137
- * isn't one.
138
- *
139
- * A transcript's `user` entries cover more than typed prompts: tool results
140
- * come back as synthetic user turns too. Those carry `tool_result` content
141
- * blocks, so a line only counts when its content is a plain string or an array
142
- * of nothing but `text` blocks. Sidechain entries (subagent conversations) are
143
- * the agent talking to itself, not the person typing, so they're excluded.
144
- *
145
- * That still leaves the harness's own writing, which is indistinguishable by
146
- * shape: subagent reports, injected skill bodies, slash-command echoes,
147
- * interrupt markers. Those are dropped two ways — `isMeta`, which Claude Code
148
- * sets on the entries it generates, and the text prefixes in
149
- * `isHarnessNoise` for the ones it doesn't.
150
- *
151
- * This is the single chokepoint: both the full scan and the minutely tick go
152
- * through here, so the histogram, the tail, the per-project counts, the
153
- * activity aggregate and the technical-score sample all see the same prompts.
154
- */
155
- export function promptTextFrom(entry) {
156
- if (!entry || typeof entry !== 'object')
157
- return null;
158
- const line = entry;
159
- if (line.type !== 'user')
160
- return null;
161
- if (line.isSidechain === true)
162
- return null;
163
- if (line.isMeta === true)
164
- return null;
165
- const content = line.message?.content;
166
- if (typeof content === 'string') {
167
- return isHarnessNoise(content) ? null : content;
168
- }
169
- if (!Array.isArray(content))
170
- return null;
171
- const texts = [];
172
- for (const block of content) {
173
- if (!block || typeof block !== 'object')
174
- return null;
175
- const { type, text } = block;
176
- // One non-text block (a tool_result, an image) disqualifies the whole
177
- // entry: it isn't a prompt the person typed.
178
- if (type !== 'text' || typeof text !== 'string')
179
- return null;
180
- texts.push(text);
181
- }
182
- if (texts.length === 0)
183
- return null;
184
- const joined = texts.join('\n');
185
- return isHarnessNoise(joined) ? null : joined;
186
- }
187
- /** Whitespace-separated word count. Zero-word prompts are dropped by callers. */
188
- export function countWords(text) {
189
- const matches = text.match(/\S+/g);
190
- return matches ? matches.length : 0;
191
- }
192
- /** The server's cap on a session id. Longer than this and the row is rejected. */
193
- export const PROMPT_SESSION_ID_MAX_CHARS = 128;
194
- /**
195
- * A transcript line as prompt activity, or null when it isn't one.
196
- *
197
- * Stricter than `promptTextFrom` on purpose: a prompt with no session id or no
198
- * usable timestamp can't be placed on a session or a day, and the server's
199
- * schema would reject it, so it counts towards the histogram (which needs
200
- * neither) and nothing else.
201
- */
202
- export function parsePromptLine(line) {
203
- if (!line.trim())
204
- return null;
205
- let parsed;
206
- try {
207
- parsed = JSON.parse(line);
208
- }
209
- catch {
210
- return null;
211
- }
212
- const text = promptTextFrom(parsed);
213
- if (text === null)
214
- return null;
215
- const words = countWords(text);
216
- if (words <= 0)
217
- return null;
218
- const entry = parsed;
219
- const sessionId = typeof entry.sessionId === 'string' ? entry.sessionId.trim() : '';
220
- if (!sessionId || sessionId.length > PROMPT_SESSION_ID_MAX_CHARS)
221
- return null;
222
- const timestamp = normalizeTimestamp(entry.timestamp);
223
- if (!timestamp)
224
- return null;
225
- return { sessionId, timestamp, words };
226
- }
227
- /** An ISO-8601 UTC string, or null when the value isn't a usable instant. */
228
- export function normalizeTimestamp(value) {
229
- if (typeof value !== 'string' && typeof value !== 'number')
230
- return null;
231
- const at = typeof value === 'number' ? value : Date.parse(value);
232
- const date = new Date(at);
233
- return Number.isFinite(date.getTime()) ? date.toISOString() : null;
234
- }
235
- export function emptyPromptActivity() {
236
- return { sessions: {}, daily: {} };
237
- }
238
- /**
239
- * Fold one prompt into an activity aggregate, returning the session and date it
240
- * landed on so an incremental caller can mark exactly those dirty.
241
- *
242
- * The date is the UTC day of the timestamp — the same attribution
243
- * `toDateStr` gives every token daily row, so the two halves of a sync agree
244
- * about which day a piece of work belongs to.
245
- */
246
- export function addPromptToActivity(activity, line) {
247
- const session = activity.sessions[line.sessionId];
248
- if (session) {
249
- if (line.timestamp < session.startedAt)
250
- session.startedAt = line.timestamp;
251
- if (line.timestamp > session.lastActiveAt) {
252
- session.lastActiveAt = line.timestamp;
253
- }
254
- session.promptCount += 1;
255
- }
256
- else {
257
- activity.sessions[line.sessionId] = {
258
- startedAt: line.timestamp,
259
- lastActiveAt: line.timestamp,
260
- promptCount: 1,
261
- };
262
- }
263
- const date = toDateStr(line.timestamp);
264
- const day = activity.daily[date];
265
- if (day) {
266
- day.prompts += 1;
267
- day.words += line.words;
268
- }
269
- else {
270
- activity.daily[date] = { prompts: 1, words: line.words };
271
- }
272
- return { sessionId: line.sessionId, date };
273
- }
274
- /**
275
- * Where the histogram's axis ends for this user's own distribution: their p90
276
- * prompt length rounded up to a multiple of 10, clamped to [10, 100]. Anything
277
- * longer is reported by `buildTail` instead.
278
- *
279
- * Per-user rather than fixed because prompt length varies enormously between
280
- * people — a fixed axis would either crush a terse user's histogram into the
281
- * first two buckets or run a verbose one off the end.
282
- */
283
- export function bucketMaxFor(wordCounts) {
284
- if (wordCounts.length === 0)
285
- return PROMPT_LENGTH_BUCKET_MIN;
286
- const sorted = [...wordCounts].sort((a, b) => a - b);
287
- const index = Math.min(sorted.length - 1, Math.floor(sorted.length * PROMPT_LENGTH_AXIS_PERCENTILE));
288
- const p90 = sorted[index] ?? PROMPT_LENGTH_BUCKET_MIN;
289
- const rounded = Math.ceil(p90 / 10) * 10;
290
- return Math.min(PROMPT_LENGTH_BUCKET_MAX, Math.max(PROMPT_LENGTH_BUCKET_MIN, rounded));
291
- }
292
- /**
293
- * Bucket the word counts. Every bucket `1..bucketMax` is an exact word count —
294
- * there is no overflow bar. Empty buckets are omitted; the chart fills the gaps.
295
- *
296
- * Prompts longer than `bucketMax` are not in here at all: they are reported by
297
- * `buildTail`, and only there. So the histogram and the tail partition the
298
- * scan — sum(histogram counts) + sum(tail counts) === totalPrompts, always.
299
- */
300
- export function buildHistogram(wordCounts, bucketMax) {
301
- const counts = new Map();
302
- for (const words of wordCounts) {
303
- if (words <= 0)
304
- continue;
305
- if (words > bucketMax)
306
- continue;
307
- counts.set(words, (counts.get(words) ?? 0) + 1);
308
- }
309
- return [...counts.entries()]
310
- .map(([length, count]) => ({ length, count }))
311
- .sort((a, b) => a.length - b.length);
312
- }
313
- /**
314
- * The exact distribution of everything *longer* than `bucketMax`, which the
315
- * histogram does not cover at all. One entry per distinct word count,
316
- * ascending; empty (never absent) when nothing exceeds `bucketMax` — the
317
- * field's presence on the wire is the marker that the histogram's bars are
318
- * exact.
319
- *
320
- * Lengths only — no prompt text is involved here, or anywhere near it.
321
- *
322
- * A machine with a long history can have thousands of distinct long lengths,
323
- * far past what the server accepts, so an over-cap tail is coarsened: lengths
324
- * are rounded to multiples of 2, then 4, 8, … until at most
325
- * `PROMPT_TAIL_MAX_ENTRIES` entries remain, summing the counts that collapse
326
- * together. Rounding is *up* so that a coarsened entry still sits above
327
- * `bucketMax` — rounding down could claim a length inside the histogram's own
328
- * exact range for a prompt the histogram never counted.
329
- *
330
- * Deterministic: the result depends only on the multiset of word counts.
331
- */
332
- export function buildTail(wordCounts, bucketMax) {
333
- const exact = new Map();
334
- for (const words of wordCounts) {
335
- if (words <= bucketMax)
336
- continue;
337
- exact.set(words, (exact.get(words) ?? 0) + 1);
338
- }
339
- if (exact.size === 0)
340
- return [];
341
- let counts = exact;
342
- let step = 1;
343
- while (counts.size > PROMPT_TAIL_MAX_ENTRIES) {
344
- step *= 2;
345
- const coarser = new Map();
346
- // Always coarsen from the exact counts, so the rounding is one clean
347
- // division rather than a rounding of a rounding.
348
- for (const [length, count] of exact) {
349
- const rounded = Math.ceil(length / step) * step;
350
- coarser.set(rounded, (coarser.get(rounded) ?? 0) + count);
351
- }
352
- counts = coarser;
353
- }
354
- return [...counts.entries()]
355
- .map(([length, count]) => ({ length, count }))
356
- .sort((a, b) => a.length - b.length);
357
- }
358
- /**
359
- * The `origin` remote of the repo at `cwd`, or null when there isn't one (not
360
- * a repo, no origin, no git binary, or the directory is gone). The URL is sent
361
- * as-is; the backend normalizes it before matching against the user's own
362
- * projects.
363
- */
364
- export async function gitOriginUrl(cwd) {
365
- try {
366
- const { stdout } = await execFileAsync('git', ['-C', cwd, 'remote', 'get-url', 'origin'], { timeout: 5_000 });
367
- const url = stdout.trim();
368
- return url.length > 0 ? url : null;
369
- }
370
- catch {
371
- return null;
372
- }
373
- }
374
- /**
375
- * Newest transcript first. The sample is meant to be the user's *recent*
376
- * prompting, so the walk order has to be time order — the directory walk's own
377
- * order is alphabetical and would hand the scorer whatever happens to sort
378
- * first, which for a long-lived machine is usually a project abandoned years
379
- * ago. A file we can't stat sorts last rather than dropping out.
380
- */
381
- async function byMtimeDesc(paths) {
382
- const stamped = await Promise.all(paths.map(async (path) => ({
383
- path,
384
- mtimeMs: await stat(path)
385
- .then((s) => s.mtimeMs)
386
- .catch(() => 0),
387
- })));
388
- return stamped.sort((a, b) => b.mtimeMs - a.mtimeMs).map((f) => f.path);
389
- }
390
- /**
391
- * Scan local Claude Code and supported IDE/agent chat transcripts.
392
- *
393
- * `includeSample` gates the raw prompt text: only the `full` consent tier
394
- * passes true, and the sample never touches disk here — it goes straight into
395
- * the upload payload the caller builds.
396
- */
397
- export async function scanPromptStats(options = {}) {
398
- const root = join(homedir(), '.claude', 'projects');
399
- const files = await byMtimeDesc(await findFiles(root, '.jsonl'));
400
- const wordCounts = [];
401
- const activity = emptyPromptActivity();
402
- const samples = [];
403
- let sampleChars = 0;
404
- const addSample = (text, timestamp) => {
405
- if (!options.includeSample)
406
- return;
407
- const at = timestamp ? Date.parse(timestamp) : 0;
408
- const clipped = text.slice(0, CONVERSATION_SAMPLE_MAX_CHARS);
409
- const index = samples.findIndex((sample) => sample.at < at);
410
- samples.splice(index < 0 ? samples.length : index, 0, { text: clipped, at });
411
- sampleChars += clipped.length + 2;
412
- while (samples.length > 1) {
413
- const oldest = samples.at(-1);
414
- if (!oldest ||
415
- sampleChars - (oldest.text.length + 2) < CONVERSATION_SAMPLE_MAX_CHARS)
416
- break;
417
- sampleChars -= oldest.text.length + 2;
418
- samples.pop();
419
- }
420
- };
421
- // Keyed by the transcript's project directory, which is Claude Code's own
422
- // grouping. The directory name is a lossy encoding of the path, so the real
423
- // working directory comes from the `cwd` recorded inside the entries.
424
- const byProjectDir = new Map();
425
- for (const filePath of files) {
426
- const projectDir = dirname(filePath);
427
- let project = byProjectDir.get(projectDir);
428
- if (!project) {
429
- project = { cwd: null, promptCount: 0, lastActiveAt: 0 };
430
- byProjectDir.set(projectDir, project);
431
- }
432
- let content;
433
- try {
434
- content = await readFile(filePath, 'utf8');
435
- }
436
- catch {
437
- continue;
438
- }
439
- for (const line of content.split('\n')) {
440
- if (!line.trim())
441
- continue;
442
- let parsed;
443
- try {
444
- parsed = JSON.parse(line);
445
- }
446
- catch {
447
- continue;
448
- }
449
- const entry = parsed;
450
- if (!project.cwd && typeof entry.cwd === 'string' && entry.cwd) {
451
- project.cwd = entry.cwd;
452
- }
453
- const text = promptTextFrom(parsed);
454
- if (text === null)
455
- continue;
456
- const words = countWords(text);
457
- if (words <= 0)
458
- continue;
459
- wordCounts.push(words);
460
- project.promptCount += 1;
461
- const at = Date.parse(String(entry.timestamp));
462
- if (Number.isFinite(at) && at > project.lastActiveAt) {
463
- project.lastActiveAt = at;
464
- }
465
- const promptLine = parsePromptLine(line);
466
- if (promptLine)
467
- addPromptToActivity(activity, promptLine);
468
- addSample(text, normalizeTimestamp(entry.timestamp));
469
- }
470
- }
471
- const sources = {
472
- claude_code: activity,
473
- };
474
- for (const source of IDE_PROMPT_SOURCES) {
475
- const sourceActivity = emptyPromptActivity();
476
- const prompts = await source.scan();
477
- // Reverse preserves the newest-first sample order for equal timestamps.
478
- for (let i = prompts.length - 1; i >= 0; i--) {
479
- const prompt = prompts[i];
480
- if (!prompt)
481
- continue;
482
- const words = countWords(prompt.text);
483
- if (words === 0)
484
- continue;
485
- wordCounts.push(words);
486
- if (prompt.timestamp) {
487
- addPromptToActivity(sourceActivity, {
488
- sessionId: prompt.sessionId,
489
- timestamp: prompt.timestamp,
490
- words,
491
- });
492
- }
493
- addSample(prompt.text, prompt.timestamp);
494
- }
495
- sources[source.id] = sourceActivity;
496
- }
497
- if (wordCounts.length === 0)
498
- return null;
499
- const bucketMax = bucketMaxFor(wordCounts);
500
- const stats = {
501
- totalPrompts: wordCounts.length,
502
- bucketMax,
503
- histogram: buildHistogram(wordCounts, bucketMax),
504
- tail: buildTail(wordCounts, bucketMax),
505
- projects: await resolveProjects(byProjectDir),
506
- activity: { ...mergePromptActivities(Object.values(sources)), sources },
507
- };
508
- if (options.includeSample && samples.length > 0) {
509
- stats.conversationSample = samples
510
- .map((sample) => sample.text)
511
- .join('\n\n')
512
- .slice(0, CONVERSATION_SAMPLE_MAX_CHARS);
513
- }
514
- return stats;
515
- }
516
- /**
517
- * The `promptStats` block as the server takes it. `activity` is deliberately
518
- * dropped: it is local bookkeeping for the tick's incremental state, and it
519
- * travels under its own top-level `promptActivity` field instead.
520
- */
521
- export function promptStatsPayload(stats) {
522
- const { activity: _activity, ...wire } = stats;
523
- return wire;
524
- }
525
- /**
526
- * Turn the per-directory tallies into repo-keyed entries. Directories with no
527
- * prompts, no recorded `cwd`, or no git origin drop out — the backend can only
528
- * match a project by its repo URL, so an entry without one is dead weight.
529
- *
530
- * Two transcript directories can resolve to the same repo (the same project
531
- * opened at different paths), so counts are summed per origin.
532
- */
533
- async function resolveProjects(byProjectDir) {
534
- const byRepo = new Map();
535
- for (const project of byProjectDir.values()) {
536
- if (project.promptCount === 0 || !project.cwd)
537
- continue;
538
- const repoUrl = await gitOriginUrl(project.cwd);
539
- if (!repoUrl)
540
- continue;
541
- const existing = byRepo.get(repoUrl);
542
- if (existing) {
543
- existing.promptCount += project.promptCount;
544
- existing.lastActiveAt = Math.max(existing.lastActiveAt, project.lastActiveAt);
545
- }
546
- else {
547
- byRepo.set(repoUrl, {
548
- promptCount: project.promptCount,
549
- lastActiveAt: project.lastActiveAt,
550
- });
551
- }
552
- }
553
- return [...byRepo.entries()].map(([repoUrl, entry]) => ({
554
- repoUrl,
555
- promptCount: entry.promptCount,
556
- // A transcript with no usable timestamp still happened; dating it now is
557
- // more honest than dropping the project or claiming the epoch.
558
- lastActiveAt: new Date(entry.lastActiveAt > 0 ? entry.lastActiveAt : Date.now()).toISOString(),
559
- }));
560
- }
561
- //# sourceMappingURL=prompt-stats.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"prompt-stats.js","sourceRoot":"","sources":["../src/prompt-stats.ts"],"names":[],"mappings":"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"}
@@ -1,14 +0,0 @@
1
- /**
2
- * A shareable referral URL for `handle`, hung off the site root so it lands on
3
- * the install/join page. `base` is a backend origin without a trailing slash
4
- * (what `resolveAppUrl` returns), e.g. `https://hacklab.so`.
5
- */
6
- export declare function referralUrl(handle: string, base: string): string;
7
- /**
8
- * A ready-to-send, one-paragraph blurb a user can drop straight into a DM (or
9
- * an AI assistant that's helping them recruit) — the "message to send it to
10
- * your cool smart hacker friends." Ends with the referral link so the whole
11
- * thing is a single copy-paste.
12
- */
13
- export declare function referralMessage(handle: string, base: string): string;
14
- //# sourceMappingURL=referral.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"referral.d.ts","sourceRoot":"","sources":["../src/referral.ts"],"names":[],"mappings":"AAQA;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAGhE;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAMpE"}
package/dist/referral.js DELETED
@@ -1,28 +0,0 @@
1
- // The referral link and its share copy live here, in one place, so every
2
- // surface that shows it (the standalone `hacklab referral` command) builds the
3
- // exact same URL and message. A referral is just
4
- // the user's handle carried on a `?ref=` query param onto the marketing site:
5
- // the root domain always resolves, an unrecognized query param can't 404, and
6
- // it's the conventional shape for the backend to attribute a signup to whoever
7
- // sent the link.
8
- /**
9
- * A shareable referral URL for `handle`, hung off the site root so it lands on
10
- * the install/join page. `base` is a backend origin without a trailing slash
11
- * (what `resolveAppUrl` returns), e.g. `https://hacklab.so`.
12
- */
13
- export function referralUrl(handle, base) {
14
- const origin = base.replace(/\/$/, '');
15
- return `${origin}/?ref=${encodeURIComponent(handle)}`;
16
- }
17
- /**
18
- * A ready-to-send, one-paragraph blurb a user can drop straight into a DM (or
19
- * an AI assistant that's helping them recruit) — the "message to send it to
20
- * your cool smart hacker friends." Ends with the referral link so the whole
21
- * thing is a single copy-paste.
22
- */
23
- export function referralMessage(handle, base) {
24
- return ('join me on hacklab — the terminal-native network for AI-native hackers. ' +
25
- 'scan your AI token usage, see where you rank, and claim your profile:\n' +
26
- referralUrl(handle, base));
27
- }
28
- //# sourceMappingURL=referral.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"referral.js","sourceRoot":"","sources":["../src/referral.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,+EAA+E;AAC/E,iDAAiD;AACjD,8EAA8E;AAC9E,8EAA8E;AAC9E,+EAA+E;AAC/E,iBAAiB;AAEjB;;;;GAIG;AACH,MAAM,UAAU,WAAW,CAAC,MAAc,EAAE,IAAY;IACtD,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAA;IACtC,OAAO,GAAG,MAAM,SAAS,kBAAkB,CAAC,MAAM,CAAC,EAAE,CAAA;AACvD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,MAAc,EAAE,IAAY;IAC1D,OAAO,CACL,0EAA0E;QAC1E,yEAAyE;QACzE,WAAW,CAAC,MAAM,EAAE,IAAI,CAAC,CAC1B,CAAA;AACH,CAAC"}
@@ -1,15 +0,0 @@
1
- export type CommandSpec = {
2
- /** The full command name, e.g. `chat`. */
3
- name: string;
4
- /** Args shown after the name in help, e.g. `<key> <val>`. Omit if it takes none. */
5
- args?: string;
6
- /** One-line description shown in `hacklab --help`. */
7
- summary: string;
8
- /** Run the command with the per-command args (the global `--env` is already stripped). */
9
- run: (args: string[]) => Promise<void> | void;
10
- };
11
- export declare const COMMANDS: CommandSpec[];
12
- /** Every command name, in registry order — the source of truth for resolution. */
13
- export declare const COMMAND_NAMES: string[];
14
- export declare function findCommand(name: string): CommandSpec | undefined;
15
- //# sourceMappingURL=registry.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AA8BA,MAAM,MAAM,WAAW,GAAG;IACxB,0CAA0C;IAC1C,IAAI,EAAE,MAAM,CAAA;IACZ,oFAAoF;IACpF,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,sDAAsD;IACtD,OAAO,EAAE,MAAM,CAAA;IACf,0FAA0F;IAC1F,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;CAC9C,CAAA;AAED,eAAO,MAAM,QAAQ,EAAE,WAAW,EAuJjC,CAAA;AAED,kFAAkF;AAClF,eAAO,MAAM,aAAa,UAA8B,CAAA;AAExD,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS,CAEjE"}