coolhand-cli 0.5.2 → 0.7.0

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.
Files changed (91) hide show
  1. package/README.md +27 -121
  2. package/dist/api/last-sync.d.ts +5 -0
  3. package/dist/api/last-sync.d.ts.map +1 -1
  4. package/dist/api/last-sync.js +5 -0
  5. package/dist/api/last-sync.js.map +1 -1
  6. package/dist/auth/callback-server.js +3 -3
  7. package/dist/auth/callback-server.js.map +1 -1
  8. package/dist/cli.d.ts +10 -0
  9. package/dist/cli.d.ts.map +1 -1
  10. package/dist/cli.js +320 -37
  11. package/dist/cli.js.map +1 -1
  12. package/dist/commands/analyze-claude-sessions.d.ts.map +1 -1
  13. package/dist/commands/analyze-claude-sessions.js +37 -6
  14. package/dist/commands/analyze-claude-sessions.js.map +1 -1
  15. package/dist/commands/claude.d.ts +10 -10
  16. package/dist/commands/claude.d.ts.map +1 -1
  17. package/dist/commands/claude.js +6 -77
  18. package/dist/commands/claude.js.map +1 -1
  19. package/dist/commands/clients.js +1 -1
  20. package/dist/commands/clients.js.map +1 -1
  21. package/dist/commands/flush-pending.d.ts +25 -0
  22. package/dist/commands/flush-pending.d.ts.map +1 -0
  23. package/dist/commands/flush-pending.js +100 -0
  24. package/dist/commands/flush-pending.js.map +1 -0
  25. package/dist/commands/get-workload.d.ts +3 -0
  26. package/dist/commands/get-workload.d.ts.map +1 -0
  27. package/dist/commands/get-workload.js +28 -0
  28. package/dist/commands/get-workload.js.map +1 -0
  29. package/dist/commands/list-workloads.d.ts +3 -0
  30. package/dist/commands/list-workloads.d.ts.map +1 -0
  31. package/dist/commands/list-workloads.js +52 -0
  32. package/dist/commands/list-workloads.js.map +1 -0
  33. package/dist/commands/login.d.ts.map +1 -1
  34. package/dist/commands/login.js +41 -6
  35. package/dist/commands/login.js.map +1 -1
  36. package/dist/commands/mcp-call.d.ts.map +1 -1
  37. package/dist/commands/mcp-call.js +57 -10
  38. package/dist/commands/mcp-call.js.map +1 -1
  39. package/dist/commands/monitor.d.ts +9 -0
  40. package/dist/commands/monitor.d.ts.map +1 -0
  41. package/dist/commands/monitor.js +10 -0
  42. package/dist/commands/monitor.js.map +1 -0
  43. package/dist/commands/status.js +2 -2
  44. package/dist/commands/status.js.map +1 -1
  45. package/dist/commands/update-workload.d.ts +3 -0
  46. package/dist/commands/update-workload.d.ts.map +1 -0
  47. package/dist/commands/update-workload.js +35 -0
  48. package/dist/commands/update-workload.js.map +1 -0
  49. package/dist/commands/whoami.js +1 -1
  50. package/dist/commands/whoami.js.map +1 -1
  51. package/dist/commands/wildcard.d.ts.map +1 -1
  52. package/dist/commands/wildcard.js +118 -20
  53. package/dist/commands/wildcard.js.map +1 -1
  54. package/dist/config.d.ts +16 -0
  55. package/dist/config.d.ts.map +1 -1
  56. package/dist/config.js +127 -6
  57. package/dist/config.js.map +1 -1
  58. package/dist/pending-store.d.ts +31 -0
  59. package/dist/pending-store.d.ts.map +1 -0
  60. package/dist/pending-store.js +81 -0
  61. package/dist/pending-store.js.map +1 -0
  62. package/dist/prompt.d.ts +13 -0
  63. package/dist/prompt.d.ts.map +1 -0
  64. package/dist/prompt.js +30 -0
  65. package/dist/prompt.js.map +1 -0
  66. package/dist/proxy/certs.d.ts +14 -0
  67. package/dist/proxy/certs.d.ts.map +1 -0
  68. package/dist/proxy/certs.js +64 -0
  69. package/dist/proxy/certs.js.map +1 -0
  70. package/dist/proxy/interceptor.d.ts +16 -0
  71. package/dist/proxy/interceptor.d.ts.map +1 -0
  72. package/dist/proxy/interceptor.js +57 -0
  73. package/dist/proxy/interceptor.js.map +1 -0
  74. package/dist/proxy/proxy.d.ts +20 -0
  75. package/dist/proxy/proxy.d.ts.map +1 -0
  76. package/dist/proxy/proxy.js +114 -0
  77. package/dist/proxy/proxy.js.map +1 -0
  78. package/dist/proxy/sender.d.ts +32 -0
  79. package/dist/proxy/sender.d.ts.map +1 -0
  80. package/dist/proxy/sender.js +66 -0
  81. package/dist/proxy/sender.js.map +1 -0
  82. package/dist/proxy/wrap-runner.d.ts +36 -0
  83. package/dist/proxy/wrap-runner.d.ts.map +1 -0
  84. package/dist/proxy/wrap-runner.js +153 -0
  85. package/dist/proxy/wrap-runner.js.map +1 -0
  86. package/dist/types.d.ts +29 -2
  87. package/dist/types.d.ts.map +1 -1
  88. package/dist/types.js.map +1 -1
  89. package/dist/version.d.ts +2 -2
  90. package/dist/version.js +1 -1
  91. package/package.json +2 -2
