@indigoai-us/hq-cloud 5.45.0 → 5.47.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/dist/bin/sync-runner.d.ts +12 -0
- package/dist/bin/sync-runner.d.ts.map +1 -1
- package/dist/bin/sync-runner.js +78 -12
- package/dist/bin/sync-runner.js.map +1 -1
- package/dist/bin/sync-runner.test.js +27 -1
- package/dist/bin/sync-runner.test.js.map +1 -1
- package/dist/cli/share.d.ts.map +1 -1
- package/dist/cli/share.js +17 -2
- package/dist/cli/share.js.map +1 -1
- package/dist/cli/share.test.js +2 -0
- package/dist/cli/share.test.js.map +1 -1
- package/dist/cli/sync-scope.test.js +1 -0
- package/dist/cli/sync-scope.test.js.map +1 -1
- package/dist/cli/sync.d.ts.map +1 -1
- package/dist/cli/sync.js +11 -1
- package/dist/cli/sync.js.map +1 -1
- package/dist/cli/sync.test.js +1 -0
- package/dist/cli/sync.test.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/object-io.d.ts +218 -0
- package/dist/object-io.d.ts.map +1 -0
- package/dist/object-io.js +588 -0
- package/dist/object-io.js.map +1 -0
- package/dist/object-io.test.d.ts +11 -0
- package/dist/object-io.test.d.ts.map +1 -0
- package/dist/object-io.test.js +568 -0
- package/dist/object-io.test.js.map +1 -0
- package/dist/s3.d.ts +37 -0
- package/dist/s3.d.ts.map +1 -1
- package/dist/s3.js +207 -198
- package/dist/s3.js.map +1 -1
- package/dist/skill-telemetry.d.ts +107 -0
- package/dist/skill-telemetry.d.ts.map +1 -0
- package/dist/skill-telemetry.js +395 -0
- package/dist/skill-telemetry.js.map +1 -0
- package/dist/skill-telemetry.test.d.ts +2 -0
- package/dist/skill-telemetry.test.d.ts.map +1 -0
- package/dist/skill-telemetry.test.js +219 -0
- package/dist/skill-telemetry.test.js.map +1 -0
- package/dist/vault-client.d.ts +91 -0
- package/dist/vault-client.d.ts.map +1 -1
- package/dist/vault-client.js +45 -0
- package/dist/vault-client.js.map +1 -1
- package/package.json +1 -1
- package/scripts/presign-transport-e2e.mjs +203 -0
- package/scripts/vault-rebaseline.sh +275 -0
- package/scripts/vault-rescue.sh +291 -0
- package/src/bin/sync-runner.test.ts +41 -0
- package/src/bin/sync-runner.ts +91 -13
- package/src/cli/share.test.ts +2 -0
- package/src/cli/share.ts +29 -2
- package/src/cli/sync-scope.test.ts +1 -0
- package/src/cli/sync.test.ts +1 -0
- package/src/cli/sync.ts +22 -1
- package/src/index.ts +16 -0
- package/src/object-io.test.ts +663 -0
- package/src/object-io.ts +782 -0
- package/src/s3.ts +259 -233
- package/src/skill-telemetry.test.ts +279 -0
- package/src/skill-telemetry.ts +499 -0
- package/src/vault-client.ts +135 -0
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skill-invocation telemetry collector.
|
|
3
|
+
*
|
|
4
|
+
* Sibling to `./telemetry.ts` (the token-usage collector). Where that one
|
|
5
|
+
* promotes token-accounting fields off each Claude Code session row, this one
|
|
6
|
+
* extracts *which skill / slash-command was invoked*, reading the SAME
|
|
7
|
+
* `~/.claude/projects/**\/*.jsonl` session logs but with an independent
|
|
8
|
+
* byte-offset cursor at `~/.hq/skill-telemetry-cursor.json` and shipping to
|
|
9
|
+
* `/v1/skill-invocations`.
|
|
10
|
+
*
|
|
11
|
+
* Why a separate collector rather than folding into `./telemetry.ts`: the
|
|
12
|
+
* token path is proven and its per-batch cursor mechanics are load-bearing.
|
|
13
|
+
* Skill events are sparse, so this collector uses a simpler all-or-nothing
|
|
14
|
+
* per-run cursor commit (re-delivery is idempotent server-side via the
|
|
15
|
+
* composite eventKey). Keeping it standalone means a bug here can never
|
|
16
|
+
* regress token telemetry.
|
|
17
|
+
*
|
|
18
|
+
* Two capture paths, both recoverable from the transcript (verified against
|
|
19
|
+
* real sessions):
|
|
20
|
+
* - User-typed slash command → a `user` row whose content carries
|
|
21
|
+
* `<command-name>/foo</command-name>` (+ optional `<command-args>`).
|
|
22
|
+
* - Model-invoked skill → an `assistant` row with a `tool_use` block whose
|
|
23
|
+
* `name === "Skill"` and `input.skill` names the skill.
|
|
24
|
+
* The two are mutually exclusive per invocation, so there is no double-count.
|
|
25
|
+
*
|
|
26
|
+
* Privacy: raw `<command-args>` / `input.args` content is NEVER sent to the
|
|
27
|
+
* cloud — only a `hasArgs` boolean. This matches the message-stripping posture
|
|
28
|
+
* of `./telemetry.ts::sanitizeRow`, which deliberately drops all prompt/tool
|
|
29
|
+
* content client-side. Flip `INCLUDE_ARGS_PREVIEW` only with a deliberate
|
|
30
|
+
* privacy review and a matching server-side allowlist change.
|
|
31
|
+
*
|
|
32
|
+
* Trust model + error handling are identical to `./telemetry.ts`: personUid is
|
|
33
|
+
* resolved server-side from the JWT (never the body), and all errors are
|
|
34
|
+
* swallowed so telemetry never aborts or delays a sync.
|
|
35
|
+
*/
|
|
36
|
+
import type { SkillInvocationBatch, SkillInvocationIngestResult, TelemetryOptInResponse } from "./vault-client.js";
|
|
37
|
+
export interface SkillTelemetryClientSurface {
|
|
38
|
+
getTelemetryOptIn(): Promise<TelemetryOptInResponse>;
|
|
39
|
+
postSkillInvocations(batch: SkillInvocationBatch): Promise<SkillInvocationIngestResult>;
|
|
40
|
+
}
|
|
41
|
+
export interface CollectSkillTelemetryOptions {
|
|
42
|
+
client: SkillTelemetryClientSurface;
|
|
43
|
+
machineId: string;
|
|
44
|
+
installerVersion: string;
|
|
45
|
+
/**
|
|
46
|
+
* When set, only invocations whose recorded `cwd` equals this path are
|
|
47
|
+
* emitted — scoping capture to the HQ project and excluding skill usage in
|
|
48
|
+
* unrelated repos on the same machine. The walk still covers all of
|
|
49
|
+
* `~/.claude/projects` (so the cursor stays consistent and no session is
|
|
50
|
+
* silently missed by a project-dir-name encoding guess), but non-matching
|
|
51
|
+
* events are dropped before they are batched. Omit to capture every project.
|
|
52
|
+
*/
|
|
53
|
+
hqRoot?: string;
|
|
54
|
+
/** Override `~/.claude/projects` for tests. */
|
|
55
|
+
claudeProjectsRoot?: string;
|
|
56
|
+
/** Override `~/.hq/skill-telemetry-cursor.json` for tests. */
|
|
57
|
+
cursorPath?: string;
|
|
58
|
+
/** Override `~/.hq/menubar.json` (the offline opt-in fallback) for tests. */
|
|
59
|
+
menubarPath?: string;
|
|
60
|
+
/** Diagnostic sink. No-op by default. */
|
|
61
|
+
log?: (msg: string) => void;
|
|
62
|
+
}
|
|
63
|
+
export interface CollectSkillTelemetryResult {
|
|
64
|
+
enabled: boolean;
|
|
65
|
+
optInSource: "server" | "menubar-fallback" | "skipped";
|
|
66
|
+
filesScanned: number;
|
|
67
|
+
eventsSent: number;
|
|
68
|
+
batchesSent: number;
|
|
69
|
+
}
|
|
70
|
+
/** A single extracted skill-invocation event. Mirrors the server allowlist in
|
|
71
|
+
* `apps/hq-pro/src/vault-service/handlers/skill-invocations.ts` (KEEP_FIELDS).
|
|
72
|
+
* Any drift surfaces as `unexpected-event-field` in the ingest result. */
|
|
73
|
+
export interface SkillEvent {
|
|
74
|
+
skill: string;
|
|
75
|
+
source: "typed" | "model";
|
|
76
|
+
sessionId?: string;
|
|
77
|
+
timestamp?: string;
|
|
78
|
+
uuid?: string;
|
|
79
|
+
cwd?: string;
|
|
80
|
+
hasArgs: boolean;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Extract zero or more skill-invocation events from a single parsed session
|
|
84
|
+
* row. A `user` row yields at most one typed command; an `assistant` row can
|
|
85
|
+
* carry multiple `Skill` tool_use blocks (rare, but handled).
|
|
86
|
+
*/
|
|
87
|
+
export declare function extractSkillEvents(row: unknown): SkillEvent[];
|
|
88
|
+
/**
|
|
89
|
+
* Scan, extract, and POST any new skill-invocation events.
|
|
90
|
+
*
|
|
91
|
+
* Cursor model (per-batch commit, matching the token collector for robustness):
|
|
92
|
+
* each file is scanned from its stored byte offset to EOF; extracted events
|
|
93
|
+
* carry the byte offset of the line they came from. Events are flushed in
|
|
94
|
+
* ≤1 MiB batches, and the cursor advances **per successful batch** — so if one
|
|
95
|
+
* batch in a large (e.g. first-run backfill) fails, the batches that already
|
|
96
|
+
* succeeded stay committed and only the rest re-send next sync.
|
|
97
|
+
*
|
|
98
|
+
* Per-file commit rule:
|
|
99
|
+
* - All of a file's events sent OK (including zero-event files) → commit EOF,
|
|
100
|
+
* so quiet/non-skill tails are never re-scanned.
|
|
101
|
+
* - Some of a file's events failed → commit the max byte offset whose batch
|
|
102
|
+
* succeeded (partial progress); the remainder re-sends next sync.
|
|
103
|
+
* Server-side dedup on the composite eventKey makes any re-send idempotent.
|
|
104
|
+
* Rotation/truncation resets the offset to 0 (re-read from the top).
|
|
105
|
+
*/
|
|
106
|
+
export declare function collectAndSendSkillTelemetry(opts: CollectSkillTelemetryOptions): Promise<CollectSkillTelemetryResult>;
|
|
107
|
+
//# sourceMappingURL=skill-telemetry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-telemetry.d.ts","sourceRoot":"","sources":["../src/skill-telemetry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAMH,OAAO,KAAK,EACV,oBAAoB,EACpB,2BAA2B,EAC3B,sBAAsB,EACvB,MAAM,mBAAmB,CAAC;AAI3B,MAAM,WAAW,2BAA2B;IAC1C,iBAAiB,IAAI,OAAO,CAAC,sBAAsB,CAAC,CAAC;IACrD,oBAAoB,CAClB,KAAK,EAAE,oBAAoB,GAC1B,OAAO,CAAC,2BAA2B,CAAC,CAAC;CACzC;AAED,MAAM,WAAW,4BAA4B;IAC3C,MAAM,EAAE,2BAA2B,CAAC;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,EAAE,MAAM,CAAC;IACzB;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,+CAA+C;IAC/C,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,8DAA8D;IAC9D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,6EAA6E;IAC7E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,yCAAyC;IACzC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CAC7B;AAED,MAAM,WAAW,2BAA2B;IAC1C,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,QAAQ,GAAG,kBAAkB,GAAG,SAAS,CAAC;IACvD,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;2EAE2E;AAC3E,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;CAClB;AAiED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,OAAO,GAAG,UAAU,EAAE,CA+D7D;AAiDD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,4BAA4B,CAChD,IAAI,EAAE,4BAA4B,GACjC,OAAO,CAAC,2BAA2B,CAAC,CAuMtC"}
|
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skill-invocation telemetry collector.
|
|
3
|
+
*
|
|
4
|
+
* Sibling to `./telemetry.ts` (the token-usage collector). Where that one
|
|
5
|
+
* promotes token-accounting fields off each Claude Code session row, this one
|
|
6
|
+
* extracts *which skill / slash-command was invoked*, reading the SAME
|
|
7
|
+
* `~/.claude/projects/**\/*.jsonl` session logs but with an independent
|
|
8
|
+
* byte-offset cursor at `~/.hq/skill-telemetry-cursor.json` and shipping to
|
|
9
|
+
* `/v1/skill-invocations`.
|
|
10
|
+
*
|
|
11
|
+
* Why a separate collector rather than folding into `./telemetry.ts`: the
|
|
12
|
+
* token path is proven and its per-batch cursor mechanics are load-bearing.
|
|
13
|
+
* Skill events are sparse, so this collector uses a simpler all-or-nothing
|
|
14
|
+
* per-run cursor commit (re-delivery is idempotent server-side via the
|
|
15
|
+
* composite eventKey). Keeping it standalone means a bug here can never
|
|
16
|
+
* regress token telemetry.
|
|
17
|
+
*
|
|
18
|
+
* Two capture paths, both recoverable from the transcript (verified against
|
|
19
|
+
* real sessions):
|
|
20
|
+
* - User-typed slash command → a `user` row whose content carries
|
|
21
|
+
* `<command-name>/foo</command-name>` (+ optional `<command-args>`).
|
|
22
|
+
* - Model-invoked skill → an `assistant` row with a `tool_use` block whose
|
|
23
|
+
* `name === "Skill"` and `input.skill` names the skill.
|
|
24
|
+
* The two are mutually exclusive per invocation, so there is no double-count.
|
|
25
|
+
*
|
|
26
|
+
* Privacy: raw `<command-args>` / `input.args` content is NEVER sent to the
|
|
27
|
+
* cloud — only a `hasArgs` boolean. This matches the message-stripping posture
|
|
28
|
+
* of `./telemetry.ts::sanitizeRow`, which deliberately drops all prompt/tool
|
|
29
|
+
* content client-side. Flip `INCLUDE_ARGS_PREVIEW` only with a deliberate
|
|
30
|
+
* privacy review and a matching server-side allowlist change.
|
|
31
|
+
*
|
|
32
|
+
* Trust model + error handling are identical to `./telemetry.ts`: personUid is
|
|
33
|
+
* resolved server-side from the JWT (never the body), and all errors are
|
|
34
|
+
* swallowed so telemetry never aborts or delays a sync.
|
|
35
|
+
*/
|
|
36
|
+
import { promises as fs } from "node:fs";
|
|
37
|
+
import * as os from "node:os";
|
|
38
|
+
import * as path from "node:path";
|
|
39
|
+
// Privacy switch — keep false (see file header). When false, raw argument text
|
|
40
|
+
// never leaves the machine; only the `hasArgs` boolean is emitted.
|
|
41
|
+
const INCLUDE_ARGS_PREVIEW = false;
|
|
42
|
+
async function loadCursor(cursorPath) {
|
|
43
|
+
try {
|
|
44
|
+
const raw = await fs.readFile(cursorPath, "utf-8");
|
|
45
|
+
const parsed = JSON.parse(raw);
|
|
46
|
+
if (parsed && typeof parsed === "object" && parsed.files && typeof parsed.files === "object") {
|
|
47
|
+
return { version: parsed.version ?? "1", files: parsed.files };
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
// Missing / unparseable — start fresh.
|
|
52
|
+
}
|
|
53
|
+
return { version: "1", files: {} };
|
|
54
|
+
}
|
|
55
|
+
async function saveCursor(cursorPath, cursor) {
|
|
56
|
+
await fs.mkdir(path.dirname(cursorPath), { recursive: true });
|
|
57
|
+
const tmp = `${cursorPath}.tmp`;
|
|
58
|
+
await fs.writeFile(tmp, JSON.stringify(cursor, null, 2), "utf-8");
|
|
59
|
+
await fs.rename(tmp, cursorPath);
|
|
60
|
+
}
|
|
61
|
+
async function readLocalTelemetryEnabled(menubarPath) {
|
|
62
|
+
try {
|
|
63
|
+
const raw = await fs.readFile(menubarPath, "utf-8");
|
|
64
|
+
const parsed = JSON.parse(raw);
|
|
65
|
+
return parsed.telemetryEnabled === true;
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
// ── Extractor ───────────────────────────────────────────────────────────────
|
|
72
|
+
const CMD_NAME = /<command-name>\s*\/?([^<]+?)\s*<\/command-name>/;
|
|
73
|
+
const CMD_ARGS = /<command-args>([\s\S]*?)<\/command-args>/;
|
|
74
|
+
function rowText(content) {
|
|
75
|
+
if (typeof content === "string")
|
|
76
|
+
return content;
|
|
77
|
+
if (Array.isArray(content)) {
|
|
78
|
+
return content
|
|
79
|
+
.map((b) => (b && typeof b === "object" && typeof b.text === "string"
|
|
80
|
+
? b.text
|
|
81
|
+
: ""))
|
|
82
|
+
.join(" ");
|
|
83
|
+
}
|
|
84
|
+
return "";
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Extract zero or more skill-invocation events from a single parsed session
|
|
88
|
+
* row. A `user` row yields at most one typed command; an `assistant` row can
|
|
89
|
+
* carry multiple `Skill` tool_use blocks (rare, but handled).
|
|
90
|
+
*/
|
|
91
|
+
export function extractSkillEvents(row) {
|
|
92
|
+
if (!row || typeof row !== "object" || Array.isArray(row))
|
|
93
|
+
return [];
|
|
94
|
+
const obj = row;
|
|
95
|
+
const type = obj.type;
|
|
96
|
+
const msg = obj.message && typeof obj.message === "object" && !Array.isArray(obj.message)
|
|
97
|
+
? obj.message
|
|
98
|
+
: undefined;
|
|
99
|
+
if (!msg)
|
|
100
|
+
return [];
|
|
101
|
+
const sessionId = typeof obj.sessionId === "string" ? obj.sessionId : undefined;
|
|
102
|
+
const timestamp = typeof obj.timestamp === "string" ? obj.timestamp : undefined;
|
|
103
|
+
const cwd = typeof obj.cwd === "string" ? obj.cwd : undefined;
|
|
104
|
+
const rowUuid = typeof obj.uuid === "string" ? obj.uuid : undefined;
|
|
105
|
+
// Path A — user-typed slash command.
|
|
106
|
+
if (type === "user") {
|
|
107
|
+
const text = rowText(msg.content);
|
|
108
|
+
const m = CMD_NAME.exec(text);
|
|
109
|
+
if (!m)
|
|
110
|
+
return [];
|
|
111
|
+
const a = CMD_ARGS.exec(text);
|
|
112
|
+
return [
|
|
113
|
+
{
|
|
114
|
+
skill: m[1].trim(),
|
|
115
|
+
source: "typed",
|
|
116
|
+
sessionId,
|
|
117
|
+
timestamp,
|
|
118
|
+
cwd,
|
|
119
|
+
uuid: rowUuid,
|
|
120
|
+
hasArgs: Boolean(a && a[1].trim()),
|
|
121
|
+
},
|
|
122
|
+
];
|
|
123
|
+
}
|
|
124
|
+
// Path B — model-invoked Skill tool_use.
|
|
125
|
+
if (type === "assistant" && Array.isArray(msg.content)) {
|
|
126
|
+
const out = [];
|
|
127
|
+
for (const blk of msg.content) {
|
|
128
|
+
if (!blk || typeof blk !== "object")
|
|
129
|
+
continue;
|
|
130
|
+
const b = blk;
|
|
131
|
+
if (b.type !== "tool_use" || b.name !== "Skill")
|
|
132
|
+
continue;
|
|
133
|
+
const input = b.input && typeof b.input === "object" && !Array.isArray(b.input)
|
|
134
|
+
? b.input
|
|
135
|
+
: {};
|
|
136
|
+
const skill = typeof input.skill === "string" ? input.skill : "";
|
|
137
|
+
if (!skill)
|
|
138
|
+
continue;
|
|
139
|
+
const args = input.args;
|
|
140
|
+
out.push({
|
|
141
|
+
skill,
|
|
142
|
+
source: "model",
|
|
143
|
+
sessionId,
|
|
144
|
+
timestamp,
|
|
145
|
+
cwd,
|
|
146
|
+
// Prefer the tool_use block id (stable, globally unique) for dedup.
|
|
147
|
+
uuid: typeof b.id === "string" ? b.id : rowUuid,
|
|
148
|
+
hasArgs: typeof args === "string" ? args.trim().length > 0 : Boolean(args),
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
return out;
|
|
152
|
+
}
|
|
153
|
+
return [];
|
|
154
|
+
}
|
|
155
|
+
/** Shape the event for the wire. Drops raw args unless explicitly enabled. */
|
|
156
|
+
function toWireRow(ev) {
|
|
157
|
+
const row = {
|
|
158
|
+
skill: ev.skill,
|
|
159
|
+
source: ev.source,
|
|
160
|
+
hasArgs: ev.hasArgs,
|
|
161
|
+
};
|
|
162
|
+
if (ev.sessionId !== undefined)
|
|
163
|
+
row.sessionId = ev.sessionId;
|
|
164
|
+
if (ev.timestamp !== undefined)
|
|
165
|
+
row.timestamp = ev.timestamp;
|
|
166
|
+
if (ev.uuid !== undefined)
|
|
167
|
+
row.uuid = ev.uuid;
|
|
168
|
+
if (ev.cwd !== undefined)
|
|
169
|
+
row.cwd = ev.cwd;
|
|
170
|
+
// INCLUDE_ARGS_PREVIEW is intentionally a compile-time constant `false`;
|
|
171
|
+
// the guarded branch documents the (currently disabled) egress path.
|
|
172
|
+
if (INCLUDE_ARGS_PREVIEW) {
|
|
173
|
+
// Reserved: a server allowlist change must land before this is enabled.
|
|
174
|
+
}
|
|
175
|
+
return row;
|
|
176
|
+
}
|
|
177
|
+
// ── File walker ───────────────────────────────────────────────────────────────
|
|
178
|
+
async function listJsonlFiles(root) {
|
|
179
|
+
const out = [];
|
|
180
|
+
async function walk(dir) {
|
|
181
|
+
let entries;
|
|
182
|
+
try {
|
|
183
|
+
entries = await fs.readdir(dir, { withFileTypes: true });
|
|
184
|
+
}
|
|
185
|
+
catch {
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
for (const ent of entries) {
|
|
189
|
+
const full = path.join(dir, ent.name);
|
|
190
|
+
if (ent.isDirectory()) {
|
|
191
|
+
await walk(full);
|
|
192
|
+
}
|
|
193
|
+
else if (ent.isFile() && ent.name.endsWith(".jsonl")) {
|
|
194
|
+
out.push(full);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
await walk(root);
|
|
199
|
+
return out;
|
|
200
|
+
}
|
|
201
|
+
const MAX_BATCH_BYTES = 1_000_000;
|
|
202
|
+
// ── Main entry point ──────────────────────────────────────────────────────────
|
|
203
|
+
/**
|
|
204
|
+
* Scan, extract, and POST any new skill-invocation events.
|
|
205
|
+
*
|
|
206
|
+
* Cursor model (per-batch commit, matching the token collector for robustness):
|
|
207
|
+
* each file is scanned from its stored byte offset to EOF; extracted events
|
|
208
|
+
* carry the byte offset of the line they came from. Events are flushed in
|
|
209
|
+
* ≤1 MiB batches, and the cursor advances **per successful batch** — so if one
|
|
210
|
+
* batch in a large (e.g. first-run backfill) fails, the batches that already
|
|
211
|
+
* succeeded stay committed and only the rest re-send next sync.
|
|
212
|
+
*
|
|
213
|
+
* Per-file commit rule:
|
|
214
|
+
* - All of a file's events sent OK (including zero-event files) → commit EOF,
|
|
215
|
+
* so quiet/non-skill tails are never re-scanned.
|
|
216
|
+
* - Some of a file's events failed → commit the max byte offset whose batch
|
|
217
|
+
* succeeded (partial progress); the remainder re-sends next sync.
|
|
218
|
+
* Server-side dedup on the composite eventKey makes any re-send idempotent.
|
|
219
|
+
* Rotation/truncation resets the offset to 0 (re-read from the top).
|
|
220
|
+
*/
|
|
221
|
+
export async function collectAndSendSkillTelemetry(opts) {
|
|
222
|
+
const home = os.homedir();
|
|
223
|
+
const claudeProjectsRoot = opts.claudeProjectsRoot ?? path.join(home, ".claude", "projects");
|
|
224
|
+
const cursorPath = opts.cursorPath ?? path.join(home, ".hq", "skill-telemetry-cursor.json");
|
|
225
|
+
const menubarPath = opts.menubarPath ?? path.join(home, ".hq", "menubar.json");
|
|
226
|
+
const log = opts.log ?? (() => { });
|
|
227
|
+
// Normalize the scope path once (drop a single trailing slash, keeping "/").
|
|
228
|
+
const normalizePath = (p) => (p.length > 1 ? p.replace(/\/+$/, "") : p);
|
|
229
|
+
const scopeCwd = opts.hqRoot !== undefined ? normalizePath(opts.hqRoot) : undefined;
|
|
230
|
+
// 1. Opt-in check — reuse the same gate as token telemetry.
|
|
231
|
+
let enabled;
|
|
232
|
+
let optInSource;
|
|
233
|
+
try {
|
|
234
|
+
const resp = await opts.client.getTelemetryOptIn();
|
|
235
|
+
enabled = resp.enabled === true;
|
|
236
|
+
optInSource = "server";
|
|
237
|
+
}
|
|
238
|
+
catch (err) {
|
|
239
|
+
log(`[skill-telemetry] opt-in check failed (${err.message ?? err}) — falling back to local menubar.json`);
|
|
240
|
+
enabled = await readLocalTelemetryEnabled(menubarPath);
|
|
241
|
+
optInSource = "menubar-fallback";
|
|
242
|
+
}
|
|
243
|
+
if (!enabled) {
|
|
244
|
+
return { enabled: false, optInSource, filesScanned: 0, eventsSent: 0, batchesSent: 0 };
|
|
245
|
+
}
|
|
246
|
+
// 2. Cursor + file enumeration.
|
|
247
|
+
const cursor = await loadCursor(cursorPath);
|
|
248
|
+
const files = await listJsonlFiles(claudeProjectsRoot);
|
|
249
|
+
const fileScans = {};
|
|
250
|
+
const rotationResets = {};
|
|
251
|
+
const sourced = [];
|
|
252
|
+
for (const filePath of files) {
|
|
253
|
+
let stat;
|
|
254
|
+
try {
|
|
255
|
+
stat = await fs.stat(filePath);
|
|
256
|
+
}
|
|
257
|
+
catch {
|
|
258
|
+
continue;
|
|
259
|
+
}
|
|
260
|
+
const currentSize = stat.size;
|
|
261
|
+
const currentMtime = Math.floor(stat.mtimeMs / 1000);
|
|
262
|
+
const stored = cursor.files[filePath] ?? { offset: 0, mtime: 0 };
|
|
263
|
+
let offset = stored.offset;
|
|
264
|
+
// Rotation / truncation → re-read from the top.
|
|
265
|
+
const rotated = currentSize < offset || (stored.mtime > 0 && currentMtime < stored.mtime);
|
|
266
|
+
if (rotated) {
|
|
267
|
+
offset = 0;
|
|
268
|
+
rotationResets[filePath] = { offset: 0, mtime: currentMtime };
|
|
269
|
+
}
|
|
270
|
+
// Record the scan even when there are no new bytes — a fully-drained file
|
|
271
|
+
// (eventCount 0, offset already at EOF) should still settle at EOF below.
|
|
272
|
+
fileScans[filePath] = { eof: currentSize, mtime: currentMtime, eventCount: 0 };
|
|
273
|
+
if (offset >= currentSize && !rotated)
|
|
274
|
+
continue;
|
|
275
|
+
let content;
|
|
276
|
+
try {
|
|
277
|
+
const fh = await fs.open(filePath, "r");
|
|
278
|
+
try {
|
|
279
|
+
const length = Math.max(0, currentSize - offset);
|
|
280
|
+
const buf = Buffer.alloc(length);
|
|
281
|
+
await fh.read(buf, 0, length, offset);
|
|
282
|
+
content = buf.toString("utf-8");
|
|
283
|
+
}
|
|
284
|
+
finally {
|
|
285
|
+
await fh.close();
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
catch {
|
|
289
|
+
// Could not read — drop the scan so we don't claim progress for it.
|
|
290
|
+
delete fileScans[filePath];
|
|
291
|
+
continue;
|
|
292
|
+
}
|
|
293
|
+
// Compute the absolute end-byte offset of each line in the read region.
|
|
294
|
+
const segments = content.split("\n");
|
|
295
|
+
let cumulative = offset;
|
|
296
|
+
for (let i = 0; i < segments.length; i++) {
|
|
297
|
+
cumulative += Buffer.byteLength(segments[i], "utf-8");
|
|
298
|
+
if (i < segments.length - 1)
|
|
299
|
+
cumulative += 1; // the split newline byte
|
|
300
|
+
const endOffset = cumulative;
|
|
301
|
+
const trimmed = segments[i].trim();
|
|
302
|
+
if (trimmed.length === 0)
|
|
303
|
+
continue;
|
|
304
|
+
let parsed;
|
|
305
|
+
try {
|
|
306
|
+
parsed = JSON.parse(trimmed);
|
|
307
|
+
}
|
|
308
|
+
catch {
|
|
309
|
+
continue;
|
|
310
|
+
}
|
|
311
|
+
for (const ev of extractSkillEvents(parsed)) {
|
|
312
|
+
// Scope filter: only emit invocations made from the HQ project.
|
|
313
|
+
if (scopeCwd !== undefined && (ev.cwd === undefined || normalizePath(ev.cwd) !== scopeCwd)) {
|
|
314
|
+
continue;
|
|
315
|
+
}
|
|
316
|
+
sourced.push({ row: toWireRow(ev), filePath, endOffset });
|
|
317
|
+
fileScans[filePath].eventCount++;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
// 4. Flush in ≤1 MiB batches, advancing per-file progress on each 2xx.
|
|
322
|
+
let eventsSent = 0;
|
|
323
|
+
let batchesSent = 0;
|
|
324
|
+
// Per file: count of events successfully sent + max committed byte offset.
|
|
325
|
+
const sentCount = {};
|
|
326
|
+
const committedOffset = {};
|
|
327
|
+
const envelopeBytes = Buffer.byteLength(JSON.stringify({ machineId: opts.machineId, installerVersion: opts.installerVersion, events: [] }), "utf-8");
|
|
328
|
+
let batch = [];
|
|
329
|
+
let batchBytes = envelopeBytes;
|
|
330
|
+
const flush = async () => {
|
|
331
|
+
if (batch.length === 0)
|
|
332
|
+
return;
|
|
333
|
+
const toSend = batch;
|
|
334
|
+
batch = [];
|
|
335
|
+
batchBytes = envelopeBytes;
|
|
336
|
+
try {
|
|
337
|
+
await opts.client.postSkillInvocations({
|
|
338
|
+
machineId: opts.machineId,
|
|
339
|
+
installerVersion: opts.installerVersion,
|
|
340
|
+
events: toSend.map((s) => s.row),
|
|
341
|
+
});
|
|
342
|
+
batchesSent++;
|
|
343
|
+
eventsSent += toSend.length;
|
|
344
|
+
// Advance per-file progress for the events in this (successful) batch.
|
|
345
|
+
for (const s of toSend) {
|
|
346
|
+
sentCount[s.filePath] = (sentCount[s.filePath] ?? 0) + 1;
|
|
347
|
+
const prev = committedOffset[s.filePath] ?? 0;
|
|
348
|
+
if (s.endOffset > prev)
|
|
349
|
+
committedOffset[s.filePath] = s.endOffset;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
catch (err) {
|
|
353
|
+
log(`[skill-telemetry] postSkillInvocations failed (${err.message ?? err}) — these rows re-send next sync`);
|
|
354
|
+
// Cursor not advanced for this batch; eventKey dedups the eventual re-send.
|
|
355
|
+
}
|
|
356
|
+
};
|
|
357
|
+
for (const s of sourced) {
|
|
358
|
+
const rowBytes = Buffer.byteLength(JSON.stringify(s.row), "utf-8");
|
|
359
|
+
const addCost = rowBytes + (batch.length > 0 ? 1 : 0);
|
|
360
|
+
if (batch.length > 0 && batchBytes + addCost > MAX_BATCH_BYTES) {
|
|
361
|
+
await flush();
|
|
362
|
+
batchBytes = envelopeBytes + rowBytes;
|
|
363
|
+
}
|
|
364
|
+
else {
|
|
365
|
+
batchBytes += addCost;
|
|
366
|
+
}
|
|
367
|
+
batch.push(s);
|
|
368
|
+
}
|
|
369
|
+
await flush();
|
|
370
|
+
// 5. Build the new cursor: loaded < rotationResets < per-file commit.
|
|
371
|
+
// A file settles at EOF only when every event extracted from it this run
|
|
372
|
+
// was sent OK (zero-event files included); otherwise it settles at the
|
|
373
|
+
// highest byte offset whose batch succeeded, so the rest re-sends.
|
|
374
|
+
const finalFiles = { ...cursor.files };
|
|
375
|
+
for (const [fp, entry] of Object.entries(rotationResets))
|
|
376
|
+
finalFiles[fp] = entry;
|
|
377
|
+
for (const [fp, scan] of Object.entries(fileScans)) {
|
|
378
|
+
if ((sentCount[fp] ?? 0) >= scan.eventCount) {
|
|
379
|
+
finalFiles[fp] = { offset: scan.eof, mtime: scan.mtime };
|
|
380
|
+
}
|
|
381
|
+
else if (fp in committedOffset) {
|
|
382
|
+
finalFiles[fp] = { offset: committedOffset[fp], mtime: scan.mtime };
|
|
383
|
+
}
|
|
384
|
+
// else: no progress for this file — leave loaded/rotation-reset offset.
|
|
385
|
+
}
|
|
386
|
+
await saveCursor(cursorPath, { version: "1", files: finalFiles });
|
|
387
|
+
return {
|
|
388
|
+
enabled: true,
|
|
389
|
+
optInSource,
|
|
390
|
+
filesScanned: files.length,
|
|
391
|
+
eventsSent,
|
|
392
|
+
batchesSent,
|
|
393
|
+
};
|
|
394
|
+
}
|
|
395
|
+
//# sourceMappingURL=skill-telemetry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-telemetry.js","sourceRoot":"","sources":["../src/skill-telemetry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-telemetry.test.d.ts","sourceRoot":"","sources":["../src/skill-telemetry.test.ts"],"names":[],"mappings":""}
|