hacklab 0.21.2 → 0.22.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.
- package/README.md +101 -10
- package/dist/commands/config.d.ts.map +1 -1
- package/dist/commands/config.js +3 -3
- package/dist/commands/config.js.map +1 -1
- package/dist/commands/daemon.d.ts.map +1 -1
- package/dist/commands/daemon.js +4 -2
- package/dist/commands/daemon.js.map +1 -1
- package/dist/commands/scan.d.ts.map +1 -1
- package/dist/commands/scan.js +6 -2
- package/dist/commands/scan.js.map +1 -1
- package/dist/commands/setup.d.ts.map +1 -1
- package/dist/commands/setup.js +5 -3
- package/dist/commands/setup.js.map +1 -1
- package/dist/commands/sync.js +11 -4
- package/dist/commands/sync.js.map +1 -1
- package/dist/config.d.ts +4 -3
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js.map +1 -1
- package/dist/daily-sync.d.ts +14 -2
- package/dist/daily-sync.d.ts.map +1 -1
- package/dist/daily-sync.js +20 -9
- package/dist/daily-sync.js.map +1 -1
- package/dist/prompt-consent.d.ts +4 -6
- package/dist/prompt-consent.d.ts.map +1 -1
- package/dist/prompt-consent.js +16 -9
- package/dist/prompt-consent.js.map +1 -1
- package/dist/prompt-stats.d.ts +14 -2
- package/dist/prompt-stats.d.ts.map +1 -1
- package/dist/prompt-stats.js +83 -26
- package/dist/prompt-stats.js.map +1 -1
- package/dist/scanners/antigravity.d.ts +41 -0
- package/dist/scanners/antigravity.d.ts.map +1 -0
- package/dist/scanners/antigravity.js +210 -0
- package/dist/scanners/antigravity.js.map +1 -0
- package/dist/scanners/github-copilot-telemetry.d.ts +23 -0
- package/dist/scanners/github-copilot-telemetry.d.ts.map +1 -0
- package/dist/scanners/github-copilot-telemetry.js +220 -0
- package/dist/scanners/github-copilot-telemetry.js.map +1 -0
- package/dist/scanners/github-copilot.d.ts +68 -0
- package/dist/scanners/github-copilot.d.ts.map +1 -0
- package/dist/scanners/github-copilot.js +262 -0
- package/dist/scanners/github-copilot.js.map +1 -0
- package/dist/scanners/incremental.d.ts +19 -4
- package/dist/scanners/incremental.d.ts.map +1 -1
- package/dist/scanners/incremental.js +104 -23
- package/dist/scanners/incremental.js.map +1 -1
- package/dist/scanners/index.d.ts.map +1 -1
- package/dist/scanners/index.js +16 -2
- package/dist/scanners/index.js.map +1 -1
- package/dist/scanners/util.d.ts +1 -1
- package/dist/scanners/util.d.ts.map +1 -1
- package/dist/scanners/util.js.map +1 -1
- package/dist/sync.d.ts +2 -0
- package/dist/sync.d.ts.map +1 -1
- package/dist/sync.js +4 -0
- package/dist/sync.js.map +1 -1
- package/package.json +3 -1
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { homedir } from 'node:os';
|
|
3
|
+
import { basename, dirname, join } from 'node:path';
|
|
4
|
+
import protobuf from 'protobufjs/minimal.js';
|
|
5
|
+
import { queryDb } from './sqlite.js';
|
|
6
|
+
import { findFiles, TokenCollector } from './util.js';
|
|
7
|
+
const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
8
|
+
/** Current shared Antigravity storage and the older IDE-specific directory. */
|
|
9
|
+
function antigravityRoots() {
|
|
10
|
+
return ['antigravity', 'antigravity-cli', 'antigravity-ide'].map((name) => join(homedir(), '.gemini', name));
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Source: github.com/mehdawimohamed/antigravity-conversation-exporter/export_chat.py
|
|
14
|
+
* Layout: brain/<UUID>/.system_generated/logs/transcript[_full].jsonl.
|
|
15
|
+
* Readable transcripts only. A session can have both variants;
|
|
16
|
+
* `transcript_full.jsonl` is preferred by scanAntigravityPrompts().
|
|
17
|
+
*/
|
|
18
|
+
export async function antigravityTranscriptFiles() {
|
|
19
|
+
const files = (await Promise.all(antigravityRoots().map((root) => findFiles(join(root, 'brain'), '.jsonl')))).flat();
|
|
20
|
+
return files.filter((file) => {
|
|
21
|
+
const name = basename(file);
|
|
22
|
+
return (basename(dirname(file)) === 'logs' &&
|
|
23
|
+
basename(dirname(dirname(file))) === '.system_generated' &&
|
|
24
|
+
(name === 'transcript.jsonl' || name === 'transcript_full.jsonl') &&
|
|
25
|
+
UUID.test(basename(dirname(dirname(dirname(file))))));
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Parse a legacy IDE transcript line. The public exporter identifies a typed
|
|
30
|
+
* user prompt as `source: USER_EXPLICIT`, `type: USER_INPUT`, with a
|
|
31
|
+
* `USER_REQUEST` body. It prefers `created_at`, falling back to the legacy
|
|
32
|
+
* `timestamp`; absent or invalid timestamps remain null rather than guessed.
|
|
33
|
+
*/
|
|
34
|
+
export function parseAntigravityLegacyPromptLine(line, sessionId) {
|
|
35
|
+
let parsed;
|
|
36
|
+
try {
|
|
37
|
+
parsed = JSON.parse(line);
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
if (!parsed || typeof parsed !== 'object')
|
|
43
|
+
return null;
|
|
44
|
+
const entry = parsed;
|
|
45
|
+
if (entry.source !== 'USER_EXPLICIT' ||
|
|
46
|
+
entry.type !== 'USER_INPUT' ||
|
|
47
|
+
typeof entry.content !== 'string') {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
const request = entry.content.match(/<USER_REQUEST>([\s\S]*?)<\/USER_REQUEST>/)?.[1];
|
|
51
|
+
if (!request || !request.trim())
|
|
52
|
+
return null;
|
|
53
|
+
return {
|
|
54
|
+
text: request,
|
|
55
|
+
sessionId: `antigravity-ide:${sessionId}`,
|
|
56
|
+
timestamp: normalizeTimestamp(entry.created_at) ??
|
|
57
|
+
normalizeTimestamp(entry.timestamp),
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
/** Read each conversation once even when both storage roots retain a copy. */
|
|
61
|
+
export async function scanAntigravityPrompts() {
|
|
62
|
+
const files = await antigravityTranscriptFiles();
|
|
63
|
+
const preferred = new Map();
|
|
64
|
+
for (const file of files) {
|
|
65
|
+
const sessionId = basename(dirname(dirname(dirname(file))));
|
|
66
|
+
const current = preferred.get(sessionId);
|
|
67
|
+
if (!current || basename(file) === 'transcript_full.jsonl') {
|
|
68
|
+
preferred.set(sessionId, file);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
const prompts = [];
|
|
72
|
+
for (const [sessionId, file] of preferred) {
|
|
73
|
+
let content;
|
|
74
|
+
try {
|
|
75
|
+
content = await readFile(file, 'utf8');
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
for (const line of content.split(/\r?\n/)) {
|
|
81
|
+
const prompt = parseAntigravityLegacyPromptLine(line, sessionId);
|
|
82
|
+
if (prompt)
|
|
83
|
+
prompts.push(prompt);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return prompts;
|
|
87
|
+
}
|
|
88
|
+
function normalizeTimestamp(value) {
|
|
89
|
+
if (typeof value !== 'string' && typeof value !== 'number')
|
|
90
|
+
return null;
|
|
91
|
+
const time = typeof value === 'number' ? value : Date.parse(value);
|
|
92
|
+
const date = new Date(time);
|
|
93
|
+
return Number.isFinite(date.getTime()) ? date.toISOString() : null;
|
|
94
|
+
}
|
|
95
|
+
async function antigravityConversationDbs() {
|
|
96
|
+
return (await Promise.all(antigravityRoots().map((root) => findFiles(join(root, 'conversations'), '.db'))))
|
|
97
|
+
.flat()
|
|
98
|
+
.filter((path) => UUID.test(basename(path, '.db')));
|
|
99
|
+
}
|
|
100
|
+
/** Fingerprint WAL writes too; the read-only reader sees them after checkpoint. */
|
|
101
|
+
export async function antigravityTokenFiles() {
|
|
102
|
+
return (await antigravityConversationDbs()).flatMap((path) => [
|
|
103
|
+
path,
|
|
104
|
+
`${path}-wal`,
|
|
105
|
+
]);
|
|
106
|
+
}
|
|
107
|
+
function protoFields(bytes) {
|
|
108
|
+
const reader = protobuf.Reader.create(bytes);
|
|
109
|
+
const fields = new Map();
|
|
110
|
+
while (reader.pos < reader.len) {
|
|
111
|
+
const tag = reader.uint32();
|
|
112
|
+
const field = tag >>> 3;
|
|
113
|
+
if (field === 0)
|
|
114
|
+
throw new Error('invalid protobuf field');
|
|
115
|
+
switch (tag & 7) {
|
|
116
|
+
case 0:
|
|
117
|
+
fields.set(field, Number(reader.uint64()));
|
|
118
|
+
break;
|
|
119
|
+
case 2:
|
|
120
|
+
fields.set(field, reader.bytes());
|
|
121
|
+
break;
|
|
122
|
+
default:
|
|
123
|
+
reader.skipType(tag & 7);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return fields;
|
|
127
|
+
}
|
|
128
|
+
function tokenField(fields, field) {
|
|
129
|
+
const value = fields.get(field) ?? 0;
|
|
130
|
+
if (typeof value !== 'number' || !Number.isSafeInteger(value) || value < 0) {
|
|
131
|
+
throw new Error('invalid token count');
|
|
132
|
+
}
|
|
133
|
+
return value;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Source: Eneasf/antigravity-token-dashboard docs/TELEMETRY_SPEC.md.
|
|
137
|
+
* steps.metadata: field 1 Timestamp, field 9 UsageMetadata. Input field 2 is
|
|
138
|
+
* uncached; field 5 is cached input; output field 3 already includes reasoning
|
|
139
|
+
* (fields 9 and 10). Never add those output subsets again.
|
|
140
|
+
*/
|
|
141
|
+
export function parseAntigravityUsage(metadata) {
|
|
142
|
+
try {
|
|
143
|
+
const fields = protoFields(metadata);
|
|
144
|
+
const timeBytes = fields.get(1);
|
|
145
|
+
const usageBytes = fields.get(9);
|
|
146
|
+
if (!(timeBytes instanceof Uint8Array) ||
|
|
147
|
+
!(usageBytes instanceof Uint8Array))
|
|
148
|
+
return null;
|
|
149
|
+
const time = protoFields(timeBytes);
|
|
150
|
+
if (!time.has(1))
|
|
151
|
+
return null;
|
|
152
|
+
const seconds = tokenField(time, 1);
|
|
153
|
+
const nanos = tokenField(time, 2);
|
|
154
|
+
if (nanos >= 1_000_000_000)
|
|
155
|
+
return null;
|
|
156
|
+
const at = new Date(seconds * 1000 + Math.floor(nanos / 1_000_000));
|
|
157
|
+
if (!Number.isFinite(at.getTime()))
|
|
158
|
+
return null;
|
|
159
|
+
const usage = protoFields(usageBytes);
|
|
160
|
+
const tokens = tokenField(usage, 2) + tokenField(usage, 3) + tokenField(usage, 5);
|
|
161
|
+
if (!Number.isSafeInteger(tokens) || tokens <= 0)
|
|
162
|
+
return null;
|
|
163
|
+
const modelId = tokenField(usage, 1);
|
|
164
|
+
// Preserve the actual enum: unofficial name tables disagree across builds.
|
|
165
|
+
const model = modelId ? `antigravity-model-${modelId}` : '';
|
|
166
|
+
const response = usage.get(11);
|
|
167
|
+
return {
|
|
168
|
+
date: at.toISOString().slice(0, 10),
|
|
169
|
+
model,
|
|
170
|
+
tokens,
|
|
171
|
+
responseId: response instanceof Uint8Array
|
|
172
|
+
? Buffer.from(response).toString('utf8').trim() || null
|
|
173
|
+
: null,
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
catch {
|
|
177
|
+
// An unknown/truncated protobuf is not evidence of token usage.
|
|
178
|
+
return null;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
export async function scanAntigravity() {
|
|
182
|
+
const collector = new TokenCollector('antigravity');
|
|
183
|
+
const generations = new Map();
|
|
184
|
+
for (const path of await antigravityConversationDbs()) {
|
|
185
|
+
try {
|
|
186
|
+
const rows = await queryDb(path, 'SELECT idx, metadata FROM steps WHERE step_type = 15 ORDER BY idx');
|
|
187
|
+
for (const [index, metadata] of rows) {
|
|
188
|
+
if (typeof index !== 'number' || !(metadata instanceof Uint8Array))
|
|
189
|
+
continue;
|
|
190
|
+
const usage = parseAntigravityUsage(metadata);
|
|
191
|
+
if (!usage)
|
|
192
|
+
continue;
|
|
193
|
+
const key = usage.responseId
|
|
194
|
+
? `response:${usage.responseId}`
|
|
195
|
+
: `step:${basename(path, '.db')}:${index}`;
|
|
196
|
+
const previous = generations.get(key);
|
|
197
|
+
if (!previous || usage.tokens > previous.tokens)
|
|
198
|
+
generations.set(key, usage);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
catch (error) {
|
|
202
|
+
console.warn(`Antigravity usage unavailable in ${basename(path)}: ${error instanceof Error ? error.message : String(error)}`);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
for (const usage of generations.values()) {
|
|
206
|
+
collector.addDaily(usage.date, usage.model, usage.tokens, 1);
|
|
207
|
+
}
|
|
208
|
+
return collector.result();
|
|
209
|
+
}
|
|
210
|
+
//# sourceMappingURL=antigravity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"antigravity.js","sourceRoot":"","sources":["../../src/scanners/antigravity.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export type CopilotTelemetrySources = {
|
|
2
|
+
files: string[];
|
|
3
|
+
databases: string[];
|
|
4
|
+
};
|
|
5
|
+
export type CopilotInference = {
|
|
6
|
+
sessionId: string;
|
|
7
|
+
model: string;
|
|
8
|
+
timestamp: string;
|
|
9
|
+
tokens: number;
|
|
10
|
+
};
|
|
11
|
+
/** Discover only Copilot-owned exports; never sweep generic agent telemetry. */
|
|
12
|
+
export declare function copilotTelemetrySources(userDirs: string[]): Promise<CopilotTelemetrySources>;
|
|
13
|
+
/**
|
|
14
|
+
* VS Code's SQLiteSpanExporter preserves SDK trace/span IDs, including embedded
|
|
15
|
+
* CLI spans. Count completed native Copilot trace leaves only, deduplicating the
|
|
16
|
+
* DB and file exports. Require the owning agent span: a Claude/Codex delegate's
|
|
17
|
+
* usage belongs to its native scanner, and a model called Claude is not itself
|
|
18
|
+
* evidence that the harness was Claude Code.
|
|
19
|
+
* Sources: microsoft/vscode extensions/copilot/src/platform/otel/node/{
|
|
20
|
+
* fileExporters.ts,sqlite/sqliteSpanExporter.ts,sqlite/otelSqliteStore.ts}.
|
|
21
|
+
*/
|
|
22
|
+
export declare function readCopilotTelemetry(sources: CopilotTelemetrySources): Promise<CopilotInference[]>;
|
|
23
|
+
//# sourceMappingURL=github-copilot-telemetry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github-copilot-telemetry.d.ts","sourceRoot":"","sources":["../../src/scanners/github-copilot-telemetry.ts"],"names":[],"mappings":"AAQA,MAAM,MAAM,uBAAuB,GAAG;IAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IAAC,SAAS,EAAE,MAAM,EAAE,CAAA;CAAE,CAAA;AAC9E,MAAM,MAAM,gBAAgB,GAAG;IAC7B,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,MAAM,CAAA;CACf,CAAA;AAiBD,gFAAgF;AAChF,wBAAsB,uBAAuB,CAC3C,QAAQ,EAAE,MAAM,EAAE,GACjB,OAAO,CAAC,uBAAuB,CAAC,CA0ClC;AAgDD;;;;;;;;GAQG;AACH,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,uBAAuB,GAC/B,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAoJ7B"}
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { homedir } from 'node:os';
|
|
3
|
+
import { basename, join, resolve } from 'node:path';
|
|
4
|
+
import { parse as parseJsonc } from 'jsonc-parser';
|
|
5
|
+
import { queryDb } from './sqlite.js';
|
|
6
|
+
import { findFiles } from './util.js';
|
|
7
|
+
function object(value) {
|
|
8
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value)
|
|
9
|
+
? value
|
|
10
|
+
: {};
|
|
11
|
+
}
|
|
12
|
+
/** Discover only Copilot-owned exports; never sweep generic agent telemetry. */
|
|
13
|
+
export async function copilotTelemetrySources(userDirs) {
|
|
14
|
+
const root = process.env.COPILOT_HOME || join(homedir(), '.copilot');
|
|
15
|
+
const files = new Set(await findFiles(join(root, 'otel'), '.jsonl'));
|
|
16
|
+
const explicit = process.env.COPILOT_OTEL_FILE_EXPORTER_PATH?.trim();
|
|
17
|
+
if (explicit)
|
|
18
|
+
files.add(resolve(explicit));
|
|
19
|
+
const databases = new Set();
|
|
20
|
+
for (const userDir of userDirs) {
|
|
21
|
+
const settings = [
|
|
22
|
+
join(userDir, 'settings.json'),
|
|
23
|
+
...(await findFiles(join(userDir, 'profiles'), 'settings.json')),
|
|
24
|
+
];
|
|
25
|
+
for (const path of settings) {
|
|
26
|
+
try {
|
|
27
|
+
const config = object(parseJsonc(await readFile(path, 'utf8')));
|
|
28
|
+
const outfile = config['github.copilot.chat.otel.outfile'];
|
|
29
|
+
if (typeof outfile === 'string' && outfile.trim())
|
|
30
|
+
files.add(resolve(outfile.trim()));
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
if (error.code !== 'ENOENT') {
|
|
34
|
+
console.warn(`Copilot telemetry settings unavailable: ${error instanceof Error ? error.message : String(error)}`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
const candidates = [
|
|
39
|
+
...(await findFiles(join(userDir, 'globalStorage', 'github.copilot-chat'), '.db')),
|
|
40
|
+
...(await findFiles(join(userDir, 'profiles'), '.db')),
|
|
41
|
+
];
|
|
42
|
+
for (const path of candidates) {
|
|
43
|
+
if (/[\\/]globalStorage[\\/]github\.copilot-chat[\\/]agent-traces\.db$/i.test(path))
|
|
44
|
+
databases.add(path);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return { files: [...files], databases: [...databases] };
|
|
48
|
+
}
|
|
49
|
+
function hrTime(value) {
|
|
50
|
+
if (!Array.isArray(value) ||
|
|
51
|
+
value.length !== 2 ||
|
|
52
|
+
!Number.isSafeInteger(value[0]) ||
|
|
53
|
+
!Number.isSafeInteger(value[1]) ||
|
|
54
|
+
value[0] < 0 ||
|
|
55
|
+
value[1] < 0 ||
|
|
56
|
+
value[1] >= 1_000_000_000)
|
|
57
|
+
return NaN;
|
|
58
|
+
return value[0] * 1000 + Math.floor(value[1] / 1_000_000);
|
|
59
|
+
}
|
|
60
|
+
/** Direct ReadableSpan JSON from Copilot's file exporter, not aggregate metrics. */
|
|
61
|
+
function fileSpan(line) {
|
|
62
|
+
try {
|
|
63
|
+
const record = object(JSON.parse(line));
|
|
64
|
+
const context = object(record._spanContext ?? record.spanContext);
|
|
65
|
+
const parent = object(record.parentSpanContext);
|
|
66
|
+
const traceId = record.traceId ?? context.traceId;
|
|
67
|
+
const spanId = record.spanId ?? context.spanId;
|
|
68
|
+
const parentSpanId = record.parentSpanId ?? parent.spanId ?? '';
|
|
69
|
+
if (typeof traceId !== 'string' ||
|
|
70
|
+
!traceId ||
|
|
71
|
+
typeof spanId !== 'string' ||
|
|
72
|
+
!spanId ||
|
|
73
|
+
typeof parentSpanId !== 'string')
|
|
74
|
+
return null;
|
|
75
|
+
const endTime = hrTime(record.endTime);
|
|
76
|
+
if (!Number.isFinite(endTime) || endTime <= 0)
|
|
77
|
+
return null;
|
|
78
|
+
return {
|
|
79
|
+
traceId,
|
|
80
|
+
spanId,
|
|
81
|
+
parentSpanId,
|
|
82
|
+
endTime,
|
|
83
|
+
attributes: object(record.attributes),
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
// Partial lines and the exporter's known '{}' serialization failure carry no usage.
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* VS Code's SQLiteSpanExporter preserves SDK trace/span IDs, including embedded
|
|
93
|
+
* CLI spans. Count completed native Copilot trace leaves only, deduplicating the
|
|
94
|
+
* DB and file exports. Require the owning agent span: a Claude/Codex delegate's
|
|
95
|
+
* usage belongs to its native scanner, and a model called Claude is not itself
|
|
96
|
+
* evidence that the harness was Claude Code.
|
|
97
|
+
* Sources: microsoft/vscode extensions/copilot/src/platform/otel/node/{
|
|
98
|
+
* fileExporters.ts,sqlite/sqliteSpanExporter.ts,sqlite/otelSqliteStore.ts}.
|
|
99
|
+
*/
|
|
100
|
+
export async function readCopilotTelemetry(sources) {
|
|
101
|
+
const spans = new Map();
|
|
102
|
+
for (const path of sources.files) {
|
|
103
|
+
try {
|
|
104
|
+
for (const line of (await readFile(path, 'utf8')).split('\n')) {
|
|
105
|
+
const span = fileSpan(line);
|
|
106
|
+
if (span)
|
|
107
|
+
spans.set(`${span.traceId}:${span.spanId}`, span);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
catch (error) {
|
|
111
|
+
if (error.code !== 'ENOENT') {
|
|
112
|
+
console.warn(`Copilot telemetry unavailable in ${basename(path)}: ${error instanceof Error ? error.message : String(error)}`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
for (const path of sources.databases) {
|
|
117
|
+
try {
|
|
118
|
+
const rows = await queryDb(path, `SELECT span_id, trace_id, parent_span_id,
|
|
119
|
+
end_time_ms, operation_name, agent_name, conversation_id, chat_session_id,
|
|
120
|
+
response_model, request_model, input_tokens, output_tokens,
|
|
121
|
+
(SELECT value FROM span_attributes
|
|
122
|
+
WHERE span_id = s.span_id AND key = 'gen_ai.agent.id') AS agent_id
|
|
123
|
+
FROM spans AS s`);
|
|
124
|
+
for (const row of rows) {
|
|
125
|
+
const [spanId, traceId, parentSpanId, endTime, operation, agent, conversation, chatSession, responseModel, requestModel, input, output, agentId,] = row;
|
|
126
|
+
if (typeof spanId !== 'string' ||
|
|
127
|
+
!spanId ||
|
|
128
|
+
typeof traceId !== 'string' ||
|
|
129
|
+
!traceId ||
|
|
130
|
+
typeof endTime !== 'number' ||
|
|
131
|
+
!Number.isFinite(endTime) ||
|
|
132
|
+
endTime <= 0)
|
|
133
|
+
continue;
|
|
134
|
+
spans.set(`${traceId}:${spanId}`, {
|
|
135
|
+
spanId,
|
|
136
|
+
traceId,
|
|
137
|
+
parentSpanId: typeof parentSpanId === 'string' ? parentSpanId : '',
|
|
138
|
+
endTime,
|
|
139
|
+
attributes: {
|
|
140
|
+
'gen_ai.operation.name': operation,
|
|
141
|
+
'gen_ai.agent.name': agent,
|
|
142
|
+
'gen_ai.agent.id': agentId,
|
|
143
|
+
'gen_ai.conversation.id': conversation || chatSession,
|
|
144
|
+
'gen_ai.response.model': responseModel,
|
|
145
|
+
'gen_ai.request.model': requestModel,
|
|
146
|
+
'gen_ai.usage.input_tokens': input,
|
|
147
|
+
'gen_ai.usage.output_tokens': output,
|
|
148
|
+
},
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
catch (error) {
|
|
153
|
+
console.warn(`Copilot trace database unavailable: ${error instanceof Error ? error.message : String(error)}`);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
const inferences = [];
|
|
157
|
+
for (const span of spans.values()) {
|
|
158
|
+
const attributes = span.attributes;
|
|
159
|
+
if (attributes['gen_ai.operation.name'] !== 'chat')
|
|
160
|
+
continue;
|
|
161
|
+
let session = attributes['gen_ai.conversation.id'] ??
|
|
162
|
+
attributes['copilot_chat.chat_session_id'];
|
|
163
|
+
let native = false;
|
|
164
|
+
let delegated = false;
|
|
165
|
+
let cursor = span;
|
|
166
|
+
const seen = new Set();
|
|
167
|
+
while (cursor && !seen.has(cursor.spanId)) {
|
|
168
|
+
seen.add(cursor.spanId);
|
|
169
|
+
if (cursor.attributes['gen_ai.agent.id'] === 'github.copilot.default')
|
|
170
|
+
native = true;
|
|
171
|
+
const agent = cursor.attributes['gen_ai.agent.name'];
|
|
172
|
+
if (typeof agent === 'string') {
|
|
173
|
+
const name = agent.toLowerCase();
|
|
174
|
+
if (name === 'github copilot chat' ||
|
|
175
|
+
name === 'copilot' ||
|
|
176
|
+
name === 'copilotcli' ||
|
|
177
|
+
name === 'github-copilot')
|
|
178
|
+
native = true;
|
|
179
|
+
if (name === 'claude' ||
|
|
180
|
+
name === 'claude-code' ||
|
|
181
|
+
name === 'claude_code' ||
|
|
182
|
+
name === 'codex')
|
|
183
|
+
delegated = true;
|
|
184
|
+
}
|
|
185
|
+
session ||=
|
|
186
|
+
cursor.attributes['gen_ai.conversation.id'] ??
|
|
187
|
+
cursor.attributes['copilot_chat.chat_session_id'];
|
|
188
|
+
cursor = spans.get(`${span.traceId}:${cursor.parentSpanId}`);
|
|
189
|
+
}
|
|
190
|
+
if (!native || delegated || typeof session !== 'string' || !session)
|
|
191
|
+
continue;
|
|
192
|
+
const model = attributes['gen_ai.response.model'] || attributes['gen_ai.request.model'];
|
|
193
|
+
const input = attributes['gen_ai.usage.input_tokens'];
|
|
194
|
+
const output = attributes['gen_ai.usage.output_tokens'];
|
|
195
|
+
if (typeof model !== 'string' ||
|
|
196
|
+
!model ||
|
|
197
|
+
typeof input !== 'number' ||
|
|
198
|
+
typeof output !== 'number' ||
|
|
199
|
+
!Number.isSafeInteger(input) ||
|
|
200
|
+
input < 0 ||
|
|
201
|
+
!Number.isSafeInteger(output) ||
|
|
202
|
+
output < 0)
|
|
203
|
+
continue;
|
|
204
|
+
// GenAI input includes cache subsets; output includes reasoning subsets.
|
|
205
|
+
const tokens = input + output;
|
|
206
|
+
const date = new Date(span.endTime);
|
|
207
|
+
if (!Number.isSafeInteger(tokens) ||
|
|
208
|
+
tokens <= 0 ||
|
|
209
|
+
!Number.isFinite(date.getTime()))
|
|
210
|
+
continue;
|
|
211
|
+
inferences.push({
|
|
212
|
+
sessionId: session,
|
|
213
|
+
model,
|
|
214
|
+
timestamp: date.toISOString(),
|
|
215
|
+
tokens,
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
return inferences;
|
|
219
|
+
}
|
|
220
|
+
//# sourceMappingURL=github-copilot-telemetry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github-copilot-telemetry.js","sourceRoot":"","sources":["../../src/scanners/github-copilot-telemetry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAC3C,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACjC,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnD,OAAO,EAAE,KAAK,IAAI,UAAU,EAAE,MAAM,cAAc,CAAA;AAElD,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AACrC,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA;AAmBrC,SAAS,MAAM,CAAC,KAAc;IAC5B,OAAO,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QACzE,CAAC,CAAE,KAAoB;QACvB,CAAC,CAAC,EAAE,CAAA;AACR,CAAC;AAED,gFAAgF;AAChF,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,QAAkB;IAElB,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,UAAU,CAAC,CAAA;IACpE,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,MAAM,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAA;IACpE,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,+BAA+B,EAAE,IAAI,EAAE,CAAA;IACpE,IAAI,QAAQ;QAAE,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAA;IAC1C,MAAM,SAAS,GAAG,IAAI,GAAG,EAAU,CAAA;IACnC,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,MAAM,QAAQ,GAAG;YACf,IAAI,CAAC,OAAO,EAAE,eAAe,CAAC;YAC9B,GAAG,CAAC,MAAM,SAAS,CAAC,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC,EAAE,eAAe,CAAC,CAAC;SACjE,CAAA;QACD,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;YAC5B,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,MAAM,CAAC,UAAU,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,CAAA;gBAC/D,MAAM,OAAO,GAAG,MAAM,CAAC,kCAAkC,CAAC,CAAA;gBAC1D,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,CAAC,IAAI,EAAE;oBAC/C,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAA;YACtC,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;oBACvD,OAAO,CAAC,IAAI,CACV,2CAA2C,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CACpG,CAAA;gBACH,CAAC;YACH,CAAC;QACH,CAAC;QACD,MAAM,UAAU,GAAG;YACjB,GAAG,CAAC,MAAM,SAAS,CACjB,IAAI,CAAC,OAAO,EAAE,eAAe,EAAE,qBAAqB,CAAC,EACrD,KAAK,CACN,CAAC;YACF,GAAG,CAAC,MAAM,SAAS,CAAC,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC,EAAE,KAAK,CAAC,CAAC;SACvD,CAAA;QACD,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;YAC9B,IACE,oEAAoE,CAAC,IAAI,CACvE,IAAI,CACL;gBAED,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;QACvB,CAAC;IACH,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,CAAC,GAAG,KAAK,CAAC,EAAE,SAAS,EAAE,CAAC,GAAG,SAAS,CAAC,EAAE,CAAA;AACzD,CAAC;AAED,SAAS,MAAM,CAAC,KAAc;IAC5B,IACE,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QACrB,KAAK,CAAC,MAAM,KAAK,CAAC;QAClB,CAAC,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAC/B,CAAC,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAC/B,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC;QACZ,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC;QACZ,KAAK,CAAC,CAAC,CAAC,IAAI,aAAa;QAEzB,OAAO,GAAG,CAAA;IACZ,OAAO,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC,CAAA;AAC3D,CAAC;AAED,oFAAoF;AACpF,SAAS,QAAQ,CAAC,IAAY;IAC5B,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAA;QACvC,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,YAAY,IAAI,MAAM,CAAC,WAAW,CAAC,CAAA;QACjE,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAA;QAC/C,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,IAAI,OAAO,CAAC,OAAO,CAAA;QACjD,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,IAAI,OAAO,CAAC,MAAM,CAAA;QAC9C,MAAM,YAAY,GAAG,MAAM,CAAC,YAAY,IAAI,MAAM,CAAC,MAAM,IAAI,EAAE,CAAA;QAC/D,IACE,OAAO,OAAO,KAAK,QAAQ;YAC3B,CAAC,OAAO;YACR,OAAO,MAAM,KAAK,QAAQ;YAC1B,CAAC,MAAM;YACP,OAAO,YAAY,KAAK,QAAQ;YAEhC,OAAO,IAAI,CAAA;QACb,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;QACtC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,OAAO,IAAI,CAAC;YAAE,OAAO,IAAI,CAAA;QAC1D,OAAO;YACL,OAAO;YACP,MAAM;YACN,YAAY;YACZ,OAAO;YACP,UAAU,EAAE,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC;SACtC,CAAA;IACH,CAAC;IAAC,MAAM,CAAC;QACP,oFAAoF;QACpF,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,OAAgC;IAEhC,MAAM,KAAK,GAAG,IAAI,GAAG,EAAgB,CAAA;IACrC,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;QACjC,IAAI,CAAC;YACH,KAAK,MAAM,IAAI,IAAI,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC9D,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAA;gBAC3B,IAAI,IAAI;oBAAE,KAAK,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,MAAM,EAAE,EAAE,IAAI,CAAC,CAAA;YAC7D,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBACvD,OAAO,CAAC,IAAI,CACV,oCAAoC,QAAQ,CAAC,IAAI,CAAC,KAAK,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAChH,CAAA;YACH,CAAC;QACH,CAAC;IACH,CAAC;IACD,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;QACrC,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,OAAO,CACxB,IAAI,EACJ;;;;;wBAKgB,CACjB,CAAA;YACD,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;gBACvB,MAAM,CACJ,MAAM,EACN,OAAO,EACP,YAAY,EACZ,OAAO,EACP,SAAS,EACT,KAAK,EACL,YAAY,EACZ,WAAW,EACX,aAAa,EACb,YAAY,EACZ,KAAK,EACL,MAAM,EACN,OAAO,EACR,GAAG,GAAG,CAAA;gBACP,IACE,OAAO,MAAM,KAAK,QAAQ;oBAC1B,CAAC,MAAM;oBACP,OAAO,OAAO,KAAK,QAAQ;oBAC3B,CAAC,OAAO;oBACR,OAAO,OAAO,KAAK,QAAQ;oBAC3B,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC;oBACzB,OAAO,IAAI,CAAC;oBAEZ,SAAQ;gBACV,KAAK,CAAC,GAAG,CAAC,GAAG,OAAO,IAAI,MAAM,EAAE,EAAE;oBAChC,MAAM;oBACN,OAAO;oBACP,YAAY,EAAE,OAAO,YAAY,KAAK,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE;oBAClE,OAAO;oBACP,UAAU,EAAE;wBACV,uBAAuB,EAAE,SAAS;wBAClC,mBAAmB,EAAE,KAAK;wBAC1B,iBAAiB,EAAE,OAAO;wBAC1B,wBAAwB,EAAE,YAAY,IAAI,WAAW;wBACrD,uBAAuB,EAAE,aAAa;wBACtC,sBAAsB,EAAE,YAAY;wBACpC,2BAA2B,EAAE,KAAK;wBAClC,4BAA4B,EAAE,MAAM;qBACrC;iBACF,CAAC,CAAA;YACJ,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,IAAI,CACV,uCAAuC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAChG,CAAA;QACH,CAAC;IACH,CAAC;IACD,MAAM,UAAU,GAAuB,EAAE,CAAA;IACzC,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;QAClC,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,CAAA;QAClC,IAAI,UAAU,CAAC,uBAAuB,CAAC,KAAK,MAAM;YAAE,SAAQ;QAC5D,IAAI,OAAO,GACT,UAAU,CAAC,wBAAwB,CAAC;YACpC,UAAU,CAAC,8BAA8B,CAAC,CAAA;QAC5C,IAAI,MAAM,GAAG,KAAK,CAAA;QAClB,IAAI,SAAS,GAAG,KAAK,CAAA;QACrB,IAAI,MAAM,GAAqB,IAAI,CAAA;QACnC,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAA;QAC9B,OAAO,MAAM,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;YAC1C,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;YACvB,IAAI,MAAM,CAAC,UAAU,CAAC,iBAAiB,CAAC,KAAK,wBAAwB;gBACnE,MAAM,GAAG,IAAI,CAAA;YACf,MAAM,KAAK,GAAG,MAAM,CAAC,UAAU,CAAC,mBAAmB,CAAC,CAAA;YACpD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;gBAC9B,MAAM,IAAI,GAAG,KAAK,CAAC,WAAW,EAAE,CAAA;gBAChC,IACE,IAAI,KAAK,qBAAqB;oBAC9B,IAAI,KAAK,SAAS;oBAClB,IAAI,KAAK,YAAY;oBACrB,IAAI,KAAK,gBAAgB;oBAEzB,MAAM,GAAG,IAAI,CAAA;gBACf,IACE,IAAI,KAAK,QAAQ;oBACjB,IAAI,KAAK,aAAa;oBACtB,IAAI,KAAK,aAAa;oBACtB,IAAI,KAAK,OAAO;oBAEhB,SAAS,GAAG,IAAI,CAAA;YACpB,CAAC;YACD,OAAO;gBACL,MAAM,CAAC,UAAU,CAAC,wBAAwB,CAAC;oBAC3C,MAAM,CAAC,UAAU,CAAC,8BAA8B,CAAC,CAAA;YACnD,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,OAAO,IAAI,MAAM,CAAC,YAAY,EAAE,CAAC,CAAA;QAC9D,CAAC;QACD,IAAI,CAAC,MAAM,IAAI,SAAS,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,CAAC,OAAO;YACjE,SAAQ;QACV,MAAM,KAAK,GACT,UAAU,CAAC,uBAAuB,CAAC,IAAI,UAAU,CAAC,sBAAsB,CAAC,CAAA;QAC3E,MAAM,KAAK,GAAG,UAAU,CAAC,2BAA2B,CAAC,CAAA;QACrD,MAAM,MAAM,GAAG,UAAU,CAAC,4BAA4B,CAAC,CAAA;QACvD,IACE,OAAO,KAAK,KAAK,QAAQ;YACzB,CAAC,KAAK;YACN,OAAO,KAAK,KAAK,QAAQ;YACzB,OAAO,MAAM,KAAK,QAAQ;YAC1B,CAAC,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC;YAC5B,KAAK,GAAG,CAAC;YACT,CAAC,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC;YAC7B,MAAM,GAAG,CAAC;YAEV,SAAQ;QACV,yEAAyE;QACzE,MAAM,MAAM,GAAG,KAAK,GAAG,MAAM,CAAA;QAC7B,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;QACnC,IACE,CAAC,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC;YAC7B,MAAM,IAAI,CAAC;YACX,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YAEhC,SAAQ;QACV,UAAU,CAAC,IAAI,CAAC;YACd,SAAS,EAAE,OAAO;YAClB,KAAK;YACL,SAAS,EAAE,IAAI,CAAC,WAAW,EAAE;YAC7B,MAAM;SACP,CAAC,CAAA;IACJ,CAAC;IACD,OAAO,UAAU,CAAA;AACnB,CAAC"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { ScanResult } from './util.js';
|
|
2
|
+
/** A user-authored Copilot prompt retained by a local Copilot transcript. */
|
|
3
|
+
export type GitHubCopilotPrompt = {
|
|
4
|
+
/** Stable across scans and distinct from other harness session ids. */
|
|
5
|
+
sessionId: string;
|
|
6
|
+
/** The prompt text. Send only under the existing full-consent flow. */
|
|
7
|
+
text: string;
|
|
8
|
+
/** The event's recorded instant, or null when the source did not record one. */
|
|
9
|
+
timestamp: string | null;
|
|
10
|
+
};
|
|
11
|
+
type CopilotSource = 'vscode' | 'cli';
|
|
12
|
+
type ParseOptions = {
|
|
13
|
+
source: CopilotSource;
|
|
14
|
+
/** Required for Copilot CLI events, whose session id is the parent directory name. */
|
|
15
|
+
sessionId?: string;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Source: microsoft/vscode, extensions/copilot/src/extension/chat/vscode-node/
|
|
19
|
+
* sessionTranscriptService.ts (session.start + user.message JSONL).
|
|
20
|
+
* VS Code's built-in GitHub Copilot extension writes these JSONL transcripts
|
|
21
|
+
* under workspace storage. We intentionally name only its extension storage,
|
|
22
|
+
* never generic VS Code chat persistence, so another chat provider cannot be
|
|
23
|
+
* mistaken for Copilot.
|
|
24
|
+
*/
|
|
25
|
+
export declare function githubCopilotVsCodeWorkspaceStorageRoots(): string[];
|
|
26
|
+
/** Copilot CLI uses this state root; COPILOT_HOME takes precedence at scan time. */
|
|
27
|
+
export declare function githubCopilotCliSessionStateDir(): string;
|
|
28
|
+
/**
|
|
29
|
+
* Local files deliberately written by GitHub Copilot only.
|
|
30
|
+
*
|
|
31
|
+
* VS Code transcript persistence is currently limited to the extension's
|
|
32
|
+
* `github.copilot-chat/transcripts` directory. Copilot CLI persists one
|
|
33
|
+
* `events.jsonl` file per session. Neither generic VS Code workspace state nor
|
|
34
|
+
* exported chats are read, avoiding duplicate/snapshot records and unrelated
|
|
35
|
+
* providers' chats.
|
|
36
|
+
*/
|
|
37
|
+
export declare function githubCopilotFiles(): Promise<string[]>;
|
|
38
|
+
/**
|
|
39
|
+
* Parse the documented JSONL event shape written by VS Code's Copilot
|
|
40
|
+
* transcript service and the Copilot CLI SDK. Synthetic SDK user messages
|
|
41
|
+
* (for example tool/skill traffic) are excluded; only absent or `user` sources
|
|
42
|
+
* represent a person-entered prompt.
|
|
43
|
+
*/
|
|
44
|
+
export declare function parseGitHubCopilotJsonl(content: string, options: ParseOptions): GitHubCopilotPrompt[];
|
|
45
|
+
/**
|
|
46
|
+
* Read raw local prompts only for the consented prompt pipeline. Token scanning
|
|
47
|
+
* below uses numeric usage records independently of prompt-sharing consent.
|
|
48
|
+
*/
|
|
49
|
+
export declare function scanGitHubCopilotPrompts(): Promise<GitHubCopilotPrompt[]>;
|
|
50
|
+
export declare function githubCopilotTokenFiles(): Promise<string[]>;
|
|
51
|
+
export type CopilotUsageSnapshot = {
|
|
52
|
+
sessionId: string;
|
|
53
|
+
model: string;
|
|
54
|
+
timestamp: string;
|
|
55
|
+
tokens: number;
|
|
56
|
+
messages: number;
|
|
57
|
+
};
|
|
58
|
+
/**
|
|
59
|
+
* SDK session.shutdown is durable, unlike ephemeral assistant.usage events.
|
|
60
|
+
* modelMetrics is cumulative across resumes. Input already includes both cache
|
|
61
|
+
* buckets, output already includes reasoning; agentMetrics is a breakdown of
|
|
62
|
+
* these same modelMetrics, not additional usage.
|
|
63
|
+
* Sources: github/copilot-sdk generated/session-events.ts; ccusage.com/guide/copilot/
|
|
64
|
+
*/
|
|
65
|
+
export declare function parseGitHubCopilotUsage(content: string, fallbackSessionId: string): CopilotUsageSnapshot[];
|
|
66
|
+
export declare function scanGitHubCopilot(): Promise<ScanResult>;
|
|
67
|
+
export {};
|
|
68
|
+
//# sourceMappingURL=github-copilot.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github-copilot.d.ts","sourceRoot":"","sources":["../../src/scanners/github-copilot.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAG3C,6EAA6E;AAC7E,MAAM,MAAM,mBAAmB,GAAG;IAChC,uEAAuE;IACvE,SAAS,EAAE,MAAM,CAAA;IACjB,uEAAuE;IACvE,IAAI,EAAE,MAAM,CAAA;IACZ,gFAAgF;IAChF,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;CACzB,CAAA;AAED,KAAK,aAAa,GAAG,QAAQ,GAAG,KAAK,CAAA;AAErC,KAAK,YAAY,GAAG;IAClB,MAAM,EAAE,aAAa,CAAA;IACrB,sFAAsF;IACtF,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAED;;;;;;;GAOG;AACH,wBAAgB,wCAAwC,IAAI,MAAM,EAAE,CAuCnE;AAED,oFAAoF;AACpF,wBAAgB,+BAA+B,IAAI,MAAM,CAKxD;AAED;;;;;;;;GAQG;AACH,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAsB5D;AAcD;;;;;GAKG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,YAAY,GACpB,mBAAmB,EAAE,CAwDvB;AAED;;;GAGG;AACH,wBAAsB,wBAAwB,IAAI,OAAO,CACvD,mBAAmB,EAAE,CACtB,CAoBA;AAQD,wBAAsB,uBAAuB,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CASjE;AAED,MAAM,MAAM,oBAAoB,GAAG;IACjC,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;CACjB,CAAA;AAMD;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,MAAM,EACf,iBAAiB,EAAE,MAAM,GACxB,oBAAoB,EAAE,CA4DxB;AAED,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,UAAU,CAAC,CA8D7D"}
|