@@ -0,0 +1,114 @@
1
+ import * as mockttp from "mockttp";
2
+ import { shouldCapture, sanitizeHeaders, flattenHeaders } from "./interceptor.js";
3
+ import { sendToCoolhand } from "./sender.js";
4
+ /**
5
+ * Start an HTTPS MITM proxy that intercepts LLM API calls
6
+ * and forwards them to the Coolhand platform.
7
+ */
8
+ export async function startProxy(ca, options) {
9
+ const server = mockttp.getLocal({
10
+ https: { key: ca.key, cert: ca.cert },
11
+ });
12
+ // Track pending requests by ID for pairing with responses
13
+ const pendingRequests = new Map();
14
+ // Track in-flight sendToCoolhand calls so stop() can drain them before halting
15
+ const inFlightSends = new Set();
16
+ await server.on("request", (req) => {
17
+ // Guard against a PatternMatchingService constructor failure — if shouldCapture
18
+ // throws, skip capture for this request rather than crashing the event handler.
19
+ let capture;
20
+ try {
21
+ capture = shouldCapture(req.url);
22
+ }
23
+ catch {
24
+ return;
25
+ }
26
+ if (!capture) {
27
+ return;
28
+ }
29
+ pendingRequests.set(req.id, {
30
+ method: req.method,
31
+ url: req.url,
32
+ headers: flattenHeaders(req.headers),
33
+ bodyPromise: Promise.resolve().then(() => req.body.getText()),
34
+ startTimestamp: req.timingEvents?.startTimestamp ?? performance.now(),
35
+ timestamp: new Date().toISOString(),
36
+ });
37
+ });
38
+ await server.on("abort", (req) => {
39
+ // The stored bodyPromise continues running and resolves normally; its
40
+ // result is simply discarded. This is intentional — no cleanup needed.
41
+ pendingRequests.delete(req.id);
42
+ });
43
+ await server.on("response", (res) => {
44
+ const req = pendingRequests.get(res.id);
45
+ if (!req) {
46
+ return;
47
+ }
48
+ pendingRequests.delete(res.id);
49
+ const endTimestamp = res.timingEvents?.responseSentTimestamp ?? performance.now();
50
+ const durationMs = endTimestamp - req.startTimestamp;
51
+ // Read request and response bodies concurrently — req.bodyPromise started
52
+ // when the request arrived and is likely already settled by the time the
53
+ // response handler fires, so Promise.all adds no extra latency.
54
+ const send = Promise.all([res.body.getText(), req.bodyPromise]).then(([responseBodyText, requestBodyText]) => {
55
+ const captured = {
56
+ request: {
57
+ method: req.method,
58
+ url: req.url,
59
+ headers: sanitizeHeaders(req.headers),
60
+ body: requestBodyText,
61
+ },
62
+ response: {
63
+ statusCode: res.statusCode,
64
+ headers: sanitizeHeaders(flattenHeaders(res.headers)),
65
+ body: responseBodyText,
66
+ },
67
+ timestamp: req.timestamp,
68
+ };
69
+ if (!options.silent) {
70
+ console.error(`[coolhand-proxy] Captured ${req.method} ${req.url} -> ${res.statusCode} (${Math.round(durationMs)}ms)`);
71
+ }
72
+ return sendToCoolhand(captured, {
73
+ apiKey: options.apiKey,
74
+ apiEndpoint: options.apiEndpoint,
75
+ silent: options.silent,
76
+ collector: options.collector,
77
+ });
78
+ }).catch((err) => {
79
+ if (!options.silent) {
80
+ console.error("[coolhand-proxy] Capture/send error:", err);
81
+ }
82
+ });
83
+ inFlightSends.add(send);
84
+ send.finally(() => inFlightSends.delete(send));
85
+ });
86
+ // Pass all requests through to their real destinations
87
+ await server.forAnyRequest().thenPassThrough();
88
+ await server.start(options.port ?? 0);
89
+ const port = server.port;
90
+ if (!options.silent) {
91
+ console.error(`[coolhand-proxy] Proxy started on port ${port}`);
92
+ }
93
+ return {
94
+ port,
95
+ stop: async () => {
96
+ // Stop the server first so no new response events can fire and add to
97
+ // inFlightSends after we snapshot it for draining. This relies on
98
+ // mockttp's server.stop() completing all queued event callbacks before
99
+ // resolving — a 15 s hard deadline guards against any future change to
100
+ // that guarantee or a pathological send that never settles.
101
+ await server.stop();
102
+ // Each in-flight send has a 10 s AbortController timeout so all sends
103
+ // settle within that window; the 15 s deadline is a safety net.
104
+ const drainDeadline = Date.now() + 15000;
105
+ while (inFlightSends.size > 0 && Date.now() < drainDeadline) {
106
+ await Promise.allSettled([...inFlightSends]);
107
+ }
108
+ if (!options.silent) {
109
+ console.error("[coolhand-proxy] Proxy stopped");
110
+ }
111
+ },
112
+ };
113
+ }
114
+ //# sourceMappingURL=proxy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proxy.js","sourceRoot":"","sources":["../../src/proxy/proxy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ export interface CapturedInteraction {
2
+ request: {
3
+ method: string;
4
+ url: string;
5
+ headers: Record<string, string>;
6
+ body: string | undefined;
7
+ };
8
+ response: {
9
+ statusCode: number;
10
+ headers: Record<string, string>;
11
+ body: string | undefined;
12
+ };
13
+ timestamp: string;
14
+ }
15
+ interface SendOptions {
16
+ apiKey: string;
17
+ apiEndpoint?: string;
18
+ silent?: boolean;
19
+ collector?: string;
20
+ }
21
+ /** @internal Reset the call ID counter. Exposed for test isolation only.
22
+ * Call in beforeEach in any test file that imports sendToCoolhand — Jest
23
+ * may share this module instance across test files in the same worker.
24
+ */
25
+ export declare function resetCallIdForTesting(): void;
26
+ /**
27
+ * Forward a captured interaction to the Coolhand API.
28
+ * Uses the same payload format as coolhand-node's LoggingService.
29
+ */
30
+ export declare function sendToCoolhand(captured: CapturedInteraction, options: SendOptions): Promise<void>;
31
+ export {};
32
+ //# sourceMappingURL=sender.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sender.d.ts","sourceRoot":"","sources":["../../src/proxy/sender.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE;QACP,MAAM,EAAE,MAAM,CAAC;QACf,GAAG,EAAE,MAAM,CAAC;QACZ,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAChC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;KAC1B,CAAC;IACF,QAAQ,EAAE;QACR,UAAU,EAAE,MAAM,CAAC;QACnB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAChC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;KAC1B,CAAC;IACF,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,UAAU,WAAW;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAMD;;;GAGG;AACH,wBAAgB,qBAAqB,IAAI,IAAI,CAAiB;AAE9D;;;GAGG;AACH,wBAAsB,cAAc,CAClC,QAAQ,EAAE,mBAAmB,EAC7B,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,IAAI,CAAC,CAuDf"}
@@ -0,0 +1,66 @@
1
+ import { parseBody } from "coolhand-node";
2
+ import { PACKAGE_IDENTIFIER } from "../version.js";
3
+ const DEFAULT_ENDPOINT = "https://coolhandlabs.com/api/v2/llm_request_logs";
4
+ let _nextId = 0;
5
+ /** @internal Reset the call ID counter. Exposed for test isolation only.
6
+ * Call in beforeEach in any test file that imports sendToCoolhand — Jest
7
+ * may share this module instance across test files in the same worker.
8
+ */
9
+ export function resetCallIdForTesting() { _nextId = 0; }
10
+ /**
11
+ * Forward a captured interaction to the Coolhand API.
12
+ * Uses the same payload format as coolhand-node's LoggingService.
13
+ */
14
+ export async function sendToCoolhand(captured, options) {
15
+ const { apiKey, silent } = options;
16
+ const endpoint = options.apiEndpoint ?? DEFAULT_ENDPOINT;
17
+ const controller = new AbortController();
18
+ const timeout = setTimeout(() => controller.abort(), 10000);
19
+ try {
20
+ const payload = {
21
+ llm_request_log: {
22
+ raw_request: {
23
+ id: ++_nextId,
24
+ method: captured.request.method,
25
+ url: captured.request.url,
26
+ headers: captured.request.headers,
27
+ request_body: parseBody(captured.request.body),
28
+ response_body: parseBody(captured.response.body),
29
+ response_headers: captured.response.headers,
30
+ status_code: captured.response.statusCode,
31
+ timestamp: captured.timestamp,
32
+ protocol: new URL(captured.request.url).protocol.replace(":", ""),
33
+ },
34
+ collector: options.collector ?? `${PACKAGE_IDENTIFIER}/claude`,
35
+ },
36
+ };
37
+ const response = await fetch(endpoint, {
38
+ method: "POST",
39
+ headers: {
40
+ "Content-Type": "application/json",
41
+ "X-API-Key": apiKey,
42
+ },
43
+ body: JSON.stringify(payload),
44
+ signal: controller.signal,
45
+ });
46
+ // Cancel the abort timer as soon as the response headers arrive so that
47
+ // slow error-body reads (response.text() below) don't trigger it.
48
+ clearTimeout(timeout);
49
+ if (!response.ok) {
50
+ if (!silent) {
51
+ const body = await response.text();
52
+ console.error(`[coolhand-proxy] Failed to send to Coolhand (${response.status}): ${body}`);
53
+ }
54
+ }
55
+ else if (!silent) {
56
+ console.error(`[coolhand-proxy] Logged ${captured.request.method} ${captured.request.url}`);
57
+ }
58
+ }
59
+ catch (error) {
60
+ clearTimeout(timeout);
61
+ if (!silent) {
62
+ console.error(`[coolhand-proxy] Failed to send to Coolhand:`, error);
63
+ }
64
+ }
65
+ }
66
+ //# sourceMappingURL=sender.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sender.js","sourceRoot":"","sources":["../../src/proxy/sender.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAwBnD,MAAM,gBAAgB,GAAG,kDAAkD,CAAC;AAE5E,IAAI,OAAO,GAAG,CAAC,CAAC;AAEhB;;;GAGG;AACH,MAAM,UAAU,qBAAqB,KAAW,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC;AAE9D;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,QAA6B,EAC7B,OAAoB;IAEpB,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;IACnC,MAAM,QAAQ,GAAG,OAAO,CAAC,WAAW,IAAI,gBAAgB,CAAC;IAEzD,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,KAAM,CAAC,CAAC;IAE7D,IAAI,CAAC;QACH,MAAM,OAAO,GAAG;YACd,eAAe,EAAE;gBACf,WAAW,EAAE;oBACX,EAAE,EAAE,EAAE,OAAO;oBACb,MAAM,EAAE,QAAQ,CAAC,OAAO,CAAC,MAAM;oBAC/B,GAAG,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG;oBACzB,OAAO,EAAE,QAAQ,CAAC,OAAO,CAAC,OAAO;oBACjC,YAAY,EAAE,SAAS,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC;oBAC9C,aAAa,EAAE,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC;oBAChD,gBAAgB,EAAE,QAAQ,CAAC,QAAQ,CAAC,OAAO;oBAC3C,WAAW,EAAE,QAAQ,CAAC,QAAQ,CAAC,UAAU;oBACzC,SAAS,EAAE,QAAQ,CAAC,SAAS;oBAC7B,QAAQ,EAAE,IAAI,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC;iBAClE;gBACD,SAAS,EAAE,OAAO,CAAC,SAAS,IAAI,GAAG,kBAAkB,SAAS;aAC/D;SACF,CAAC;QAEF,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,QAAQ,EAAE;YACrC,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,WAAW,EAAE,MAAM;aACpB;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;YAC7B,MAAM,EAAE,UAAU,CAAC,MAAM;SAC1B,CAAC,CAAC;QACH,wEAAwE;QACxE,kEAAkE;QAClE,YAAY,CAAC,OAAO,CAAC,CAAC;QAEtB,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,IAAI,CAAC,MAAM,EAAE,CAAC;gBACZ,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;gBACnC,OAAO,CAAC,KAAK,CACX,gDAAgD,QAAQ,CAAC,MAAM,MAAM,IAAI,EAAE,CAC5E,CAAC;YACJ,CAAC;QACH,CAAC;aAAM,IAAI,CAAC,MAAM,EAAE,CAAC;YACnB,OAAO,CAAC,KAAK,CAAC,2BAA2B,QAAQ,CAAC,OAAO,CAAC,MAAM,IAAI,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;QAC9F,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,YAAY,CAAC,OAAO,CAAC,CAAC;QACtB,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAO,CAAC,KAAK,CAAC,8CAA8C,EAAE,KAAK,CAAC,CAAC;QACvE,CAAC;IACH,CAAC;AACH,CAAC"}
@@ -0,0 +1,36 @@
1
+ import { spawn } from 'child_process';
2
+ import { startProxy, type ProxyInstance } from './proxy.js';
3
+ import { getOrCreateCA } from './certs.js';
4
+ export interface WrapDeps {
5
+ spawnFn?: typeof spawn;
6
+ startProxyFn?: (ca: Awaited<ReturnType<typeof getOrCreateCA>>, opts: Parameters<typeof startProxy>[1]) => Promise<ProxyInstance>;
7
+ }
8
+ /**
9
+ * On Windows, .cmd shims cannot be spawned without a shell. Rather than using
10
+ * shell:true (which forwards args as an unquoted string to cmd.exe, enabling
11
+ * metacharacter injection), we invoke cmd.exe /d /s /c directly with each arg
12
+ * double-quoted and windowsVerbatimArguments:true so Node does not re-quote them.
13
+ *
14
+ * Quoting rules applied per arg:
15
+ * 1. Double trailing backslashes (a trailing \ would escape the closing ")
16
+ * 2. Escape embedded " as ""
17
+ * 3. Escape % as %% to prevent cmd.exe environment-variable expansion
18
+ * 4. Wrap in double quotes unconditionally
19
+ */
20
+ export declare function resolveWrapSpawn(cmd: string, args: string[], platform?: NodeJS.Platform): {
21
+ cmd: string;
22
+ spawnArgs: string[];
23
+ windowsVerbatimArguments?: true;
24
+ };
25
+ /**
26
+ * Build the full ingest endpoint for a given client's base_url.
27
+ * The CLI stores only the site base_url, so append the ingest path here.
28
+ * Returns undefined for the default base_url (the proxy already uses the right endpoint).
29
+ */
30
+ export declare function endpointForBaseUrl(baseUrl: string): string | undefined;
31
+ /**
32
+ * Run an arbitrary child command behind the Coolhand proxy with the stored API key
33
+ * filled in. Starts an in-process HTTPS MITM proxy and spawns `cmd` with proxy env vars.
34
+ */
35
+ export declare function runWrapped(cmd: string, args: string[], clientId: string | undefined, deps?: WrapDeps): Promise<number>;
36
+ //# sourceMappingURL=wrap-runner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wrap-runner.d.ts","sourceRoot":"","sources":["../../src/proxy/wrap-runner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAKtC,OAAO,EAAE,UAAU,EAAE,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAe,MAAM,YAAY,CAAC;AAGxD,MAAM,WAAW,QAAQ;IACvB,OAAO,CAAC,EAAE,OAAO,KAAK,CAAC;IACvB,YAAY,CAAC,EAAE,CAAC,EAAE,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO,aAAa,CAAC,CAAC,EAAE,IAAI,EAAE,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,aAAa,CAAC,CAAC;CAClI;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EAAE,EACd,QAAQ,kBAAmB,GAC1B;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,EAAE,CAAC;IAAC,wBAAwB,CAAC,EAAE,IAAI,CAAA;CAAE,CAgBvE;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAKtE;AAED;;;GAGG;AACH,wBAAsB,UAAU,CAC9B,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EAAE,EACd,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,IAAI,GAAE,QAAa,GAClB,OAAO,CAAC,MAAM,CAAC,CA4FjB"}
@@ -0,0 +1,153 @@
1
+ import { spawn } from 'child_process';
2
+ import { ExitCode, CliError } from '../errors.js';
3
+ import { logger, redact } from '../logger.js';
4
+ import { loadConfig, resolveClient } from '../config.js';
5
+ import { DEFAULT_BASE_URL } from '../types.js';
6
+ import { startProxy } from './proxy.js';
7
+ import { getOrCreateCA, getCertPath } from './certs.js';
8
+ import { PACKAGE_IDENTIFIER } from '../version.js';
9
+ /**
10
+ * On Windows, .cmd shims cannot be spawned without a shell. Rather than using
11
+ * shell:true (which forwards args as an unquoted string to cmd.exe, enabling
12
+ * metacharacter injection), we invoke cmd.exe /d /s /c directly with each arg
13
+ * double-quoted and windowsVerbatimArguments:true so Node does not re-quote them.
14
+ *
15
+ * Quoting rules applied per arg:
16
+ * 1. Double trailing backslashes (a trailing \ would escape the closing ")
17
+ * 2. Escape embedded " as ""
18
+ * 3. Escape % as %% to prevent cmd.exe environment-variable expansion
19
+ * 4. Wrap in double quotes unconditionally
20
+ */
21
+ export function resolveWrapSpawn(cmd, args, platform = process.platform) {
22
+ if (platform !== 'win32') {
23
+ return { cmd, spawnArgs: args };
24
+ }
25
+ const escaped = args.map((a) => {
26
+ const s = a
27
+ .replace(/(\\+)$/, '$1$1') // double trailing backslashes
28
+ .replace(/"/g, '""') // escape embedded quotes
29
+ .replace(/%/g, '%%'); // prevent env-var expansion
30
+ return `"${s}"`;
31
+ });
32
+ return {
33
+ cmd: process.env['ComSpec'] ?? 'cmd.exe',
34
+ spawnArgs: ['/d', '/s', '/c', [`"${cmd}"`, ...escaped].join(' ')],
35
+ windowsVerbatimArguments: true,
36
+ };
37
+ }
38
+ /**
39
+ * Build the full ingest endpoint for a given client's base_url.
40
+ * The CLI stores only the site base_url, so append the ingest path here.
41
+ * Returns undefined for the default base_url (the proxy already uses the right endpoint).
42
+ */
43
+ export function endpointForBaseUrl(baseUrl) {
44
+ if (!baseUrl || baseUrl === DEFAULT_BASE_URL) {
45
+ return undefined;
46
+ }
47
+ return `${baseUrl.replace(/\/+$/, '')}/api/v2/llm_request_logs`;
48
+ }
49
+ /**
50
+ * Run an arbitrary child command behind the Coolhand proxy with the stored API key
51
+ * filled in. Starts an in-process HTTPS MITM proxy and spawns `cmd` with proxy env vars.
52
+ */
53
+ export async function runWrapped(cmd, args, clientId, deps = {}) {
54
+ const spawnFn = deps.spawnFn ?? spawn;
55
+ try {
56
+ const cfg = await loadConfig();
57
+ const entry = await resolveClient(cfg, clientId);
58
+ if (!entry.api_key) {
59
+ throw new CliError('NOT_CONFIGURED', 'This client has no public API key — LLM capture requires the public key. Run `coolhand login` to re-authenticate.');
60
+ }
61
+ const ca = await getOrCreateCA();
62
+ const certPath = getCertPath();
63
+ const apiEndpoint = endpointForBaseUrl(entry.base_url);
64
+ const proxy = await (deps.startProxyFn ?? startProxy)(ca, {
65
+ apiKey: entry.api_key,
66
+ apiEndpoint,
67
+ silent: true,
68
+ collector: `${PACKAGE_IDENTIFIER}/${cmd}`,
69
+ });
70
+ return new Promise((resolve) => {
71
+ let stopped = false;
72
+ // stopped is set synchronously before the first await so concurrent
73
+ // callers (error + close can both fire) see it immediately and skip.
74
+ const stopOnce = () => {
75
+ if (stopped) {
76
+ return Promise.resolve();
77
+ }
78
+ stopped = true;
79
+ return proxy.stop();
80
+ };
81
+ let child;
82
+ try {
83
+ const { cmd: spawnCmd, spawnArgs, windowsVerbatimArguments } = resolveWrapSpawn(cmd, args);
84
+ child = spawnFn(spawnCmd, spawnArgs, {
85
+ stdio: 'inherit',
86
+ windowsVerbatimArguments,
87
+ env: {
88
+ ...process.env,
89
+ COOLHAND_API_KEY: entry.api_key,
90
+ HTTP_PROXY: `http://127.0.0.1:${proxy.port}`,
91
+ HTTPS_PROXY: `http://127.0.0.1:${proxy.port}`,
92
+ NO_PROXY: 'localhost,127.0.0.1,::1',
93
+ SSL_CERT_FILE: certPath,
94
+ NODE_EXTRA_CA_CERTS: certPath,
95
+ REQUESTS_CA_BUNDLE: certPath,
96
+ },
97
+ });
98
+ }
99
+ catch (spawnErr) {
100
+ if (spawnErr instanceof Error) {
101
+ logger.info(`Error: ${redact(spawnErr.message)}`);
102
+ }
103
+ // Chain .catch → .then so resolve() is called only after stop() drains,
104
+ // mirroring the error/close handler pattern and avoiding abandoned sends.
105
+ stopOnce()
106
+ .catch((e) => {
107
+ const msg = e instanceof Error ? redact(e.message) : String(e);
108
+ logger.info(`Error: ${msg}`);
109
+ })
110
+ .then(() => resolve(ExitCode.INTERNAL));
111
+ return;
112
+ }
113
+ child.on('error', async (err) => {
114
+ try {
115
+ await stopOnce();
116
+ }
117
+ catch (stopErr) {
118
+ if (stopErr instanceof Error) {
119
+ logger.info(`Error: ${redact(stopErr.message)}`);
120
+ }
121
+ }
122
+ finally {
123
+ logger.info(`Error: ${redact(err.message)}`);
124
+ resolve(ExitCode.INTERNAL);
125
+ }
126
+ });
127
+ child.on('close', async (code) => {
128
+ try {
129
+ await stopOnce();
130
+ }
131
+ catch (stopErr) {
132
+ if (stopErr instanceof Error) {
133
+ logger.info(`Error: ${redact(stopErr.message)}`);
134
+ }
135
+ }
136
+ finally {
137
+ resolve(code ?? ExitCode.INTERNAL);
138
+ }
139
+ });
140
+ });
141
+ }
142
+ catch (err) {
143
+ if (err instanceof CliError) {
144
+ logger.info(`Error: ${redact(err.message)} [${err.code}]`);
145
+ return err.exitCode;
146
+ }
147
+ if (err instanceof Error) {
148
+ logger.info(`Error: ${redact(err.message)}`);
149
+ }
150
+ return ExitCode.INTERNAL;
151
+ }
152
+ }
153
+ //# sourceMappingURL=wrap-runner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wrap-runner.js","sourceRoot":"","sources":["../../src/proxy/wrap-runner.ts"],"names":[],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  export interface ClientEntry {
2
2
  client_id: string;
3
3
  client_name: string;
4
- api_key: string;
4
+ api_key?: string;
5
5
  private_key?: string;
6
6
  base_url: string;
7
7
  saved_at: string;
@@ -35,7 +35,7 @@ export interface ClientsOptions {
35
35
  json?: boolean;
36
36
  }
37
37
  export interface CallbackResult {
38
- token: string;
38
+ token?: string;
39
39
  clientName: string;
40
40
  clientId: string;
41
41
  private_token?: string;
@@ -50,6 +50,28 @@ export interface StatusOutput {
50
50
  }>;
51
51
  default_client_id: string | null;
52
52
  }
53
+ export interface ListWorkloadsOptions {
54
+ search?: string;
55
+ page?: number;
56
+ perPage?: number;
57
+ includeArchived?: boolean;
58
+ includeSystem?: boolean;
59
+ includeTemplates?: boolean;
60
+ json?: boolean;
61
+ clientId?: string;
62
+ }
63
+ export interface GetWorkloadOptions {
64
+ id: string;
65
+ json?: boolean;
66
+ clientId?: string;
67
+ }
68
+ export interface UpdateWorkloadOptions {
69
+ id: string;
70
+ name?: string;
71
+ description?: string;
72
+ json?: boolean;
73
+ clientId?: string;
74
+ }
53
75
  export interface SearchOptimizationsOptions {
54
76
  status?: string;
55
77
  type?: string;
@@ -102,6 +124,11 @@ export interface ClaudeOptions {
102
124
  args: string[];
103
125
  clientId?: string;
104
126
  }
127
+ export interface MonitorOptions {
128
+ command: string;
129
+ args: string[];
130
+ clientId?: string;
131
+ }
105
132
  export declare const DEFAULT_BASE_URL = "https://coolhandlabs.com";
106
133
  export declare const DEFAULT_TIMEOUT_MS: number;
107
134
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAyHA,MAAM,CAAC,MAAM,gBAAgB,GAAG,0BAA0B,CAAC;AAC3D,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC"}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AA0JA,MAAM,CAAC,MAAM,gBAAgB,GAAG,0BAA0B,CAAC;AAC3D,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC"}
package/dist/version.d.ts CHANGED
@@ -2,10 +2,10 @@
2
2
  * Auto-generated from package.json — do not edit manually.
3
3
  * Run `npm run sync-version` or `npm run build` to regenerate.
4
4
  */
5
- export declare const PACKAGE_VERSION = "0.5.2";
5
+ export declare const PACKAGE_VERSION = "0.7.0";
6
6
  export declare const PACKAGE_NAME = "coolhand-cli";
7
7
  /**
8
8
  * Full package identifier
9
9
  */
10
- export declare const PACKAGE_IDENTIFIER = "coolhand-cli-0.5.2";
10
+ export declare const PACKAGE_IDENTIFIER = "coolhand-cli-0.7.0";
11
11
  //# sourceMappingURL=version.d.ts.map
package/dist/version.js CHANGED
@@ -2,7 +2,7 @@
2
2
  * Auto-generated from package.json — do not edit manually.
3
3
  * Run `npm run sync-version` or `npm run build` to regenerate.
4
4
  */
5
- export const PACKAGE_VERSION = '0.5.2';
5
+ export const PACKAGE_VERSION = '0.7.0';
6
6
  export const PACKAGE_NAME = 'coolhand-cli';
7
7
  /**
8
8
  * Full package identifier
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "coolhand-cli",
3
- "version": "0.5.2",
3
+ "version": "0.7.0",
4
4
  "description": "CLI for authenticating with Coolhand and retrieving API tokens from a local dev environment",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -60,7 +60,7 @@
60
60
  },
61
61
  "dependencies": {
62
62
  "coolhand-node": "^0.8.0",
63
- "coolhand-proxy": "^0.0.1"
63
+ "mockttp": "^4.2.1"
64
64
  },
65
65
  "overrides": {
66
66
  "js-yaml": "^4.2.0"