@cydm/pie 2.6.11 → 2.7.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.
Files changed (34) hide show
  1. package/README.md +68 -2
  2. package/dist/builtin/extensions/ask-user/index.js +3 -3
  3. package/dist/builtin/extensions/plan-mode/index.js +130 -21
  4. package/dist/builtin/extensions/subagent/index.js +4 -5
  5. package/dist/builtin/extensions/todo/index.js +3 -3
  6. package/dist/builtin/skills/computer-use-axi/SKILL.md +103 -0
  7. package/dist/builtin/skills/computer-use-axi/computer-use-axi-cli.js +37 -0
  8. package/dist/builtin/{extensions/computer-use/index.js → skills/computer-use-axi/computer-use-axi-runtime.js} +754 -642
  9. package/dist/builtin/skills/computer-use-axi/package.json +11 -0
  10. package/dist/chunks/{chunk-ZVM234WE.js → chunk-6RBSTII7.js} +669 -594
  11. package/dist/chunks/{chunk-MA4CHFN4.js → chunk-IPNAFMOJ.js} +172 -230
  12. package/dist/chunks/{chunk-7B4IIBVS.js → chunk-R5I2QLF2.js} +1269 -4
  13. package/dist/chunks/{chunk-PAC62XU4.js → chunk-TWILEFLD.js} +25 -3
  14. package/dist/chunks/{src-HPIBCE2I.js → src-E7NCXMU5.js} +2 -2
  15. package/dist/chunks/{test-stream-Y7WXELAJ.js → test-stream-BWBJTFNI.js} +1 -1
  16. package/dist/cli.js +1979 -384
  17. package/models.schema.json +52 -0
  18. package/package.json +3 -3
  19. package/dist/builtin/extensions/computer-use/package.json +0 -14
  20. package/dist/builtin/extensions/computer-use/scripts/build-native.mjs +0 -278
  21. package/dist/builtin/extensions/computer-use/scripts/test-native-retention.mjs +0 -204
  22. package/dist/chunks/chunk-5353DEEC.js +0 -130
  23. package/dist/chunks/webapi-MBCKO7ZV.js +0 -2481
  24. package/dist/code-intel-worker.cjs +0 -211227
  25. /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/prebuilt/linux/arm64/linux-bridge +0 -0
  26. /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/prebuilt/linux/x64/linux-bridge +0 -0
  27. /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/prebuilt/macos/arm64/pie-computer-use +0 -0
  28. /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/prebuilt/macos/universal/pie-computer-use.app/Contents/Info.plist +0 -0
  29. /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/prebuilt/macos/universal/pie-computer-use.app/Contents/MacOS/pie-computer-use +0 -0
  30. /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/prebuilt/macos/universal/pie-computer-use.app/Contents/_CodeSignature/CodeResources +0 -0
  31. /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/prebuilt/macos/x64/pie-computer-use +0 -0
  32. /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/prebuilt/windows/windows-bridge.exe +0 -0
  33. /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/scripts/helper-path.mjs +0 -0
  34. /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/scripts/setup-helper.mjs +0 -0
package/README.md CHANGED
@@ -335,7 +335,7 @@ Platform notes:
335
335
  - **Windows**: the helper installs to `~/.pie/helpers/computer-use/windows-bridge.exe` and needs an interactive desktop session.
336
336
  - **Linux**: the helper installs to `~/.pie/helpers/computer-use/linux-bridge` and needs an AT-SPI2 bus (a running desktop session; headless servers are not supported).
337
337
 
338
- Config: `~/.pie/extensions/computer-use.json` (user) or `.pie/computer-use.json` (project) with `browser_use`, `headless`, `cursor_overlay`, `managed_browser`; env overrides `PIE_COMPUTER_USE_BROWSER_USE` / `PIE_COMPUTER_USE_HEADLESS` / `PIE_COMPUTER_USE_CURSOR_OVERLAY` / `PIE_COMPUTER_USE_MANAGED_BROWSER`. Run `/computer-use` (slash command) to inspect the loaded config, and `pie doctor` for helper install status. The extension can be toggled like any other (`/settings/extensions`, identity `computer-use`).
338
+ Config: `~/.pie/extensions/computer-use.json` (user) or `.pie/computer-use.json` (project) with `browser_use`, `headless`, `cursor_overlay`, `managed_browser`; env overrides `PIE_COMPUTER_USE_BROWSER_USE` / `PIE_COMPUTER_USE_HEADLESS` / `PIE_COMPUTER_USE_CURSOR_OVERLAY` / `PIE_COMPUTER_USE_MANAGED_BROWSER`. The engine ships as the `computer-use-axi` skill: invoke it through bash (`node <skill baseDir>/computer-use-axi-cli.js <command>`) per its SKILL.md, and run `pie doctor` for helper install status.
339
339
 
