@todoforai/cli 0.1.42 → 0.1.43

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
@@ -97,7 +97,7 @@ Pick **TODOforAI** from the agent dropdown in AI Chat.
97
97
 
98
98
  **VS Code** — no built-in ACP client yet; install a community ACP client extension (e.g. [`strato-space.acp-plugin`](https://marketplace.visualstudio.com/items?itemName=strato-space.acp-plugin)) and add the same `agent_servers` entry to `settings.json`.
99
99
 
100
- Options like `--agent`, `--project`, `--path`, `--api-url` apply to `acp` as well (e.g. `"args": ["acp", "--agent", "backend"]`). If `todoforai-cli` is not on the editor's `PATH`, use its absolute path (`which todoforai-cli`).
100
+ `--agent`, `--project` and `--api-url` apply to `acp` as well (e.g. `"args": ["acp", "--agent", "backend"]`). If `todoforai-cli` is not on the editor's `PATH`, use its absolute path (`which todoforai-cli`).
101
101
 
102
102
  ## All Options
103
103
 
@@ -43177,8 +43177,7 @@ class FrontendWebSocket {
43177
43177
  });
43178
43178
  this.ws.on("close", () => {
43179
43179
  this.connected = false;
43180
- for (const [todoId, ev] of [...this.completionEvents])
43181
- ev.resolve({ type: "socket:closed", payload: { todoId, status: "DISCONNECTED" }, success: false });
43180
+ this.settleAll();
43182
43181
  });
43183
43182
  this.ws.on("error", (err) => {
43184
43183
  log("error", "WS error:", err.message);
@@ -43187,8 +43186,13 @@ class FrontendWebSocket {
43187
43186
  });
43188
43187
  });
43189
43188
  }
