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

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 (3) hide show
  1. package/README.md +23 -0
  2. package/bin/cvm.mjs +46 -0
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -25,6 +25,29 @@ cvm mcp # Cloud MCP server over stdio
25
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.
26
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).
27
27
 
28
+ ## Human Code lifecycle
29
+
30
+ These fixed commands use the same saved human sign-in as `cvm login`. They do
31
+ not expose credentials, allocate computers, or grant Code access to agent
32
+ connections. Server authorization remains authoritative; an agent connection is
33
+ still denied. No arbitrary HTTP paths, request bodies, or headers are accepted.
34
+
35
+ ```sh
36
+ cvm human code computers
37
+ cvm human code runtimes
38
+ cvm human code workspace WORKSPACE_UUID
39
+ cvm human code archive WORKSPACE_UUID --yes
40
+ cvm human code --help
41
+ ```
42
+
43
+ IDs must be canonical hyphenated UUIDs. Archive requires `--yes` (`-y`) even on
44
+ a terminal: it terminates sessions and may delete the workspace's computer when
45
+ no active workspace uses it. Without confirmation, no request (including login
46
+ refresh) is made. These commands accept `--format json|jsonl|table`; `table`
47
+ pretty-prints the lifecycle JSON. They use the built-in saved context and its
48
+ normal environment overrides, not named operation profiles. Errors omit
49
+ upstream response details to avoid disclosing credentials.
50
+
28
51
  ## Setup
29
52
 
30
53
  `cvm setup` connects your coding agents to Caveman Cloud. Each step is safe to run again, and running it again is how you repair a setup.
package/bin/cvm.mjs CHANGED
@@ -195,12 +195,56 @@ async function setup(args){
195
195
  return run(args,{client,context,login,call,cvm:realpathSync(fileURLToPath(import.meta.url))});
196
196
  }
197
197
 
198
+ // Fixed human lifecycle routes, deliberately outside the operation/MCP catalog.
199
+ // The normal built-in context owns credentials; this command never exports them.
200
+ async function humanCode(args){
201
+ const {CloudClient,CloudError,inertJSON}=await client();
202
+ const usage='cvm human code computers|runtimes|workspace ID|archive ID --yes [--format json|jsonl|table]';
203
+ const fail=(code,message,exit)=>new CloudError(code,message,exit);
204
+ let format=process.stdout.isTTY?'table':'json';
205
+ try{
206
+ let values,positionals;
207
+ try{({values,positionals}=parseArgs({args,strict:true,allowPositionals:true,options:{help:{type:'boolean',short:'h'},format:{type:'string'},yes:{type:'boolean',short:'y'}}}));}
208
+ catch{throw fail('cave_usage',`Use ${usage}.`,2);}
209
+ format=values.format??format;
210
+ if(!['json','jsonl','table'].includes(format))throw fail('cave_usage','Format must be json, jsonl, or table.',2);
211
+ const [family,verb,id]=positionals;
212
+ const write=value=>process.stdout.write(inertJSON(value,format==='table'?2:undefined)+'\n');
213
+ if(values.help||!positionals.length||positionals.length===1&&family==='code'){
214
+ write({usage,summary:'Human Code lifecycle. Uses your normal saved sign-in; agent connections remain forbidden. Archive terminates sessions and may delete an unused workspace computer. No computer allocation.'});return 0;
215
+ }
216
+ if(family!=='code'||!['computers','runtimes','workspace','archive'].includes(verb))throw fail('cave_usage',`Use ${usage}.`,2);
217
+ const needsID=verb==='workspace'||verb==='archive';
218
+ if(positionals.length!==(needsID?3:2)||needsID&&(id.length!==36||!/^[a-f0-9]{8}(?:-[a-f0-9]{4}){3}-[a-f0-9]{12}$/i.test(id)))throw fail('cave_usage','Supply exactly one workspace UUID for workspace or archive; no ID for computers or runtimes.',2);
219
+ if(values.yes&&verb!=='archive')throw fail('cave_usage','--yes is only for archive.',2);
220
+ // Validate and confirm before even resolving context (which may refresh login).
221
+ if(verb==='archive'&&!values.yes)throw fail('cave_confirmation_required','Archiving terminates sessions and may delete the unused workspace computer. Repeat with --yes to confirm.',2);
222
+ const path=needsID?`/api/v1/code/workspaces/${encodeURIComponent(id)}${verb==='archive'?'/archive':''}`:`/api/v1/code/${verb}`;
223
+ try{
224
+ const api=new CloudClient(await context());
225
+ write(await api.request(path,verb==='archive'?{body:{}}:{}));return 0;
226
+ }catch(error){
227
+ // Do not print upstream bodies, messages, details, URLs or unknown errors:
228
+ // they can contain credentials or terminal controls. Preserve denial codes.
229
+ if(error.httpStatus){
230
+ const code=error.httpStatus===403&&error.code==='cave_agent_operation_forbidden'?'cave_agent_operation_forbidden':'cave_request_failed';
231
+ throw fail(code,`Code lifecycle request failed (HTTP ${error.httpStatus}).`,error.exitCode);
232
+ }
233
+ const safe={cave_auth_required:'Run cvm login.',cave_endpoint_invalid:'Cloud endpoint must be HTTPS or loopback HTTP without credentials, query or fragment.',cave_network_error:'Cloud request failed. Inspect workspace state before retrying archive.',cave_timeout:'Cloud request timed out. Inspect workspace state before retrying archive.',cave_invalid_response:'Cloud returned an invalid JSON response.',cave_result_too_large:'Cloud response exceeded the size limit.'};
234
+ throw fail(Object.hasOwn(safe,error.code)?error.code:'cave_failed',safe[error.code]??'Code lifecycle command failed.',error instanceof CloudError?error.exitCode:1);
235
+ }
236
+ }catch(error){
237
+ process.stdout.write(inertJSON({schema_version:1,ok:false,status:'failed',error:{code:error.code,message:error.message}},format==='table'?2:undefined)+'\n');return error.exitCode;
238
+ }
239
+ }
240
+
198
241
  // What cvm answers before the client, for `cvm --help` and `cvm <family>`.