340
340
  ## Web Research
341
341
 
@@ -349,7 +349,7 @@ Pie exposes one default model-visible web tool: `web_research`. Use it for publi
349
349
 
350
350
  Pie's default tools operate from the current workspace. File tools are workspace-scoped, `~/.pie` is allowlisted for Pie configuration/session support, and shell commands return structured timeout/truncation/error details. The canonical shell tool is still named `bash` for compatibility; on Windows `shell:auto` uses PowerShell, and callers can explicitly request `bash`, `powershell`, or `cmd`. High-risk shell commands require confirmation outside YOLO mode. `/settings/yolo` relaxes filesystem sandbox directory restrictions and should only be used in trusted workspaces. `pie permissions` prints the current policy-derived safety summary.
351
351
 
352
- In interactive Plan mode (`/tools/plan`), workspace editing tools are unavailable. The `bash` guard accepts simple read commands and read-only pipelines such as `rg 'TODO' . | head -20`; it blocks redirects, command substitution, and write-capable subcommands. Use `plan_scratch` to write, read, or list temporary text drafts in a directory dedicated to the current session. Shell redirection to `/tmp` remains blocked in Plan mode. Leave Plan mode before changing workspace files.
352
+ In interactive Plan mode (`/tools/plan`), workspace editing tools are unavailable. The `bash` guard accepts simple read commands and read-only pipelines such as `rg 'TODO' . | head -20`; it blocks redirects, command substitution, and write-capable subcommands. Use `plan_scratch` to write, read, or list temporary text drafts in a directory dedicated to the current session. Shell redirection to `/tmp` remains blocked in Plan mode. When the plan is ready, the agent submits the ordered steps with `plan_submit` and you choose to execute immediately (progress is tracked through `[DONE:n]` markers in responses), keep planning, or refine the plan in a prefilled editor; a plan written as plain text under a `Plan:`/`计划:` heading is still detected as a fallback. Leave Plan mode before changing workspace files.
353
353
 
354
354
  ## Code Intelligence
355
355
 
@@ -441,3 +441,69 @@ If the package version already exists on npm, bump `products/cli/package.json` f
441
441
  ## License
442
442
 
443
443
  MIT
444
+
445
+ ### Experimental Responses profiles
446
+
447
+ In `models.json`, set a profile's `api` to `"openai-responses"`, `baseUrl` to
448
+ its API root (for example `https://api.openai.com/v1`), and `apiKeyEnv` to your
449
+ credential environment variable. Supply model IDs and limits in `models` as
450
+ usual. Optional profile/model `transport` is `"sse"` (default), `"websocket"`
451
+ (strict), or `"auto"` (WS with conservative pre-submission SSE fallback).
452
+ Model transport overrides profile transport. API selection is explicit.
453
+
454
+ A profile may declare `endpoints: { "<api>": "https://..." }` and each model
455
+ may select `api` (otherwise it inherits the profile API). Supported keys are
456
+ `openai-completions`, `openai-responses`, and `anthropic-messages`; endpoint URLs
457
+ follow the same absolute HTTP(S) validation as `baseUrl`. The resolved API uses
458
+ `endpoints[api]` when present, otherwise `baseUrl`. An explicitly different model
459
+ API **requires** its endpoint entry; an explicit same-API selection can use
460
+ `baseUrl`. Remote catalogs additionally require every endpoint to share the
461
+ authenticated catalog origin. `modelOverrides` cannot change these routes.
462
+
463
+ For example, Bigmodel's Chat Completions and Responses roots differ. This is a
464
+ configuration example, not special provider logic; use distinct model IDs within
465
+ the profile (replace the Chat model ID with your supported model):
466
+
467
+ ```json
468
+ {
469
+ "profiles": {
470
+ "bigmodel": {
471
+ "api": "openai-completions",
472
+ "baseUrl": "https://open.bigmodel.cn/api/coding/paas/v4",
473
+ "endpoints": {
474
+ "openai-responses": "https://open.bigmodel.cn/api/v1"
475
+ },
476
+ "apiKeyEnv": "BIGMODEL_API_KEY",
477
+ "transport": "sse",
478
+ "models": [
479
+ {
480
+ "id": "glm-5.2", "api": "openai-completions", "input": ["text"],
481
+ "contextWindow": 128000, "maxTokens": 4096,
482
+ "cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
483
+ },
484
+ {
485
+ "id": "glm-5.3", "api": "openai-responses", "input": ["text"],
486
+ "contextWindow": 128000, "maxTokens": 4096,
487
+ "cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
488
+ }
489
+ ]
490
+ }
491
+ }
492
+ }
493
+ ```
494
+
495
+ Limits/prices above are illustrative, not provider metadata. Keep Bigmodel and
496
+ Kimi Responses on SSE for the tested endpoints/accounts: Responses support does
497
+ not imply usable WS sessions. Current benchmarks show continuation upload savings,
498
+ not consistent latency improvement; SSE stays default, WS/continuation opt-in.
499
+
500
+ Pie defaults to `store: false`. Optional `compat` fields are `store`,
501
+ `supportsStore`, `supportsReasoningEffort`, `supportsEncryptedReasoning`, and
502
+ `responsesContinuation`. Set the latter to true to enable verified same-connection
503
+ WS delta requests. SSE remains full-context. Local history remains authoritative;
504
+ rewind, compact, reset and model/credential changes discard or re-evaluate anchors.
505
+ Connection loss after submission is surfaced without automatic replay.
506
+
507
+ Text/images and function tools are supported; audio/video inputs fail explicitly.
508
+ Connection reuse, delta continuation and prompt-cache hits are separate facts.
509
+ See [transport validation and opt-in benchmarks](../../docs/maintenance/responses-transport.md).
@@ -1,9 +1,9 @@
1
1
  import { createRequire as __createRequire } from "node:module"; const require = __createRequire(import.meta.url);
