@jagit/hook-copilot 0.0.5 → 0.0.7
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/index.d.ts +25 -0
- package/dist/index.js +83 -9
- package/package.json +4 -3
package/dist/index.d.ts
CHANGED
|
@@ -80,6 +80,31 @@ interface CopilotDebugUsage {
|
|
|
80
80
|
sourcePath: string;
|
|
81
81
|
modelUsage: Record<string, ModelUsageBucket>;
|
|
82
82
|
}
|
|
83
|
+
/** Resolves the root workspaceStorage directory for the current platform. */
|
|
84
|
+
export interface WorkspaceStorageResolver {
|
|
85
|
+
resolve(): string;
|
|
86
|
+
}
|
|
87
|
+
/** Linux: ~/.config/Code/User/workspaceStorage */
|
|
88
|
+
export declare class LinuxWorkspaceStorageResolver implements WorkspaceStorageResolver {
|
|
89
|
+
resolve(): string;
|
|
90
|
+
}
|
|
91
|
+
/** macOS: ~/Library/Application Support/Code/User/workspaceStorage */
|
|
92
|
+
export declare class MacOSWorkspaceStorageResolver implements WorkspaceStorageResolver {
|
|
93
|
+
resolve(): string;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Windows: %APPDATA%\Code\User\workspaceStorage
|
|
97
|
+
* Falls back to %USERPROFILE%\AppData\Roaming when APPDATA is unset.
|
|
98
|
+
*/
|
|
99
|
+
export declare class WindowsWorkspaceStorageResolver implements WorkspaceStorageResolver {
|
|
100
|
+
resolve(): string;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Returns the appropriate WorkspaceStorageResolver for the current OS.
|
|
104
|
+
* Override in tests by passing a custom resolver directly to the functions
|
|
105
|
+
* that accept a `baseDir` parameter.
|
|
106
|
+
*/
|
|
107
|
+
export declare function platformWorkspaceStorageResolver(): WorkspaceStorageResolver;
|
|
83
108
|
export declare function inferWorkspaceIdBySession(sessionId: string, hookTimestamp?: string, baseDir?: string): WorkspaceCandidate | undefined;
|
|
84
109
|
interface TranscriptPathLocation {
|
|
85
110
|
workspaceId: string;
|
package/dist/index.js
CHANGED
|
@@ -1,10 +1,48 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { existsSync, readFileSync, readdirSync, realpathSync, statSync } from "node:fs";
|
|
3
|
-
import { homedir } from "node:os";
|
|
3
|
+
import { homedir, platform } from "node:os";
|
|
4
4
|
import { join } from "node:path";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
6
|
import { resolveGitUsername, reportSession } from "@jagit/agent-reporter";
|
|
7
|
-
|
|
7
|
+
/** Linux: ~/.config/Code/User/workspaceStorage */
|
|
8
|
+
export class LinuxWorkspaceStorageResolver {
|
|
9
|
+
resolve() {
|
|
10
|
+
return join(homedir(), ".config", "Code", "User", "workspaceStorage");
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
/** macOS: ~/Library/Application Support/Code/User/workspaceStorage */
|
|
14
|
+
export class MacOSWorkspaceStorageResolver {
|
|
15
|
+
resolve() {
|
|
16
|
+
return join(homedir(), "Library", "Application Support", "Code", "User", "workspaceStorage");
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Windows: %APPDATA%\Code\User\workspaceStorage
|
|
21
|
+
* Falls back to %USERPROFILE%\AppData\Roaming when APPDATA is unset.
|
|
22
|
+
*/
|
|
23
|
+
export class WindowsWorkspaceStorageResolver {
|
|
24
|
+
resolve() {
|
|
25
|
+
const appData = process.env["APPDATA"] ??
|
|
26
|
+
join(homedir(), "AppData", "Roaming");
|
|
27
|
+
return join(appData, "Code", "User", "workspaceStorage");
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Returns the appropriate WorkspaceStorageResolver for the current OS.
|
|
32
|
+
* Override in tests by passing a custom resolver directly to the functions
|
|
33
|
+
* that accept a `baseDir` parameter.
|
|
34
|
+
*/
|
|
35
|
+
export function platformWorkspaceStorageResolver() {
|
|
36
|
+
switch (platform()) {
|
|
37
|
+
case "darwin":
|
|
38
|
+
return new MacOSWorkspaceStorageResolver();
|
|
39
|
+
case "win32":
|
|
40
|
+
return new WindowsWorkspaceStorageResolver();
|
|
41
|
+
default:
|
|
42
|
+
return new LinuxWorkspaceStorageResolver();
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
const WORKSPACE_STORAGE_DIR = platformWorkspaceStorageResolver().resolve();
|
|
8
46
|
// ─── Helpers ─────────────────────────────────────────────────────────────────
|
|
9
47
|
function readTranscript(path) {
|
|
10
48
|
return readFileSync(path, "utf-8")
|
|
@@ -127,6 +165,9 @@ function extractTokensFromObject(obj) {
|
|
|
127
165
|
let totalTokens = 0;
|
|
128
166
|
let costUsd = 0;
|
|
129
167
|
let foundAny = false;
|
|
168
|
+
let sawInputKey = false;
|
|
169
|
+
let sawCacheReadStyleKey = false;
|
|
170
|
+
let sawCachedSubsetKey = false;
|
|
130
171
|
for (const [rawKey, rawValue] of Object.entries(obj)) {
|
|
131
172
|
const key = normalizeKey(rawKey);
|
|
132
173
|
const value = toFiniteNumber(rawValue);
|
|
@@ -136,11 +177,19 @@ function extractTokensFromObject(obj) {
|
|
|
136
177
|
if (["inputtokens", "prompttokens", "requesttokens"].includes(key)) {
|
|
137
178
|
inputTokens += value;
|
|
138
179
|
foundAny = true;
|
|
180
|
+
sawInputKey = true;
|
|
139
181
|
continue;
|
|
140
182
|
}
|
|
141
|
-
if (["cachedinputtokens", "
|
|
183
|
+
if (["cachedinputtokens", "cachereadinputtokens"].includes(key)) {
|
|
142
184
|
cachedInputTokens += value;
|
|
143
185
|
foundAny = true;
|
|
186
|
+
sawCacheReadStyleKey = true;
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
if (["cachedtokens", "promptcachehitstokens"].includes(key)) {
|
|
190
|
+
cachedInputTokens += value;
|
|
191
|
+
foundAny = true;
|
|
192
|
+
sawCachedSubsetKey = true;
|
|
144
193
|
continue;
|
|
145
194
|
}
|
|
146
195
|
if (["outputtokens", "completiontokens", "responsetokens"].includes(key)) {
|
|
@@ -162,8 +211,14 @@ function extractTokensFromObject(obj) {
|
|
|
162
211
|
if (!foundAny) {
|
|
163
212
|
return null;
|
|
164
213
|
}
|
|
214
|
+
// Some providers report inputTokens as total prompt tokens and expose cached
|
|
215
|
+
// tokens as a subset. Convert to non-cached input tokens to match JaGit's
|
|
216
|
+
// input/cached split and avoid double-counting in aggregates.
|
|
217
|
+
if (sawInputKey && sawCachedSubsetKey && !sawCacheReadStyleKey) {
|
|
218
|
+
inputTokens = Math.max(0, inputTokens - cachedInputTokens);
|
|
219
|
+
}
|
|
165
220
|
if (totalTokens === 0) {
|
|
166
|
-
totalTokens = inputTokens + outputTokens;
|
|
221
|
+
totalTokens = inputTokens + cachedInputTokens + outputTokens;
|
|
167
222
|
}
|
|
168
223
|
return { inputTokens, cachedInputTokens, outputTokens, totalTokens, costUsd };
|
|
169
224
|
}
|
|
@@ -293,14 +348,33 @@ export function resolveDebugUsageBySession(sessionId, hookTimestamp, baseDir = W
|
|
|
293
348
|
* we sum the total number of individual tool requests across all turns.
|
|
294
349
|
*/
|
|
295
350
|
function countToolCalls(entries) {
|
|
296
|
-
|
|
351
|
+
const toolCallIds = new Set();
|
|
352
|
+
let anonymousCalls = 0;
|
|
297
353
|
for (const e of entries) {
|
|
298
|
-
if (e.type
|
|
354
|
+
if (e.type === "assistant.message") {
|
|
355
|
+
const msg = e;
|
|
356
|
+
for (const req of msg.data?.toolRequests ?? []) {
|
|
357
|
+
if (typeof req.toolCallId === "string" && req.toolCallId.length > 0) {
|
|
358
|
+
toolCallIds.add(req.toolCallId);
|
|
359
|
+
}
|
|
360
|
+
else {
|
|
361
|
+
anonymousCalls += 1;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
299
364
|
continue;
|
|
300
|
-
|
|
301
|
-
|
|
365
|
+
}
|
|
366
|
+
if (e.type === "tool.execution_start" || e.type === "tool.execution_complete") {
|
|
367
|
+
const data = isRecord(e.data) ? e.data : undefined;
|
|
368
|
+
const toolCallId = data?.toolCallId;
|
|
369
|
+
if (typeof toolCallId === "string" && toolCallId.length > 0) {
|
|
370
|
+
toolCallIds.add(toolCallId);
|
|
371
|
+
}
|
|
372
|
+
else {
|
|
373
|
+
anonymousCalls += 1;
|
|
374
|
+
}
|
|
375
|
+
}
|
|
302
376
|
}
|
|
303
|
-
return
|
|
377
|
+
return toolCallIds.size + anonymousCalls;
|
|
304
378
|
}
|
|
305
379
|
/**
|
|
306
380
|
* Extract the earliest timestamp from the transcript.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jagit/hook-copilot",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.7",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"jagit-hook-copilot": "dist/index.js"
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"dist"
|
|
10
10
|
],
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"@jagit/agent-reporter": "0.0.
|
|
12
|
+
"@jagit/agent-reporter": "0.0.7"
|
|
13
13
|
},
|
|
14
14
|
"devDependencies": {
|
|
15
15
|
"@types/node": "^25.9.3",
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
"scripts": {
|
|
19
19
|
"build": "tsc -p tsconfig.json",
|
|
20
20
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
21
|
-
"test": "vitest run"
|
|
21
|
+
"test": "vitest run",
|
|
22
|
+
"test:live": "tsx scripts/test-live.ts"
|
|
22
23
|
}
|
|
23
24
|
}
|