@camelai/camelrun 0.11.1 → 0.12.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 CHANGED
@@ -16,7 +16,6 @@ revision only when it changed, and `--apply` moves live agents to it between the
16
16
 
17
17
  ```yaml
18
18
  key: support
19
- model: anthropic/claude-sonnet-5-5
20
19
  systemPromptFile: prompts/support.md
21
20
  builtins: [web_search, ask_user]
22
21
  mcpServers:
package/dist/api.js CHANGED
@@ -1,8 +1,13 @@
1
- /** A refused call: the runtime's `error` message, with the HTTP status and its `code` when it gave one. */
1
+ /**
2
+ * A refused call: the runtime's `error` message, with the HTTP status and its `code` when it gave one. The message
3
+ * suits every surface; `cliHint` is what to do about it with the CLI, which only the CLI shows (an MCP client's model
4
+ * would try to run it).
5
+ */
2
6
  export class ApiError extends Error {
3
7
  status;
4
8
  code;
5
- constructor(status, message, code) { super(message); this.status = status; this.code = code; }
9
+ cliHint;
10
+ constructor(status, message, code, cliHint) { super(message); this.status = status; this.code = code; this.cliHint = cliHint; }
6
11
  }
7
12
  /** SHA-256 as hex, with Web Crypto: the same in Node and browsers. */
8
13
  async function sha256(text) {
@@ -39,7 +44,7 @@ export class Api {
39
44
  }
40
45
  if (!response.ok) {
41
46
  const message = json?.error ?? json?.message ?? (text.slice(0, 300) || response.statusText);
42
- throw new ApiError(response.status, response.status === 401 ? `${message} (check your API key: camelrun login)` : message, json?.code);
47
+ throw new ApiError(response.status, message, json?.code, response.status === 401 ? "check your API key: camelrun login" : undefined);
43
48
  }
44
49
  return json;
45
50
  }
@@ -66,7 +71,7 @@ export class Api {
66
71
  const agents = await this.get("/v1/agents");
67
72
  const found = agents.find(agent => agent.key === keyOrId);
68
73
  if (!found)
69
- throw new ApiError(404, `No agent with key ${JSON.stringify(keyOrId)} (camelrun agents list shows them)`);
74
+ throw new ApiError(404, `No agent with key ${JSON.stringify(keyOrId)} in this account`, undefined, "camelrun agents list shows them");
70
75
  return found.id;
71
76
  }
72
77
  }
package/dist/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { existsSync, writeFileSync } from "node:fs";
2
2
  import { createInterface } from "node:readline/promises";
3
3
  import { parseArgs } from "node:util";
4
- import { Api, enc } from "./api.js";
4
+ import { Api, ApiError, enc } from "./api.js";
5
5
  import { DEFAULT_URL, forget, resolve, save } from "./config.js";
6
6
  import { DEFAULT_FILES, template } from "./manifest.js";
7
7
  import { findManifest, loadManifests } from "./manifest-files.js";
@@ -189,7 +189,8 @@ export async function main(argv, io = { out: text => process.stdout.write(text +
189
189
  }
190
190
  }
191
191
  catch (error) {
192
- io.err(json && !(error instanceof UsageError) ? JSON.stringify({ error: error.message, ...("status" in error ? { status: error.status, code: error.code } : {}) }) : `Error: ${error.message}`);
192
+ const message = error.message + (error instanceof ApiError && error.cliHint ? ` (${error.cliHint})` : "");
193
+ io.err(json && !(error instanceof UsageError) ? JSON.stringify({ error: message, ...("status" in error ? { status: error.status, code: error.code } : {}) }) : `Error: ${message}`);
193
194
  return 1;
194
195
  }
195
196
  }
@@ -197,9 +198,9 @@ async function login(flags, io, print) {
197
198
  let apiKey = flags["api-key"] || io.env.CAMELAI_API_KEY;
198
199
  if (!apiKey) {
199
200
  if (!process.stdin.isTTY)
200
- throw new UsageError("Pass --api-key art_… (or set CAMELAI_API_KEY); create one under API tokens at https://run.camelai.com/console");
201
+ throw new UsageError("Pass --api-key art_… (or set CAMELAI_API_KEY). Create one at https://run.camelai.com/console/tokens. Coding agents: read https://run.camelai.com/SKILL.md");
201
202
  const prompt = createInterface({ input: process.stdin, output: process.stderr });
202
- apiKey = (await prompt.question("API key (from https://run.camelai.com/console, API tokens): ")).trim();
203
+ apiKey = (await prompt.question("API key (create one at https://run.camelai.com/console/tokens): ")).trim();
203
204
  prompt.close();
204
205
  }
205
206
  const url = flags.url || io.env.CAMELAI_URL || DEFAULT_URL;
package/dist/config.js CHANGED
@@ -37,6 +37,6 @@ export function resolve(flags, env = process.env) {
37
37
  const saved = readSaved(env);
38
38
  const apiKey = flags.apiKey || env.CAMELAI_API_KEY || saved.apiKey;
39
39
  if (!apiKey)
40
- throw new Error("No API key: run `camelrun login`, or set CAMELAI_API_KEY (create one under API tokens at https://run.camelai.com/console)");
40
+ throw new Error("No API key: run `camelrun login`, or set CAMELAI_API_KEY. Create one at https://run.camelai.com/console/tokens. Coding agents: read https://run.camelai.com/SKILL.md");
41
41
  return { apiKey, url: flags.url || env.CAMELAI_URL || saved.url || DEFAULT_URL };
42
42
  }
package/dist/tools.js CHANGED
@@ -68,7 +68,10 @@ export function tools(api, options = {}) {
68
68
  const client = api();
69
69
  return client.call("DELETE", `/v1/definitions/${await client.definitionId(definition)}`);
70
70
  }, destructive);
71
- tool("list_agents", "List agents", "The account's agents: key, id, model, and whether each is running. Changes nothing.", {}, () => api().get("/v1/agents"), read);
71
+ tool("list_agents", "List agents", "The account's agents: key, id, name and model. `loaded` is whether the agent is in a runtime's memory now, idle or not; it says nothing about whether a run is going (run_agent and get_run do). `toolsConnected` is whether an application serving its attached tools is connected. Changes nothing.", {}, async () => {
72
+ const list = await api().get("/v1/agents");
73
+ return list.map(({ id, key, name, model, running, connected, expiresAt }) => ({ key, id, name, model, loaded: running, toolsConnected: connected, expiresAt }));
74
+ }, read);
72
75
  tool("get_agent", "Get agent", "An agent's configuration, the definition revision it has, and every source of its tools with what each offers. Changes nothing.", { agent }, async ({ agent }) => {
73
76
  const client = api();
74
77
  return client.get(`/v1/agents/${enc(await client.agentId(agent))}`);
@@ -129,7 +132,7 @@ export function tools(api, options = {}) {
129
132
  }, async ({ agent, ...schedule }) => {
130
133
  const client = api();
131
134
  return client.call("POST", `/v1/agents/${enc(await client.agentId(agent))}/schedules`, schedule);
132
- }, add);
135
+ }, { ...add, openWorldHint: true });
133
136
  tool("delete_schedule", "Delete schedule", "Cancel a scheduled wake-up; this cannot be undone.", { agent, scheduleId: z.string() }, async ({ agent, scheduleId }) => {
134
137
  const client = api();
135
138
  return client.call("DELETE", `/v1/agents/${enc(await client.agentId(agent))}/schedules/${enc(scheduleId)}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camelai/camelrun",
3
- "version": "0.11.1",
3
+ "version": "0.12.0",
4
4
  "description": "camelRun CLI: deploy and manage agents on camelRun from a terminal, or from a coding agent over MCP (camelrun mcp).",
5
5
  "type": "module",
6
6
  "license": "MIT",