43189
+ settleAll() {
43190
+ for (const [todoId, ev] of [...this.completionEvents])
43191
+ ev.resolve({ type: "socket:closed", payload: { todoId, status: "DISCONNECTED" }, success: false });
43192
+ }
43190
43193
  async close() {
43191
43194
  this.connected = false;
43195
+ this.settleAll();
43192
43196
  this.ws?.close();
43193
43197
  this.ws = null;
43194
43198
  this.callbacks.clear();
@@ -43197,6 +43201,10 @@ class FrontendWebSocket {
43197
43201
  this.pendingBlocks.clear();
43198
43202
  this.lastReadyPayload.clear();
43199
43203
  }
43204
+ forget(todoId) {
43205
+ for (const m of [this.callbacks, this.completionEvents, this.completionResults, this.pendingBlocks, this.lastReadyPayload])
43206
+ m.delete(todoId);
43207
+ }
43200
43208
  handleMessage(data) {
43201
43209
  const msgType = data.type || "";
43202
43210
  const payload = data.payload || {};
@@ -43326,11 +43334,14 @@ class FrontendWebSocket {
43326
43334
  if (!await this.subscribe(todoId, callback)) {
43327
43335
  throw new Error(`Failed to subscribe to todo ${todoId}`);
43328
43336
  }
43337
+ return this.completion(todoId);
43338
+ }
43339
+ completion(todoId) {
43329
43340
  const early = this.completionResults.get(todoId);
43330
43341
  if (early) {
43331
43342
  this.completionResults.delete(todoId);
43332
43343
  this.callbacks.delete(todoId);
43333
- return early;
43344
+ return Promise.resolve(early);
43334
43345
  }
43335
43346
  return new Promise((resolve) => {
43336
43347
  this.completionEvents.set(todoId, {
@@ -44429,7 +44440,7 @@ import { parseArgs } from "util";
44429
44440
  // package.json
44430
44441
  var package_default = {
44431
44442
  name: "@todoforai/cli",
44432
- version: "0.1.42",
44443
+ version: "0.1.43",
44433
44444
  type: "module",
44434
44445
  bin: {
44435
44446
  "todoforai-cli": "bin/todoforai-cli.js",
@@ -52549,12 +52560,14 @@ class TodoforaiAgent {
52549
52560
  api;
52550
52561
  ws;
52551
52562
  projectId;
52563
+ agentQuery;
52552
52564
  sessions = new Map;
52553
- constructor(conn, api, ws, projectId) {
52565
+ constructor(conn, api, ws, projectId, agentQuery) {
52554
52566
  this.conn = conn;
52555
52567
  this.api = api;
52556
52568
  this.ws = ws;
52557
52569
  this.projectId = projectId;
52570
+ this.agentQuery = agentQuery;
52558
52571
  }
52559
52572
  async initialize() {
52560
52573
  return { protocolVersion: PROTOCOL_VERSION, agentCapabilities: { promptCapabilities: { embeddedContext: true } }, authMethods: [] };
@@ -52569,10 +52582,19 @@ class TodoforaiAgent {
52569
52582
  throw RequestError.internalError("no project on this account");
52570
52583
  return this.projectId = id;
52571
52584
  }
52585
+ async resolveAgent(cwd) {
52586
+ if (this.agentQuery) {
52587
+ const { match, ambiguous } = resolveAgentMatch(await this.api.listAgentSettings(), this.agentQuery);
52588
+ if (!match)
52589
+ throw RequestError.invalidParams(`agent '${this.agentQuery}' ${ambiguous?.length ? "is ambiguous" : "not found"}`);
52590
+ return match;
52591
+ }
52592
+ return (await this.api.listAgentSettings({ workspacePath: cwd }))[0] ?? await autoCreateAgent(this.api, cwd);
52593
+ }
52572
52594
  async newSession(p) {
52573
52595
  const projectId = await this.resolveProject();
52574
52596
  const cwd = realpathSync(p.cwd);
52575
- const agent = (await this.api.listAgentSettings({ workspacePath: cwd }))[0] ?? await autoCreateAgent(this.api, cwd);
52597
+ const agent = await this.resolveAgent(cwd);
52576
52598
  const todoId = crypto.randomUUID();
52577
52599
  this.sessions.set(todoId, { todoId, projectId, agent });
52578
52600
  log2(`session ${todoId} agent=${agent.name} cwd=${cwd}`);
@@ -52672,13 +52694,17 @@ ${b.resource.text}
52672
52694
  };
52673
52695
  try {
52674
52696
  const msg = await this.api.addMessage(s.projectId, text, s.agent, s.todoId, undefined, NEVER_SCHEDULED_TIMESTAMP);
52675
- const done = this.ws.waitForCompletion(s.todoId, onEvent);
52697
+ if (!await this.ws.subscribe(s.todoId, onEvent))
52698
+ throw new Error("subscribe failed");
52699
+ const done = this.ws.completion(s.todoId);
52676
52700
  if (turn.cancelled)
52677
52701
  return { stopReason: "cancelled" };
52678
52702
  await this.api.updateAndStart(s.todoId, s.agent, msg.messages?.at(-1)?.id);
52679
52703
  turn.started = true;
52680
- const result = await done;
52681
52704
  if (turn.cancelled)
52705
+ await this.ws.sendInterrupt(s.projectId, s.todoId);
52706
+ const result = await done;
52707
+ if (turn.cancelled || /^CANCELLED/.test(result?.payload?.status))
52682
52708
  return { stopReason: "cancelled" };
52683
52709
  if (!result?.success)
52684
52710
  throw RequestError.internalError(`todo ended with status ${result?.payload?.status ?? "unknown"}`);
@@ -52689,7 +52715,7 @@ ${b.resource.text}
52689
52715
  throw RequestError.internalError(String(e?.message || e));
52690
52716
  } finally {
52691
52717
  turn.done = true;
52692
- this.ws.setCallback(s.todoId);
52718
+ this.ws.forget(s.todoId);
52693
52719
  }
52694
52720
  }
52695
52721
  }
@@ -52702,7 +52728,7 @@ async function runAcp(apiUrl, apiKey, opts) {
52702
52728
  if (!wsOk)
52703
52729
  throw new Error("frontend websocket connect failed");
52704
52730
  const stream2 = ndJsonStream(Writable.toWeb(process.stdout), Readable.toWeb(process.stdin));
52705
- new AgentSideConnection((conn) => new TodoforaiAgent(conn, api, ws, opts.projectId), stream2);
52731
+ new AgentSideConnection((conn) => new TodoforaiAgent(conn, api, ws, opts.projectId, opts.agent), stream2);
52706
52732
  log2(`ready (${apiUrl})`);
52707
52733
  await new Promise((resolve3) => {
52708
52734
  process.stdin.once("end", resolve3);
@@ -52977,7 +53003,7 @@ Cancelled by user (Ctrl+C)
52977
53003
  `);
52978
53004
  process.exit(2);
52979
53005
  }
52980
- await runAcp(apiUrl, apiKey, { projectId: args.project || getEnv("PROJECT_ID") || cfgScope.data.default_project_id, noBridge: !!args["no-bridge"] });
53006
+ await runAcp(apiUrl, apiKey, { projectId: args.project || getEnv("PROJECT_ID") || cfgScope.data.default_project_id, agent: args.agent, noBridge: !!args["no-bridge"] });
52981
53007
  return;
52982
53008
  }
52983
53009
  if (positionals[0] === "status") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@todoforai/cli",
3
- "version": "0.1.42",
3
+ "version": "0.1.43",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "todoforai-cli": "bin/todoforai-cli.js",