hacklab 0.7.5 → 0.9.0
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 +20 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +147 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/book.d.ts +14 -0
- package/dist/commands/book.d.ts.map +1 -0
- package/dist/commands/book.js +90 -0
- package/dist/commands/book.js.map +1 -0
- package/dist/commands/chat.d.ts +1 -1
- package/dist/commands/chat.d.ts.map +1 -1
- package/dist/commands/chat.js +3 -0
- package/dist/commands/chat.js.map +1 -1
- package/dist/commands/hacker.js +18 -9
- package/dist/commands/hacker.js.map +1 -1
- package/dist/commands/join.d.ts +4 -2
- package/dist/commands/join.d.ts.map +1 -1
- package/dist/commands/join.js +78 -45
- package/dist/commands/join.js.map +1 -1
- package/dist/commands/keys.d.ts +2 -0
- package/dist/commands/keys.d.ts.map +1 -0
- package/dist/commands/keys.js +138 -0
- package/dist/commands/keys.js.map +1 -0
- package/dist/commands/login.d.ts.map +1 -1
- package/dist/commands/login.js +3 -6
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/org.d.ts +7 -7
- package/dist/commands/org.d.ts.map +1 -1
- package/dist/commands/org.js +407 -32
- package/dist/commands/org.js.map +1 -1
- package/dist/commands/profile.d.ts.map +1 -1
- package/dist/commands/profile.js +1 -5
- package/dist/commands/profile.js.map +1 -1
- package/dist/commands/scout.d.ts +18 -0
- package/dist/commands/scout.d.ts.map +1 -0
- package/dist/commands/scout.js +232 -0
- package/dist/commands/scout.js.map +1 -0
- package/dist/daily-sync.d.ts +16 -1
- package/dist/daily-sync.d.ts.map +1 -1
- package/dist/daily-sync.js +66 -2
- package/dist/daily-sync.js.map +1 -1
- package/dist/field-normalize.d.ts +4 -0
- package/dist/field-normalize.d.ts.map +1 -0
- package/dist/field-normalize.js +8 -0
- package/dist/field-normalize.js.map +1 -0
- package/dist/index.js +18 -143
- package/dist/index.js.map +1 -1
- package/dist/machine.d.ts +15 -0
- package/dist/machine.d.ts.map +1 -0
- package/dist/machine.js +64 -0
- package/dist/machine.js.map +1 -0
- package/dist/org-fields.d.ts +57 -0
- package/dist/org-fields.d.ts.map +1 -0
- package/dist/org-fields.js +167 -0
- package/dist/org-fields.js.map +1 -0
- package/dist/posthog.d.ts +34 -5
- package/dist/posthog.d.ts.map +1 -1
- package/dist/posthog.js +217 -13
- package/dist/posthog.js.map +1 -1
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +25 -4
- package/dist/registry.js.map +1 -1
- package/dist/scanners/index.d.ts +6 -0
- package/dist/scanners/index.d.ts.map +1 -1
- package/dist/scanners/index.js +48 -51
- package/dist/scanners/index.js.map +1 -1
- package/dist/scanners/sqlite.d.ts +18 -0
- package/dist/scanners/sqlite.d.ts.map +1 -0
- package/dist/scanners/sqlite.js +63 -0
- package/dist/scanners/sqlite.js.map +1 -0
- package/dist/sync.d.ts +3 -0
- package/dist/sync.d.ts.map +1 -1
- package/dist/sync.js +7 -0
- package/dist/sync.js.map +1 -1
- package/dist/ui.d.ts +1 -0
- package/dist/ui.d.ts.map +1 -1
- package/dist/ui.js +5 -0
- package/dist/ui.js.map +1 -1
- package/package.json +3 -1
package/dist/posthog.js
CHANGED
|
@@ -1,20 +1,224 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { promises as fs } from 'node:fs';
|
|
3
|
+
import { createRequire } from 'node:module';
|
|
4
|
+
import { dirname, join } from 'node:path';
|
|
1
5
|
import { PostHog } from 'posthog-node';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
import { envNameForUrl, getSessionPath, resolveAppUrl } from './session.js';
|
|
7
|
+
import { dim } from './ui.js';
|
|
8
|
+
// Single source of the published version (one level up from this module in both
|
|
9
|
+
// `dist/` and `src/`), tagged onto every event so we can slice by CLI version.
|
|
10
|
+
const require = createRequire(import.meta.url);
|
|
11
|
+
const { version: CLI_VERSION } = require('../package.json');
|
|
12
|
+
// The PostHog *project* API key for the CLI's own project (id 226792, separate
|
|
13
|
+
// from the web app's project 226288). It's a publishable client key (phc_…,
|
|
14
|
+
// write-only) that ships inside the published npm package regardless, so
|
|
15
|
+
// committing it here is fine. `POSTHOG_API_KEY` overrides it for dev/testing.
|
|
16
|
+
// The CLI never reads Vercel env (it runs on users' machines), so its key lives
|
|
17
|
+
// here, not in Vercel.
|
|
18
|
+
const PROJECT_API_KEY = process.env.POSTHOG_API_KEY ??
|
|
19
|
+
'phc_oCCCCjjTXkmknHh5gjEhsqJNuJ77BqsZUU96MRtAHoYQ';
|
|
20
|
+
const HOST = process.env.POSTHOG_HOST ?? 'https://eu.i.posthog.com';
|
|
21
|
+
// Telemetry state (anon id + one-time-notice flag) lives next to the session
|
|
22
|
+
// file, so it honors HACKLAB_SESSION_PATH exactly like the update-check cache.
|
|
23
|
+
function telemetryPath() {
|
|
24
|
+
return join(dirname(getSessionPath()), 'telemetry.json');
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Telemetry is opt-OUT. It's off when the user sets `HACKLAB_NO_TELEMETRY`
|
|
28
|
+
* (mirrors `HACKLAB_NO_UPDATE_CHECK`) or the cross-tool `DO_NOT_TRACK` standard
|
|
29
|
+
* (https://consoledonottrack.com). Checked at every entry point, so a disabled
|
|
30
|
+
* CLI never constructs a client, phones home, or installs exception handlers.
|
|
31
|
+
*/
|
|
32
|
+
export function isTelemetryDisabled() {
|
|
33
|
+
if (process.env.HACKLAB_NO_TELEMETRY)
|
|
34
|
+
return true;
|
|
35
|
+
const dnt = process.env.DO_NOT_TRACK;
|
|
36
|
+
return dnt === '1' || dnt === 'true';
|
|
37
|
+
}
|
|
38
|
+
async function readState() {
|
|
39
|
+
try {
|
|
40
|
+
return JSON.parse(await fs.readFile(telemetryPath(), 'utf8'));
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
return {};
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
async function writeState(state) {
|
|
47
|
+
try {
|
|
48
|
+
await fs.mkdir(dirname(telemetryPath()), { recursive: true });
|
|
49
|
+
await fs.writeFile(telemetryPath(), `${JSON.stringify(state, null, 2)}\n`, 'utf8');
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
// Best-effort: a failed write just means a fresh anon id / re-shown notice.
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* A stable anonymous device id for events that fire before (or without) login.
|
|
57
|
+
* Generated once and persisted; on login we `alias` it to the real handle so
|
|
58
|
+
* PostHog stitches the anonymous history onto the identified user.
|
|
59
|
+
*/
|
|
60
|
+
async function getAnonymousId() {
|
|
61
|
+
const state = await readState();
|
|
62
|
+
if (state.anonymousId)
|
|
63
|
+
return state.anonymousId;
|
|
64
|
+
const anonymousId = `anon_${randomUUID()}`;
|
|
65
|
+
await writeState({ ...state, anonymousId });
|
|
66
|
+
return anonymousId;
|
|
67
|
+
}
|
|
68
|
+
let client = null;
|
|
69
|
+
function getClient() {
|
|
70
|
+
if (!client) {
|
|
71
|
+
client = new PostHog(PROJECT_API_KEY, {
|
|
72
|
+
host: HOST,
|
|
73
|
+
// We flush explicitly after every capture (and on shutdown), so disable
|
|
74
|
+
// both of posthog-node's background-flush triggers: the count trigger
|
|
75
|
+
// (flushAt — set high enough that a single CLI run never hits it) and the
|
|
76
|
+
// timer (flushInterval: 0). This matters because a background flush routes
|
|
77
|
+
// its failure to a hardcoded console.error we can't intercept — it would
|
|
78
|
+
// dump a network stack trace into the user's terminal on a flaky
|
|
79
|
+
// connection. Our explicit flush rejects into our own try/catch instead,
|
|
80
|
+
// so a telemetry failure stays silent.
|
|
81
|
+
flushAt: 1000,
|
|
82
|
+
flushInterval: 0,
|
|
83
|
+
// Best-effort telemetry: don't retry a failed send. The default is 3
|
|
84
|
+
// retries with a 3s backoff, and that backoff timer is what keeps a
|
|
85
|
+
// one-shot CLI alive for ~10s after the command visibly finished when the
|
|
86
|
+
// network is down. No retries → fail fast → the process exits promptly.
|
|
87
|
+
fetchRetryCount: 0,
|
|
88
|
+
// Tighter than the 10s default so a black-holed connection gives up fast.
|
|
89
|
+
requestTimeout: 3000,
|
|
90
|
+
enableExceptionAutocapture: true,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
return client;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Properties attached to every CLI event. CLI and web now live in separate
|
|
97
|
+
* PostHog projects, but we still tag `source: 'cli'` as a cheap, explicit
|
|
98
|
+
* discriminator — handy if the two datasets are ever combined, and it costs
|
|
99
|
+
* nothing to keep.
|
|
100
|
+
*/
|
|
101
|
+
function defaultProperties() {
|
|
102
|
+
return {
|
|
103
|
+
source: 'cli',
|
|
104
|
+
cli_version: CLI_VERSION,
|
|
105
|
+
os: process.platform,
|
|
106
|
+
arch: process.arch,
|
|
107
|
+
node_version: process.versions.node,
|
|
108
|
+
environment: envNameForUrl(resolveAppUrl()) ?? 'unknown',
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
// Never let a stuck network hold up the CLI: cap any send at a couple seconds
|
|
112
|
+
// and move on. The timer is unref'd so it can't by itself keep the process
|
|
113
|
+
// alive after the real work is done.
|
|
114
|
+
async function withTimeout(p, ms = 2000) {
|
|
115
|
+
await Promise.race([
|
|
116
|
+
p.catch(() => undefined),
|
|
117
|
+
new Promise((resolve) => {
|
|
118
|
+
const t = setTimeout(resolve, ms);
|
|
119
|
+
t.unref?.();
|
|
120
|
+
}),
|
|
121
|
+
]);
|
|
122
|
+
}
|
|
9
123
|
/**
|
|
10
|
-
* Capture an event and
|
|
11
|
-
*
|
|
12
|
-
*
|
|
124
|
+
* Capture an event and flush it. Falls back to the anonymous device id when no
|
|
125
|
+
* handle is given, so pre-auth usage is still counted (and later stitched onto
|
|
126
|
+
* the user via `identifyUser`). Fire-and-forget: gated on opt-out, wrapped so it
|
|
127
|
+
* can never slow down or break the command that called it.
|
|
13
128
|
*/
|
|
14
129
|
export async function captureEvent(distinctId, event, properties) {
|
|
15
|
-
if (
|
|
130
|
+
if (isTelemetryDisabled())
|
|
16
131
|
return;
|
|
17
|
-
|
|
18
|
-
|
|
132
|
+
try {
|
|
133
|
+
const id = distinctId ?? (await getAnonymousId());
|
|
134
|
+
const ph = getClient();
|
|
135
|
+
ph.capture({
|
|
136
|
+
distinctId: id,
|
|
137
|
+
event,
|
|
138
|
+
properties: { ...defaultProperties(), ...properties },
|
|
139
|
+
});
|
|
140
|
+
await withTimeout(ph.flush());
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
// Telemetry must never break a command. Swallow everything.
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Identify the logged-in user and merge any anonymous pre-login history onto
|
|
148
|
+
* them. `properties` is passed straight through (callers set `$set` /
|
|
149
|
+
* `$set_once`). Opt-out gated and fully wrapped.
|
|
150
|
+
*/
|
|
151
|
+
export async function identifyUser(handle, properties) {
|
|
152
|
+
if (isTelemetryDisabled())
|
|
153
|
+
return;
|
|
154
|
+
try {
|
|
155
|
+
const ph = getClient();
|
|
156
|
+
const { anonymousId } = await readState();
|
|
157
|
+
if (anonymousId && anonymousId !== handle) {
|
|
158
|
+
ph.alias({ distinctId: handle, alias: anonymousId });
|
|
159
|
+
}
|
|
160
|
+
ph.identify({ distinctId: handle, properties });
|
|
161
|
+
await withTimeout(ph.flush());
|
|
162
|
+
}
|
|
163
|
+
catch {
|
|
164
|
+
// Identification is best-effort — never break login/join over it.
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
/** Report an unhandled error to PostHog. Opt-out gated and wrapped. */
|
|
168
|
+
export async function captureException(error, distinctId) {
|
|
169
|
+
if (isTelemetryDisabled())
|
|
170
|
+
return;
|
|
171
|
+
try {
|
|
172
|
+
const ph = getClient();
|
|
173
|
+
const id = distinctId ?? (await getAnonymousId());
|
|
174
|
+
ph.captureException(error, id, defaultProperties());
|
|
175
|
+
await withTimeout(ph.flush());
|
|
176
|
+
}
|
|
177
|
+
catch {
|
|
178
|
+
// Swallow — a telemetry failure must not mask the original error.
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Final drain before the process exits. No-op if telemetry never initialized.
|
|
183
|
+
* Uses flush(), not shutdown(): shutdown() routes a failed flush to a hardcoded
|
|
184
|
+
* console.error (a network stack trace in the user's terminal), whereas flush()
|
|
185
|
+
* rejects into our own catch and stays silent. There are no background timers to
|
|
186
|
+
* clear (flushInterval is 0), so flush() is a complete drain here.
|
|
187
|
+
*/
|
|
188
|
+
export async function shutdownTelemetry() {
|
|
189
|
+
if (!client)
|
|
190
|
+
return;
|
|
191
|
+
try {
|
|
192
|
+
await withTimeout(client.flush());
|
|
193
|
+
}
|
|
194
|
+
catch {
|
|
195
|
+
// Best-effort final flush.
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* One-time, one-line notice that the CLI collects anonymous usage, with the
|
|
200
|
+
* opt-out. Interactive only (never in pipes / CI / the quiet daily run), shown
|
|
201
|
+
* once per machine (flagged in telemetry.json). Mirrors the update-check nudge:
|
|
202
|
+
* stderr, TTY-gated, and wrapped so it can never break or delay a command.
|
|
203
|
+
*/
|
|
204
|
+
export async function maybePrintTelemetryNotice() {
|
|
205
|
+
try {
|
|
206
|
+
if (isTelemetryDisabled())
|
|
207
|
+
return;
|
|
208
|
+
if (!process.stdout.isTTY)
|
|
209
|
+
return;
|
|
210
|
+
const state = await readState();
|
|
211
|
+
if (state.noticeShownAt)
|
|
212
|
+
return;
|
|
213
|
+
await writeState({
|
|
214
|
+
...state,
|
|
215
|
+
anonymousId: state.anonymousId ?? `anon_${randomUUID()}`,
|
|
216
|
+
noticeShownAt: new Date().toISOString(),
|
|
217
|
+
});
|
|
218
|
+
process.stderr.write(`${dim('hacklab collects anonymous usage analytics to improve the CLI — opt out with HACKLAB_NO_TELEMETRY=1 (or DO_NOT_TRACK=1).')}\n`);
|
|
219
|
+
}
|
|
220
|
+
catch {
|
|
221
|
+
// A notice must never break or delay the actual command.
|
|
222
|
+
}
|
|
19
223
|
}
|
|
20
224
|
//# sourceMappingURL=posthog.js.map
|
package/dist/posthog.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"posthog.js","sourceRoot":"","sources":["../src/posthog.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;
|
|
1
|
+
{"version":3,"file":"posthog.js","sourceRoot":"","sources":["../src/posthog.ts"],"names":[],"mappings":"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"}
|
package/dist/registry.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAsBA,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,EAyGjC,CAAA;AAED,kFAAkF;AAClF,eAAO,MAAM,aAAa,UAA8B,CAAA;AAExD,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS,CAEjE"}
|
package/dist/registry.js
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
|
+
import { book, parseBookArgs } from './commands/book.js';
|
|
1
2
|
import { chat } from './commands/chat.js';
|
|
2
3
|
import { configCommand } from './commands/config.js';
|
|
3
4
|
import { drop, parseDropArgs } from './commands/drop.js';
|
|
4
5
|
import { essay } from './commands/essay.js';
|
|
5
6
|
import { hacker } from './commands/hacker.js';
|
|
6
7
|
import { join } from './commands/join.js';
|
|
8
|
+
import { keys } from './commands/keys.js';
|
|
7
9
|
import { login } from './commands/login.js';
|
|
8
10
|
import { logout } from './commands/logout.js';
|
|
9
11
|
import { org } from './commands/org.js';
|
|
10
12
|
import { profile } from './commands/profile.js';
|
|
11
13
|
import { project } from './commands/project.js';
|
|
14
|
+
import { scout } from './commands/scout.js';
|
|
12
15
|
import { sync } from './commands/sync.js';
|
|
13
16
|
import { update } from './commands/update.js';
|
|
14
17
|
import { whoami } from './commands/whoami.js';
|
|
@@ -62,10 +65,16 @@ export const COMMANDS = [
|
|
|
62
65
|
summary: 'publish this repo as a project (--json for agents)',
|
|
63
66
|
run: (args) => project(args),
|
|
64
67
|
},
|
|
68
|
+
{
|
|
69
|
+
name: 'book',
|
|
70
|
+
args: '"Title" --author "Name"',
|
|
71
|
+
summary: 'shelve a book you have read (--takeaways "…")',
|
|
72
|
+
run: (args) => book(parseBookArgs(args)),
|
|
73
|
+
},
|
|
65
74
|
{
|
|
66
75
|
name: 'org',
|
|
67
|
-
args: '[claim|create]',
|
|
68
|
-
summary: 'claim, create, or edit your organization',
|
|
76
|
+
args: '[list|view|set|apply|claim|create]',
|
|
77
|
+
summary: 'claim, create, or edit your organization (--json for agents)',
|
|
69
78
|
run: (args) => org(args),
|
|
70
79
|
},
|
|
71
80
|
{
|
|
@@ -82,16 +91,28 @@ export const COMMANDS = [
|
|
|
82
91
|
},
|
|
83
92
|
{
|
|
84
93
|
name: 'hacker',
|
|
85
|
-
args: 'view
|
|
86
|
-
summary:
|
|
94
|
+
args: 'view [handle]',
|
|
95
|
+
summary: 'view a hacker profile — yours by default (--json for agents)',
|
|
87
96
|
run: (args) => hacker(args),
|
|
88
97
|
},
|
|
98
|
+
{
|
|
99
|
+
name: 'scout',
|
|
100
|
+
args: 'search|picks [flags]',
|
|
101
|
+
summary: 'talent scouting for partners: search the pool, or our curated picks (invite-only)',
|
|
102
|
+
run: (args) => scout(args),
|
|
103
|
+
},
|
|
89
104
|
{
|
|
90
105
|
name: 'profile',
|
|
91
106
|
args: '[view|set|edit|apply]',
|
|
92
107
|
summary: 'view and edit your own profile (--json for agents)',
|
|
93
108
|
run: (args) => profile(args),
|
|
94
109
|
},
|
|
110
|
+
{
|
|
111
|
+
name: 'keys',
|
|
112
|
+
args: '[create|list|revoke]',
|
|
113
|
+
summary: 'manage API keys for your agent profile endpoint',
|
|
114
|
+
run: (args) => keys(args),
|
|
115
|
+
},
|
|
95
116
|
{
|
|
96
117
|
name: 'update',
|
|
97
118
|
summary: 'update the hacklab CLI to the latest version',
|
package/dist/registry.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAA;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AACpD,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AACxD,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAA;AAC3C,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAA;AAC7C,OAAO,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAA;AACzC,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAA;AAC3C,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAA;AAC7C,OAAO,EAAE,GAAG,EAAE,MAAM,mBAAmB,CAAA;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAA;AAC/C,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAA;AAC/C,OAAO,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAA;AACzC,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAA;AAC7C,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAA;AAiB7C,MAAM,CAAC,MAAM,QAAQ,GAAkB;IACrC;QACE,IAAI,EAAE,MAAM;QACZ,IAAI,EAAE,aAAa;QACnB,OAAO,EAAE,iCAAiC;QAC1C,GAAG,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;KAC7D;IACD;QACE,IAAI,EAAE,MAAM;QACZ,IAAI,EAAE,mBAAmB;QACzB,OAAO,EAAE,qCAAqC;QAC9C,GAAG,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC;KAC1B;IACD;QACE,IAAI,EAAE,QAAQ;QACd,OAAO,EAAE,+BAA+B;QACxC,GAAG,EAAE,GAAG,EAAE,CAAC,MAAM,EAAE;KACpB;IACD;QACE,IAAI,EAAE,MAAM;QACZ,IAAI,EAAE,WAAW;QACjB,OAAO,EAAE,0BAA0B;QACnC,GAAG,EAAE,CAAC,IAAI,EAAE,EAAE;YACZ,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,aAAa,CAAC,IAAI,CAAC,CAAA;YACzC,OAAO,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,CAAA;QACxB,CAAC;KACF;IACD;QACE,IAAI,EAAE,OAAO;QACb,IAAI,EAAE,aAAa;QACnB,OAAO,EACL,oEAAoE;QACtE,GAAG,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;KAC9D;IACD;QACE,IAAI,EAAE,QAAQ;QACd,OAAO,EAAE,0CAA0C;QACnD,GAAG,EAAE,GAAG,EAAE,CAAC,MAAM,EAAE;KACpB;IACD;QACE,IAAI,EAAE,QAAQ;QACd,IAAI,EAAE,aAAa;QACnB,OAAO,EAAE,2CAA2C;QACpD,GAAG,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC;KACnC;IACD;QACE,IAAI,EAAE,SAAS;QACf,IAAI,EAAE,mBAAmB;QACzB,OAAO,EAAE,oDAAoD;QAC7D,GAAG,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;KAC7B;IACD;QACE,IAAI,EAAE,KAAK;QACX,IAAI,EAAE,
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"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"}
|
package/dist/scanners/index.d.ts
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { type CursorScanStatus, type CursorStats, type DailyToolEntry, type HourlyEntry, type ScanResult } from './util.js';
|
|
2
2
|
export * from './util.js';
|
|
3
3
|
export declare function scanClaudeCode(): Promise<ScanResult>;
|
|
4
|
+
/**
|
|
5
|
+
* Extract the session date from a Codex session path laid out as
|
|
6
|
+
* `YYYY/MM/DD/file.jsonl`, or null if the path doesn't carry one. Splits on
|
|
7
|
+
* either separator so it works on Windows (backslashes) too.
|
|
8
|
+
*/
|
|
9
|
+
export declare function codexDateFromRelPath(relPath: string): string | null;
|
|
4
10
|
export declare function scanCodex(): Promise<ScanResult>;
|
|
5
11
|
export declare function scanHermes(): Promise<ScanResult>;
|
|
6
12
|
export declare function scanOpenclaw(): Promise<ScanResult>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/scanners/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/scanners/index.ts"],"names":[],"mappings":"AAMA,OAAO,EACL,KAAK,gBAAgB,EACrB,KAAK,WAAW,EAChB,KAAK,cAAc,EAGnB,KAAK,WAAW,EAChB,KAAK,UAAU,EAGhB,MAAM,WAAW,CAAA;AAElB,cAAc,WAAW,CAAA;AAKzB,wBAAsB,cAAc,IAAI,OAAO,CAAC,UAAU,CAAC,CAuD1D;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAMnE;AAED,wBAAsB,SAAS,IAAI,OAAO,CAAC,UAAU,CAAC,CA4CrD;AAED,wBAAsB,UAAU,IAAI,OAAO,CAAC,UAAU,CAAC,CAkDtD;AAED,wBAAsB,YAAY,IAAI,OAAO,CAAC,UAAU,CAAC,CAgFxD;AAED,wBAAsB,YAAY,IAAI,OAAO,CAAC,UAAU,CAAC,CAyFxD;AAsCD;;;;;;;;;GASG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,OAAO,CAAC,CAU1D;AAED,wBAAsB,eAAe,IAAI,OAAO,CAAC,UAAU,CAAC,CA8D3D;AAED,wBAAsB,aAAa,IAAI,OAAO,CAAC,UAAU,CAAC,CAkHzD;AAED,MAAM,MAAM,aAAa,GAAG;IAC1B,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAClC,WAAW,EAAE,cAAc,EAAE,CAAA;IAC7B,YAAY,EAAE,WAAW,EAAE,CAAA;IAC3B,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACnC,UAAU,EAAE,MAAM,CAAA;IAClB,WAAW,EAAE,WAAW,GAAG,IAAI,CAAA;IAC/B,gBAAgB,EAAE,gBAAgB,CAAA;CACnC,CAAA;AAsBD,6EAA6E;AAC7E,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC,CAc9D;AAED;;;;;GAKG;AACH,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,UAAU,EAAE,GACpB,OAAO,CAAC,UAAU,EAAE,CAAC,CAGvB;AAED,iEAAiE;AACjE,wBAAgB,cAAc,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,aAAa,CA+BnE;AAED;;;GAGG;AACH,wBAAsB,YAAY,IAAI,OAAO,CAAC,aAAa,CAAC,CAE3D"}
|
package/dist/scanners/index.js
CHANGED
|
@@ -2,6 +2,7 @@ import { readdir, readFile, stat } from 'node:fs/promises';
|
|
|
2
2
|
import { homedir } from 'node:os';
|
|
3
3
|
import { join } from 'node:path';
|
|
4
4
|
import { resolveCursorAuth } from '../config.js';
|
|
5
|
+
import { num, queryDb, str } from './sqlite.js';
|
|
5
6
|
import { emptyResult, findFiles, TokenCollector, toDateStr, } from './util.js';
|
|
6
7
|
export * from './util.js';
|
|
7
8
|
// One self-contained scanner per tool. Each returns a uniform ScanResult and
|
|
@@ -62,6 +63,18 @@ export async function scanClaudeCode() {
|
|
|
62
63
|
}
|
|
63
64
|
return collector.result();
|
|
64
65
|
}
|
|
66
|
+
/**
|
|
67
|
+
* Extract the session date from a Codex session path laid out as
|
|
68
|
+
* `YYYY/MM/DD/file.jsonl`, or null if the path doesn't carry one. Splits on
|
|
69
|
+
* either separator so it works on Windows (backslashes) too.
|
|
70
|
+
*/
|
|
71
|
+
export function codexDateFromRelPath(relPath) {
|
|
72
|
+
const parts = relPath.split(/[\\/]/);
|
|
73
|
+
if (parts.length >= 3) {
|
|
74
|
+
return `${parts[0]}-${parts[1]?.padStart(2, '0')}-${parts[2]?.padStart(2, '0')}`;
|
|
75
|
+
}
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
65
78
|
export async function scanCodex() {
|
|
66
79
|
const dir = join(homedir(), '.codex', 'sessions');
|
|
67
80
|
try {
|
|
@@ -75,16 +88,9 @@ export async function scanCodex() {
|
|
|
75
88
|
for (const filePath of files) {
|
|
76
89
|
try {
|
|
77
90
|
const content = await readFile(filePath, 'utf8');
|
|
78
|
-
// Date from path: .codex/sessions/YYYY/MM/DD/file.jsonl
|
|
91
|
+
// Date from path: .codex/sessions/YYYY/MM/DD/file.jsonl.
|
|
79
92
|
const relPath = filePath.slice(dir.length + 1);
|
|
80
|
-
const
|
|
81
|
-
let date;
|
|
82
|
-
if (parts.length >= 3) {
|
|
83
|
-
date = `${parts[0]}-${parts[1]?.padStart(2, '0')}-${parts[2]?.padStart(2, '0')}`;
|
|
84
|
-
}
|
|
85
|
-
else {
|
|
86
|
-
date = toDateStr((await stat(filePath)).mtime);
|
|
87
|
-
}
|
|
93
|
+
const date = codexDateFromRelPath(relPath) ?? toDateStr((await stat(filePath)).mtime);
|
|
88
94
|
// Codex stores running totals; take the max per file.
|
|
89
95
|
let maxTotal = 0;
|
|
90
96
|
let fileModel = '';
|
|
@@ -123,28 +129,27 @@ export async function scanHermes() {
|
|
|
123
129
|
catch {
|
|
124
130
|
return emptyResult('hermes');
|
|
125
131
|
}
|
|
126
|
-
const { execSync } = await import('node:child_process');
|
|
127
132
|
const collector = new TokenCollector('hermes');
|
|
128
133
|
try {
|
|
129
|
-
const
|
|
130
|
-
if (
|
|
134
|
+
const rows = await queryDb(dbPath, `select s.id, coalesce(s.model,'') as model, s.started_at, s.input_tokens, s.output_tokens, s.cache_read_tokens, s.cache_write_tokens, s.reasoning_tokens, coalesce((select count(*) from messages m where m.session_id = s.id and m.role = 'assistant'), 0) as msg_count from sessions s`);
|
|
135
|
+
if (rows.length === 0)
|
|
131
136
|
return emptyResult('hermes');
|
|
132
|
-
for (const row of
|
|
133
|
-
const [, model, startedAt, inputTokens, outputTokens, cacheRead, cacheWrite, reasoning, msgCount,] = row
|
|
134
|
-
const tokens = (
|
|
135
|
-
(
|
|
136
|
-
(
|
|
137
|
-
(
|
|
138
|
-
(
|
|
137
|
+
for (const row of rows) {
|
|
138
|
+
const [, model, startedAt, inputTokens, outputTokens, cacheRead, cacheWrite, reasoning, msgCount,] = row;
|
|
139
|
+
const tokens = num(inputTokens) +
|
|
140
|
+
num(outputTokens) +
|
|
141
|
+
num(cacheRead) +
|
|
142
|
+
num(cacheWrite) +
|
|
143
|
+
num(reasoning);
|
|
139
144
|
if (tokens <= 0)
|
|
140
145
|
continue;
|
|
141
|
-
const tsSec =
|
|
146
|
+
const tsSec = num(startedAt);
|
|
142
147
|
if (!Number.isFinite(tsSec) || tsSec <= 0)
|
|
143
148
|
continue;
|
|
144
149
|
const d = new Date(Math.round(tsSec * 1000));
|
|
145
150
|
const date = toDateStr(d);
|
|
146
|
-
const m = (model
|
|
147
|
-
const messages =
|
|
151
|
+
const m = str(model).trim();
|
|
152
|
+
const messages = num(msgCount) || 1;
|
|
148
153
|
collector.addDaily(date, m, tokens, messages);
|
|
149
154
|
collector.addHourly(date, d.getHours(), m, tokens, messages);
|
|
150
155
|
}
|
|
@@ -250,23 +255,18 @@ export async function scanOpenCode() {
|
|
|
250
255
|
const dbPath = join(baseDir, 'opencode.db');
|
|
251
256
|
try {
|
|
252
257
|
await stat(dbPath);
|
|
253
|
-
const
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
const
|
|
258
|
-
const tokens = (Number.parseInt(inp ?? '0', 10) || 0) +
|
|
259
|
-
(Number.parseInt(out ?? '0', 10) || 0) +
|
|
260
|
-
(Number.parseInt(cr ?? '0', 10) || 0) +
|
|
261
|
-
(Number.parseInt(cw ?? '0', 10) || 0) +
|
|
262
|
-
(Number.parseInt(reason ?? '0', 10) || 0);
|
|
258
|
+
const rows = await queryDb(dbPath, `SELECT json_extract(data,'$.time.created'), coalesce(json_extract(data,'$.modelID'),''), coalesce(json_extract(data,'$.tokens.input'),0), coalesce(json_extract(data,'$.tokens.output'),0), coalesce(json_extract(data,'$.tokens.cache.read'),0), coalesce(json_extract(data,'$.tokens.cache.write'),0), coalesce(json_extract(data,'$.tokens.reasoning'),0) FROM message WHERE json_extract(data,'$.role')='assistant'`);
|
|
259
|
+
if (rows.length > 0) {
|
|
260
|
+
for (const row of rows) {
|
|
261
|
+
const [time, model, inp, out, cr, cw, reason] = row;
|
|
262
|
+
const tokens = num(inp) + num(out) + num(cr) + num(cw) + num(reason);
|
|
263
263
|
if (tokens <= 0)
|
|
264
264
|
continue;
|
|
265
|
-
const tsMs =
|
|
265
|
+
const tsMs = num(time);
|
|
266
266
|
if (!Number.isFinite(tsMs) || tsMs <= 0)
|
|
267
267
|
continue;
|
|
268
268
|
const d = new Date(tsMs);
|
|
269
|
-
const m = (model
|
|
269
|
+
const m = str(model).trim();
|
|
270
270
|
collector.addDaily(toDateStr(d), m, tokens, 1);
|
|
271
271
|
collector.addHourly(toDateStr(d), d.getHours(), m, tokens, 1);
|
|
272
272
|
}
|
|
@@ -395,35 +395,32 @@ export async function scanCursorLocal() {
|
|
|
395
395
|
catch {
|
|
396
396
|
return { ...emptyResult('cursor'), cursorStats: null };
|
|
397
397
|
}
|
|
398
|
-
const { execSync } = await import('node:child_process');
|
|
399
398
|
const collector = new TokenCollector('cursor');
|
|
400
399
|
try {
|
|
401
|
-
const
|
|
402
|
-
if (
|
|
400
|
+
const rows = await queryDb(dbPath, `select commitHash, linesAdded, linesDeleted, composerLinesAdded, composerLinesDeleted, humanLinesAdded, humanLinesDeleted, v2AiPercentage from scored_commits;`);
|
|
401
|
+
if (rows.length === 0)
|
|
403
402
|
return { ...emptyResult('cursor'), cursorStats: null };
|
|
404
|
-
const rows = raw.split('\n');
|
|
405
403
|
let totalTokens = 0;
|
|
406
404
|
let totalAiLines = 0;
|
|
407
405
|
let totalHumanLines = 0;
|
|
408
406
|
let aiPctSum = 0;
|
|
409
407
|
for (const row of rows) {
|
|
410
|
-
const
|
|
411
|
-
const
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
408
|
+
const composerAdded = num(row[3]);
|
|
409
|
+
const composerDeleted = num(row[4]);
|
|
410
|
+
const humanAdded = num(row[5]);
|
|
411
|
+
const aiLines = composerAdded + composerDeleted;
|
|
412
|
+
totalAiLines += composerAdded;
|
|
413
|
+
totalHumanLines += humanAdded;
|
|
414
|
+
aiPctSum += num(row[7]);
|
|
416
415
|
totalTokens += aiLines * 30;
|
|
417
416
|
}
|
|
418
417
|
let models = [];
|
|
419
418
|
try {
|
|
420
|
-
const
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
});
|
|
426
|
-
}
|
|
419
|
+
const modelRows = await queryDb(dbPath, `select model, count(*) from ai_code_hashes where model is not null and model != '' group by model order by count(*) desc;`);
|
|
420
|
+
models = modelRows.map((row) => ({
|
|
421
|
+
model: str(row[0]),
|
|
422
|
+
uses: num(row[1]),
|
|
423
|
+
}));
|
|
427
424
|
}
|
|
428
425
|
catch {
|
|
429
426
|
// optional
|