codiedev 0.9.26 → 0.9.28
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 +15 -3
- package/assets/opencode-plugin.mjs +54 -0
- package/assets/tui-brand-plugin.tsx +63 -0
- package/dist/backup/cache.js +2 -2
- package/dist/captureLog.js +6 -3
- package/dist/cli.js +7 -0
- package/dist/codie.d.ts +2 -0
- package/dist/codie.js +233 -0
- package/dist/codieLauncher.d.ts +41 -0
- package/dist/codieLauncher.js +352 -0
- package/dist/codieRuntime.d.ts +19 -0
- package/dist/codieRuntime.js +91 -0
- package/dist/codieRuntimeInstall.d.ts +27 -0
- package/dist/codieRuntimeInstall.js +145 -0
- package/dist/configDir.d.ts +1 -0
- package/dist/configDir.js +54 -0
- package/dist/connect.js +8 -2
- package/dist/hook.js +39 -41
- package/dist/upgradeNudge.js +6 -5
- package/dist/utils.d.ts +23 -3
- package/dist/utils.js +288 -20
- package/package.json +13 -5
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.codiedevStateDir = codiedevStateDir;
|
|
37
|
+
// Single source of truth for where the CLI's config/state lives on disk.
|
|
38
|
+
//
|
|
39
|
+
// Defaults to ~/.codiedev. The desktop app sets CODIEDEV_CONFIG_DIR to
|
|
40
|
+
// ~/.codiedev-desktop so a desktop session never touches the user's real
|
|
41
|
+
// prod config — env-based (not a flag) so detached capture-finish/upload
|
|
42
|
+
// children inherit the override automatically.
|
|
43
|
+
//
|
|
44
|
+
// Deliberately dependency-free (only node:path/os) so it can be imported
|
|
45
|
+
// by both utils.ts and modules utils.ts itself imports (e.g. captureLog.ts)
|
|
46
|
+
// without creating a circular import.
|
|
47
|
+
const path = __importStar(require("path"));
|
|
48
|
+
const os = __importStar(require("os"));
|
|
49
|
+
const CONFIG_DIR = process.env.CODIEDEV_CONFIG_DIR?.trim()
|
|
50
|
+
? path.resolve(process.env.CODIEDEV_CONFIG_DIR.trim())
|
|
51
|
+
: path.join(os.homedir(), ".codiedev");
|
|
52
|
+
function codiedevStateDir() {
|
|
53
|
+
return CONFIG_DIR;
|
|
54
|
+
}
|
package/dist/connect.js
CHANGED
|
@@ -270,9 +270,11 @@ async function runConnect(args = []) {
|
|
|
270
270
|
const hasClaude = (0, utils_1.claudeCodeInstalled)();
|
|
271
271
|
const hasCodex = (0, utils_1.codexInstalled)();
|
|
272
272
|
const hasCursor = (0, utils_1.cursorInstalled)();
|
|
273
|
+
const hasOpenCode = (0, utils_1.openCodeInstalled)();
|
|
273
274
|
(0, shared_1.recordInstallEvent)(config, { step: "detect", target: "claude-code", ok: hasClaude });
|
|
274
275
|
(0, shared_1.recordInstallEvent)(config, { step: "detect", target: "codex", ok: hasCodex });
|
|
275
276
|
(0, shared_1.recordInstallEvent)(config, { step: "detect", target: "cursor", ok: hasCursor });
|
|
277
|
+
(0, shared_1.recordInstallEvent)(config, { step: "detect", target: "opencode", ok: hasOpenCode });
|
|
276
278
|
const installed = [];
|
|
277
279
|
// Machine-readable target keys reported back to the backend via
|
|
278
280
|
// /api/cli/markInstalled so the portal's "Connected" state reflects
|
|
@@ -311,6 +313,10 @@ async function runConnect(args = []) {
|
|
|
311
313
|
runInstall("cursor-hook", utils_1.installCursorHook, "Cursor sessionEnd (capture + auto-backup) hooks (~/.cursor/hooks.json)", "cursor-hook");
|
|
312
314
|
runInstall("cursor-instructions", utils_1.installCursorInstructions, "Cursor agent instructions (~/.cursor/rules/codiedev.mdc)", "cursor-instructions");
|
|
313
315
|
}
|
|
316
|
+
// Always stage the adapter. It is dormant until OpenCode starts, which lets
|
|
317
|
+
// a user connect Claude Code today and install the Codie harness tomorrow
|
|
318
|
+
// without needing a second setup ritual.
|
|
319
|
+
runInstall("opencode-capture-adapter", utils_1.installOpenCodeCapturePlugin, "OpenCode session capture adapter (~/.config/opencode/plugins/codiedev.js)", "opencode-capture");
|
|
314
320
|
// Tell the backend which targets we wired up so the portal's onboarding
|
|
315
321
|
// card flips to "Connected" only when something actually installed —
|
|
316
322
|
// not on bare token validation. Best-effort: a network failure here
|
|
@@ -333,8 +339,8 @@ async function runConnect(args = []) {
|
|
|
333
339
|
});
|
|
334
340
|
}
|
|
335
341
|
}
|
|
336
|
-
if (!hasClaude && !hasCodex && !hasCursor) {
|
|
337
|
-
console.warn("\nNo
|
|
342
|
+
if (!hasClaude && !hasCodex && !hasCursor && !hasOpenCode) {
|
|
343
|
+
console.warn("\nNo existing AI client detected; the Codie/OpenCode adapter is ready for a later install.");
|
|
338
344
|
console.warn("If you just installed Claude Code, launch it once (so ~/.claude is created),");
|
|
339
345
|
console.warn("then re-run `npx codiedev connect` to wire up the capture hook.");
|
|
340
346
|
}
|
package/dist/hook.js
CHANGED
|
@@ -46,36 +46,6 @@ const limitEvent_1 = require("./limitEvent");
|
|
|
46
46
|
const version_1 = require("./version");
|
|
47
47
|
const captureLog_1 = require("./captureLog");
|
|
48
48
|
const captureExclusions_1 = require("./captureExclusions");
|
|
49
|
-
function getJson(url, bearerToken) {
|
|
50
|
-
return new Promise((resolve, reject) => {
|
|
51
|
-
const parsed = new URL(url);
|
|
52
|
-
const options = {
|
|
53
|
-
hostname: parsed.hostname,
|
|
54
|
-
port: parsed.port || (parsed.protocol === "https:" ? 443 : 80),
|
|
55
|
-
path: parsed.pathname + parsed.search,
|
|
56
|
-
method: "GET",
|
|
57
|
-
headers: {
|
|
58
|
-
Authorization: `Bearer ${bearerToken}`,
|
|
59
|
-
"X-Codiedev-Cli-Version": version_1.CLI_VERSION,
|
|
60
|
-
},
|
|
61
|
-
};
|
|
62
|
-
const lib = parsed.protocol === "https:" ? https : http;
|
|
63
|
-
const req = lib.request(options, (res) => {
|
|
64
|
-
let body = "";
|
|
65
|
-
res.on("data", (c) => (body += c));
|
|
66
|
-
res.on("end", () => {
|
|
67
|
-
try {
|
|
68
|
-
resolve(JSON.parse(body));
|
|
69
|
-
}
|
|
70
|
-
catch {
|
|
71
|
-
reject(new Error("bad json"));
|
|
72
|
-
}
|
|
73
|
-
});
|
|
74
|
-
});
|
|
75
|
-
req.on("error", reject);
|
|
76
|
-
req.end();
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
49
|
// Pure builder for the discovery additionalContext. Returns null when there are
|
|
80
50
|
// no matches. The suggested `codiedev pull` command carries the EXACT top key
|
|
81
51
|
// (e.g. "pr-push.md") rather than a "<key>" placeholder — otherwise agents
|
|
@@ -106,7 +76,10 @@ async function runDiscover(prompt) {
|
|
|
106
76
|
if (!config)
|
|
107
77
|
process.exit(0);
|
|
108
78
|
try {
|
|
109
|
-
|
|
79
|
+
// POST body, never a query param: raw prompts in GET query strings land
|
|
80
|
+
// in server/proxy access logs (SIG-16). The server keeps accepting legacy
|
|
81
|
+
// GETs from older CLIs during the transition.
|
|
82
|
+
const res = await postJsonForResponse(`${config.backendUrl}/api/cli/skill-discovery`, { q: prompt }, config.token);
|
|
110
83
|
const skills = res?.skills ?? [];
|
|
111
84
|
const additionalContext = buildDiscoveryContext(skills);
|
|
112
85
|
if (additionalContext) {
|
|
@@ -177,7 +150,7 @@ async function postSessionSkip(config, sessionId, reason) {
|
|
|
177
150
|
// so the backend can later compute captured ÷ started. Deliberately tiny — no
|
|
178
151
|
// transcript read, no git — so it never slows session startup. Best-effort +
|
|
179
152
|
// silent (SessionStart hook output is ignored by Claude Code).
|
|
180
|
-
async function runSessionStart(hookInput) {
|
|
153
|
+
async function runSessionStart(hookInput, source = "claude-code") {
|
|
181
154
|
const config = (0, utils_1.readConfig)();
|
|
182
155
|
if (!config)
|
|
183
156
|
process.exit(0);
|
|
@@ -186,7 +159,7 @@ async function runSessionStart(hookInput) {
|
|
|
186
159
|
await postJson(`${config.backendUrl}/api/cli/sessionStart`, {
|
|
187
160
|
sessionId: hookInput.session_id,
|
|
188
161
|
startedAt: Date.now(),
|
|
189
|
-
source
|
|
162
|
+
source,
|
|
190
163
|
}, config.token, PING_TIMEOUT_MS);
|
|
191
164
|
}
|
|
192
165
|
catch {
|
|
@@ -340,6 +313,10 @@ function resolveMode(arg) {
|
|
|
340
313
|
return "codex";
|
|
341
314
|
if (arg === "capture-cursor")
|
|
342
315
|
return "cursor";
|
|
316
|
+
if (arg === "capture-opencode" || arg === "capture-opencode-final")
|
|
317
|
+
return "opencode";
|
|
318
|
+
if (arg === "capture-desktop" || arg === "capture-desktop-final")
|
|
319
|
+
return "desktop";
|
|
343
320
|
return "claude-code";
|
|
344
321
|
}
|
|
345
322
|
async function main() {
|
|
@@ -466,8 +443,8 @@ async function main() {
|
|
|
466
443
|
return;
|
|
467
444
|
}
|
|
468
445
|
// SessionStart: post the capture-coverage denominator ping. Tiny + fast.
|
|
469
|
-
if (process.argv[2] === "session-start") {
|
|
470
|
-
await runSessionStart(hookInput);
|
|
446
|
+
if (process.argv[2] === "session-start" || process.argv[2] === "session-start-opencode") {
|
|
447
|
+
await runSessionStart(hookInput, process.argv[2] === "session-start-opencode" ? "opencode" : "claude-code");
|
|
471
448
|
return;
|
|
472
449
|
}
|
|
473
450
|
// Self-heal: a user who upgraded the CLI but hasn't re-run `connect` gets
|
|
@@ -610,6 +587,11 @@ async function runCaptureFinish(input) {
|
|
|
610
587
|
}
|
|
611
588
|
async function runCaptureFinishInner(input, config, session_id, transcript_path, cwd, workspace_roots) {
|
|
612
589
|
const mode = resolveMode(input.mode);
|
|
590
|
+
// Desktop transcripts (opencode SDK {info,parts}[] dumps) are byte-identical
|
|
591
|
+
// to opencode's, so every parser below EXCEPT parseUsage treats desktop
|
|
592
|
+
// exactly as opencode via this mapping. parseUsage is the one exception —
|
|
593
|
+
// see the rawTranscriptContent note below.
|
|
594
|
+
const parserMode = mode === "desktop" ? "opencode" : mode;
|
|
613
595
|
const workspaceRoot = workspace_roots && workspace_roots.length > 0
|
|
614
596
|
? workspace_roots[0]
|
|
615
597
|
: cwd || process.cwd();
|
|
@@ -632,10 +614,19 @@ async function runCaptureFinishInner(input, config, session_id, transcript_path,
|
|
|
632
614
|
await postSessionSkip(config, session_id, reason);
|
|
633
615
|
return;
|
|
634
616
|
}
|
|
617
|
+
// Snapshot the RAW transcript before normalization below flattens it to
|
|
618
|
+
// Claude Code's newline-JSONL shape — that flattening drops info.cost /
|
|
619
|
+
// info.providerID, which desktop's parseUsage (below) needs and opencode's
|
|
620
|
+
// doesn't. Every other mode leaves transcriptContent untouched here, so this
|
|
621
|
+
// is a no-op for them.
|
|
622
|
+
const rawTranscriptContent = transcriptContent;
|
|
623
|
+
if (parserMode === "opencode") {
|
|
624
|
+
transcriptContent = (0, utils_1.normalizeOpenCodeTranscript)(transcriptContent);
|
|
625
|
+
}
|
|
635
626
|
// Resolve repo URL. Codex embeds it in session_meta; CC and Cursor both
|
|
636
627
|
// need the git remote of the workspace.
|
|
637
628
|
let remoteUrl = null;
|
|
638
|
-
if (
|
|
629
|
+
if (parserMode === "codex") {
|
|
639
630
|
remoteUrl = (0, utils_1.extractCodexRepoUrl)(transcriptContent);
|
|
640
631
|
}
|
|
641
632
|
// The worktrees the session actually wrote to — resolved up front because
|
|
@@ -656,9 +647,9 @@ async function runCaptureFinishInner(input, config, session_id, transcript_path,
|
|
|
656
647
|
// Best-effort local match — backend re-resolves from `remoteUrl` against the
|
|
657
648
|
// company's current repo list, so a stale/empty local cache doesn't matter.
|
|
658
649
|
const matchedRepo = remoteUrl ? (0, utils_1.matchRepo)(remoteUrl, config.repos) : null;
|
|
659
|
-
const stats =
|
|
650
|
+
const stats = parserMode === "codex"
|
|
660
651
|
? (0, utils_1.parseCodexStats)(transcriptContent)
|
|
661
|
-
:
|
|
652
|
+
: parserMode === "cursor"
|
|
662
653
|
? { messageCount: 0, toolCallCount: 0 }
|
|
663
654
|
: (0, utils_1.parseClaudeCodeStats)(transcriptContent);
|
|
664
655
|
const transcriptBase64 = Buffer.from(transcriptContent, "utf8").toString("base64");
|
|
@@ -688,10 +679,13 @@ async function runCaptureFinishInner(input, config, session_id, transcript_path,
|
|
|
688
679
|
const headShas = [...new Set([...keys.headShas, ...authoredShas])];
|
|
689
680
|
const headSha = keys.headSha ?? headShas[0] ?? null;
|
|
690
681
|
// Cost/velocity/steering signals parsed straight from the transcript we're
|
|
691
|
-
// already holding — no extra hooks, no extra git/process calls.
|
|
692
|
-
|
|
682
|
+
// already holding — no extra hooks, no extra git/process calls. parseUsage
|
|
683
|
+
// keeps the literal mode (it has its own desktop parser) and reads the RAW
|
|
684
|
+
// pre-normalization content for desktop; parseSteering routes through
|
|
685
|
+
// parserMode like the parsers above.
|
|
686
|
+
const usage = (0, utils_1.parseUsage)(mode === "desktop" ? rawTranscriptContent : transcriptContent, mode);
|
|
693
687
|
const sessionStartedAt = (0, utils_1.parseSessionStart)(transcriptContent);
|
|
694
|
-
const steering = (0, utils_1.parseSteering)(transcriptContent,
|
|
688
|
+
const steering = (0, utils_1.parseSteering)(transcriptContent, parserMode);
|
|
695
689
|
const payload = (0, utils_1.buildCapturePayload)({
|
|
696
690
|
sessionId: session_id,
|
|
697
691
|
transcriptBase64,
|
|
@@ -709,6 +703,8 @@ async function runCaptureFinishInner(input, config, session_id, transcript_path,
|
|
|
709
703
|
inputTokens: usage.inputTokens,
|
|
710
704
|
outputTokens: usage.outputTokens,
|
|
711
705
|
cacheTokens: usage.cacheTokens,
|
|
706
|
+
cacheReadTokens: usage.cacheReadTokens,
|
|
707
|
+
cacheCreationTokens: usage.cacheCreationTokens,
|
|
712
708
|
model: usage.model,
|
|
713
709
|
sessionStartedAt,
|
|
714
710
|
interruptCount: steering.interrupts,
|
|
@@ -716,6 +712,8 @@ async function runCaptureFinishInner(input, config, session_id, transcript_path,
|
|
|
716
712
|
// Carry the final flag into the HTTP body — the server uses it to decide
|
|
717
713
|
// whether to close the session lease (true) or renew it (false/absent).
|
|
718
714
|
final: input.final,
|
|
715
|
+
// Desktop-only measured spend (undefined for every other source).
|
|
716
|
+
costUsd: usage.costUsd,
|
|
719
717
|
});
|
|
720
718
|
// Throttle decision: final captures go immediately; non-final (per-turn Stop)
|
|
721
719
|
// are deferred if we uploaded this session recently, to avoid per-turn churn.
|
package/dist/upgradeNudge.js
CHANGED
|
@@ -4,9 +4,10 @@
|
|
|
4
4
|
// __tests__/versionCheck.test.ts; this module does the IO (registry fetch +
|
|
5
5
|
// disk cache) and is exercised by manual smoke.
|
|
6
6
|
//
|
|
7
|
-
// Cache lives at
|
|
8
|
-
//
|
|
9
|
-
//
|
|
7
|
+
// Cache lives at <codiedevStateDir()>/.update-cache.json (~/.codiedev by
|
|
8
|
+
// default; ~/.codiedev-desktop under CODIEDEV_CONFIG_DIR). 24h TTL — long
|
|
9
|
+
// enough that the registry isn't hit on every command, short enough that
|
|
10
|
+
// newly-published versions surface the day after release.
|
|
10
11
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
11
12
|
if (k2 === undefined) k2 = k;
|
|
12
13
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
@@ -44,10 +45,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
44
45
|
exports.maybePrintUpgradeNudge = maybePrintUpgradeNudge;
|
|
45
46
|
const fs = __importStar(require("fs"));
|
|
46
47
|
const path = __importStar(require("path"));
|
|
47
|
-
const os = __importStar(require("os"));
|
|
48
48
|
const version_1 = require("./version");
|
|
49
49
|
const versionCheck_1 = require("./versionCheck");
|
|
50
|
-
const
|
|
50
|
+
const configDir_1 = require("./configDir");
|
|
51
|
+
const CACHE_PATH = path.join((0, configDir_1.codiedevStateDir)(), ".update-cache.json");
|
|
51
52
|
const CACHE_TTL_MS = 24 * 60 * 60 * 1000;
|
|
52
53
|
const REGISTRY_URL = "https://registry.npmjs.org/codiedev/latest";
|
|
53
54
|
const FETCH_TIMEOUT_MS = 1500;
|
package/dist/utils.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import * as fs from "fs";
|
|
2
2
|
import { spawn as nodeSpawn } from "child_process";
|
|
3
3
|
import type { CaptureLogEntry } from "./captureLog";
|
|
4
|
+
import { codiedevStateDir } from "./configDir";
|
|
5
|
+
export { codiedevStateDir };
|
|
4
6
|
export interface CodiedevConfig {
|
|
5
7
|
token: string;
|
|
6
8
|
companyId: string;
|
|
@@ -16,6 +18,7 @@ export interface CodiedevConfig {
|
|
|
16
18
|
deviceName?: string;
|
|
17
19
|
captureIgnoredPaths?: string[];
|
|
18
20
|
}
|
|
21
|
+
export declare const CONFIG_PATH: string;
|
|
19
22
|
export declare function readConfig(): CodiedevConfig | null;
|
|
20
23
|
export declare function writeConfig(config: CodiedevConfig): void;
|
|
21
24
|
/** Exported for permission-focused tests; normal callers use writeConfig. */
|
|
@@ -64,11 +67,14 @@ export interface CapturePayloadInput {
|
|
|
64
67
|
inputTokens?: number;
|
|
65
68
|
outputTokens?: number;
|
|
66
69
|
cacheTokens?: number;
|
|
70
|
+
cacheReadTokens?: number;
|
|
71
|
+
cacheCreationTokens?: number;
|
|
67
72
|
model?: string | null;
|
|
68
73
|
sessionStartedAt?: number | null;
|
|
69
74
|
interruptCount?: number;
|
|
70
75
|
rejectionCount?: number;
|
|
71
76
|
final?: boolean;
|
|
77
|
+
costUsd?: number;
|
|
72
78
|
}
|
|
73
79
|
export declare function buildCapturePayload(input: CapturePayloadInput): Record<string, unknown>;
|
|
74
80
|
export declare function hashToken(token: string): string;
|
|
@@ -77,6 +83,11 @@ export declare function resetStableNodeCacheForTests(): void;
|
|
|
77
83
|
export declare function claudeCodeInstalled(): boolean;
|
|
78
84
|
export declare function codexInstalled(): boolean;
|
|
79
85
|
export declare function cursorInstalled(): boolean;
|
|
86
|
+
export declare function openCodeInstalled(): boolean;
|
|
87
|
+
/** Install a dormant global OpenCode adapter. Installing it unconditionally
|
|
88
|
+
* keeps `codiedev connect` as the only setup step even when Codie/OpenCode is
|
|
89
|
+
* installed later. OpenCode loads this file from its documented plugin dir. */
|
|
90
|
+
export declare function installOpenCodeCapturePlugin(): void;
|
|
80
91
|
/**
|
|
81
92
|
* VS Code with the GitHub Copilot Chat extension installed. The extension
|
|
82
93
|
* directory pattern is `~/.vscode/extensions/github.copilot-chat-*`. We treat
|
|
@@ -158,16 +169,26 @@ export interface SteeringStats {
|
|
|
158
169
|
}
|
|
159
170
|
export declare function parseClaudeSteering(content: string): SteeringStats;
|
|
160
171
|
export declare function parseCodexSteering(content: string): SteeringStats;
|
|
161
|
-
export declare function parseSteering(content: string, mode: "claude-code" | "codex" | "cursor"): SteeringStats;
|
|
172
|
+
export declare function parseSteering(content: string, mode: "claude-code" | "codex" | "cursor" | "opencode"): SteeringStats;
|
|
162
173
|
export interface UsageStats {
|
|
163
174
|
inputTokens: number;
|
|
164
175
|
outputTokens: number;
|
|
176
|
+
/** Legacy fold of read + creation — kept for older servers. */
|
|
165
177
|
cacheTokens: number;
|
|
178
|
+
cacheReadTokens: number;
|
|
179
|
+
cacheCreationTokens: number;
|
|
166
180
|
model: string | null;
|
|
181
|
+
/** Engine-reported spend (opencode SDK `info.cost`). Desktop mode only. */
|
|
182
|
+
costUsd?: number;
|
|
167
183
|
}
|
|
168
|
-
export declare function parseUsage(content: string, mode: "claude-code" | "codex" | "cursor"): UsageStats;
|
|
184
|
+
export declare function parseUsage(content: string, mode: "claude-code" | "codex" | "cursor" | "opencode" | "desktop"): UsageStats;
|
|
169
185
|
export declare function parseSessionStart(content: string): number | null;
|
|
170
186
|
export declare function parseClaudeCodeStats(content: string): ParsedStats;
|
|
187
|
+
/** Convert OpenCode's SDK message array (`{info, parts}[]`) into the same
|
|
188
|
+
* newline-delimited shape used by Claude Code. The rest of capture—privacy
|
|
189
|
+
* exclusions, git keys, token parsing, scrubbing, storage, and merge joins—can
|
|
190
|
+
* therefore stay one shared pipeline instead of becoming a parallel product. */
|
|
191
|
+
export declare function normalizeOpenCodeTranscript(content: string): string;
|
|
171
192
|
export declare function parseCodexStats(content: string): ParsedStats;
|
|
172
193
|
export declare function extractCodexRepoUrl(content: string): string | null;
|
|
173
194
|
export interface CaptureUploadJob {
|
|
@@ -299,4 +320,3 @@ interface DeferredUploadDeps extends UploadDeps {
|
|
|
299
320
|
}
|
|
300
321
|
export declare function runDeferredUpload(jobFile: string, delayMs: number, deps: DeferredUploadDeps): Promise<void>;
|
|
301
322
|
export declare function transcriptReadSkipReason(err: unknown): string;
|
|
302
|
-
export {};
|