@cydm/pie 2.6.12 → 2.7.1
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 +85 -3
- package/dist/builtin/extensions/ask-user/index.js +3 -3
- package/dist/builtin/extensions/plan-mode/index.js +130 -21
- package/dist/builtin/extensions/subagent/index.js +15 -6
- package/dist/builtin/extensions/todo/index.js +3 -3
- package/dist/builtin/skills/computer-use-axi/SKILL.md +172 -0
- package/dist/builtin/{extensions/computer-use/index.js → skills/computer-use-axi/computer-use-axi-broker.js} +2122 -708
- package/dist/builtin/skills/computer-use-axi/computer-use-axi-cli.js +37 -0
- package/dist/builtin/skills/computer-use-axi/computer-use-axi-runtime.js +728 -0
- package/dist/builtin/skills/computer-use-axi/package.json +11 -0
- package/dist/chunks/{chunk-PPEWRUMQ.js → chunk-M44CWVDZ.js} +1249 -752
- package/dist/chunks/{chunk-HHNOENEH.js → chunk-NJFPBU36.js} +14 -1
- package/dist/chunks/{chunk-AAEBH6KX.js → chunk-W74NRSRV.js} +239 -231
- package/dist/chunks/{chunk-7B4IIBVS.js → chunk-XUROMYTT.js} +1747 -14
- package/dist/chunks/{src-OWQI5M6W.js → src-C4KA4G75.js} +2 -2
- package/dist/chunks/{test-stream-Y7WXELAJ.js → test-stream-A5ZELKNG.js} +1 -1
- package/dist/cli.js +863 -305
- package/models.schema.json +57 -0
- package/package.json +3 -3
- package/dist/builtin/extensions/computer-use/package.json +0 -14
- package/dist/builtin/extensions/computer-use/scripts/build-native.mjs +0 -278
- package/dist/builtin/extensions/computer-use/scripts/test-native-retention.mjs +0 -204
- package/dist/chunks/chunk-5353DEEC.js +0 -130
- package/dist/chunks/webapi-MBCKO7ZV.js +0 -2481
- package/dist/code-intel-worker.cjs +0 -211227
- /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/prebuilt/linux/arm64/linux-bridge +0 -0
- /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/prebuilt/linux/x64/linux-bridge +0 -0
- /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/prebuilt/macos/arm64/pie-computer-use +0 -0
- /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/prebuilt/macos/universal/pie-computer-use.app/Contents/Info.plist +0 -0
- /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/prebuilt/macos/universal/pie-computer-use.app/Contents/MacOS/pie-computer-use +0 -0
- /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/prebuilt/macos/universal/pie-computer-use.app/Contents/_CodeSignature/CodeResources +0 -0
- /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/prebuilt/macos/x64/pie-computer-use +0 -0
- /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/prebuilt/windows/windows-bridge.exe +0 -0
- /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/scripts/helper-path.mjs +0 -0
- /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/scripts/setup-helper.mjs +0 -0
package/README.md
CHANGED
|
@@ -83,7 +83,7 @@ Required model fields:
|
|
|
83
83
|
|
|
84
84
|
- `id`
|
|
85
85
|
- `input`
|
|
86
|
-
- `cost`
|
|
86
|
+
- `cost` (`input`, `output`, `cacheRead`, `cacheWrite`; optional `cacheWriteLong`)
|
|
87
87
|
- `contextWindow`
|
|
88
88
|
- `maxTokens`
|
|
89
89
|
|
|
@@ -104,6 +104,22 @@ pie models init --stdout
|
|
|
104
104
|
|
|
105
105
|
For editor auto-complete and validation, you can also point the optional `"$schema"` field in your local `models.json` at your installed `@cydm/pie/models.schema.json` file.
|
|
106
106
|
|
|
107
|
+
`cost` may additionally carry `cacheWriteLong` — the per-million-token rate for 1h-TTL cache writes on providers that report a TTL breakdown (Anthropic-style routes). It is optional; legacy configs without it keep working. When it is absent, long writes are priced at the Anthropic 2x-input estimate and the calculated cost is marked `cacheWriteLongEstimated` so it is not presented as a precise provider bill.
|
|
108
|
+
|
|
109
|
+
### Settings
|
|
110
|
+
|
|
111
|
+
`~/.pie/settings.json` (or `./.pie/settings.json` for project scope) holds CLI defaults. Relevant prompt-cache keys:
|
|
112
|
+
|
|
113
|
+
```jsonc
|
|
114
|
+
{
|
|
115
|
+
// Explicit Anthropic prompt-cache TTL: "none" | "short" | "long".
|
|
116
|
+
// Absent keeps the provider default (Anthropic: short/5m).
|
|
117
|
+
"promptCacheRetention": "short"
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Priority is **per-request option > CLI setting > provider default**. The setting is forwarded only on Anthropic prompt-cache routes; it never forces OpenAI-compatible `store` or another provider's cache mode. Pie does not auto-switch TTL from observed hit rates — choose `long` explicitly when the 1h write premium is worth it.
|
|
122
|
+
|
|
107
123
|
### Remote model catalogs
|
|
108
124
|
|
|
109
125
|
Pie can add centrally managed models without replacing local profiles or defaults. Add a catalog to `~/.pie/models.json` and keep the virtual key in an environment variable:
|
|
@@ -335,7 +351,7 @@ Platform notes:
|
|
|
335
351
|
- **Windows**: the helper installs to `~/.pie/helpers/computer-use/windows-bridge.exe` and needs an interactive desktop session.
|
|
336
352
|
- **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
353
|
|
|
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`.
|
|
354
|
+
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
355
|
|
|
340
356
|
## Web Research
|
|
341
357
|
|
|
@@ -349,7 +365,7 @@ Pie exposes one default model-visible web tool: `web_research`. Use it for publi
|
|
|
349
365
|
|
|
350
366
|
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
367
|
|
|
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.
|
|
368
|
+
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
369
|
|
|
354
370
|
## Code Intelligence
|
|
355
371
|
|
|
@@ -441,3 +457,69 @@ If the package version already exists on npm, bump `products/cli/package.json` f
|
|
|
441
457
|
## License
|
|
442
458
|
|
|
443
459
|
MIT
|
|
460
|
+
|
|
461
|
+
### Experimental Responses profiles
|
|
462
|
+
|
|
463
|
+
In `models.json`, set a profile's `api` to `"openai-responses"`, `baseUrl` to
|
|
464
|
+
its API root (for example `https://api.openai.com/v1`), and `apiKeyEnv` to your
|
|
465
|
+
credential environment variable. Supply model IDs and limits in `models` as
|
|
466
|
+
usual. Optional profile/model `transport` is `"sse"` (default), `"websocket"`
|
|
467
|
+
(strict), or `"auto"` (WS with conservative pre-submission SSE fallback).
|
|
468
|
+
Model transport overrides profile transport. API selection is explicit.
|
|
469
|
+
|
|
470
|
+
A profile may declare `endpoints: { "<api>": "https://..." }` and each model
|
|
471
|
+
may select `api` (otherwise it inherits the profile API). Supported keys are
|
|
472
|
+
`openai-completions`, `openai-responses`, and `anthropic-messages`; endpoint URLs
|
|
473
|
+
follow the same absolute HTTP(S) validation as `baseUrl`. The resolved API uses
|
|
474
|
+
`endpoints[api]` when present, otherwise `baseUrl`. An explicitly different model
|
|
475
|
+
API **requires** its endpoint entry; an explicit same-API selection can use
|
|
476
|
+
`baseUrl`. Remote catalogs additionally require every endpoint to share the
|
|
477
|
+
authenticated catalog origin. `modelOverrides` cannot change these routes.
|
|
478
|
+
|
|
479
|
+
For example, Bigmodel's Chat Completions and Responses roots differ. This is a
|
|
480
|
+
configuration example, not special provider logic; use distinct model IDs within
|
|
481
|
+
the profile (replace the Chat model ID with your supported model):
|
|
482
|
+
|
|
483
|
+
```json
|
|
484
|
+
{
|
|
485
|
+
"profiles": {
|
|
486
|
+
"bigmodel": {
|
|
487
|
+
"api": "openai-completions",
|
|
488
|
+
"baseUrl": "https://open.bigmodel.cn/api/coding/paas/v4",
|
|
489
|
+
"endpoints": {
|
|
490
|
+
"openai-responses": "https://open.bigmodel.cn/api/v1"
|
|
491
|
+
},
|
|
492
|
+
"apiKeyEnv": "BIGMODEL_API_KEY",
|
|
493
|
+
"transport": "sse",
|
|
494
|
+
"models": [
|
|
495
|
+
{
|
|
496
|
+
"id": "glm-5.2", "api": "openai-completions", "input": ["text"],
|
|
497
|
+
"contextWindow": 128000, "maxTokens": 4096,
|
|
498
|
+
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
|
|
499
|
+
},
|
|
500
|
+
{
|
|
501
|
+
"id": "glm-5.3", "api": "openai-responses", "input": ["text"],
|
|
502
|
+
"contextWindow": 128000, "maxTokens": 4096,
|
|
503
|
+
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
|
|
504
|
+
}
|
|
505
|
+
]
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
```
|
|
510
|
+
|
|
511
|
+
Limits/prices above are illustrative, not provider metadata. Keep Bigmodel and
|
|
512
|
+
Kimi Responses on SSE for the tested endpoints/accounts: Responses support does
|
|
513
|
+
not imply usable WS sessions. Current benchmarks show continuation upload savings,
|
|
514
|
+
not consistent latency improvement; SSE stays default, WS/continuation opt-in.
|
|
515
|
+
|
|
516
|
+
Pie defaults to `store: false`. Optional `compat` fields are `store`,
|
|
517
|
+
`supportsStore`, `supportsReasoningEffort`, `supportsEncryptedReasoning`, and
|
|
518
|
+
`responsesContinuation`. Set the latter to true to enable verified same-connection
|
|
519
|
+
WS delta requests. SSE remains full-context. Local history remains authoritative;
|
|
520
|
+
rewind, compact, reset and model/credential changes discard or re-evaluate anchors.
|
|
521
|
+
Connection loss after submission is surfaced without automatic replay.
|
|
522
|
+
|
|
523
|
+
Text/images and function tools are supported; audio/video inputs fail explicitly.
|
|
524
|
+
Connection reuse, delta continuation and prompt-cache hits are separate facts.
|
|
525
|
+
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-
|
|
5
|
-
import "../../../chunks/chunk-
|
|
6
|
-
import "../../../chunks/chunk-
|
|
4
|
+
} from "../../../chunks/chunk-M44CWVDZ.js";
|
|
5
|
+
import "../../../chunks/chunk-NJFPBU36.js";
|
|
6
|
+
import "../../../chunks/chunk-XUROMYTT.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-
|
|
11
|
-
import "../../../chunks/chunk-
|
|
12
|
-
import "../../../chunks/chunk-
|
|
10
|
+
} from "../../../chunks/chunk-M44CWVDZ.js";
|
|
11
|
+
import "../../../chunks/chunk-NJFPBU36.js";
|
|
12
|
+
import "../../../chunks/chunk-XUROMYTT.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
|
|
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) =>
|
|
197
|
-
|
|
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
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
const
|
|
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
|
-
|
|
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,16 @@
|
|
|
1
1
|
import { createRequire as __createRequire } from "node:module"; const require = __createRequire(import.meta.url);
|
|
2
2
|
import {
|
|
3
|
-
createCliHostCapabilities
|
|
4
|
-
|
|
3
|
+
createCliHostCapabilities,
|
|
4
|
+
formatTransportLifecycle,
|
|
5
|
+
logTransportLifecycle
|
|
6
|
+
} from "../../../chunks/chunk-W74NRSRV.js";
|
|
5
7
|
import {
|
|
6
8
|
SUBAGENT_SESSION_RECORD_VERSION,
|
|
7
9
|
createSharedFileSystemTools,
|
|
8
10
|
createSubagentCapability
|
|
9
|
-
} from "../../../chunks/chunk-
|
|
10
|
-
import "../../../chunks/chunk-
|
|
11
|
-
import "../../../chunks/chunk-
|
|
12
|
-
import "../../../chunks/chunk-5353DEEC.js";
|
|
11
|
+
} from "../../../chunks/chunk-M44CWVDZ.js";
|
|
12
|
+
import "../../../chunks/chunk-NJFPBU36.js";
|
|
13
|
+
import "../../../chunks/chunk-XUROMYTT.js";
|
|
13
14
|
import "../../../chunks/chunk-XXGYUYXI.js";
|
|
14
15
|
import "../../../chunks/chunk-LZQXQOPJ.js";
|
|
15
16
|
|
|
@@ -393,6 +394,14 @@ function subagentExtension(ctx) {
|
|
|
393
394
|
log: (message) => ctx.log(message),
|
|
394
395
|
notify: ctx.hasUI ? (message, type) => ctx.ui.notify(message, type === "success" ? "info" : type) : void 0,
|
|
395
396
|
debugLog: (module, message, data) => ctx.log(`[subagent:${module}] ${message}${data !== void 0 ? ` ${JSON.stringify(data)}` : ""}`),
|
|
397
|
+
// Body-free Responses transport timeline for CHILD agents: 5 of the 7
|
|
398
|
+
// incident failures happened inside subagents with no transport record.
|
|
399
|
+
onTransportLifecycle: (event) => {
|
|
400
|
+
logTransportLifecycle(event);
|
|
401
|
+
if (event.phase === "timeout" || event.cleanupOutcome === "request_abandoned") {
|
|
402
|
+
ctx.log(formatTransportLifecycle(event));
|
|
403
|
+
}
|
|
404
|
+
},
|
|
396
405
|
resolveModelClass: (modelClass) => ctx.resolveModelClass?.(modelClass),
|
|
397
406
|
resolveModelRef: (modelRef) => ctx.resolveModelRef?.(modelRef),
|
|
398
407
|
createRuntimeTools: (mode) => {
|
|
@@ -8,9 +8,9 @@ import {
|
|
|
8
8
|
executeManageTodoList,
|
|
9
9
|
executionStateToTodos,
|
|
10
10
|
restoreExecutionState
|
|
11
|
-
} from "../../../chunks/chunk-
|
|
12
|
-
import "../../../chunks/chunk-
|
|
13
|
-
import "../../../chunks/chunk-
|
|
11
|
+
} from "../../../chunks/chunk-M44CWVDZ.js";
|
|
12
|
+
import "../../../chunks/chunk-NJFPBU36.js";
|
|
13
|
+
import "../../../chunks/chunk-XUROMYTT.js";
|
|
14
14
|
import "../../../chunks/chunk-XXGYUYXI.js";
|
|
15
15
|
import "../../../chunks/chunk-LZQXQOPJ.js";
|
|
16
16
|
|
|
@@ -0,0 +1,172 @@
|
|
|
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
|
+
## How it runs
|
|
21
|
+
|
|
22
|
+
The CLI is a short-lived client. A local **broker** owns the execution engine,
|
|
23
|
+
native helper handles, observation state, resource scheduling, `@o` output
|
|
24
|
+
refs, and image artifacts. The broker starts on demand, is shared by every Pie
|
|
25
|
+
session on this desktop, and exits after 30 minutes with no in-flight or
|
|
26
|
+
unconfirmed work. It is not a system service and opens no network listener
|
|
27
|
+
(Unix socket on macOS/Linux, per-user named pipe on Windows).
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
node <baseDir>/computer-use-axi-cli.js status # broker pid/generation/queues
|
|
31
|
+
node <baseDir>/computer-use-axi-cli.js stop # safe shutdown, owns only its processes
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
A broker restart creates a new generation. State ids from the old generation
|
|
35
|
+
are reported as expired; they are never restored or replayed — run `roots` and
|
|
36
|
+
`observe` again.
|
|
37
|
+
|
|
38
|
+
`stop` is a safe drain, not a hard kill. While a native action is still
|
|
39
|
+
settling, the stopping broker keeps its endpoint bound and rejects new
|
|
40
|
+
connections with `broker_draining`; a bootstrapping broker waits for that
|
|
41
|
+
drain instead of starting a second execution authority. Retry shortly after a
|
|
42
|
+
`broker_draining` rejection rather than racing another broker.
|
|
43
|
+
|
|
44
|
+
## Current guidance lives in the CLI
|
|
45
|
+
|
|
46
|
+
`--help` prints the full command surface; each command's output carries its
|
|
47
|
+
own next-step guidance. This file covers the flow semantics.
|
|
48
|
+
|
|
49
|
+
## The loop
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
node <baseDir>/computer-use-axi-cli.js roots # list @r roots
|
|
53
|
+
node <baseDir>/computer-use-axi-cli.js observe --root @r1 # outline + stateId
|
|
54
|
+
node <baseDir>/computer-use-axi-cli.js search --state S1 --text Save
|
|
55
|
+
node <baseDir>/computer-use-axi-cli.js act --state S1 --actions '[{"action":"press","ref":"@e12"}]'
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
1. `roots` finds controllable windows/pages and mints `@r` refs.
|
|
59
|
+
2. `observe` captures one root and returns a folded outline plus a `stateId`.
|
|
60
|
+
`--mode semantic` is cheapest (no OCR/images), `fused` is the default,
|
|
61
|
+
`visual` forces image evidence.
|
|
62
|
+
3. `search` / `expand` / `inspect` query that saved state (`--state S1`) —
|
|
63
|
+
no re-observation needed. Search needs at least one of `--text`, `--role`,
|
|
64
|
+
`--capability`; refine broad queries instead of paging.
|
|
65
|
+
4. `act` performs checked actions against the same state and returns the
|
|
66
|
+
successor state with a new `stateId` — use it directly for follow-ups.
|
|
67
|
+
Observe again only after uncertain external changes or eviction errors.
|
|
68
|
+
|
|
69
|
+
## Refs and state
|
|
70
|
+
|
|
71
|
+
- `@rN` root refs come from `roots`; they stay stable per window identity.
|
|
72
|
+
- `@eN` element refs + the owning `stateId` come from `observe`/`search`;
|
|
73
|
+
every state-consuming command takes `--state`.
|
|
74
|
+
- States are stale-checked by epoch: acting twice from one stateId fails the
|
|
75
|
+
second time by design — consume the successor stateId the act output names.
|
|
76
|
+
- `@oN` refs continue long truncated output: `read --ref @o1 --offset N`
|
|
77
|
+
(byte offsets; no `--state` needed for `@o`). The broker allocates these.
|
|
78
|
+
- `pictureOnly` nodes have no semantic element: coordinate actions only, and
|
|
79
|
+
only from an image-bearing (visual) state.
|
|
80
|
+
|
|
81
|
+
## Image evidence
|
|
82
|
+
|
|
83
|
+
Visual observations do not print base64. The broker writes the original
|
|
84
|
+
screenshot to a private file (`0700` directory, `0600` file under the Pie
|
|
85
|
+
config directory) and the text result names its absolute path, dimensions,
|
|
86
|
+
sha256, broker generation, and owning `stateId`.
|
|
87
|
+
|
|
88
|
+
When the result includes an `Image evidence:` line, call the normal
|
|
89
|
+
`read_file` tool on that absolute path before using coordinates. The image
|
|
90
|
+
belongs only to the returned `stateId`: after acting, use the successor
|
|
91
|
+
image/state, not the old one. Artifacts are evicted with their state; if the
|
|
92
|
+
file is gone, observe again instead of guessing coordinates. The broker never
|
|
93
|
+
scales or transforms the bytes it stores.
|
|
94
|
+
|
|
95
|
+
## Owners and concurrency
|
|
96
|
+
|
|
97
|
+
The Pie host passes an opaque owner identity into the shell; separate sessions
|
|
98
|
+
have separate observations, `@o` refs, and artifact directories. Manual CLI
|
|
99
|
+
use without that environment resolves to a stable `standalone` namespace.
|
|
100
|
+
Owners are **not** an OS security boundary — every client is the same local
|
|
101
|
+
user. Two owners acting on the same app/page share one resource lane and one
|
|
102
|
+
epoch counter, so the second write is rejected as stale rather than
|
|
103
|
+
overlapping. `status` reports only an owner **count** and non-reversible
|
|
104
|
+
fingerprints; it never prints another session's owner id.
|
|
105
|
+
|
|
106
|
+
## Acting and batching
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
node <baseDir>/computer-use-axi-cli.js act --state S1 --actions '[
|
|
110
|
+
{"action":"click","ref":"@e18"},
|
|
111
|
+
{"action":"typeText","text":"hello"}
|
|
112
|
+
]' --expect '{"text":"hello"}'
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
- Batch steps only when the second does not need to inspect the first's
|
|
116
|
+
result; steps run sequentially in one transaction.
|
|
117
|
+
- Attach `--expect` (JSON condition: `text`/`role`/`value`/`ref`/`scope-ref`/
|
|
118
|
+
`until`/`timeout-ms`) when an action has an observable completion signal —
|
|
119
|
+
but only within the same root: a modal/sheet or a closing window is a NEW
|
|
120
|
+
root, so expect cannot see it; run the action without `--expect` and read
|
|
121
|
+
the returned root note instead.
|
|
122
|
+
- Focus-following works only inside one act transaction: after a click into
|
|
123
|
+
an editable region, later `typeText`/`keypress` steps in the SAME
|
|
124
|
+
`--actions` array may omit `ref`. A standalone keypress (for example
|
|
125
|
+
`["cmd","w"]`) must carry `ref` (the window or a specific element).
|
|
126
|
+
- On failure the output still names the successor state — inspect it instead
|
|
127
|
+
of blindly replaying.
|
|
128
|
+
- Acting requires the platform helper: on macOS first use installs
|
|
129
|
+
`pie-computer-use.app` and asks for Accessibility + Screen Recording
|
|
130
|
+
grants. If a helper/setup error appears, run
|
|
131
|
+
`node <baseDir>/scripts/setup-helper.mjs` once, grant the permissions, and
|
|
132
|
+
retry.
|
|
133
|
+
|
|
134
|
+
## Uncertain outcomes
|
|
135
|
+
|
|
136
|
+
If a command returns `Outcome unknown` (the client timed out or lost the
|
|
137
|
+
broker connection after dispatch), the native action may already have run.
|
|
138
|
+
Do **not** replay it. The broker keeps that resource lane occupied until the
|
|
139
|
+
native helper confirms completion; run `observe` to establish a successor
|
|
140
|
+
state and decide from there. Reusing the same `--request-id` retrieves the
|
|
141
|
+
original result (or `in-flight`/`outcome-unknown`); it never dispatches again.
|
|
142
|
+
|
|
143
|
+
## Browser pages
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
node <baseDir>/computer-use-axi-cli.js browser launch --url https://example.com
|
|
147
|
+
node <baseDir>/computer-use-axi-cli.js browser navigate --state S1 --url https://other.example
|
|
148
|
+
node <baseDir>/computer-use-axi-cli.js browser eval --state S1 --expr 'document.title'
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Browser states use the same outline/action/condition contracts as desktop
|
|
152
|
+
states. Native browser windows are ordinary desktop UI — use `roots`/
|
|
153
|
+
`observe`/`act` on them. Browser control may need enabling via the
|
|
154
|
+
computer-use config (`browser_use`).
|
|
155
|
+
|
|
156
|
+
## Test-only backend
|
|
157
|
+
|
|
158
|
+
The deterministic fake desktop backend used by the broker test suite is not
|
|
159
|
+
shipped in release bundles. In a source checkout it activates only when both
|
|
160
|
+
`PIE_COMPUTER_USE_FAKE_BACKEND=1` and
|
|
161
|
+
`PIE_COMPUTER_USE_ENABLE_TEST_COMMANDS=1` are set; otherwise the setting is
|
|
162
|
+
ignored with a warning and the real platform backend is used. Never rely on it
|
|
163
|
+
for real UI work.
|
|
164
|
+
|
|
165
|
+
## Output bounds and exit codes
|
|
166
|
+
|
|
167
|
+
Model-facing output is capped (~48 KiB / 2 000 lines); oversized results
|
|
168
|
+
return a preview plus an `@o` continuation ref. Exit codes: `0` ok, `1` tool
|
|
169
|
+
or broker error (message on stderr), `2` usage error, `3` broker
|
|
170
|
+
version/generation mismatch (run `stop`, then retry). `--json` wraps
|
|
171
|
+
`{ content, details, isError }` for programmatic use; `--request-id` makes a
|
|
172
|
+
retry idempotent.
|