coolhand-cli 0.8.0 → 0.10.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.
- package/README.md +6 -2
- package/dist/api/last-sync.d.ts.map +1 -1
- package/dist/api/last-sync.js +2 -1
- package/dist/api/last-sync.js.map +1 -1
- package/dist/api/log-client.d.ts +17 -0
- package/dist/api/log-client.d.ts.map +1 -0
- package/dist/api/log-client.js +40 -0
- package/dist/api/log-client.js.map +1 -0
- package/dist/base-url.d.ts +7 -0
- package/dist/base-url.d.ts.map +1 -0
- package/dist/base-url.js +14 -0
- package/dist/base-url.js.map +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +242 -9
- package/dist/cli.js.map +1 -1
- package/dist/commands/analyze-claude-sessions.d.ts.map +1 -1
- package/dist/commands/analyze-claude-sessions.js +10 -21
- package/dist/commands/analyze-claude-sessions.js.map +1 -1
- package/dist/commands/fetch-log.d.ts +3 -0
- package/dist/commands/fetch-log.d.ts.map +1 -0
- package/dist/commands/fetch-log.js +42 -0
- package/dist/commands/fetch-log.js.map +1 -0
- package/dist/commands/login.d.ts.map +1 -1
- package/dist/commands/login.js +3 -2
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/map-claude-projects.d.ts +22 -0
- package/dist/commands/map-claude-projects.d.ts.map +1 -0
- package/dist/commands/map-claude-projects.js +282 -0
- package/dist/commands/map-claude-projects.js.map +1 -0
- package/dist/commands/search-logs.d.ts +3 -0
- package/dist/commands/search-logs.d.ts.map +1 -0
- package/dist/commands/search-logs.js +77 -0
- package/dist/commands/search-logs.js.map +1 -0
- package/dist/commands/upload-client-file.d.ts +3 -0
- package/dist/commands/upload-client-file.d.ts.map +1 -0
- package/dist/commands/upload-client-file.js +43 -0
- package/dist/commands/upload-client-file.js.map +1 -0
- package/dist/commands/wildcard.d.ts +6 -6
- package/dist/commands/wildcard.d.ts.map +1 -1
- package/dist/commands/wildcard.js +14 -11
- package/dist/commands/wildcard.js.map +1 -1
- package/dist/config.d.ts +11 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +31 -8
- package/dist/config.js.map +1 -1
- package/dist/errors.d.ts +1 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js.map +1 -1
- package/dist/log-request.d.ts +4 -0
- package/dist/log-request.d.ts.map +1 -1
- package/dist/log-request.js +8 -1
- package/dist/log-request.js.map +1 -1
- package/dist/logger.d.ts +1 -0
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +30 -1
- package/dist/logger.js.map +1 -1
- package/dist/proxy/certs.d.ts.map +1 -1
- package/dist/proxy/certs.js +145 -5
- package/dist/proxy/certs.js.map +1 -1
- package/dist/proxy/interceptor.d.ts +8 -1
- package/dist/proxy/interceptor.d.ts.map +1 -1
- package/dist/proxy/interceptor.js +36 -3
- package/dist/proxy/interceptor.js.map +1 -1
- package/dist/proxy/proxy.d.ts.map +1 -1
- package/dist/proxy/proxy.js +4 -3
- package/dist/proxy/proxy.js.map +1 -1
- package/dist/proxy/wrap-runner.d.ts +0 -12
- package/dist/proxy/wrap-runner.d.ts.map +1 -1
- package/dist/proxy/wrap-runner.js +24 -11
- package/dist/proxy/wrap-runner.js.map +1 -1
- package/dist/sessions/claude-scanner.d.ts +3 -0
- package/dist/sessions/claude-scanner.d.ts.map +1 -1
- package/dist/sessions/claude-scanner.js +8 -0
- package/dist/sessions/claude-scanner.js.map +1 -1
- package/dist/sessions/cowork-scanner.d.ts.map +1 -1
- package/dist/sessions/cowork-scanner.js +6 -1
- package/dist/sessions/cowork-scanner.js.map +1 -1
- package/dist/sessions/redact-secrets.d.ts.map +1 -1
- package/dist/sessions/redact-secrets.js +10 -2
- package/dist/sessions/redact-secrets.js.map +1 -1
- package/dist/sessions/session-filter.d.ts +3 -1
- package/dist/sessions/session-filter.d.ts.map +1 -1
- package/dist/sessions/session-filter.js +9 -3
- package/dist/sessions/session-filter.js.map +1 -1
- package/dist/types.d.ts +48 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/upload-client-file.d.ts +31 -0
- package/dist/upload-client-file.d.ts.map +1 -0
- package/dist/upload-client-file.js +81 -0
- package/dist/upload-client-file.js.map +1 -0
- package/dist/version.d.ts +2 -2
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/package.json +10 -8
package/README.md
CHANGED
|
@@ -37,7 +37,7 @@ See [Session capture](./docs/session-capture.md) for capture logic, duplicate-av
|
|
|
37
37
|
|
|
38
38
|
## Wildcard (agent complaint box)
|
|
39
39
|
|
|
40
|
-
When an agent is blocked because a capability does not exist in its environment, it can record the blocker and get back an unambiguous "stop and move on" response:
|
|
40
|
+
When an agent is blocked — because a capability does not exist in its environment, or because a task would take too long to complete — it can record the blocker and get back an unambiguous "stop and move on" response:
|
|
41
41
|
|
|
42
42
|
```bash
|
|
43
43
|
coolhand wildcard \
|
|
@@ -46,7 +46,7 @@ coolhand wildcard \
|
|
|
46
46
|
--thinking "I attempted to connect to localhost:5432 but got connection refused. I checked for a running postgres process and found none. Without a live database I cannot apply or validate the migration."
|
|
47
47
|
```
|
|
48
48
|
|
|
49
|
-
The command records the complaint as feedback tagged `creator_type: agent`, prints a terminal de-loop message, and exits `0` so the agent stops and moves on. The de-loop always fires — even if the feedback could not be recorded (not logged in or a server error) — because the missing capability is real regardless of whether the server was reachable, and a logged-out agent in a sandbox is exactly who this command is for. When recording fails the message says so plainly and a warning is logged, so the failure still surfaces without trapping the agent in the retry loop the command exists to break. When no API key is available, the feedback is saved locally to `~/.coolhand/pending/` and will be uploaded automatically the next time you run `coolhand login`.
|
|
49
|
+
The command records the complaint as feedback tagged `creator_type: agent`, prints a terminal de-loop message, and exits `0` so the agent stops and moves on. The de-loop always fires — even if the feedback could not be recorded (not logged in or a server error) — because the blocker (a missing capability, or a task that would take too long) is real regardless of whether the server was reachable, and a logged-out agent in a sandbox is exactly who this command is for. When recording fails the message says so plainly and a warning is logged, so the failure still surfaces without trapping the agent in the retry loop the command exists to break. When no API key is available, the feedback is saved locally to `~/.coolhand/pending/` and will be uploaded automatically the next time you run `coolhand login`.
|
|
50
50
|
|
|
51
51
|
Set `COOLHAND_AGENT_NAME` to avoid passing `--agent-name` on every call. Optional `--thinking` attaches the reasoning that led to the blocker; `--log-id` ties it to a specific LLM request log.
|
|
52
52
|
|
|
@@ -89,7 +89,11 @@ coolhand close-optimization opt-123 "Added the suggested index; verified query l
|
|
|
89
89
|
| `coolhand close-optimization` | Close an optimization with a reason |
|
|
90
90
|
| `coolhand search-feedback` | Search and filter feedback records |
|
|
91
91
|
| `coolhand get-feedback` | Fetch a single feedback record by ID |
|
|
92
|
+
| `coolhand fetch-log` | Fetch the input/output content of a single LLM request log |
|
|
93
|
+
| `coolhand search-logs` | Search LLM request logs with flexible filters |
|
|
92
94
|
| `coolhand analyze-claude-sessions` | Submit Claude sessions for pattern and cost analysis |
|
|
95
|
+
| `coolhand map-claude-projects` | Upload a file-tree map (names + metadata only) of every folder named "claude" |
|
|
96
|
+
| `coolhand upload-client-file` | Upload a local file to Coolhand as a client file |
|
|
93
97
|
| `coolhand wildcard` | Record an agent blocker and exit cleanly |
|
|
94
98
|
|
|
95
99
|
See [docs/commands.md](./docs/commands.md) for full flag reference and usage notes.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"last-sync.d.ts","sourceRoot":"","sources":["../../src/api/last-sync.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"last-sync.d.ts","sourceRoot":"","sources":["../../src/api/last-sync.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,aAAa,CAAC,IAAI,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,CAmE1F"}
|
package/dist/api/last-sync.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { loadConfig, getClient } from '../config.js';
|
|
2
|
+
import { isAllowedBaseUrlScheme } from '../base-url.js';
|
|
2
3
|
import { DEFAULT_BASE_URL } from '../types.js';
|
|
3
4
|
/**
|
|
4
5
|
* Ask the server for the timestamp of the most recent Claude Code log it already holds, so
|
|
@@ -37,7 +38,7 @@ export async function fetchLastSync(opts = {}) {
|
|
|
37
38
|
let url;
|
|
38
39
|
try {
|
|
39
40
|
const parsedBaseUrl = new URL(baseUrl);
|
|
40
|
-
if (parsedBaseUrl
|
|
41
|
+
if (!isAllowedBaseUrlScheme(parsedBaseUrl)) {
|
|
41
42
|
return null;
|
|
42
43
|
}
|
|
43
44
|
const endpoint = new URL('/api/v2/llm_request_logs', parsedBaseUrl);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"last-sync.js","sourceRoot":"","sources":["../../src/api/last-sync.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE/C;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,OAA8B,EAAE;IAClE,IAAI,MAA0B,CAAC;IAC/B,IAAI,OAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,UAAU,EAAE,CAAC;QAC/B,MAAM,MAAM,GAAG,SAAS,CAAC,GAAG,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC7C,MAAM,GAAG,MAAM,EAAE,WAAW,IAAI,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC;QACjE,OAAO,GAAG,MAAM,EAAE,QAAQ,IAAI,gBAAgB,CAAC;IACjD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,GAAW,CAAC;IAChB,IAAI,CAAC;QACH,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC;QACvC,IAAI,
|
|
1
|
+
{"version":3,"file":"last-sync.js","sourceRoot":"","sources":["../../src/api/last-sync.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Coolhand } from 'coolhand-node';
|
|
2
|
+
import { CliError } from '../errors.js';
|
|
3
|
+
/**
|
|
4
|
+
* Resolves the CLI's stored client and returns a `Coolhand` instance authenticated with its
|
|
5
|
+
* *private* key. `getLogContent`/`searchLogs` require the private key — the public key used by
|
|
6
|
+
* `monitor`/`logRequest` will 401 here.
|
|
7
|
+
*/
|
|
8
|
+
export declare function getLogClient(opts?: {
|
|
9
|
+
clientId?: string;
|
|
10
|
+
}): Promise<Coolhand>;
|
|
11
|
+
/**
|
|
12
|
+
* Maps an error thrown by `Coolhand#getLogContent`/`searchLogs` to a `CliError` with a clear,
|
|
13
|
+
* actionable message — a 401 means the stored private key was rejected (mirrors `feedback-client.ts`'s
|
|
14
|
+
* hint), a 404 uses the caller-supplied message (e.g. `Log "x" not found`).
|
|
15
|
+
*/
|
|
16
|
+
export declare function mapLogHttpError(err: unknown, notFoundMessage: string): CliError;
|
|
17
|
+
//# sourceMappingURL=log-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log-client.d.ts","sourceRoot":"","sources":["../../src/api/log-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAa,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAGxC;;;;GAIG;AACH,wBAAsB,YAAY,CAAC,IAAI,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,CAoBtF;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,GAAG,QAAQ,CAc/E"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Coolhand, HttpError } from 'coolhand-node';
|
|
2
|
+
import { CliError } from '../errors.js';
|
|
3
|
+
import { loadConfig, resolveClient } from '../config.js';
|
|
4
|
+
/**
|
|
5
|
+
* Resolves the CLI's stored client and returns a `Coolhand` instance authenticated with its
|
|
6
|
+
* *private* key. `getLogContent`/`searchLogs` require the private key — the public key used by
|
|
7
|
+
* `monitor`/`logRequest` will 401 here.
|
|
8
|
+
*/
|
|
9
|
+
export async function getLogClient(opts = {}) {
|
|
10
|
+
const cfg = await loadConfig();
|
|
11
|
+
const client = await resolveClient(cfg, opts.clientId);
|
|
12
|
+
if (!client.private_key) {
|
|
13
|
+
throw new CliError('NO_PRIVATE_KEY', "No private key configured. Run 'coolhand login --scope private' first.");
|
|
14
|
+
}
|
|
15
|
+
try {
|
|
16
|
+
// Coolhand validates baseUrl in its constructor (https required; http only for localhost).
|
|
17
|
+
return new Coolhand({ apiKey: client.private_key, baseUrl: client.base_url, silent: true });
|
|
18
|
+
}
|
|
19
|
+
catch (err) {
|
|
20
|
+
throw new CliError('INVALID_BASE_URL', `Invalid base_url for client: ${client.base_url} (${err.message})`);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Maps an error thrown by `Coolhand#getLogContent`/`searchLogs` to a `CliError` with a clear,
|
|
25
|
+
* actionable message — a 401 means the stored private key was rejected (mirrors `feedback-client.ts`'s
|
|
26
|
+
* hint), a 404 uses the caller-supplied message (e.g. `Log "x" not found`).
|
|
27
|
+
*/
|
|
28
|
+
export function mapLogHttpError(err, notFoundMessage) {
|
|
29
|
+
if (err instanceof HttpError) {
|
|
30
|
+
if (err.status === 401) {
|
|
31
|
+
return new CliError('LOG_ERROR', "The stored private key was rejected. Run 'coolhand login --scope private' to re-authenticate.");
|
|
32
|
+
}
|
|
33
|
+
if (err.status === 404) {
|
|
34
|
+
return new CliError('LOG_ERROR', notFoundMessage);
|
|
35
|
+
}
|
|
36
|
+
return new CliError('LOG_ERROR', `Log request failed (${err.status}): ${err.message}`);
|
|
37
|
+
}
|
|
38
|
+
return new CliError('LOG_ERROR', `Log request failed: ${err.message}`);
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=log-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log-client.js","sourceRoot":"","sources":["../../src/api/log-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACxC,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAEzD;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,OAA8B,EAAE;IACjE,MAAM,GAAG,GAAG,MAAM,UAAU,EAAE,CAAC;IAC/B,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,GAAG,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;IAEvD,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;QACxB,MAAM,IAAI,QAAQ,CAChB,gBAAgB,EAChB,wEAAwE,CACzE,CAAC;IACJ,CAAC;IAED,IAAI,CAAC;QACH,2FAA2F;QAC3F,OAAO,IAAI,QAAQ,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,WAAW,EAAE,OAAO,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9F,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,QAAQ,CAChB,kBAAkB,EAClB,gCAAgC,MAAM,CAAC,QAAQ,KAAM,GAAa,CAAC,OAAO,GAAG,CAC9E,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,GAAY,EAAE,eAAuB;IACnE,IAAI,GAAG,YAAY,SAAS,EAAE,CAAC;QAC7B,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YACvB,OAAO,IAAI,QAAQ,CACjB,WAAW,EACX,+FAA+F,CAChG,CAAC;QACJ,CAAC;QACD,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YACvB,OAAO,IAAI,QAAQ,CAAC,WAAW,EAAE,eAAe,CAAC,CAAC;QACpD,CAAC;QACD,OAAO,IAAI,QAAQ,CAAC,WAAW,EAAE,uBAAuB,GAAG,CAAC,MAAM,MAAM,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;IACzF,CAAC;IACD,OAAO,IAAI,QAAQ,CAAC,WAAW,EAAE,uBAAwB,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;AACpF,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mirrors the scheme rule coolhand-node's `BaseService` enforces on `baseUrl`:
|
|
3
|
+
* https:// is always allowed; http:// only for localhost/127.0.0.1/[::1].
|
|
4
|
+
*/
|
|
5
|
+
export declare function isLoopbackHostname(hostname: string): boolean;
|
|
6
|
+
export declare function isAllowedBaseUrlScheme(url: URL): boolean;
|
|
7
|
+
//# sourceMappingURL=base-url.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base-url.d.ts","sourceRoot":"","sources":["../src/base-url.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAE5D;AAED,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAKxD"}
|
package/dist/base-url.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mirrors the scheme rule coolhand-node's `BaseService` enforces on `baseUrl`:
|
|
3
|
+
* https:// is always allowed; http:// only for localhost/127.0.0.1/[::1].
|
|
4
|
+
*/
|
|
5
|
+
export function isLoopbackHostname(hostname) {
|
|
6
|
+
return hostname === 'localhost' || hostname === '127.0.0.1' || hostname === '[::1]';
|
|
7
|
+
}
|
|
8
|
+
export function isAllowedBaseUrlScheme(url) {
|
|
9
|
+
if (url.protocol === 'https:') {
|
|
10
|
+
return true;
|
|
11
|
+
}
|
|
12
|
+
return url.protocol === 'http:' && isLoopbackHostname(url.hostname);
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=base-url.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base-url.js","sourceRoot":"","sources":["../src/base-url.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,QAAgB;IACjD,OAAO,QAAQ,KAAK,WAAW,IAAI,QAAQ,KAAK,WAAW,IAAI,QAAQ,KAAK,OAAO,CAAC;AACtF,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,GAAQ;IAC7C,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,GAAG,CAAC,QAAQ,KAAK,OAAO,IAAI,kBAAkB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AACtE,CAAC"}
|
package/dist/cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAmDA,UAAU,UAAU;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,EAAE,CAAC,CAAC;CACpD;AAmVD;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG;IAAE,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,CAgE7F;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,UAAU,CAiDpD;AAwnBD,wBAAsB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CA8IzD"}
|
package/dist/cli.js
CHANGED
|
@@ -14,15 +14,19 @@ import { run as runWildcard } from './commands/wildcard.js';
|
|
|
14
14
|
import { run as runClaude } from './commands/claude.js';
|
|
15
15
|
import { run as runMonitor } from './commands/monitor.js';
|
|
16
16
|
import { run as runAnalyzeClaudeSessions } from './commands/analyze-claude-sessions.js';
|
|
17
|
+
import { run as runMapClaudeProjects } from './commands/map-claude-projects.js';
|
|
18
|
+
import { run as runUploadClientFile } from './commands/upload-client-file.js';
|
|
17
19
|
import { run as runListWorkloads } from './commands/list-workloads.js';
|
|
18
20
|
import { run as runGetWorkload } from './commands/get-workload.js';
|
|
19
21
|
import { run as runUpdateWorkload } from './commands/update-workload.js';
|
|
22
|
+
import { run as runFetchLog } from './commands/fetch-log.js';
|
|
23
|
+
import { run as runSearchLogs } from './commands/search-logs.js';
|
|
20
24
|
import { run as runFlushPending, spawnBackgroundFlush } from './commands/flush-pending.js';
|
|
21
25
|
import { run as runSearchFeedback } from './commands/search-feedback.js';
|
|
22
26
|
import { run as runGetFeedback } from './commands/get-feedback.js';
|
|
23
27
|
import { countPending, flushFailed } from './pending-store.js';
|
|
24
28
|
import { confirm } from './prompt.js';
|
|
25
|
-
const BOOLEAN_FLAGS = new Set(['all', 'help', 'h', 'json', 'version', 'v', 'dry-run', 'include-archived', 'include-system', 'include-templates', 'full', 'matched', 'unmatched']);
|
|
29
|
+
const BOOLEAN_FLAGS = new Set(['all', 'help', 'h', 'json', 'version', 'v', 'dry-run', 'include-archived', 'include-system', 'include-templates', 'full', 'matched', 'unmatched', 'include-thinking', 'unmatched-only', 'include-prompts']);
|
|
26
30
|
/** Flags whose repeated occurrences accumulate into an array instead of overwriting. */
|
|
27
31
|
const REPEATABLE_FLAGS = new Set(['project', 'exclude-project']);
|
|
28
32
|
const COMMANDS = [
|
|
@@ -35,6 +39,7 @@ const COMMANDS = [
|
|
|
35
39
|
{ flag: '--scope private', description: 'Request a private key alongside the public key' },
|
|
36
40
|
{ flag: '--write-env PATH', description: 'Idempotently set COOLHAND_API_KEY (and COOLHAND_PRIVATE_KEY if --scope private) in PATH' },
|
|
37
41
|
{ flag: '--client-id ID', description: 'Hint to the server about which client to select' },
|
|
42
|
+
{ flag: '--timeout-ms MS', description: 'How long to wait for the browser callback (default: 300000, i.e. 5 minutes)' },
|
|
38
43
|
{ flag: '--json', description: 'Emit JSON output instead of human-readable text' },
|
|
39
44
|
],
|
|
40
45
|
},
|
|
@@ -45,6 +50,7 @@ const COMMANDS = [
|
|
|
45
50
|
options: [
|
|
46
51
|
{ flag: '--client-id ID', description: 'Remove a specific client' },
|
|
47
52
|
{ flag: '--all', description: 'Remove every stored client' },
|
|
53
|
+
{ flag: '--json', description: 'Emit JSON output instead of human-readable text' },
|
|
48
54
|
],
|
|
49
55
|
},
|
|
50
56
|
{
|
|
@@ -127,10 +133,13 @@ const COMMANDS = [
|
|
|
127
133
|
{
|
|
128
134
|
name: 'wildcard',
|
|
129
135
|
aliases: ['complaint-box', 'report-blocker'],
|
|
130
|
-
oneLiner: 'Agent complaint box: report
|
|
136
|
+
oneLiner: 'Agent complaint box: report a missing capability or a task that would take too long, and stop',
|
|
131
137
|
usage: 'coolhand wildcard --complaint "<what is blocking you>" --agent-name <name> [options]',
|
|
132
138
|
options: [
|
|
133
|
-
{
|
|
139
|
+
{
|
|
140
|
+
flag: '--complaint TEXT',
|
|
141
|
+
description: 'What capability is missing, or why the task would take too long (required)',
|
|
142
|
+
},
|
|
134
143
|
{ flag: '--agent-name NAME', description: 'Identifier for the calling agent (or set COOLHAND_AGENT_NAME)' },
|
|
135
144
|
{ flag: '--thinking TEXT', description: 'Optional reasoning/context that led to the blocker' },
|
|
136
145
|
{ flag: '--log-id N', description: 'Optional LLM request log id this blocker relates to' },
|
|
@@ -182,6 +191,31 @@ const COMMANDS = [
|
|
|
182
191
|
{ flag: '--exclude-project NAME', description: 'Skip sessions from matching project folders (repeatable, comma-separable)' },
|
|
183
192
|
],
|
|
184
193
|
},
|
|
194
|
+
{
|
|
195
|
+
name: 'map-claude-projects',
|
|
196
|
+
oneLiner: 'Upload a file-tree map (names + metadata, no file contents) of every folder named "claude" found under the home directory',
|
|
197
|
+
usage: 'coolhand map-claude-projects [options]',
|
|
198
|
+
options: [
|
|
199
|
+
{ flag: '--root PATH', description: 'Search PATH instead of the home directory' },
|
|
200
|
+
{ flag: '--output PATH', description: 'Also write the generated markdown report to PATH, for local inspection' },
|
|
201
|
+
{ flag: '--dry-run', description: 'Build the map and report its size without uploading' },
|
|
202
|
+
{ flag: '--client-id ID', description: 'Use a specific stored client' },
|
|
203
|
+
{ flag: '--json', description: 'Emit JSON output instead of human-readable text' },
|
|
204
|
+
],
|
|
205
|
+
},
|
|
206
|
+
{
|
|
207
|
+
name: 'upload-client-file',
|
|
208
|
+
oneLiner: 'Upload a local file to Coolhand as a client file',
|
|
209
|
+
usage: 'coolhand upload-client-file <file-path> [options]',
|
|
210
|
+
options: [
|
|
211
|
+
{ flag: '--name NAME', description: 'Display name for the client file (defaults to the filename)' },
|
|
212
|
+
{ flag: '--file-type TYPE', description: 'One of: slide_deck, report, document (defaults to document)' },
|
|
213
|
+
{ flag: '--description TEXT', description: 'Optional description' },
|
|
214
|
+
{ flag: '--dry-run', description: 'Validate and size the file without uploading' },
|
|
215
|
+
{ flag: '--client-id ID', description: 'Use a specific stored client' },
|
|
216
|
+
{ flag: '--json', description: 'Emit JSON output instead of human-readable text' },
|
|
217
|
+
],
|
|
218
|
+
},
|
|
185
219
|
{
|
|
186
220
|
name: 'claude',
|
|
187
221
|
oneLiner: 'Run the Claude CLI through the Coolhand proxy (captures LLM calls)',
|
|
@@ -237,6 +271,41 @@ const COMMANDS = [
|
|
|
237
271
|
{ flag: '--json', description: 'Emit JSON output instead of human-readable text' },
|
|
238
272
|
],
|
|
239
273
|
},
|
|
274
|
+
{
|
|
275
|
+
name: 'fetch-log',
|
|
276
|
+
oneLiner: 'Fetch the input/output content of a single LLM request log',
|
|
277
|
+
usage: 'coolhand fetch-log <log-id> [options]',
|
|
278
|
+
options: [
|
|
279
|
+
{ flag: '--section VALUE', description: 'Which part of each content field to return: full (default), beginning, or end' },
|
|
280
|
+
{ flag: '--max-chars N', description: 'Maximum characters to return per content field' },
|
|
281
|
+
{ flag: '--search-query TEXT', description: 'Search within the log content instead of returning raw content (cannot combine with --section/--max-chars)' },
|
|
282
|
+
{ flag: '--include-thinking', description: 'Include thinking/reasoning response content' },
|
|
283
|
+
{ flag: '--client-id ID', description: 'Use a specific stored client' },
|
|
284
|
+
{ flag: '--json', description: 'Emit JSON output instead of human-readable text' },
|
|
285
|
+
],
|
|
286
|
+
},
|
|
287
|
+
{
|
|
288
|
+
name: 'search-logs',
|
|
289
|
+
oneLiner: 'Search LLM request logs with flexible filters',
|
|
290
|
+
usage: 'coolhand search-logs [options]',
|
|
291
|
+
options: [
|
|
292
|
+
{ flag: '--template-id ID', description: 'Filter by template hashid' },
|
|
293
|
+
{ flag: '--workload-id ID', description: 'Filter by workload hashid (matches all templates in that workload)' },
|
|
294
|
+
{ flag: '--system-prompt-contains TEXT', description: 'Case-insensitive substring to match in the system prompt' },
|
|
295
|
+
{ flag: '--user-prompt-contains TEXT', description: 'Case-insensitive substring to match in the user prompt' },
|
|
296
|
+
{ flag: '--model VALUE', description: "Filter by model name (e.g. 'gpt-4o', 'claude-3-5-sonnet')" },
|
|
297
|
+
{ flag: '--source-api VALUE', description: "Filter by source API (e.g. 'openai', 'anthropic', 'vertex')" },
|
|
298
|
+
{ flag: '--source-api-result VALUE', description: 'Filter by result status: success, failed, operational, unmatched' },
|
|
299
|
+
{ flag: '--unmatched-only', description: 'Only return logs with no assigned template' },
|
|
300
|
+
{ flag: '--days-back N', description: 'Limit to logs created in the last N days (unrestricted if omitted)' },
|
|
301
|
+
{ flag: '--include-prompts', description: 'Include system_prompt and user_prompt in results (may be large)' },
|
|
302
|
+
{ flag: '--sort VALUE', description: "Sort expression, e.g. 'created_at desc' (default: newest first)" },
|
|
303
|
+
{ flag: '--page N', description: 'Page number (default: 1)' },
|
|
304
|
+
{ flag: '--per-page N', description: 'Results per page (default: 25, max: 100)' },
|
|
305
|
+
{ flag: '--client-id ID', description: 'Use a specific stored client' },
|
|
306
|
+
{ flag: '--json', description: 'Emit JSON output instead of human-readable text' },
|
|
307
|
+
],
|
|
308
|
+
},
|
|
240
309
|
{
|
|
241
310
|
name: 'help',
|
|
242
311
|
oneLiner: 'Show this message or per-command help',
|
|
@@ -494,16 +563,20 @@ function searchOptimizationsOptions(parsed) {
|
|
|
494
563
|
opts.to = parsed.flags.to;
|
|
495
564
|
}
|
|
496
565
|
if (typeof parsed.flags['page'] === 'string') {
|
|
497
|
-
const
|
|
498
|
-
|
|
499
|
-
|
|
566
|
+
const raw = parsed.flags['page'];
|
|
567
|
+
const n = parseInt(raw, 10);
|
|
568
|
+
if (!/^\d+$/.test(raw) || isNaN(n) || n < 1) {
|
|
569
|
+
throw new CliError('INVALID_ARGS', '--page must be a positive integer');
|
|
500
570
|
}
|
|
571
|
+
opts.page = n;
|
|
501
572
|
}
|
|
502
573
|
if (typeof parsed.flags['per-page'] === 'string') {
|
|
503
|
-
const
|
|
504
|
-
|
|
505
|
-
|
|
574
|
+
const raw = parsed.flags['per-page'];
|
|
575
|
+
const n = parseInt(raw, 10);
|
|
576
|
+
if (!/^\d+$/.test(raw) || isNaN(n) || n < 1 || n > 50) {
|
|
577
|
+
throw new CliError('INVALID_ARGS', '--per-page must be an integer between 1 and 50');
|
|
506
578
|
}
|
|
579
|
+
opts.perPage = n;
|
|
507
580
|
}
|
|
508
581
|
if (typeof parsed.flags['template-id'] === 'string') {
|
|
509
582
|
opts.templateId = parsed.flags['template-id'];
|
|
@@ -622,6 +695,55 @@ function analyzeClaudeSessionsOptions(parsed) {
|
|
|
622
695
|
}
|
|
623
696
|
return opts;
|
|
624
697
|
}
|
|
698
|
+
function mapClaudeProjectsOptions(parsed) {
|
|
699
|
+
const opts = {};
|
|
700
|
+
if (typeof parsed.flags.root === 'string') {
|
|
701
|
+
opts.root = parsed.flags.root;
|
|
702
|
+
}
|
|
703
|
+
if (typeof parsed.flags.output === 'string') {
|
|
704
|
+
opts.output = parsed.flags.output;
|
|
705
|
+
}
|
|
706
|
+
if (parsed.flags['dry-run'] === true) {
|
|
707
|
+
opts.dryRun = true;
|
|
708
|
+
}
|
|
709
|
+
if (typeof parsed.flags['client-id'] === 'string') {
|
|
710
|
+
opts.clientId = parsed.flags['client-id'];
|
|
711
|
+
}
|
|
712
|
+
if (parsed.flags.json === true) {
|
|
713
|
+
opts.json = true;
|
|
714
|
+
}
|
|
715
|
+
return opts;
|
|
716
|
+
}
|
|
717
|
+
const CLIENT_FILE_TYPES = new Set(['slide_deck', 'report', 'document']);
|
|
718
|
+
function uploadClientFileOptions(parsed) {
|
|
719
|
+
const filePath = parsed.positional[0];
|
|
720
|
+
if (!filePath) {
|
|
721
|
+
throw new CliError('INVALID_ARGS', 'upload-client-file requires a <file-path> argument');
|
|
722
|
+
}
|
|
723
|
+
const opts = { filePath };
|
|
724
|
+
if (typeof parsed.flags.name === 'string') {
|
|
725
|
+
opts.name = parsed.flags.name;
|
|
726
|
+
}
|
|
727
|
+
if (typeof parsed.flags['file-type'] === 'string') {
|
|
728
|
+
if (!CLIENT_FILE_TYPES.has(parsed.flags['file-type'])) {
|
|
729
|
+
throw new CliError('INVALID_ARGS', '--file-type must be one of: slide_deck, report, document');
|
|
730
|
+
}
|
|
731
|
+
opts.fileType = parsed.flags['file-type'];
|
|
732
|
+
}
|
|
733
|
+
if (typeof parsed.flags.description === 'string') {
|
|
734
|
+
opts.description = parsed.flags.description;
|
|
735
|
+
}
|
|
736
|
+
if (parsed.flags['dry-run'] === true) {
|
|
737
|
+
opts.dryRun = true;
|
|
738
|
+
}
|
|
739
|
+
if (typeof parsed.flags['client-id'] === 'string') {
|
|
740
|
+
opts.clientId = parsed.flags['client-id'];
|
|
741
|
+
}
|
|
742
|
+
if (parsed.flags.json === true) {
|
|
743
|
+
opts.json = true;
|
|
744
|
+
}
|
|
745
|
+
return opts;
|
|
746
|
+
}
|
|
625
747
|
function getWorkloadOptions(parsed) {
|
|
626
748
|
const id = parsed.flags['id'];
|
|
627
749
|
if (typeof id !== 'string' || id.length === 0) {
|
|
@@ -670,6 +792,109 @@ function updateWorkloadOptions(parsed) {
|
|
|
670
792
|
}
|
|
671
793
|
return opts;
|
|
672
794
|
}
|
|
795
|
+
const LOG_SECTIONS = new Set(['full', 'beginning', 'end']);
|
|
796
|
+
function fetchLogOptions(parsed) {
|
|
797
|
+
const logId = parsed.positional[0];
|
|
798
|
+
if (!logId) {
|
|
799
|
+
throw new CliError('INVALID_ARGS', 'fetch-log requires a <log-id> argument');
|
|
800
|
+
}
|
|
801
|
+
const opts = { logId };
|
|
802
|
+
if (typeof parsed.flags['section'] === 'string') {
|
|
803
|
+
const section = parsed.flags['section'];
|
|
804
|
+
if (!LOG_SECTIONS.has(section)) {
|
|
805
|
+
throw new CliError('INVALID_ARGS', '--section must be one of: full, beginning, end');
|
|
806
|
+
}
|
|
807
|
+
opts.section = section;
|
|
808
|
+
}
|
|
809
|
+
if (typeof parsed.flags['max-chars'] === 'string') {
|
|
810
|
+
const raw = parsed.flags['max-chars'];
|
|
811
|
+
const n = parseInt(raw, 10);
|
|
812
|
+
if (!/^\d+$/.test(raw) || isNaN(n) || n < 1) {
|
|
813
|
+
throw new CliError('INVALID_ARGS', '--max-chars must be a positive integer');
|
|
814
|
+
}
|
|
815
|
+
opts.maxChars = n;
|
|
816
|
+
}
|
|
817
|
+
if (typeof parsed.flags['search-query'] === 'string') {
|
|
818
|
+
opts.searchQuery = parsed.flags['search-query'];
|
|
819
|
+
}
|
|
820
|
+
if (opts.searchQuery !== undefined && (opts.section !== undefined || opts.maxChars !== undefined)) {
|
|
821
|
+
throw new CliError('INVALID_ARGS', '--search-query cannot be combined with --section or --max-chars');
|
|
822
|
+
}
|
|
823
|
+
if (parsed.flags['include-thinking'] === true) {
|
|
824
|
+
opts.includeThinking = true;
|
|
825
|
+
}
|
|
826
|
+
if (typeof parsed.flags['client-id'] === 'string') {
|
|
827
|
+
opts.clientId = parsed.flags['client-id'];
|
|
828
|
+
}
|
|
829
|
+
if (parsed.flags.json === true) {
|
|
830
|
+
opts.json = true;
|
|
831
|
+
}
|
|
832
|
+
return opts;
|
|
833
|
+
}
|
|
834
|
+
function searchLogsOptions(parsed) {
|
|
835
|
+
const opts = {};
|
|
836
|
+
if (typeof parsed.flags['template-id'] === 'string') {
|
|
837
|
+
opts.templateId = parsed.flags['template-id'];
|
|
838
|
+
}
|
|
839
|
+
if (typeof parsed.flags['workload-id'] === 'string') {
|
|
840
|
+
opts.workloadId = parsed.flags['workload-id'];
|
|
841
|
+
}
|
|
842
|
+
if (typeof parsed.flags['system-prompt-contains'] === 'string') {
|
|
843
|
+
opts.systemPromptContains = parsed.flags['system-prompt-contains'];
|
|
844
|
+
}
|
|
845
|
+
if (typeof parsed.flags['user-prompt-contains'] === 'string') {
|
|
846
|
+
opts.userPromptContains = parsed.flags['user-prompt-contains'];
|
|
847
|
+
}
|
|
848
|
+
if (typeof parsed.flags['model'] === 'string') {
|
|
849
|
+
opts.model = parsed.flags['model'];
|
|
850
|
+
}
|
|
851
|
+
if (typeof parsed.flags['source-api'] === 'string') {
|
|
852
|
+
opts.sourceApi = parsed.flags['source-api'];
|
|
853
|
+
}
|
|
854
|
+
if (typeof parsed.flags['source-api-result'] === 'string') {
|
|
855
|
+
opts.sourceApiResult = parsed.flags['source-api-result'];
|
|
856
|
+
}
|
|
857
|
+
if (parsed.flags['unmatched-only'] === true) {
|
|
858
|
+
opts.unmatchedOnly = true;
|
|
859
|
+
}
|
|
860
|
+
if (typeof parsed.flags['days-back'] === 'string') {
|
|
861
|
+
const raw = parsed.flags['days-back'];
|
|
862
|
+
const n = parseInt(raw, 10);
|
|
863
|
+
if (!/^\d+$/.test(raw) || isNaN(n) || n < 1) {
|
|
864
|
+
throw new CliError('INVALID_ARGS', '--days-back must be a positive integer');
|
|
865
|
+
}
|
|
866
|
+
opts.daysBack = n;
|
|
867
|
+
}
|
|
868
|
+
if (parsed.flags['include-prompts'] === true) {
|
|
869
|
+
opts.includePrompts = true;
|
|
870
|
+
}
|
|
871
|
+
if (typeof parsed.flags['sort'] === 'string') {
|
|
872
|
+
opts.sort = parsed.flags['sort'];
|
|
873
|
+
}
|
|
874
|
+
if (typeof parsed.flags['page'] === 'string') {
|
|
875
|
+
const raw = parsed.flags['page'];
|
|
876
|
+
const n = parseInt(raw, 10);
|
|
877
|
+
if (!/^\d+$/.test(raw) || isNaN(n) || n < 1) {
|
|
878
|
+
throw new CliError('INVALID_ARGS', '--page must be a positive integer');
|
|
879
|
+
}
|
|
880
|
+
opts.page = n;
|
|
881
|
+
}
|
|
882
|
+
if (typeof parsed.flags['per-page'] === 'string') {
|
|
883
|
+
const raw = parsed.flags['per-page'];
|
|
884
|
+
const n = parseInt(raw, 10);
|
|
885
|
+
if (!/^\d+$/.test(raw) || isNaN(n) || n < 1 || n > 100) {
|
|
886
|
+
throw new CliError('INVALID_ARGS', '--per-page must be an integer between 1 and 100');
|
|
887
|
+
}
|
|
888
|
+
opts.perPage = n;
|
|
889
|
+
}
|
|
890
|
+
if (typeof parsed.flags['client-id'] === 'string') {
|
|
891
|
+
opts.clientId = parsed.flags['client-id'];
|
|
892
|
+
}
|
|
893
|
+
if (parsed.flags.json === true) {
|
|
894
|
+
opts.json = true;
|
|
895
|
+
}
|
|
896
|
+
return opts;
|
|
897
|
+
}
|
|
673
898
|
function listWorkloadsOptions(parsed) {
|
|
674
899
|
const opts = {};
|
|
675
900
|
if (typeof parsed.flags.search === 'string') {
|
|
@@ -951,12 +1176,20 @@ export async function run(argv) {
|
|
|
951
1176
|
return await runGetFeedback(getFeedbackOptions(parsed));
|
|
952
1177
|
case 'analyze-claude-sessions':
|
|
953
1178
|
return await runAnalyzeClaudeSessions(analyzeClaudeSessionsOptions(parsed));
|
|
1179
|
+
case 'map-claude-projects':
|
|
1180
|
+
return await runMapClaudeProjects(mapClaudeProjectsOptions(parsed));
|
|
1181
|
+
case 'upload-client-file':
|
|
1182
|
+
return await runUploadClientFile(uploadClientFileOptions(parsed));
|
|
954
1183
|
case 'list-workloads':
|
|
955
1184
|
return await runListWorkloads(listWorkloadsOptions(parsed));
|
|
956
1185
|
case 'get-workload':
|
|
957
1186
|
return await runGetWorkload(getWorkloadOptions(parsed));
|
|
958
1187
|
case 'update-workload':
|
|
959
1188
|
return await runUpdateWorkload(updateWorkloadOptions(parsed));
|
|
1189
|
+
case 'fetch-log':
|
|
1190
|
+
return await runFetchLog(fetchLogOptions(parsed));
|
|
1191
|
+
case 'search-logs':
|
|
1192
|
+
return await runSearchLogs(searchLogsOptions(parsed));
|
|
960
1193
|
default:
|
|
961
1194
|
logger.info(`Unknown command: ${parsed.command}`);
|
|
962
1195
|
logger.info(buildSummaryHelp());
|