199
242
  const commands=[
200
243
  {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
244
  {id:'login',usage:'cvm login [--instance URL] [--no-browser]',summary:'Sign in with the browser.'},
202
245
  {id:'logout',usage:'cvm logout',summary:'Sign out and revoke this device.'},
203
246
  {id:'mcp',usage:'cvm mcp',summary:'Serve the Cloud MCP server over stdio.'},
247
+ {id:'human.code',usage:'cvm human code computers|runtimes|workspace ID|archive ID --yes',summary:'Human Code lifecycle using your normal saved sign-in; no agent access.'},
204
248
  {id:'evals.init',usage:'cvm evals init [PATH]',summary:'Write a starter eval file (example.eval.json).'},
205
249
  {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
250
  {id:'evals.watch',usage:'cvm evals watch RUN_ID',summary:'Follow one run until it settles.'},
@@ -227,6 +271,8 @@ if(argv[0]==='--version'||argv[0]==='-v'){
227
271
  process.stdout.write(JSON.stringify({schema_version:1,ok:false,status:'failed',error:{code:error.exitCode?error.code:'cave_failed',message:error.message}})+'\n');
228
272
  process.exitCode=exit;
229
273
  }
274
+ }else if(argv[0]==='human'&&argv[1]==='code'){
275
+ process.exitCode=await humanCode(argv.slice(1));
230
276
  }else if(argv[0]==='mcp'&&argv.length===1){
231
277
  const {serveCloudMCP}=await import('../dist/cloud-mcp.mjs');
232
278
  // A launcher may narrow the server to the operations one task needs.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@caveman-ai/cloud",
3
- "version": "0.1.0-rc.33",
3
+ "version": "0.1.0-rc.35",
4
4
  "description": "cvm, the Caveman Cloud CLI: every Cloud operation from the terminal, plus the Cloud MCP server. Sign in with `cvm login`; `cvm setup` signs in, picks the project, installs the Caveman Cloud skill and registers the Cloud MCP server in every coding agent it finds.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",