@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
package/dist/api-client.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export declare class ApiClient {
|
|
2
2
|
private baseUrl;
|
|
3
|
-
private apiKey
|
|
4
|
-
constructor(baseUrl: string, apiKey
|
|
3
|
+
private apiKey?;
|
|
4
|
+
constructor(baseUrl: string, apiKey?: string | undefined);
|
|
5
5
|
get(path: string): Promise<unknown>;
|
|
6
6
|
post(path: string, body: unknown): Promise<unknown>;
|
|
7
7
|
}
|
package/dist/api-client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api-client.d.ts","sourceRoot":"","sources":["../src/api-client.ts"],"names":[],"mappings":"AAAA,qBAAa,SAAS;IAElB,OAAO,CAAC,OAAO;IACf,OAAO,CAAC,MAAM;
|
|
1
|
+
{"version":3,"file":"api-client.d.ts","sourceRoot":"","sources":["../src/api-client.ts"],"names":[],"mappings":"AAAA,qBAAa,SAAS;IAElB,OAAO,CAAC,OAAO;IACf,OAAO,CAAC,MAAM,CAAC;gBADP,OAAO,EAAE,MAAM,EACf,MAAM,CAAC,EAAE,MAAM,YAAA;IAGnB,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAWnC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;CAe1D"}
|
package/dist/api-client.js
CHANGED
|
@@ -7,7 +7,7 @@ export class ApiClient {
|
|
|
7
7
|
}
|
|
8
8
|
async get(path) {
|
|
9
9
|
const res = await fetch(`${this.baseUrl}${path}`, {
|
|
10
|
-
headers: { "X-Api-Key": this.apiKey },
|
|
10
|
+
headers: this.apiKey ? { "X-Api-Key": this.apiKey } : {},
|
|
11
11
|
});
|
|
12
12
|
if (!res.ok) {
|
|
13
13
|
const text = await res.text();
|
|
@@ -20,7 +20,7 @@ export class ApiClient {
|
|
|
20
20
|
method: "POST",
|
|
21
21
|
headers: {
|
|
22
22
|
"Content-Type": "application/json",
|
|
23
|
-
"X-Api-Key": this.apiKey,
|
|
23
|
+
...(this.apiKey ? { "X-Api-Key": this.apiKey } : {}),
|
|
24
24
|
},
|
|
25
25
|
body: JSON.stringify(body),
|
|
26
26
|
});
|
package/dist/api-client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api-client.js","sourceRoot":"","sources":["../src/api-client.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,SAAS;IAEV;IACA;IAFV,YACU,OAAe,EACf,
|
|
1
|
+
{"version":3,"file":"api-client.js","sourceRoot":"","sources":["../src/api-client.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,SAAS;IAEV;IACA;IAFV,YACU,OAAe,EACf,MAAe;QADf,YAAO,GAAP,OAAO,CAAQ;QACf,WAAM,GAAN,MAAM,CAAS;IACtB,CAAC;IAEJ,KAAK,CAAC,GAAG,CAAC,IAAY;QACpB,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,IAAI,CAAC,OAAO,GAAG,IAAI,EAAE,EAAE;YAChD,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE;SACzD,CAAC,CAAC;QACH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;YAC9B,MAAM,IAAI,KAAK,CAAC,aAAa,GAAG,CAAC,MAAM,KAAK,IAAI,EAAE,CAAC,CAAC;QACtD,CAAC;QACD,OAAO,GAAG,CAAC,IAAI,EAAE,CAAC;IACpB,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,IAAY,EAAE,IAAa;QACpC,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,IAAI,CAAC,OAAO,GAAG,IAAI,EAAE,EAAE;YAChD,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aACrD;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;SAC3B,CAAC,CAAC;QACH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;YAC9B,MAAM,IAAI,KAAK,CAAC,aAAa,GAAG,CAAC,MAAM,KAAK,IAAI,EAAE,CAAC,CAAC;QACtD,CAAC;QACD,OAAO,GAAG,CAAC,IAAI,EAAE,CAAC;IACpB,CAAC;CACF"}
|
package/dist/cli.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { readFileSync } from "fs";
|
|
3
|
+
import { dirname, join } from "path";
|
|
4
|
+
import { fileURLToPath } from "url";
|
|
2
5
|
import { program } from "commander";
|
|
3
6
|
import { loginCommand } from "./commands/login.js";
|
|
4
7
|
import { registerCommand } from "./commands/register.js";
|
|
@@ -9,31 +12,41 @@ import { historyCommand } from "./commands/history.js";
|
|
|
9
12
|
import { autoSubmitCommand } from "./commands/auto-submit.js";
|
|
10
13
|
import { setupHookCommand } from "./commands/setup-hook.js";
|
|
11
14
|
import { daemonCommand } from "./commands/daemon.js";
|
|
15
|
+
import { removeHookCommand } from "./commands/remove-hook.js";
|
|
16
|
+
import { CLI_NAME, DEFAULT_PROFILE, PROD_SERVER_URL } from "./constants.js";
|
|
17
|
+
const profileOptionDescription = `Config profile (default: ${DEFAULT_PROFILE})`;
|
|
18
|
+
const packageVersion = JSON.parse(readFileSync(join(dirname(fileURLToPath(import.meta.url)), "../package.json"), "utf-8")).version;
|
|
12
19
|
program
|
|
13
|
-
.name(
|
|
20
|
+
.name(CLI_NAME)
|
|
14
21
|
.description("Trace Marketplace CLI — submit AI coding sessions, get paid")
|
|
15
|
-
.version(
|
|
22
|
+
.version(packageVersion);
|
|
16
23
|
program
|
|
17
24
|
.command("login")
|
|
18
|
-
.description("Sign in via browser
|
|
19
|
-
.
|
|
25
|
+
.description("Sign in via browser and save your API key")
|
|
26
|
+
.option("--profile <name>", profileOptionDescription)
|
|
27
|
+
.option("--server-url <url>", `Server URL (default prod: ${PROD_SERVER_URL})`)
|
|
28
|
+
.action((opts) => loginCommand({ profile: opts.profile, serverUrl: opts.serverUrl }).catch(handleError));
|
|
20
29
|
program
|
|
21
30
|
.command("register")
|
|
22
|
-
.description("
|
|
23
|
-
.option("--
|
|
24
|
-
.
|
|
31
|
+
.description("Alias for login — signs in via browser and saves your API key")
|
|
32
|
+
.option("--profile <name>", profileOptionDescription)
|
|
33
|
+
.option("--server-url <url>", `Server URL (default prod: ${PROD_SERVER_URL})`)
|
|
34
|
+
.action((opts) => registerCommand({ profile: opts.profile, serverUrl: opts.serverUrl }).catch(handleError));
|
|
25
35
|
program
|
|
26
36
|
.command("whoami")
|
|
27
37
|
.description("Show your account info and balance")
|
|
28
|
-
.
|
|
38
|
+
.option("--profile <name>", profileOptionDescription)
|
|
39
|
+
.action((opts) => whoamiCommand({ profile: opts.profile }).catch(handleError));
|
|
29
40
|
program
|
|
30
41
|
.command("submit")
|
|
31
42
|
.description("Auto-detect and submit traces from Claude Code, Codex CLI, and Cursor")
|
|
43
|
+
.option("--profile <name>", profileOptionDescription)
|
|
32
44
|
.option("--tool <tool>", "Only submit from specific tool (claude-code|codex|cursor)")
|
|
33
45
|
.option("--session <id>", "Only submit a specific session ID")
|
|
34
46
|
.option("--dry-run", "Preview without submitting")
|
|
35
47
|
.option("--created-since <duration>", "Only include sessions created within duration (e.g. 30d, 12h, 30m)", "30d")
|
|
36
48
|
.action((opts) => submitCommand({
|
|
49
|
+
profile: opts.profile,
|
|
37
50
|
tool: opts.tool,
|
|
38
51
|
session: opts.session,
|
|
39
52
|
dryRun: opts.dryRun,
|
|
@@ -42,27 +55,45 @@ program
|
|
|
42
55
|
program
|
|
43
56
|
.command("status")
|
|
44
57
|
.description("Show pending submissions and balance")
|
|
45
|
-
.
|
|
58
|
+
.option("--profile <name>", profileOptionDescription)
|
|
59
|
+
.action((opts) => statusCommand({ profile: opts.profile }).catch(handleError));
|
|
46
60
|
program
|
|
47
61
|
.command("history")
|
|
48
62
|
.description("Show submission history")
|
|
49
|
-
.
|
|
63
|
+
.option("--profile <name>", profileOptionDescription)
|
|
64
|
+
.action((opts) => historyCommand({ profile: opts.profile }).catch(handleError));
|
|
50
65
|
program
|
|
51
66
|
.command("auto-submit")
|
|
52
67
|
.description("Submit the current session (called by tool hooks — do not run manually)")
|
|
68
|
+
.option("--profile <name>", profileOptionDescription)
|
|
53
69
|
.option("--tool <tool>", "Tool that triggered the hook (claude-code|cursor|codex)")
|
|
54
70
|
.option("--session <id>", "Session ID (for cursor/codex hooks)")
|
|
55
71
|
.option("--file <path>", "Direct path to session file (for claude-code)")
|
|
56
|
-
.action((opts) => autoSubmitCommand({ tool: opts.tool, session: opts.session, file: opts.file }));
|
|
72
|
+
.action((opts) => autoSubmitCommand({ profile: opts.profile, tool: opts.tool, session: opts.session, file: opts.file }));
|
|
57
73
|
program
|
|
58
74
|
.command("daemon")
|
|
59
|
-
.description("
|
|
60
|
-
.
|
|
75
|
+
.description("Poll for new sessions and auto-submit them; use --once for cron or --watch for live mode")
|
|
76
|
+
.option("--profile <name>", profileOptionDescription)
|
|
77
|
+
.option("--interval <seconds>", "Polling interval in seconds", "60")
|
|
78
|
+
.option("--once", "Run one polling pass and exit")
|
|
79
|
+
.option("--watch", "Use live filesystem watch mode instead of polling")
|
|
80
|
+
.action((opts) => daemonCommand({
|
|
81
|
+
profile: opts.profile,
|
|
82
|
+
interval: opts.interval,
|
|
83
|
+
once: opts.once,
|
|
84
|
+
watch: opts.watch,
|
|
85
|
+
}).catch(handleError));
|
|
61
86
|
program
|
|
62
87
|
.command("setup-hook")
|
|
63
88
|
.description("Install session-end hooks for Claude Code, Cursor, and Codex CLI")
|
|
89
|
+
.option("--profile <name>", profileOptionDescription)
|
|
64
90
|
.option("--tool <tool>", "Only set up hook for specific tool (claude-code|cursor|codex)")
|
|
65
|
-
.action((opts) => setupHookCommand({ tool: opts.tool }).catch(handleError));
|
|
91
|
+
.action((opts) => setupHookCommand({ profile: opts.profile, tool: opts.tool }).catch(handleError));
|
|
92
|
+
program
|
|
93
|
+
.command("remove-hook")
|
|
94
|
+
.description("Remove tracemp hooks from Claude Code, Cursor, and Codex CLI")
|
|
95
|
+
.option("--tool <tool>", "Only remove hook for specific tool (claude-code|cursor|codex)")
|
|
96
|
+
.action((opts) => removeHookCommand({ tool: opts.tool }).catch(handleError));
|
|
66
97
|
function handleError(e) {
|
|
67
98
|
console.error(e.message ?? String(e));
|
|
68
99
|
process.exit(1);
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
interface AutoSubmitOptions {
|
|
2
|
+
profile?: string;
|
|
2
3
|
tool?: string;
|
|
3
4
|
session?: string;
|
|
4
5
|
file?: string;
|
|
5
6
|
}
|
|
6
|
-
export declare function log(msg: string): void;
|
|
7
|
+
export declare function log(msg: string, profile?: string): void;
|
|
7
8
|
export declare function autoSubmitCommand(opts: AutoSubmitOptions): Promise<void>;
|
|
8
9
|
export {};
|
|
9
10
|
//# sourceMappingURL=auto-submit.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auto-submit.d.ts","sourceRoot":"","sources":["../../src/commands/auto-submit.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"auto-submit.d.ts","sourceRoot":"","sources":["../../src/commands/auto-submit.ts"],"names":[],"mappings":"AAgBA,UAAU,iBAAiB;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,wBAAgB,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,SAAkB,QAKzD;AAED,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAM9E"}
|
|
@@ -1,19 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* auto-submit — called by tool hooks (Claude Code Stop, Cursor sessionEnd).
|
|
3
3
|
* Non-interactive: never prompts, always exits 0 so it never blocks the user's tool.
|
|
4
|
-
* Logs results to ~/.config/tracemarketplace/auto-submit.log
|
|
4
|
+
* Logs results to ~/.config/tracemarketplace/auto-submit(.<profile>).log
|
|
5
5
|
*/
|
|
6
6
|
import { readFileSync, appendFileSync, mkdirSync } from "fs";
|
|
7
|
-
import {
|
|
8
|
-
import { join } from "path";
|
|
9
|
-
import { loadConfig } from "../config.js";
|
|
7
|
+
import { getAutoSubmitLogPath, getConfigDir, loadConfig, resolveProfile } from "../config.js";
|
|
10
8
|
import { findLatestFile, findCodexFileById } from "../sessions.js";
|
|
11
|
-
import {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
mkdirSync(
|
|
9
|
+
import { loginCommandForProfile, DEFAULT_PROFILE } from "../constants.js";
|
|
10
|
+
import { buildCursorSessionSource, buildFileSessionSource, flushTrackedSessions, } from "../flush.js";
|
|
11
|
+
export function log(msg, profile = DEFAULT_PROFILE) {
|
|
12
|
+
mkdirSync(getConfigDir(), { recursive: true });
|
|
15
13
|
try {
|
|
16
|
-
appendFileSync(
|
|
14
|
+
appendFileSync(getAutoSubmitLogPath(profile), `[${new Date().toISOString()}] ${msg}\n`);
|
|
17
15
|
}
|
|
18
16
|
catch { }
|
|
19
17
|
}
|
|
@@ -22,13 +20,14 @@ export async function autoSubmitCommand(opts) {
|
|
|
22
20
|
await run(opts);
|
|
23
21
|
}
|
|
24
22
|
catch (err) {
|
|
25
|
-
log(`ERROR: ${String(err)}
|
|
23
|
+
log(`ERROR: ${String(err)}`, resolveProfile(opts.profile));
|
|
26
24
|
}
|
|
27
25
|
}
|
|
28
26
|
async function run(opts) {
|
|
29
|
-
const
|
|
27
|
+
const profile = resolveProfile(opts.profile);
|
|
28
|
+
const config = loadConfig(profile);
|
|
30
29
|
if (!config) {
|
|
31
|
-
log(
|
|
30
|
+
log(`Not authenticated — run: ${loginCommandForProfile(profile)}`, profile);
|
|
32
31
|
return;
|
|
33
32
|
}
|
|
34
33
|
// Read hook payload from stdin
|
|
@@ -40,64 +39,52 @@ async function run(opts) {
|
|
|
40
39
|
}
|
|
41
40
|
catch { }
|
|
42
41
|
const tool = opts.tool ?? inferTool(hookPayload);
|
|
43
|
-
|
|
44
|
-
|
|
42
|
+
const triggerSource = resolveTriggerSource(tool, opts, hookPayload);
|
|
43
|
+
if (!triggerSource && !tool) {
|
|
44
|
+
log("Could not determine tool", profile);
|
|
45
45
|
return;
|
|
46
46
|
}
|
|
47
|
-
log(`auto-submit triggered for tool=${tool}
|
|
47
|
+
log(`auto-submit triggered for profile=${profile} tool=${tool ?? "unknown"}`, profile);
|
|
48
|
+
const result = await flushTrackedSessions(config, triggerSource ? [triggerSource] : [], { includeIdleTracked: true });
|
|
49
|
+
logFlushResult(result, profile);
|
|
50
|
+
}
|
|
51
|
+
function logFlushResult(result, profile) {
|
|
52
|
+
for (const session of result.results) {
|
|
53
|
+
if (session.error && session.error !== "Empty session") {
|
|
54
|
+
log(`${session.source.label}: ${session.error}`, profile);
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
if (session.uploadedChunks > 0 || session.duplicateChunks > 0) {
|
|
58
|
+
const status = session.uploadedChunks > 0 ? "uploaded" : "duplicate";
|
|
59
|
+
log(`${session.source.label}: ${status} chunks=${session.uploadedChunks + session.duplicateChunks} pending=${session.pending} payout=$${(session.payoutCents / 100).toFixed(2)}`, profile);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
if (result.uploadedChunks === 0 && result.duplicateChunks === 0) {
|
|
63
|
+
log(`no finalized chunks ready; pending_sessions=${result.pendingSessions}`, profile);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
function resolveTriggerSource(tool, opts, hookPayload) {
|
|
67
|
+
if (!tool) {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
48
70
|
if (tool === "claude-code" || tool === "claude_code") {
|
|
49
|
-
// Claude Code Stop hook sends { session_id, transcript_path }
|
|
50
71
|
const filePath = opts.file
|
|
51
72
|
?? hookPayload["transcript_path"]
|
|
52
73
|
?? findLatestFile("claude_code");
|
|
53
|
-
|
|
54
|
-
log("Claude Code: no session file found");
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
const result = await submitFile("claude_code", filePath, config);
|
|
58
|
-
logResult(result, filePath);
|
|
74
|
+
return filePath ? buildFileSessionSource("claude_code", filePath) : null;
|
|
59
75
|
}
|
|
60
|
-
|
|
76
|
+
if (tool === "cursor") {
|
|
61
77
|
const sessionId = opts.session ?? hookPayload["sessionId"];
|
|
62
|
-
|
|
63
|
-
log("Cursor: no sessionId");
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
|
-
const result = await submitCursorSession(sessionId, config);
|
|
67
|
-
logResult(result, sessionId);
|
|
78
|
+
return sessionId ? buildCursorSessionSource(sessionId) : null;
|
|
68
79
|
}
|
|
69
|
-
|
|
70
|
-
// after_agent payload: { "thread-id": "...", "turn-id": "...", "cwd": "...", "last-assistant-message": "..." }
|
|
71
|
-
// Legacy / manual: session_path or session_id
|
|
80
|
+
if (tool === "codex" || tool === "codex_cli") {
|
|
72
81
|
const threadId = hookPayload["thread-id"] ?? "";
|
|
73
82
|
const filePath = opts.file
|
|
74
83
|
?? hookPayload["session_path"]
|
|
75
84
|
?? findCodexFileById(opts.session ?? hookPayload["session_id"] ?? threadId ?? "");
|
|
76
|
-
|
|
77
|
-
log("Codex: no session file found");
|
|
78
|
-
return;
|
|
79
|
-
}
|
|
80
|
-
const result = await submitFile("codex_cli", filePath, config);
|
|
81
|
-
logResult(result, filePath);
|
|
82
|
-
}
|
|
83
|
-
else {
|
|
84
|
-
log(`Unknown tool: ${tool}`);
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
function logResult(result, label) {
|
|
88
|
-
if (result.error) {
|
|
89
|
-
log(`${label}: ${result.error}`);
|
|
90
|
-
return;
|
|
85
|
+
return filePath ? buildFileSessionSource("codex_cli", filePath) : null;
|
|
91
86
|
}
|
|
92
|
-
|
|
93
|
-
log(`${label}: already captured — skipped`);
|
|
94
|
-
return;
|
|
95
|
-
}
|
|
96
|
-
if (result.superseded) {
|
|
97
|
-
log(`${label}: updated (${result.turnCount} turns) — $${(result.payoutCents / 100).toFixed(2)}`);
|
|
98
|
-
return;
|
|
99
|
-
}
|
|
100
|
-
log(`${label}: accepted (${result.turnCount} turns) — $${(result.payoutCents / 100).toFixed(2)}`);
|
|
87
|
+
return null;
|
|
101
88
|
}
|
|
102
89
|
function inferTool(payload) {
|
|
103
90
|
if (payload["transcript_path"])
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auto-submit.js","sourceRoot":"","sources":["../../src/commands/auto-submit.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AAC7D,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"auto-submit.js","sourceRoot":"","sources":["../../src/commands/auto-submit.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,2 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
interface DaemonOptions {
|
|
2
|
+
profile?: string;
|
|
3
|
+
interval?: string | number;
|
|
4
|
+
once?: boolean;
|
|
5
|
+
watch?: boolean;
|
|
6
|
+
}
|
|
7
|
+
export declare function daemonCommand(opts?: DaemonOptions): Promise<void>;
|
|
8
|
+
export {};
|
|
2
9
|
//# sourceMappingURL=daemon.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"daemon.d.ts","sourceRoot":"","sources":["../../src/commands/daemon.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"daemon.d.ts","sourceRoot":"","sources":["../../src/commands/daemon.ts"],"names":[],"mappings":"AAwBA,UAAU,aAAa;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC3B,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AA+CD,wBAAsB,aAAa,CAAC,IAAI,GAAE,aAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAoD3E"}
|
package/dist/commands/daemon.js
CHANGED
|
@@ -1,34 +1,35 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* Keeps a state file so already-submitted unchanged files are skipped on restart.
|
|
2
|
+
* tracemp daemon — scans local session dirs and auto-submits new work.
|
|
4
3
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* Default mode polls on an interval, which makes it cron-friendly and simpler
|
|
5
|
+
* to reason about than a long-lived filesystem watcher. `--once` runs a single
|
|
6
|
+
* pass and exits. `--watch` preserves the old live-watch behavior.
|
|
7
7
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* Server handles dedup/supersession — daemon just fires on change.
|
|
8
|
+
* State: ~/.config/tracemarketplace/daemon-state(.<profile>).json
|
|
9
|
+
* { [filePath]: { mtime: number, size: number } }
|
|
11
10
|
*/
|
|
12
11
|
import { readFileSync, writeFileSync, mkdirSync, statSync, existsSync } from "fs";
|
|
13
12
|
import { homedir } from "os";
|
|
14
13
|
import { join } from "path";
|
|
15
14
|
import chalk from "chalk";
|
|
16
|
-
import { loadConfig } from "../config.js";
|
|
15
|
+
import { getConfigDir, getDaemonStatePath, loadConfig, resolveProfile } from "../config.js";
|
|
17
16
|
import { findFiles, watchDirs } from "../sessions.js";
|
|
18
|
-
import { submitFile } from "../submitter.js";
|
|
19
17
|
import { log } from "./auto-submit.js";
|
|
20
|
-
|
|
21
|
-
|
|
18
|
+
import { loginCommandForProfile } from "../constants.js";
|
|
19
|
+
import { buildFileSessionSource, flushTrackedSessions } from "../flush.js";
|
|
20
|
+
const DEFAULT_INTERVAL_SECONDS = 60;
|
|
21
|
+
const BACKFILL_LOOKBACK_DAYS = 7;
|
|
22
|
+
function loadState(profile) {
|
|
22
23
|
try {
|
|
23
|
-
return JSON.parse(readFileSync(
|
|
24
|
+
return JSON.parse(readFileSync(getDaemonStatePath(profile), "utf-8"));
|
|
24
25
|
}
|
|
25
26
|
catch {
|
|
26
27
|
return {};
|
|
27
28
|
}
|
|
28
29
|
}
|
|
29
|
-
function saveState(state) {
|
|
30
|
-
mkdirSync(
|
|
31
|
-
writeFileSync(
|
|
30
|
+
function saveState(state, profile) {
|
|
31
|
+
mkdirSync(getConfigDir(), { recursive: true });
|
|
32
|
+
writeFileSync(getDaemonStatePath(profile), JSON.stringify(state, null, 2) + "\n");
|
|
32
33
|
}
|
|
33
34
|
function hasChanged(filePath, state) {
|
|
34
35
|
try {
|
|
@@ -51,32 +52,19 @@ function recordFile(filePath, state) {
|
|
|
51
52
|
return state;
|
|
52
53
|
}
|
|
53
54
|
}
|
|
54
|
-
async function processFile(tool, filePath, state) {
|
|
55
|
-
const
|
|
56
|
-
if (!config)
|
|
57
|
-
return state;
|
|
58
|
-
const result = await submitFile(tool, filePath, config);
|
|
55
|
+
async function processFile(tool, filePath, state, config) {
|
|
56
|
+
const result = await flushTrackedSessions(config, [buildFileSessionSource(tool, filePath)], { includeIdleTracked: true });
|
|
59
57
|
const updated = recordFile(filePath, state);
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
}
|
|
63
|
-
else if (result.duplicate) {
|
|
64
|
-
// Already current — no log noise
|
|
65
|
-
}
|
|
66
|
-
else if (result.superseded) {
|
|
67
|
-
log(`daemon: updated ${filePath} (${result.turnCount} turns) +$${(result.payoutCents / 100).toFixed(2)}`);
|
|
68
|
-
console.log(chalk.cyan(` ↑ updated`), chalk.gray(filePath.split("/").slice(-2).join("/")), chalk.green(`+$${(result.payoutCents / 100).toFixed(2)}`));
|
|
69
|
-
}
|
|
70
|
-
else if (result.accepted) {
|
|
71
|
-
log(`daemon: accepted ${filePath} (${result.turnCount} turns) +$${(result.payoutCents / 100).toFixed(2)}`);
|
|
72
|
-
console.log(chalk.green(` ✓ new`), chalk.gray(filePath.split("/").slice(-2).join("/")), chalk.green(`+$${(result.payoutCents / 100).toFixed(2)}`));
|
|
58
|
+
for (const session of result.results) {
|
|
59
|
+
logDaemonResult(session, config.profile);
|
|
73
60
|
}
|
|
74
61
|
return updated;
|
|
75
62
|
}
|
|
76
|
-
export async function daemonCommand() {
|
|
77
|
-
const
|
|
63
|
+
export async function daemonCommand(opts = {}) {
|
|
64
|
+
const profile = resolveProfile(opts.profile);
|
|
65
|
+
const config = loadConfig(profile);
|
|
78
66
|
if (!config) {
|
|
79
|
-
console.error(chalk.red(
|
|
67
|
+
console.error(chalk.red(`Not authenticated for profile '${profile}'. Run: ${loginCommandForProfile(profile)}`));
|
|
80
68
|
process.exit(1);
|
|
81
69
|
}
|
|
82
70
|
const tools = [];
|
|
@@ -88,38 +76,106 @@ export async function daemonCommand() {
|
|
|
88
76
|
console.log(chalk.yellow("No supported tools detected (Claude Code, Codex)."));
|
|
89
77
|
return;
|
|
90
78
|
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
console.log(chalk.
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
console.log(chalk.gray("
|
|
97
|
-
|
|
79
|
+
const intervalSeconds = parseIntervalSeconds(opts.interval);
|
|
80
|
+
let state = loadState(config.profile);
|
|
81
|
+
console.log(chalk.bold("tracemp daemon starting"));
|
|
82
|
+
console.log(chalk.gray(`Profile: ${config.profile}`));
|
|
83
|
+
console.log(chalk.gray(`Server: ${config.serverUrl}`));
|
|
84
|
+
console.log(chalk.gray(`Sources: ${tools.join(", ")}`));
|
|
85
|
+
if (opts.watch) {
|
|
86
|
+
console.log(chalk.gray("Mode: live watch"));
|
|
87
|
+
console.log(chalk.gray("Press Ctrl+C to stop\n"));
|
|
88
|
+
await runWatchLoop(config, tools, state);
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
console.log(chalk.gray(`Mode: poll every ${intervalSeconds}s${opts.once ? " (one shot)" : ""}\n`));
|
|
92
|
+
state = await runScanPass(config, tools, state, { logWhenEmpty: true });
|
|
93
|
+
if (opts.once)
|
|
94
|
+
return;
|
|
95
|
+
let shuttingDown = false;
|
|
96
|
+
const stop = () => {
|
|
97
|
+
if (shuttingDown)
|
|
98
|
+
return;
|
|
99
|
+
shuttingDown = true;
|
|
100
|
+
console.log(chalk.gray("\nDaemon stopped."));
|
|
101
|
+
process.exit(0);
|
|
102
|
+
};
|
|
103
|
+
process.on("SIGINT", stop);
|
|
104
|
+
process.on("SIGTERM", stop);
|
|
105
|
+
while (!shuttingDown) {
|
|
106
|
+
await sleep(intervalSeconds * 1000);
|
|
107
|
+
state = await runScanPass(config, tools, state);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
async function runScanPass(config, tools, state, opts = {}) {
|
|
111
|
+
let nextState = state;
|
|
112
|
+
let processed = 0;
|
|
98
113
|
for (const tool of tools) {
|
|
99
|
-
for (const filePath of findFiles(tool,
|
|
100
|
-
if (hasChanged(filePath,
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
114
|
+
for (const filePath of findFiles(tool, BACKFILL_LOOKBACK_DAYS)) {
|
|
115
|
+
if (!hasChanged(filePath, nextState))
|
|
116
|
+
continue;
|
|
117
|
+
nextState = await processFile(tool, filePath, nextState, config);
|
|
118
|
+
processed++;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
const idleResults = await flushTrackedSessions(config, [], { includeIdleTracked: true });
|
|
122
|
+
for (const session of idleResults.results) {
|
|
123
|
+
if (session.uploadedChunks > 0 || session.duplicateChunks > 0) {
|
|
124
|
+
logDaemonResult(session, config.profile);
|
|
104
125
|
}
|
|
105
126
|
}
|
|
106
|
-
saveState(
|
|
107
|
-
if (
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
127
|
+
saveState(nextState, config.profile);
|
|
128
|
+
if (opts.logWhenEmpty &&
|
|
129
|
+
processed === 0 &&
|
|
130
|
+
idleResults.uploadedChunks === 0 &&
|
|
131
|
+
idleResults.duplicateChunks === 0) {
|
|
132
|
+
console.log(chalk.gray("Nothing new.\n"));
|
|
133
|
+
}
|
|
134
|
+
return nextState;
|
|
135
|
+
}
|
|
136
|
+
async function runWatchLoop(config, tools, state) {
|
|
137
|
+
let nextState = await runScanPass(config, tools, state, { logWhenEmpty: true });
|
|
112
138
|
const stop = watchDirs(tools, async (tool, filePath) => {
|
|
113
|
-
if (!hasChanged(filePath,
|
|
139
|
+
if (!hasChanged(filePath, nextState))
|
|
114
140
|
return;
|
|
115
|
-
|
|
116
|
-
saveState(
|
|
141
|
+
nextState = await processFile(tool, filePath, nextState, config);
|
|
142
|
+
saveState(nextState, config.profile);
|
|
143
|
+
});
|
|
144
|
+
process.on("SIGINT", () => {
|
|
145
|
+
stop();
|
|
146
|
+
console.log(chalk.gray("\nDaemon stopped."));
|
|
147
|
+
process.exit(0);
|
|
148
|
+
});
|
|
149
|
+
process.on("SIGTERM", () => {
|
|
150
|
+
stop();
|
|
151
|
+
process.exit(0);
|
|
117
152
|
});
|
|
118
|
-
console.log(chalk.gray("Watching for new sessions...\n"));
|
|
119
|
-
// Graceful shutdown
|
|
120
|
-
process.on("SIGINT", () => { stop(); console.log(chalk.gray("\nDaemon stopped.")); process.exit(0); });
|
|
121
|
-
process.on("SIGTERM", () => { stop(); process.exit(0); });
|
|
122
|
-
// Keep alive
|
|
123
153
|
await new Promise(() => { });
|
|
124
154
|
}
|
|
155
|
+
function logDaemonResult(session, profile) {
|
|
156
|
+
if (session.error && session.error !== "Empty session") {
|
|
157
|
+
log(`daemon: ${session.source.label}: ${session.error}`, profile);
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
if (session.uploadedChunks > 0) {
|
|
161
|
+
log(`daemon: accepted ${session.source.label} chunks=${session.uploadedChunks} +$${(session.payoutCents / 100).toFixed(2)}`, profile);
|
|
162
|
+
console.log(chalk.green(" ✓ new"), chalk.gray(session.source.label.split("/").slice(-2).join("/") || session.source.label), chalk.green(`+$${(session.payoutCents / 100).toFixed(2)}`));
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
if (session.duplicateChunks > 0) {
|
|
166
|
+
console.log(chalk.cyan(" ↑ current"), chalk.gray(session.source.label.split("/").slice(-2).join("/") || session.source.label));
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
function parseIntervalSeconds(raw) {
|
|
170
|
+
if (raw === undefined)
|
|
171
|
+
return DEFAULT_INTERVAL_SECONDS;
|
|
172
|
+
const value = typeof raw === "number" ? raw : Number.parseInt(String(raw), 10);
|
|
173
|
+
if (!Number.isFinite(value) || value <= 0) {
|
|
174
|
+
throw new Error("Daemon interval must be a positive integer number of seconds.");
|
|
175
|
+
}
|
|
176
|
+
return value;
|
|
177
|
+
}
|
|
178
|
+
function sleep(ms) {
|
|
179
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
180
|
+
}
|
|
125
181
|
//# sourceMappingURL=daemon.js.map
|