@tracemarketplace/cli 0.0.11 → 0.0.15
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/api-client.d.ts +2 -2
- package/dist/api-client.d.ts.map +1 -1
- package/dist/api-client.js +2 -2
- package/dist/api-client.js.map +1 -1
- package/dist/cli.js +45 -14
- package/dist/cli.js.map +1 -1
- package/dist/commands/auto-submit.d.ts +2 -1
- package/dist/commands/auto-submit.d.ts.map +1 -1
- package/dist/commands/auto-submit.js +43 -56
- package/dist/commands/auto-submit.js.map +1 -1
- package/dist/commands/daemon.d.ts +8 -1
- package/dist/commands/daemon.d.ts.map +1 -1
- package/dist/commands/daemon.js +118 -62
- package/dist/commands/daemon.js.map +1 -1
- package/dist/commands/history.d.ts +3 -1
- package/dist/commands/history.d.ts.map +1 -1
- package/dist/commands/history.js +8 -4
- package/dist/commands/history.js.map +1 -1
- package/dist/commands/login.d.ts +5 -1
- package/dist/commands/login.d.ts.map +1 -1
- package/dist/commands/login.js +25 -9
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/register.d.ts +1 -0
- package/dist/commands/register.d.ts.map +1 -1
- package/dist/commands/register.js +4 -39
- package/dist/commands/register.js.map +1 -1
- package/dist/commands/remove-hook.d.ts +6 -0
- package/dist/commands/remove-hook.d.ts.map +1 -0
- package/dist/commands/remove-hook.js +174 -0
- package/dist/commands/remove-hook.js.map +1 -0
- package/dist/commands/setup-hook.d.ts +2 -0
- package/dist/commands/setup-hook.d.ts.map +1 -1
- package/dist/commands/setup-hook.js +86 -42
- package/dist/commands/setup-hook.js.map +1 -1
- package/dist/commands/status.d.ts +3 -1
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +8 -4
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/submit.d.ts +1 -0
- package/dist/commands/submit.d.ts.map +1 -1
- package/dist/commands/submit.js +136 -83
- package/dist/commands/submit.js.map +1 -1
- package/dist/commands/whoami.d.ts +3 -1
- package/dist/commands/whoami.d.ts.map +1 -1
- package/dist/commands/whoami.js +8 -4
- package/dist/commands/whoami.js.map +1 -1
- package/dist/config.d.ts +33 -6
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +163 -17
- package/dist/config.js.map +1 -1
- package/dist/constants.d.ts +8 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +16 -0
- package/dist/constants.js.map +1 -0
- package/dist/flush.d.ts +46 -0
- package/dist/flush.d.ts.map +1 -0
- package/dist/flush.js +338 -0
- package/dist/flush.js.map +1 -0
- package/dist/flush.test.d.ts +2 -0
- package/dist/flush.test.d.ts.map +1 -0
- package/dist/flush.test.js +175 -0
- package/dist/flush.test.js.map +1 -0
- package/dist/submitter.d.ts.map +1 -1
- package/dist/submitter.js +5 -2
- package/dist/submitter.js.map +1 -1
- package/package.json +8 -7
- package/src/api-client.ts +3 -3
- package/src/cli.ts +51 -14
- package/src/commands/auto-submit.ts +80 -40
- package/src/commands/daemon.ts +166 -59
- package/src/commands/history.ts +9 -4
- package/src/commands/login.ts +37 -9
- package/src/commands/register.ts +5 -49
- package/src/commands/remove-hook.ts +194 -0
- package/src/commands/setup-hook.ts +94 -44
- package/src/commands/status.ts +8 -4
- package/src/commands/submit.ts +189 -83
- package/src/commands/whoami.ts +8 -4
- package/src/config.ts +223 -21
- package/src/constants.ts +18 -0
- package/src/flush.test.ts +214 -0
- package/src/flush.ts +505 -0
- package/vitest.config.ts +8 -0
- package/src/submitter.ts +0 -110
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* setup-hook — installs
|
|
2
|
+
* setup-hook — installs tracemp auto-submit as a per-turn hook for AI coding tools.
|
|
3
3
|
* Run once; sessions are then captured automatically with no user action.
|
|
4
4
|
*
|
|
5
5
|
* Supported tools:
|
|
@@ -12,43 +12,45 @@ import { readFileSync, writeFileSync, mkdirSync, existsSync } from "fs";
|
|
|
12
12
|
import { homedir } from "os";
|
|
13
13
|
import { join } from "path";
|
|
14
14
|
import chalk from "chalk";
|
|
15
|
-
|
|
16
|
-
const HOOK_COMMAND = "trace auto-submit";
|
|
15
|
+
import { getAutoSubmitLogPath, resolveProfile } from "../config.js";
|
|
17
16
|
export async function setupHookCommand(opts) {
|
|
17
|
+
const profile = resolveProfile(opts.profile);
|
|
18
18
|
const tools = opts.tool ? [opts.tool] : detectInstalledTools();
|
|
19
|
+
const hookCommand = buildHookCommand(profile);
|
|
19
20
|
if (tools.length === 0) {
|
|
20
21
|
console.log(chalk.yellow("No supported AI coding tools detected."));
|
|
21
22
|
console.log(chalk.gray("Install Claude Code, Cursor, or Codex CLI, then run setup-hook again."));
|
|
22
|
-
console.log(chalk.gray("Or specify:
|
|
23
|
+
console.log(chalk.gray("Or specify: tracemp setup-hook --tool claude-code"));
|
|
23
24
|
return;
|
|
24
25
|
}
|
|
25
26
|
for (const tool of tools) {
|
|
26
27
|
try {
|
|
27
28
|
switch (tool) {
|
|
28
29
|
case "claude-code":
|
|
29
|
-
setupClaudeCode();
|
|
30
|
+
setupClaudeCode(hookCommand);
|
|
30
31
|
break;
|
|
31
32
|
case "cursor":
|
|
32
|
-
setupCursor();
|
|
33
|
+
setupCursor(hookCommand);
|
|
33
34
|
break;
|
|
34
35
|
case "codex":
|
|
35
|
-
setupCodex();
|
|
36
|
+
setupCodex(hookCommand);
|
|
36
37
|
break;
|
|
37
38
|
default:
|
|
38
|
-
console.log(chalk.yellow(`Unknown tool: ${tool}. Supported: claude-code, cursor`));
|
|
39
|
+
console.log(chalk.yellow(`Unknown tool: ${tool}. Supported: claude-code, cursor, codex`));
|
|
39
40
|
}
|
|
40
41
|
}
|
|
41
42
|
catch (err) {
|
|
42
43
|
console.error(chalk.red(`Failed to set up hook for ${tool}: ${err}`));
|
|
43
44
|
}
|
|
44
45
|
}
|
|
45
|
-
console.log(chalk.gray(`\
|
|
46
|
-
console.log(chalk.gray(`
|
|
46
|
+
console.log(chalk.gray(`\nProfile: ${profile}`));
|
|
47
|
+
console.log(chalk.gray(`Hook logs: ${getAutoSubmitLogPath(profile)}`));
|
|
48
|
+
console.log(chalk.gray("Remove hooks: tracemp remove-hook"));
|
|
47
49
|
}
|
|
48
50
|
// ─── Claude Code ────────────────────────────────────────────────────────────
|
|
49
51
|
// Hook config: ~/.claude/settings.json
|
|
50
52
|
// Stop hook fires at session end with stdin: { session_id, transcript_path }
|
|
51
|
-
function setupClaudeCode() {
|
|
53
|
+
function setupClaudeCode(hookCommand) {
|
|
52
54
|
const settingsPath = join(homedir(), ".claude", "settings.json");
|
|
53
55
|
mkdirSync(join(homedir(), ".claude"), { recursive: true });
|
|
54
56
|
let settings = {};
|
|
@@ -60,27 +62,27 @@ function setupClaudeCode() {
|
|
|
60
62
|
}
|
|
61
63
|
const hooks = settings.hooks ?? {};
|
|
62
64
|
const stopHooks = hooks["Stop"] ?? [];
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
const entry = h;
|
|
66
|
-
const innerHooks = entry.hooks;
|
|
67
|
-
|
|
65
|
+
const nextStopHooks = stopHooks
|
|
66
|
+
.map((h) => {
|
|
67
|
+
const entry = { ...h };
|
|
68
|
+
const innerHooks = Array.isArray(entry.hooks) ? entry.hooks : [];
|
|
69
|
+
entry.hooks = innerHooks.filter((ih) => !String(ih.command ?? "").includes("auto-submit"));
|
|
70
|
+
return entry;
|
|
71
|
+
})
|
|
72
|
+
.filter((entry) => Array.isArray(entry.hooks) && entry.hooks.length > 0);
|
|
73
|
+
nextStopHooks.push({
|
|
74
|
+
matcher: "",
|
|
75
|
+
hooks: [{ type: "command", command: hookCommand, async: true }],
|
|
68
76
|
});
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
hooks: [{ type: "command", command: HOOK_COMMAND }],
|
|
73
|
-
});
|
|
74
|
-
hooks["Stop"] = stopHooks;
|
|
75
|
-
settings.hooks = hooks;
|
|
76
|
-
writeFileSync(settingsPath, JSON.stringify(settings, null, 2), "utf-8");
|
|
77
|
-
}
|
|
77
|
+
hooks["Stop"] = nextStopHooks;
|
|
78
|
+
settings.hooks = hooks;
|
|
79
|
+
writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n", "utf-8");
|
|
78
80
|
console.log(chalk.green("✓ Claude Code") + chalk.gray(` — Stop hook installed in ${settingsPath}`));
|
|
79
81
|
}
|
|
80
82
|
// ─── Cursor ─────────────────────────────────────────────────────────────────
|
|
81
83
|
// Hook config: ~/.cursor/hooks.json
|
|
82
84
|
// stop fires after each assistant turn with stdin: { sessionId, terminationReason, duration }
|
|
83
|
-
function setupCursor() {
|
|
85
|
+
function setupCursor(hookCommand) {
|
|
84
86
|
const hooksPath = join(homedir(), ".cursor", "hooks.json");
|
|
85
87
|
mkdirSync(join(homedir(), ".cursor"), { recursive: true });
|
|
86
88
|
let hooks = [];
|
|
@@ -91,19 +93,17 @@ function setupCursor() {
|
|
|
91
93
|
}
|
|
92
94
|
catch { }
|
|
93
95
|
}
|
|
94
|
-
// Remove any old sessionEnd entry for
|
|
96
|
+
// Remove any old sessionEnd entry for tracemp auto-submit (migration)
|
|
95
97
|
hooks = hooks.filter((h) => {
|
|
96
98
|
const entry = h;
|
|
97
|
-
return !(entry.event === "sessionEnd" && String(entry.command ?? "").includes("
|
|
99
|
+
return !(entry.event === "sessionEnd" && String(entry.command ?? "").includes("auto-submit"));
|
|
98
100
|
});
|
|
99
|
-
|
|
101
|
+
hooks = hooks.filter((h) => {
|
|
100
102
|
const entry = h;
|
|
101
|
-
return entry.event === "stop" && String(entry.command ?? "").includes("
|
|
103
|
+
return !(entry.event === "stop" && String(entry.command ?? "").includes("auto-submit"));
|
|
102
104
|
});
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
writeFileSync(hooksPath, JSON.stringify(hooks, null, 2), "utf-8");
|
|
106
|
-
}
|
|
105
|
+
hooks.push({ event: "stop", command: hookCommand, timeout: 30 });
|
|
106
|
+
writeFileSync(hooksPath, JSON.stringify(hooks, null, 2) + "\n", "utf-8");
|
|
107
107
|
console.log(chalk.green("✓ Cursor") + chalk.gray(` — stop hook installed in ${hooksPath}`));
|
|
108
108
|
}
|
|
109
109
|
// ─── Codex CLI ───────────────────────────────────────────────────────────────
|
|
@@ -111,8 +111,8 @@ function setupCursor() {
|
|
|
111
111
|
// after_agent fires after each agent turn with stdin:
|
|
112
112
|
// { "thread-id": "...", "turn-id": "...", "cwd": "...", "last-assistant-message": "..." }
|
|
113
113
|
// Uses TOML [[hooks]] array-of-tables format.
|
|
114
|
-
const CODEX_HOOK_MARKER = "#
|
|
115
|
-
function setupCodex() {
|
|
114
|
+
export const CODEX_HOOK_MARKER = "# tracemp-hook";
|
|
115
|
+
function setupCodex(hookCommand) {
|
|
116
116
|
const configPath = join(homedir(), ".codex", "config.toml");
|
|
117
117
|
mkdirSync(join(homedir(), ".codex"), { recursive: true });
|
|
118
118
|
let existing = "";
|
|
@@ -122,12 +122,8 @@ function setupCodex() {
|
|
|
122
122
|
}
|
|
123
123
|
catch { }
|
|
124
124
|
}
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
return;
|
|
128
|
-
}
|
|
129
|
-
const hookEntry = `\n${CODEX_HOOK_MARKER}\n[[hooks]]\nevent = "after_agent"\ncommand = "${HOOK_COMMAND} --tool codex"\n`;
|
|
130
|
-
writeFileSync(configPath, existing + hookEntry, "utf-8");
|
|
125
|
+
const next = appendCodexHook(existing, `${hookCommand} --tool codex`);
|
|
126
|
+
writeFileSync(configPath, next, "utf-8");
|
|
131
127
|
console.log(chalk.green("✓ Codex") + chalk.gray(` — after_agent hook installed in ${configPath}`));
|
|
132
128
|
}
|
|
133
129
|
// ─── Tool detection ──────────────────────────────────────────────────────────
|
|
@@ -145,4 +141,52 @@ function detectInstalledTools() {
|
|
|
145
141
|
}
|
|
146
142
|
return found;
|
|
147
143
|
}
|
|
144
|
+
function buildHookCommand(profile) {
|
|
145
|
+
return `tracemp auto-submit --profile ${profile}`;
|
|
146
|
+
}
|
|
147
|
+
function appendCodexHook(content, hookCommand) {
|
|
148
|
+
const base = removeCodexHookBlocks(content).trimEnd();
|
|
149
|
+
const hookBlock = `${CODEX_HOOK_MARKER}\n[[hooks]]\nevent = "after_agent"\ncommand = "${hookCommand}"`;
|
|
150
|
+
return base ? `${base}\n\n${hookBlock}\n` : `${hookBlock}\n`;
|
|
151
|
+
}
|
|
152
|
+
function removeCodexHookBlocks(content) {
|
|
153
|
+
const lines = content.split("\n");
|
|
154
|
+
const out = [];
|
|
155
|
+
let i = 0;
|
|
156
|
+
while (i < lines.length) {
|
|
157
|
+
const line = lines[i];
|
|
158
|
+
const trimmed = line.trim();
|
|
159
|
+
if (trimmed === CODEX_HOOK_MARKER) {
|
|
160
|
+
i++;
|
|
161
|
+
while (i < lines.length && lines[i].trim() === "")
|
|
162
|
+
i++;
|
|
163
|
+
if (i < lines.length && lines[i].trim() === "[[hooks]]") {
|
|
164
|
+
i = skipHookBlock(lines, i);
|
|
165
|
+
while (i < lines.length && lines[i].trim() === "")
|
|
166
|
+
i++;
|
|
167
|
+
}
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
if (trimmed === "[[hooks]]") {
|
|
171
|
+
const blockEnd = skipHookBlock(lines, i);
|
|
172
|
+
const blockText = lines.slice(i, blockEnd).join("\n");
|
|
173
|
+
if (blockText.includes("auto-submit")) {
|
|
174
|
+
i = blockEnd;
|
|
175
|
+
while (i < lines.length && lines[i].trim() === "")
|
|
176
|
+
i++;
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
out.push(line);
|
|
181
|
+
i++;
|
|
182
|
+
}
|
|
183
|
+
return out.join("\n").replace(/\n{3,}/g, "\n\n");
|
|
184
|
+
}
|
|
185
|
+
function skipHookBlock(lines, start) {
|
|
186
|
+
let i = start + 1;
|
|
187
|
+
while (i < lines.length && !lines[i].trim().startsWith("[")) {
|
|
188
|
+
i++;
|
|
189
|
+
}
|
|
190
|
+
return i;
|
|
191
|
+
}
|
|
148
192
|
//# sourceMappingURL=setup-hook.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"setup-hook.js","sourceRoot":"","sources":["../../src/commands/setup-hook.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AACxE,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAC7B,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,KAAK,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"setup-hook.js","sourceRoot":"","sources":["../../src/commands/setup-hook.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"AAKA,wBAAsB,aAAa,CAAC,IAAI,GAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAwBlF"}
|
package/dist/commands/status.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import chalk from "chalk";
|
|
2
|
-
import { loadConfig } from "../config.js";
|
|
2
|
+
import { loadConfig, resolveProfile } from "../config.js";
|
|
3
3
|
import { ApiClient } from "../api-client.js";
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
import { loginCommandForProfile } from "../constants.js";
|
|
5
|
+
export async function statusCommand(opts = {}) {
|
|
6
|
+
const profile = resolveProfile(opts.profile);
|
|
7
|
+
const config = loadConfig(profile);
|
|
6
8
|
if (!config) {
|
|
7
|
-
console.error(chalk.red(
|
|
9
|
+
console.error(chalk.red(`Not authenticated for profile '${profile}'. Run: ${loginCommandForProfile(profile)}`));
|
|
8
10
|
process.exit(1);
|
|
9
11
|
}
|
|
10
12
|
const client = new ApiClient(config.serverUrl, config.apiKey);
|
|
@@ -13,6 +15,8 @@ export async function statusCommand() {
|
|
|
13
15
|
client.get("/api/v1/submissions"),
|
|
14
16
|
]);
|
|
15
17
|
const balance = (me.balanceCents ?? me.balance_cents ?? 0) / 100;
|
|
18
|
+
console.log(chalk.gray("Profile:"), config.profile);
|
|
19
|
+
console.log(chalk.gray("Server:"), config.serverUrl);
|
|
16
20
|
console.log(chalk.bold("Balance:"), chalk.green(`$${balance.toFixed(2)}`));
|
|
17
21
|
console.log(chalk.bold("Submissions:"), subs.length);
|
|
18
22
|
const pending = subs.filter((s) => s.acceptedCount === null);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC1D,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AAEzD,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,OAA6B,EAAE;IACjE,MAAM,OAAO,GAAG,cAAc,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC7C,MAAM,MAAM,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;IACnC,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,kCAAkC,OAAO,WAAW,sBAAsB,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;QAChH,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;IAC9D,MAAM,CAAC,EAAE,EAAE,IAAI,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QACnC,MAAM,CAAC,GAAG,CAAC,YAAY,CAA8E;QACrG,MAAM,CAAC,GAAG,CAAC,qBAAqB,CAAmB;KACpD,CAAC,CAAC;IAEH,MAAM,OAAO,GAAG,CAAE,EAAU,CAAC,YAAY,IAAK,EAAU,CAAC,aAAa,IAAI,CAAC,CAAC,GAAG,GAAG,CAAC;IACnF,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IACpD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC;IACrD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,KAAK,CAAC,KAAK,CAAC,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC3E,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,EAAG,IAAc,CAAC,MAAM,CAAC,CAAC;IAEhE,MAAM,OAAO,GAAI,IAAc,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,aAAa,KAAK,IAAI,CAAC,CAAC;IACxE,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,OAAO,CAAC,MAAM,wBAAwB,CAAC,CAAC,CAAC;IACzE,CAAC;AACH,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"submit.d.ts","sourceRoot":"","sources":["../../src/commands/submit.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"submit.d.ts","sourceRoot":"","sources":["../../src/commands/submit.ts"],"names":[],"mappings":"AAmBA,UAAU,aAAa;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAmCD,wBAAsB,aAAa,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAmPtE"}
|
package/dist/commands/submit.js
CHANGED
|
@@ -1,12 +1,21 @@
|
|
|
1
1
|
import { existsSync } from "fs";
|
|
2
|
-
import {
|
|
2
|
+
import { readFile } from "fs/promises";
|
|
3
3
|
import chalk from "chalk";
|
|
4
4
|
import ora from "ora";
|
|
5
5
|
import inquirer from "inquirer";
|
|
6
|
-
import { extractClaudeCode, extractCodex, extractCursor
|
|
7
|
-
import { loadConfig } from "../config.js";
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
6
|
+
import { extractClaudeCode, extractCodex, extractCursor } from "@tracemarketplace/shared";
|
|
7
|
+
import { loadConfig, loadState, resolveProfile, stateKey } from "../config.js";
|
|
8
|
+
import { loginCommandForProfile } from "../constants.js";
|
|
9
|
+
import { buildCursorSessionSource, buildFileSessionSource, createFreshSessionState, flushTrackedSessions, migrateLegacySessionState, planSessionUploads, } from "../flush.js";
|
|
10
|
+
import { CURSOR_DB_PATH, findFiles } from "../sessions.js";
|
|
11
|
+
function pushSessionIfNonEmpty(sessions, source, trace, emptyLabel, skippedEmpty) {
|
|
12
|
+
if (trace.turn_count > 0) {
|
|
13
|
+
sessions.push({ source, trace });
|
|
14
|
+
}
|
|
15
|
+
else {
|
|
16
|
+
skippedEmpty.push(emptyLabel);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
10
19
|
function parseSinceMs(since) {
|
|
11
20
|
const m = since.match(/^(\d+)(m|h|d)$/);
|
|
12
21
|
if (!m)
|
|
@@ -19,16 +28,18 @@ function parseSinceMs(since) {
|
|
|
19
28
|
return n * 24 * 60 * 60 * 1000;
|
|
20
29
|
}
|
|
21
30
|
export async function submitCommand(opts) {
|
|
22
|
-
const
|
|
31
|
+
const profile = resolveProfile(opts.profile);
|
|
32
|
+
const config = loadConfig(profile);
|
|
23
33
|
if (!config) {
|
|
24
|
-
console.error(chalk.red(
|
|
34
|
+
console.error(chalk.red(`Not authenticated for profile '${profile}'. Run: ${loginCommandForProfile(profile)}`));
|
|
25
35
|
process.exit(1);
|
|
26
36
|
}
|
|
27
37
|
const sinceMs = parseSinceMs(opts.since ?? "30d");
|
|
28
38
|
const sinceDays = sinceMs / (24 * 60 * 60 * 1000);
|
|
29
39
|
const spinner = ora("Discovering sessions...").start();
|
|
30
|
-
const
|
|
40
|
+
const discovered = [];
|
|
31
41
|
const errors = [];
|
|
42
|
+
const skippedEmpty = [];
|
|
32
43
|
const toolAlias = {
|
|
33
44
|
"claude-code": "claude_code",
|
|
34
45
|
"codex": "codex_cli",
|
|
@@ -38,112 +49,142 @@ export async function submitCommand(opts) {
|
|
|
38
49
|
if (tools.includes("claude_code")) {
|
|
39
50
|
const files = findFiles("claude_code", sinceDays);
|
|
40
51
|
spinner.text = `Found ${files.length} Claude Code sessions`;
|
|
41
|
-
for (const
|
|
52
|
+
for (const filePath of files) {
|
|
42
53
|
try {
|
|
43
|
-
|
|
54
|
+
pushSessionIfNonEmpty(discovered, buildFileSessionSource("claude_code", filePath), await extractClaudeCode(filePath, config.email), `Claude Code ${filePath}`, skippedEmpty);
|
|
44
55
|
}
|
|
45
56
|
catch (e) {
|
|
46
|
-
errors.push(`Claude Code ${
|
|
57
|
+
errors.push(`Claude Code ${filePath}: ${e}`);
|
|
47
58
|
}
|
|
48
59
|
}
|
|
49
60
|
}
|
|
50
61
|
if (tools.includes("codex_cli")) {
|
|
51
62
|
const files = findFiles("codex_cli", sinceDays);
|
|
52
63
|
spinner.text = `Found ${files.length} Codex sessions`;
|
|
53
|
-
for (const
|
|
64
|
+
for (const filePath of files) {
|
|
54
65
|
try {
|
|
55
|
-
|
|
56
|
-
const trace = await extractCodex(await readFile(f), config.email);
|
|
57
|
-
if (trace.turn_count > 0)
|
|
58
|
-
traces.push(trace);
|
|
66
|
+
pushSessionIfNonEmpty(discovered, buildFileSessionSource("codex_cli", filePath), await extractCodex(await readFile(filePath), config.email), `Codex ${filePath}`, skippedEmpty);
|
|
59
67
|
}
|
|
60
68
|
catch (e) {
|
|
61
|
-
errors.push(`Codex ${
|
|
69
|
+
errors.push(`Codex ${filePath}: ${e}`);
|
|
62
70
|
}
|
|
63
71
|
}
|
|
64
72
|
}
|
|
65
|
-
if (tools.includes("cursor")) {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
errors.push(`Cursor ${sessionId}: ${e}`);
|
|
90
|
-
}
|
|
73
|
+
if (tools.includes("cursor") && existsSync(CURSOR_DB_PATH)) {
|
|
74
|
+
try {
|
|
75
|
+
const { default: Database } = await import("better-sqlite3");
|
|
76
|
+
const db = new Database(CURSOR_DB_PATH, { readonly: true });
|
|
77
|
+
const cutoff = Date.now() - sinceMs;
|
|
78
|
+
const allRows = db.prepare("SELECT key, value FROM cursorDiskKV WHERE key LIKE 'composerData:%'").all();
|
|
79
|
+
const rows = allRows.filter((row) => {
|
|
80
|
+
try {
|
|
81
|
+
const data = JSON.parse(row.value);
|
|
82
|
+
return (data.createdAt ?? 0) >= cutoff;
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
db.close();
|
|
89
|
+
spinner.text = `Found ${rows.length} Cursor sessions`;
|
|
90
|
+
for (const { key } of rows) {
|
|
91
|
+
const sessionId = key.replace("composerData:", "");
|
|
92
|
+
try {
|
|
93
|
+
pushSessionIfNonEmpty(discovered, buildCursorSessionSource(sessionId), await extractCursor(CURSOR_DB_PATH, sessionId, config.email), `Cursor ${sessionId}`, skippedEmpty);
|
|
94
|
+
}
|
|
95
|
+
catch (e) {
|
|
96
|
+
errors.push(`Cursor ${sessionId}: ${e}`);
|
|
91
97
|
}
|
|
92
|
-
}
|
|
93
|
-
catch (e) {
|
|
94
|
-
errors.push(`Cursor DB: ${e}`);
|
|
95
98
|
}
|
|
96
99
|
}
|
|
100
|
+
catch (e) {
|
|
101
|
+
errors.push(`Cursor DB: ${e}`);
|
|
102
|
+
}
|
|
97
103
|
}
|
|
98
104
|
spinner.stop();
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
if (opts.session && filteredTraces.length === 0) {
|
|
105
|
+
const filtered = opts.session
|
|
106
|
+
? discovered.filter((session) => session.trace.source_session_id.startsWith(opts.session))
|
|
107
|
+
: discovered;
|
|
108
|
+
if (opts.session && filtered.length === 0) {
|
|
104
109
|
console.log(chalk.yellow(`No session found matching ID: ${opts.session}`));
|
|
105
110
|
return;
|
|
106
111
|
}
|
|
107
112
|
if (errors.length > 0) {
|
|
108
113
|
console.log(chalk.yellow(`\n${errors.length} extraction error(s):`));
|
|
109
|
-
errors.slice(0, 3).forEach((
|
|
114
|
+
errors.slice(0, 3).forEach((error) => console.log(chalk.gray(` ${error}`)));
|
|
110
115
|
if (errors.length > 3)
|
|
111
116
|
console.log(chalk.gray(` ...and ${errors.length - 3} more`));
|
|
112
117
|
}
|
|
113
|
-
if (
|
|
114
|
-
console.log(chalk.
|
|
118
|
+
if (skippedEmpty.length > 0) {
|
|
119
|
+
console.log(chalk.gray(`\nSkipped ${skippedEmpty.length} empty/in-progress session(s).`));
|
|
120
|
+
skippedEmpty.slice(0, 3).forEach((label) => console.log(chalk.gray(` ${label}`)));
|
|
121
|
+
if (skippedEmpty.length > 3) {
|
|
122
|
+
console.log(chalk.gray(` ...and ${skippedEmpty.length - 3} more`));
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
if (filtered.length === 0) {
|
|
126
|
+
console.log(chalk.yellow(`No sessions found in the last ${sinceDays} days.`));
|
|
115
127
|
return;
|
|
116
128
|
}
|
|
117
|
-
|
|
118
|
-
|
|
129
|
+
const state = loadState(config.profile);
|
|
130
|
+
const now = new Date();
|
|
131
|
+
const plannedSessions = filtered.map((session) => {
|
|
132
|
+
const key = stateKey(session.trace.source_tool, session.trace.source_session_id);
|
|
133
|
+
const existing = state.sessions[key];
|
|
134
|
+
const legacyChunkIndex = state.chunks[key];
|
|
135
|
+
const cursor = existing
|
|
136
|
+
? {
|
|
137
|
+
...existing,
|
|
138
|
+
locator: session.source.locator,
|
|
139
|
+
sourceTool: session.trace.source_tool,
|
|
140
|
+
sourceSessionId: session.trace.source_session_id,
|
|
141
|
+
}
|
|
142
|
+
: typeof legacyChunkIndex === "number"
|
|
143
|
+
? migrateLegacySessionState(session.source, session.trace, legacyChunkIndex)
|
|
144
|
+
: createFreshSessionState(session.source, session.trace);
|
|
145
|
+
const plan = planSessionUploads(session.trace, cursor, now);
|
|
146
|
+
return {
|
|
147
|
+
...session,
|
|
148
|
+
readyChunks: plan.uploads.length,
|
|
149
|
+
pending: plan.pending,
|
|
150
|
+
};
|
|
151
|
+
});
|
|
152
|
+
const readyChunkCount = plannedSessions.reduce((sum, session) => sum + session.readyChunks, 0);
|
|
153
|
+
const readySessionCount = plannedSessions.filter((session) => session.readyChunks > 0).length;
|
|
154
|
+
const pendingSessionCount = plannedSessions.filter((session) => session.pending).length;
|
|
155
|
+
console.log(chalk.gray(`Target: ${config.profile} (${config.serverUrl})`));
|
|
156
|
+
console.log(`\n${chalk.bold("Sessions scanned:")} (${plannedSessions.length} total)\n`);
|
|
119
157
|
console.log(chalk.gray(" Tool".padEnd(16) +
|
|
120
158
|
"Session ID".padEnd(20) +
|
|
121
159
|
"Turns".padEnd(8) +
|
|
122
|
-
"
|
|
123
|
-
"
|
|
124
|
-
console.log(chalk.gray(" " + "─".repeat(
|
|
125
|
-
for (const
|
|
126
|
-
const tokens = (t.total_input_tokens ?? 0) + (t.total_output_tokens ?? 0);
|
|
127
|
-
const estPayout = t.content_fidelity === "full" ? "$0.04" : "$0.02";
|
|
160
|
+
"Ready".padEnd(8) +
|
|
161
|
+
"Status"));
|
|
162
|
+
console.log(chalk.gray(" " + "─".repeat(62)));
|
|
163
|
+
for (const session of plannedSessions.slice(0, 20)) {
|
|
128
164
|
console.log(" " +
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
String(
|
|
132
|
-
String(
|
|
133
|
-
|
|
165
|
+
session.trace.source_tool.padEnd(16) +
|
|
166
|
+
session.trace.source_session_id.slice(0, 18).padEnd(20) +
|
|
167
|
+
String(session.trace.turn_count).padEnd(8) +
|
|
168
|
+
String(session.readyChunks).padEnd(8) +
|
|
169
|
+
describeSessionStatus(session));
|
|
134
170
|
}
|
|
135
|
-
if (
|
|
136
|
-
console.log(chalk.gray(` ... and ${
|
|
171
|
+
if (plannedSessions.length > 20) {
|
|
172
|
+
console.log(chalk.gray(` ... and ${plannedSessions.length - 20} more`));
|
|
137
173
|
}
|
|
174
|
+
console.log(chalk.gray(`\nReady chunks: ${readyChunkCount} across ${readySessionCount} session(s); pending sessions: ${pendingSessionCount}`));
|
|
138
175
|
if (opts.dryRun) {
|
|
139
176
|
console.log(chalk.cyan("\nDry run — nothing submitted."));
|
|
140
177
|
return;
|
|
141
178
|
}
|
|
179
|
+
if (readyChunkCount === 0) {
|
|
180
|
+
console.log(chalk.yellow("\nNo finalized chunks are ready to submit yet."));
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
142
183
|
const { confirm } = await inquirer.prompt([
|
|
143
184
|
{
|
|
144
185
|
type: "confirm",
|
|
145
186
|
name: "confirm",
|
|
146
|
-
message: `Submit ${
|
|
187
|
+
message: `Submit ${readyChunkCount} finalized chunk(s) from ${readySessionCount} session(s) to ${config.profile} (${config.serverUrl})?`,
|
|
147
188
|
default: true,
|
|
148
189
|
},
|
|
149
190
|
]);
|
|
@@ -151,22 +192,25 @@ export async function submitCommand(opts) {
|
|
|
151
192
|
console.log(chalk.gray("Cancelled."));
|
|
152
193
|
return;
|
|
153
194
|
}
|
|
154
|
-
const uploadSpinner = ora(`Submitting ${
|
|
155
|
-
const client = new ApiClient(config.serverUrl, config.apiKey);
|
|
195
|
+
const uploadSpinner = ora(`Submitting ${readyChunkCount} finalized chunk(s) to ${config.profile}...`).start();
|
|
156
196
|
try {
|
|
157
|
-
const
|
|
158
|
-
const result = (await client.post("/api/v1/traces/batch", {
|
|
159
|
-
traces: filteredTraces.map((t) => redactTrace(t, { homeDir: home })),
|
|
160
|
-
source_tool: tools[0] ?? "mixed",
|
|
161
|
-
}));
|
|
197
|
+
const result = await flushTrackedSessions(config, plannedSessions.map((session) => session.source), { includeIdleTracked: false });
|
|
162
198
|
uploadSpinner.stop();
|
|
163
|
-
const
|
|
199
|
+
const failedSessions = result.results.filter((session) => session.error && session.error !== "Empty session");
|
|
164
200
|
console.log(chalk.green("\nSubmission complete!"));
|
|
165
|
-
console.log(`
|
|
166
|
-
console.log(`
|
|
167
|
-
console.log(`
|
|
168
|
-
console.log(` Payout:
|
|
169
|
-
|
|
201
|
+
console.log(` Uploaded chunks: ${chalk.bold(result.uploadedChunks)}`);
|
|
202
|
+
console.log(` Duplicate chunks: ${chalk.gray(result.duplicateChunks)}`);
|
|
203
|
+
console.log(` Pending sessions: ${result.pendingSessions}`);
|
|
204
|
+
console.log(` Payout: ${chalk.green("$" + (result.payoutCents / 100).toFixed(2))}`);
|
|
205
|
+
if (failedSessions.length > 0) {
|
|
206
|
+
console.log(chalk.yellow(`\n${failedSessions.length} session(s) failed during submit:`));
|
|
207
|
+
failedSessions.slice(0, 3).forEach((session) => {
|
|
208
|
+
console.log(chalk.gray(` ${session.source.label}: ${session.error}`));
|
|
209
|
+
});
|
|
210
|
+
if (failedSessions.length > 3) {
|
|
211
|
+
console.log(chalk.gray(` ...and ${failedSessions.length - 3} more`));
|
|
212
|
+
}
|
|
213
|
+
}
|
|
170
214
|
}
|
|
171
215
|
catch (e) {
|
|
172
216
|
uploadSpinner.fail("Submission failed");
|
|
@@ -174,4 +218,13 @@ export async function submitCommand(opts) {
|
|
|
174
218
|
process.exit(1);
|
|
175
219
|
}
|
|
176
220
|
}
|
|
221
|
+
function describeSessionStatus(session) {
|
|
222
|
+
if (session.readyChunks > 0 && session.pending)
|
|
223
|
+
return "ready + pending";
|
|
224
|
+
if (session.readyChunks > 0)
|
|
225
|
+
return "ready";
|
|
226
|
+
if (session.pending)
|
|
227
|
+
return "pending";
|
|
228
|
+
return "up-to-date";
|
|
229
|
+
}
|
|
177
230
|
//# sourceMappingURL=submit.js.map
|