2
2
  import {
3
3
  createAskUserCapability
4
- } from "../../../chunks/chunk-ZVM234WE.js";
5
- import "../../../chunks/chunk-PAC62XU4.js";
6
- import "../../../chunks/chunk-7B4IIBVS.js";
4
+ } from "../../../chunks/chunk-6RBSTII7.js";
5
+ import "../../../chunks/chunk-TWILEFLD.js";
6
+ import "../../../chunks/chunk-R5I2QLF2.js";
7
7
  import "../../../chunks/chunk-XXGYUYXI.js";
8
8
  import "../../../chunks/chunk-LZQXQOPJ.js";
9
9
 
@@ -7,9 +7,9 @@ import {
7
7
  isPlanModeSafeCommand,
8
8
  markCompletedPlanSteps,
9
9
  restoreExecutionState
10
- } from "../../../chunks/chunk-ZVM234WE.js";
11
- import "../../../chunks/chunk-PAC62XU4.js";
12
- import "../../../chunks/chunk-7B4IIBVS.js";
10
+ } from "../../../chunks/chunk-6RBSTII7.js";
11
+ import "../../../chunks/chunk-TWILEFLD.js";
12
+ import "../../../chunks/chunk-R5I2QLF2.js";
13
13
  import {
14
14
  Type
15
15
  } from "../../../chunks/chunk-XXGYUYXI.js";
@@ -26,10 +26,13 @@ var EXECUTION_FLAG_KEY = "planExecution";
26
26
  var SCRATCH_METADATA_KEY = "planScratchId";
27
27
  var SCRATCH_NAME = /^[a-zA-Z0-9][a-zA-Z0-9._-]{0,63}$/;
28
28
  var MAX_SCRATCH_CHARS = 64e3;
29
+ var MAX_PLAN_STEPS = 50;
30
+ var MAX_PLAN_ITEM_CHARS = 500;
29
31
  function toPlanTodoItems(state) {
30
32
  return state.steps.map((step) => ({
31
33
  step: step.id,
32
34
  text: step.title,
35
+ detail: step.description || void 0,
33
36
  completed: step.status === "completed"
34
37
  }));
35
38
  }
