@caveman-ai/cloud 0.1.0-rc.30 → 0.1.0-rc.33

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 CHANGED
@@ -6,12 +6,14 @@ Every Caveman Cloud operation from the terminal, plus the Cloud MCP server.
6
6
  npx -y @caveman-ai/cloud@rc setup --project PROJECT_ID # installs cvm, signs in, connects your coding agents
7
7
  ```
8
8
 
9
- `@rc` is the newest release; `latest` is still the 0.0.1 bootstrap. `npm i -g @caveman-ai/cloud@rc` installs cvm by itself.
9
+ `@rc` is the newest release; npm's `latest` tag lags behind it, so install `@rc`. `npm i -g @caveman-ai/cloud@rc` installs cvm by itself. When cvm and the server speak different API versions, the error (and `cvm doctor`) prints the exact install command: the server's release when it reports one, else `@rc`.
10
10
 
11
11
  ```sh
12
12
  cvm login # browser sign-in; one sign-in for cvm and caveman
13
13
  cvm projects list
14
- cvm traces search --help
14
+ cvm traces # the verbs in one family
15
+ cvm traces search --help # the flags one verb takes
16
+ cvm traces tail # new traces as they arrive (Ctrl-C stops)
15
17
  cvm sql "SELECT model, count() FROM requests GROUP BY model"
16
18
  cvm tools list # every operation this Cloud offers you
17
19
  cvm mcp # Cloud MCP server over stdio
@@ -20,7 +22,7 @@ cvm mcp # Cloud MCP server over stdio
20
22
  - **Sign-in.** `cvm login` signs in with the browser device flow: it prints a code and a link, opens the browser (`--no-browser` or `CAVE_NO_BROWSER=1` to skip) and waits for you to confirm. It stores the credential where `caveman login` does (the macOS Keychain, else `~/.caveman/credentials`), so either CLI's sign-in works for both; `cvm logout` signs both out. `--instance URL` (or `CAVE_API_URL`) signs in to a private install. In CI, set `CAVE_TOKEN` (and `CAVE_API_URL` for a private install).
21
23
  - **Environment.** A flag wins over the environment, and the environment over the saved login: `CAVE_API_URL`, `CAVE_PROJECT_ID`, `CAVE_TOKEN`. The saved credential is only ever sent to the address it was saved with; another `CAVE_API_URL` needs its own `CAVE_TOKEN`.
22
24
  - **Projects.** Use `--project UUID`, `CAVE_PROJECT_ID`, `cvm context bind` (writes `.caveman-cloud.json` in the repository) or the saved default.
23
- - **Output.** JSON when piped, readable when on a terminal; `--format json|jsonl|table`.
25
+ - **Output.** JSON when piped, readable when on a terminal; `--format json|jsonl|table`. Help follows the same rule: `cvm`, `cvm <family>` and `cvm <family> <verb> --help` are screens on a terminal and JSON when piped, and a mistyped command names the nearest one.
24
26
  - **Exit codes.** 0 ok · 1 request failed · 2 usage or invalid input (HTTP 400/422) · 3 signed out or forbidden (401/403) · 4 conflict (409) · 5 a comparison or gate failed · 6 timeout, still running or not enough data · 7 rate limited (429).
25
27
 
26
28
  ## Setup
package/bin/ci.mjs CHANGED
@@ -9,7 +9,7 @@ import {randomUUID} from 'node:crypto';
9
9
  import {join} from 'node:path';
10
10
  import {parseArgs} from 'node:util';
11
11
  import {setTimeout as delay} from 'node:timers/promises';
12
- import {CloudClient,CloudError,inertJSON,runCloudCLI} from '../dist/cloud-client.mjs';
12
+ import {CloudClient,CloudError,inertJSON,runCloudCLI,versionConflictMessage} from '../dist/cloud-client.mjs';
13
13
 
14
14
  const MAX_REPORTS=20,MAX_REPORT_BYTES=10*1024*1024; // the finish route's own limits