@@ -37,6 +40,8 @@ function planModeExtension(ctx) {
37
40
  const capability = createPlanCapability();
38
41
  let planModeEnabled = false;
39
42
  let executingPlan = false;
43
+ let approvalOfferedThisTurn = false;
44
+ let lastOfferedPlanKey = "";
40
45
  function setExecutingPlan(value) {
41
46
  executingPlan = value;
42
47
  ctx.setSessionMetadata(EXECUTION_FLAG_KEY, value);
@@ -113,6 +118,34 @@ function planModeExtension(ctx) {
113
118
  ctx.setExecutionReminder(buildExecutionReminder(next) ?? void 0);
114
119
  return next;
115
120
  }
121
+ function formatPlanText(items) {
122
+ return items.map((item, index) => `${index + 1}. ${item.text}${item.detail ? `
123
+ ${item.detail}` : ""}`).join("\n");
124
+ }
125
+ function renderPlanMarkdown(goal, items) {
126
+ const heading = goal ? `## \u{1F4CB} ${goal} \u2014 ${items.length} steps` : `## \u{1F4CB} Plan \u2014 ${items.length} steps`;
127
+ const steps = items.map((item, index) => {
128
+ const line = `${index + 1}. \u2610 ${item.text}`;
129
+ return item.detail ? `${line}
130
+ - \u21B3 ${item.detail}` : line;
131
+ }).join("\n");
132
+ return `${heading}
133
+
134
+ ${steps}`;
135
+ }
136
+ function startPlanExecution(items) {
137
+ planModeEnabled = false;
138
+ ctx.setSessionMetadata(SESSION_METADATA_KEY, false);
139
+ ctx.setPlanMode(false);
140
+ setExecutingPlan(items.length > 0);
141
+ writeExecutionState(createExecutionStateFromPlan(items));
142
+ updateStatus();
143
+ return `Execute the approved plan:
144
+
145
+ ${formatPlanText(items)}
146
+
147
+ Execute the steps in order, starting with step 1. After completing a step, include [DONE:n] in your response.`;
148
+ }
116
149
  function updateStatus() {
117
150
  const state = readExecutionState();
118
151
  if (executingPlan && state.steps.length > 0) {
@@ -134,12 +167,83 @@ function planModeExtension(ctx) {
134
167
  setExecutingPlan(false);
135
168
  writeExecutionState(null);
136
169
  ctx.setSessionMetadata(SESSION_METADATA_KEY, planModeEnabled);
170
+ approvalOfferedThisTurn = false;
171
+ lastOfferedPlanKey = "";
137
172
  applyPlanModeState(planModeEnabled, true);
138
173
  ctx.ui.notify(
139
174
  planModeEnabled ? `Plan mode enabled. Available tools: ${ctx.getActiveTools().join(", ")}` : "Plan mode disabled. Full access restored."
140
175
  );
141
176
  updateStatus();
142
177
  }
178
+ ctx.registerTool({
179
+ name: "plan_submit",
180
+ label: "plan_submit",
181
+ description: "Submit the finished plan for user approval. Only useful in Plan mode: the user chooses to execute now, keep planning, or refine the plan. Use short imperative step titles; put constraints, risks, and verification notes in each step's optional detail. Do not execute any step before the user approves.",
182
+ parameters: Type.Object({
183
+ goal: Type.Optional(Type.String({ description: "One-line summary of what the plan accomplishes" })),
184
+ steps: Type.Array(
185
+ Type.Object({
186
+ title: Type.String({ description: "Short imperative step title", maxLength: MAX_PLAN_ITEM_CHARS }),
187
+ detail: Type.Optional(Type.String({ description: "Constraints, risks, or verification notes for this step", maxLength: 2e3 }))
188
+ }),
189
+ { minItems: 1, maxItems: MAX_PLAN_STEPS }
190
+ )
191
+ }),
192
+ risk: { riskClass: "session_mutation", permissionScope: "session", mutatesSession: true, availableInPlanMode: true },
193
+ async execute(args) {
194
+ const reply = (text, isError = false) => ({ content: [{ type: "text", text }], isError });
195
+ if (!planModeEnabled) {
196
+ return reply("plan_submit is only available in Plan mode. Enter Plan mode with /tools/plan first, or present the plan as text if you are not planning.", true);
197
+ }
198
+ const items = [];
199
+ for (const step of (args.steps ?? []).slice(0, MAX_PLAN_STEPS)) {
200
+ const title = String(step?.title ?? "").trim().slice(0, MAX_PLAN_ITEM_CHARS);
201
+ if (!title) continue;
202
+ const detail = typeof step?.detail === "string" && step.detail.trim() ? step.detail.trim().slice(0, 2e3) : void 0;
203
+ items.push({ step: items.length + 1, text: title, detail, completed: false });
204
+ }
205
+ if (items.length === 0) {
206
+ return reply("plan_submit requires at least one step with a non-empty title.", true);
207
+ }
208
+ approvalOfferedThisTurn = true;
209
+ lastOfferedPlanKey = JSON.stringify(items);
210
+ const rendered = items.map((item) => `${item.step}. \u2610 ${item.text}${item.detail ? `
211
+ ${item.detail}` : ""}`).join("\n");
212
+ if (!ctx.hasUI) {
213
+ return reply(`Plan submitted (${items.length} steps) in headless mode; interactive approval is unavailable, so nothing will be executed:
214
+
215
+ ${rendered}`);
216
+ }
217
+ const goal = typeof args.goal === "string" && args.goal.trim() ? args.goal.trim() : void 0;
218
+ ctx.ui.notify(renderPlanMarkdown(goal, items), "info", { markdown: true });
219
+ const yoloOption = typeof ctx.setYoloMode === "function" && !ctx.yoloMode ? ["Execute in YOLO mode (auto-approve everything)"] : [];
220
+ const choice = await ctx.ui.select(`\u{1F4CB} Plan (${items.length} steps) \u2014 what next?`, [
221
+ "Execute the plan (track progress)",
222
+ ...yoloOption,
223
+ "Stay in plan mode",
224
+ "Refine the plan"
225
+ ]);
226
+ if (choice?.startsWith("Execute")) {
227
+ if (choice.includes("YOLO")) {
228
+ ctx.setYoloMode?.(true);
229
+ ctx.ui.notify("\u26A0\uFE0F YOLO mode enabled for plan execution (sandbox directory restrictions disabled).", "warning");
230
+ }
231
+ return reply(startPlanExecution(items));
232
+ }
233
+ if (choice === "Refine the plan") {
234
+ const refinement = await ctx.ui.editor("Refine the plan (edit the plan or add feedback):", formatPlanText(items));
235
+ if (refinement?.trim()) {
236
+ return reply(`The user refined the plan:
237
+
238
+ ${refinement.trim()}
239
+
240
+ Update the plan accordingly and call plan_submit again with the revised steps. Do not execute anything yet.`);
241
+ }
242
+ return reply("The user closed refinement without changes. Stay in Plan mode and wait for guidance.");
243
+ }
244
+ return reply("The user chose to stay in Plan mode. Do not execute anything; wait for guidance or refine the plan when asked.");
245
+ }
246
+ });
143
247
  ctx.registerCommand({
144
248
  path: capability.commands?.[0]?.path ?? ["tools", "plan"],
145
249
  description: capability.commands?.[0]?.description ?? "Toggle plan mode (read-only exploration)",
@@ -158,23 +262,27 @@ function planModeExtension(ctx) {
158
262
  const command = typeof event.args === "object" && event.args !== null ? event.args.command : void 0;
159
263
  if (typeof command === "string" && !isPlanModeSafeCommand(command)) {
160
264
  ctx.ui.notify(
161
- `Plan mode: Command blocked. Use read-only commands, or plan_scratch for temporary drafts. Use /plan to leave Plan mode.
265
+ `Plan mode: Command blocked. Use read-only commands or plan_scratch for temporary drafts; submit the finished plan with plan_submit. Use /tools/plan to leave Plan mode.
162
266
  Command: ${command}`,
163
267
  "error"
164
268
  );
165
- return { block: true, reason: `Plan mode: command "${command}" is not a read-only shell command. Use plan_scratch for temporary drafts, or /plan to leave Plan mode.` };
269
+ return { block: true, reason: `Plan mode: command "${command}" is not a read-only shell command. Use plan_scratch for temporary drafts, submit the finished plan with plan_submit, or use /tools/plan to leave Plan mode.` };
166
270
  }
167
271
  });
168
272
  ctx.on("agent:start", async () => {
169
273
  const persisted = readPersistedPlanMode();
170
274
  applyPlanModeState(persisted);
171
275
  executingPlan = !persisted && readPersistedExecuting();
276
+ approvalOfferedThisTurn = false;
277
+ if (!persisted) lastOfferedPlanKey = "";
172
278
  writeExecutionState(readExecutionState());
173
279
  });
174
280
  ctx.on("session:changed", async () => {
175
281
  const enabled = readPersistedPlanMode();
176
282
  applyPlanModeState(enabled, enabled);
177
283
  executingPlan = !enabled && readPersistedExecuting();
284
+ approvalOfferedThisTurn = false;
285
+ lastOfferedPlanKey = "";
178
286
  writeExecutionState(readExecutionState());
179
287
  });
180
288
  ctx.on("turn:end", async (event) => {
@@ -193,16 +301,18 @@ Command: ${command}`,
193
301
  const state = readExecutionState();
194
302
  if (executingPlan && state.steps.length > 0) {
195
303
  if (state.steps.every((step) => step.status === "completed")) {
196
- const completedList = state.steps.map((step) => `\u2713 ${step.title}`).join("\n");
197
- ctx.ui.notify(`**Plan Complete!** \u2713
304
+ const completedList = state.steps.map((step) => `${step.id}. \u2713 ${step.title}${step.description ? `
305
+ - \u21B3 ${step.description}` : ""}`).join("\n");
306
+ ctx.ui.notify(`## \u2705 Plan complete
198
307
 
199
- ${completedList}`, "info");
308
+ ${completedList}`, "info", { markdown: true });
200
309
  setExecutingPlan(false);
201
310
  writeExecutionState(null);
202
311
  }
203
312
  return;
204
313
  }
205
314
  if (!planModeEnabled || !ctx.hasUI) return;
315
+ if (approvalOfferedThisTurn) return;
206
316
  const messages = event.messages || [];
207
317
  const lastAssistant = [...messages].reverse().find(
208
318
  (message) => message.role === "assistant" && Array.isArray(message.content)
@@ -213,27 +323,26 @@ ${completedList}`, "info");
213
323
  const text = content.filter((item) => item.type === "text").map((item) => item.text).join("\n");
214
324
  const extracted = extractPlanTodoItems(text);
215
325
  if (extracted.length === 0) return;
216
- const extractedState = writeExecutionState(createExecutionStateFromPlan(extracted));
217
- const todoListText = extractedState.steps.map((step) => `${step.id}. \u2610 ${step.title}`).join("\n");
218
- ctx.ui.notify(`**Plan Steps (${extractedState.steps.length}):**
219
- ${todoListText}`, "info");
220
- const choice = await ctx.ui.select("Plan mode - what next?", [
326
+ const planKey = JSON.stringify(extracted);
327
+ if (planKey === lastOfferedPlanKey) return;
328
+ lastOfferedPlanKey = planKey;
329
+ approvalOfferedThisTurn = true;
330
+ const todoListText = extracted.map((item, index) => `${index + 1}. \u2610 ${item.text}${item.detail ? `
331
+ - \u21B3 ${item.detail}` : ""}`).join("\n");
332
+ ctx.ui.notify(`## \u{1F4CB} Plan \u2014 ${extracted.length} steps
333
+
334
+ ${todoListText}`, "info", { markdown: true });
335
+ const choice = await ctx.ui.select(`\u{1F4CB} Plan (${extracted.length} steps) \u2014 what next?`, [
221
336
  "Execute the plan (track progress)",
222
337
  "Stay in plan mode",
223
338
  "Refine the plan"
224
339
  ]);
225
340
  if (choice?.startsWith("Execute")) {
226
- planModeEnabled = false;
227
- setExecutingPlan(extractedState.steps.length > 0);
228
- ctx.setSessionMetadata(SESSION_METADATA_KEY, false);
229
- ctx.setPlanMode(false);
230
- updateStatus();
231
- const execMessage = extractedState.steps.length > 0 ? `Execute the plan. Start with: ${extractedState.steps[0].title}. Mark completed steps with [DONE:n] in your response.` : "Execute the plan you just created.";
232
- ctx.sendUserMessage(execMessage);
341
+ ctx.sendUserMessage(startPlanExecution(extracted));
233
342
  return;
234
343
  }
235
344
  if (choice === "Refine the plan") {
236
- const refinement = await ctx.ui.editor("Refine the plan:", "");
345
+ const refinement = await ctx.ui.editor("Refine the plan (edit the plan or add feedback):", formatPlanText(extracted));
237
346
  if (refinement?.trim()) {
238
347
  ctx.sendUserMessage(refinement.trim());
239
348
  }
@@ -1,15 +1,14 @@
1
1
  import { createRequire as __createRequire } from "node:module"; const require = __createRequire(import.meta.url);
2
2
  import {
3
3
  createCliHostCapabilities
4
- } from "../../../chunks/chunk-MA4CHFN4.js";
4
+ } from "../../../chunks/chunk-IPNAFMOJ.js";
5
5
  import {
6
6
  SUBAGENT_SESSION_RECORD_VERSION,
7
7
  createSharedFileSystemTools,
8
8
  createSubagentCapability
9
- } from "../../../chunks/chunk-ZVM234WE.js";
10
- import "../../../chunks/chunk-PAC62XU4.js";
11
- import "../../../chunks/chunk-7B4IIBVS.js";
12
- import "../../../chunks/chunk-5353DEEC.js";
9
+ } from "../../../chunks/chunk-6RBSTII7.js";
10
+ import "../../../chunks/chunk-TWILEFLD.js";
11
+ import "../../../chunks/chunk-R5I2QLF2.js";
13
12
  import "../../../chunks/chunk-XXGYUYXI.js";
14
13
  import "../../../chunks/chunk-LZQXQOPJ.js";
15
14
 
@@ -8,9 +8,9 @@ import {
8
8
  executeManageTodoList,
9
9
  executionStateToTodos,
10
10
  restoreExecutionState
11
- } from "../../../chunks/chunk-ZVM234WE.js";
12
- import "../../../chunks/chunk-PAC62XU4.js";
13
- import "../../../chunks/chunk-7B4IIBVS.js";
11
+ } from "../../../chunks/chunk-6RBSTII7.js";
12
+ import "../../../chunks/chunk-TWILEFLD.js";
13
+ import "../../../chunks/chunk-R5I2QLF2.js";
14
14
  import "../../../chunks/chunk-XXGYUYXI.js";
15
15
  import "../../../chunks/chunk-LZQXQOPJ.js";
16
16
 
@@ -0,0 +1,103 @@
1
+ ---
2
+ name: computer-use-axi
3
+ description: "Drive desktop apps and managed CDP browser pages through the computer-use-axi CLI run via bash: list UI roots, capture bounded outlines, search/expand/inspect element refs, perform checked actions with postconditions, and wait for conditions. Use whenever a task needs real UI interaction - clicking through a native app, reading a screen, driving a desktop window, or acting on a browser page state. Read this before the first UI-control task or after any command usage error."
4
+ ---
5
+
6
+ # computer-use-axi
7
+
8
+ Resolve the launcher against this skill's `baseDir` and run it through the
9
+ host's shell tool (axi-style; on Windows use `shell:auto`/PowerShell, not
10
+ bash.exe):
11
+
12
+ ```bash
13
+ node <baseDir>/computer-use-axi-cli.js <command> [options]
14
+ ```
15
+
16
+ Desktop control is a last resort — prefer API/CLI/web tools when they suffice.
17
+ First use on macOS installs the `pie-computer-use.app` helper; the CLI then
18
+ asks you to grant it Accessibility and Screen Recording permissions.
19
+
20
+ ## Current guidance lives in the CLI
21
+
22
+ `--help` prints the full command surface; each command's output carries its
23
+ own next-step guidance. This file covers the flow semantics.
24
+
25
+ ## The loop
26
+
27
+ ```bash
28
+ node <baseDir>/computer-use-axi-cli.js roots # list @r roots
29
+ node <baseDir>/computer-use-axi-cli.js observe --root @r1 # outline + stateId
30
+ node <baseDir>/computer-use-axi-cli.js search --state S1 --text Save
31
+ node <baseDir>/computer-use-axi-cli.js act --state S1 --actions '[{"action":"press","ref":"@e12"}]'
32
+ ```
33
+
34
+ 1. `roots` finds controllable windows/pages and mints `@r` refs.
35
+ 2. `observe` captures one root and returns a folded outline plus a `stateId`.
36
+ `--mode semantic` is cheapest (no OCR/images), `fused` is the default,
37
+ `visual` forces image evidence.
38
+ 3. `search` / `expand` / `inspect` query that saved state (`--state S1`) —
39
+ no re-observation needed. Search needs at least one of `--text`, `--role`,
40
+ `--capability`; refine broad queries instead of paging.
41
+ 4. `act` performs checked actions against the same state and returns the
42
+ successor state with a new `stateId` — use it directly for follow-ups.
43
+ Observe again only after uncertain external changes or eviction errors.
44
+
45
+ ## Refs and state
46
+
47
+ - `@rN` root refs come from `roots`; they stay stable per window identity.
48
+ - `@eN` element refs + the owning `stateId` come from `observe`/`search`;
49
+ every state-consuming command takes `--state`.
50
+ - States are stale-checked by epoch: acting twice from one stateId fails the
51
+ second time by design — consume the successor stateId the act output names.
52
+ - `@oN` refs continue long truncated output: `read --ref @o1 --offset N`
53
+ (byte offsets; no `--state` needed for `@o`).
54
+ - `pictureOnly` nodes have no semantic element: coordinate actions only, and
55
+ only from an image-bearing (visual) state.
56
+
57
+ ## Acting and batching
58
+
59
+ ```bash
60
+ node <baseDir>/computer-use-axi-cli.js act --state S1 --actions '[
61
+ {"action":"click","ref":"@e18"},
62
+ {"action":"typeText","text":"hello"}
63
+ ]' --expect '{"text":"hello"}'
64
+ ```
65
+
66
+ - Batch steps only when the second does not need to inspect the first's
67
+ result; steps run sequentially in one transaction.
68
+ - Attach `--expect` (JSON condition: `text`/`role`/`value`/`ref`/`scope-ref`/
69
+ `until`/`timeout-ms`) when an action has an observable completion signal —
70
+ but only within the same root: a modal/sheet or a closing window is a NEW
71
+ root, so expect cannot see it; run the action without `--expect` and read
72
+ the returned root note instead.
73
+ - Focus-following works only inside one act transaction: after a click into
74
+ an editable region, later `typeText`/`keypress` steps in the SAME
75
+ `--actions` array may omit `ref`. A standalone keypress (for example
76
+ `["cmd","w"]`) must carry `ref` (the window or a specific element).
77
+ - On failure the output still names the successor state — inspect it instead
78
+ of blindly replaying.
79
+ - Acting requires the platform helper: on macOS first use installs
80
+ `pie-computer-use.app` and asks for Accessibility + Screen Recording
81
+ grants. If a helper/setup error appears, run
82
+ `node <baseDir>/scripts/setup-helper.mjs` once, grant the permissions, and
83
+ retry.
84
+
85
+ ## Browser pages
86
+
87
+ ```bash
88
+ node <baseDir>/computer-use-axi-cli.js browser launch --url https://example.com
89
+ node <baseDir>/computer-use-axi-cli.js browser navigate --state S1 --url https://other.example
90
+ node <baseDir>/computer-use-axi-cli.js browser eval --state S1 --expr 'document.title'
91
+ ```
92
+
93
+ Browser states use the same outline/action/condition contracts as desktop
94
+ states. Native browser windows are ordinary desktop UI — use `roots`/
95
+ `observe`/`act` on them. Browser control may need enabling via the
96
+ computer-use config (`browser_use`).
97
+
98
+ ## Output bounds and exit codes
99
+
100
+ Model-facing output is capped (~48 KiB / 2 000 lines); oversized results
101
+ return a preview plus an `@o` continuation ref. Exit codes: `0` ok, `1` tool
102
+ error (message on stderr), `2` usage error. `--json` wraps
103
+ `{ content, details, isError }` for programmatic use.
@@ -0,0 +1,37 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Thin launcher for Pie's packaged computer-use-axi runtime (mirrors the
5
+ * chrome-devtools-axi launcher). Resolves the esbuild bundle next to this
6
+ * file and runs it with the same argv; an explicit override wins when the
7
+ * skill directory is copied out of the package.
8
+ */
9
+ import { spawnSync } from "node:child_process";
10
+ import fs from "node:fs";
11
+ import path from "node:path";
12
+ import { fileURLToPath } from "node:url";
13
+
14
+ export function resolveComputerUseAxiCli() {
15
+ const override = process.env.PIE_COMPUTER_USE_AXI_CLI_PATH?.trim();
16
+ if (override) return override;
17
+ const here = path.dirname(fileURLToPath(import.meta.url));
18
+ for (const candidate of [
19
+ path.join(here, "computer-use-axi-runtime.js"),
20
+ path.resolve(here, "../../../dist/builtin/skills/computer-use-axi/computer-use-axi-runtime.js"),
21
+ ]) {
22
+ if (fs.existsSync(candidate)) return candidate;
23
+ }
24
+ throw new Error("Pie's computer-use-axi runtime is missing. Rebuild or reinstall Pie.");
25
+ }
26
+
27
+ function main() {
28
+ const runtime = resolveComputerUseAxiCli();
29
+ const result = spawnSync(process.execPath, [runtime, ...process.argv.slice(2)], {
30
+ stdio: "inherit",
31
+ shell: false,
32
+ env: process.env,
33
+ });
34
+ process.exit(result.status ?? 1);
35
+ }
36
+
37
+ main();