15
15
  const say=line=>process.stderr.write(line+'\n');
@@ -29,7 +29,7 @@ export async function connect(host,project){
29
29
  client.request=async(...args)=>{try{return await request(...args);}catch(error){if(error?.code==='cave_operation_version_conflict')error.message=VERSION_CONFLICT;throw error;}};
30
30
  return client;
31
31
  }
32
- export const VERSION_CONFLICT='This cvm and the Caveman server speak different API versions. Upgrade cvm (npm install -g @caveman-ai/cloud@latest), or install the cvm version that matches a self-hosted server, then run the command again.';
32
+ export const VERSION_CONFLICT=versionConflictMessage();
33
33
  function projectPath(client){
34
34
  if(!/^[a-f0-9]{8}(?:-[a-f0-9]{4}){3}-[a-f0-9]{12}$/i.test(client.projectId??''))throw new CloudError('cave_project_required','Select a project with --project, CAVE_PROJECT_ID or cvm context bind.',2);
35
35
  return `/api/v1/projects/${client.projectId}`;
package/bin/cvm.mjs CHANGED
@@ -14,6 +14,9 @@ import {parseArgs} from 'node:util';
14
14
  import {setTimeout as pause} from 'node:timers/promises';
15
15
  import {version,skillDirs,marker,installSkill} from './agents.mjs';
16
16
 
17
+ // A reader that stops early (cvm tools list | head) closes the pipe: end
18
+ // quietly, as Unix tools do, instead of an unhandled EPIPE stack trace.
19
+ for(const stream of [process.stdout,process.stderr])stream.on('error',error=>{if(error.code!=='EPIPE')throw error;process.exit(process.exitCode??0);});
17
20
  const client=()=>import('../dist/cloud-client.mjs');
18
21
  const cavemanHome=process.env.CAVEMAN_HOME??join(homedir(),'.caveman');
19
22
  const credentialsPath=join(cavemanHome,'credentials');
@@ -192,6 +195,16 @@ async function setup(args){
192
195
  return run(args,{client,context,login,call,cvm:realpathSync(fileURLToPath(import.meta.url))});
193
196
  }
194
197
 
198
+ // What cvm answers before the client, for `cvm --help` and `cvm <family>`.
199
+ const commands=[
200
+ {id:'setup',usage:'cvm setup [--project UUID] [--agent claude,codex,...] [--yes] [--no-launch] [--remove]',summary:'Connect your coding agents: sign-in, project, skill and MCP server.'},
201
+ {id:'login',usage:'cvm login [--instance URL] [--no-browser]',summary:'Sign in with the browser.'},
202
+ {id:'logout',usage:'cvm logout',summary:'Sign out and revoke this device.'},
203
+ {id:'mcp',usage:'cvm mcp',summary:'Serve the Cloud MCP server over stdio.'},
204
+ {id:'evals.init',usage:'cvm evals init [PATH]',summary:'Write a starter eval file (example.eval.json).'},
205
+ {id:'evals.ci',usage:'cvm evals ci FILE... | cvm evals ci [--suite NAME] -- TEST_COMMAND',summary:'Gate a pull request on eval files or a CI test run.'},
206
+ {id:'evals.watch',usage:'cvm evals watch RUN_ID',summary:'Follow one run until it settles.'},
207
+ ];
195
208
  const argv=process.argv.slice(2);
196
209
  // What only the operation form of `evals validate` and `evals run` takes.
197
210
  // A bare id is the experiment to run, unless it is the value of --project.
@@ -229,5 +242,5 @@ if(argv[0]==='--version'||argv[0]==='-v'){
229
242
  process.exitCode=await (argv[1]==='ci'?evalsCI:evalsWatch)(argv.slice(2),{context,login:loginCommand});
230
243
  }else{
231
244
  const {runCloudCLI}=await client();
232
- process.exitCode=await runCloudCLI(argv,{context,login:loginCommand});
245
+ process.exitCode=await runCloudCLI(argv,{context,login:loginCommand,commands});
233
246
  }