pi-ui-extend 1.0.40 → 1.0.42
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 +10 -2
- package/dist/app/app.d.ts +3 -0
- package/dist/app/app.js +26 -0
- package/dist/app/commands/command-host.d.ts +1 -0
- package/dist/app/commands/command-model-actions.js +6 -1
- package/dist/app/commands/command-registry.js +3 -3
- package/dist/app/commands/command-session-actions.d.ts +0 -1
- package/dist/app/commands/command-session-actions.js +30 -15
- package/dist/app/commands/reload-context-inventory.d.ts +11 -0
- package/dist/app/commands/reload-context-inventory.js +59 -0
- package/dist/app/extensions/extension-actions-controller.d.ts +1 -0
- package/dist/app/extensions/extension-actions-controller.js +6 -0
- package/dist/app/extensions/subagent-catalog-state.d.ts +9 -0
- package/dist/app/extensions/subagent-catalog-state.js +23 -0
- package/dist/app/icons.d.ts +14 -0
- package/dist/app/icons.js +33 -0
- package/dist/app/rendering/conversation-tool-renderer.js +2 -2
- package/dist/app/rendering/dcp-stats.d.ts +6 -1
- package/dist/app/rendering/dcp-stats.js +214 -46
- package/dist/app/rendering/editor-panels.js +17 -8
- package/dist/app/session/lazy-session-manager.js +12 -1
- package/dist/app/session/session-lifecycle-controller.d.ts +1 -0
- package/dist/app/session/session-lifecycle-controller.js +6 -0
- package/dist/app/session/tabs-controller.d.ts +3 -5
- package/dist/app/session/tabs-controller.js +31 -22
- package/dist/app/subagents/subagents-files.js +60 -1
- package/dist/app/subagents/subagents-model.d.ts +15 -1
- package/dist/app/subagents/subagents-model.js +52 -17
- package/dist/app/types.d.ts +7 -0
- package/dist/bundled-extensions/session-title/config.js +1 -1
- package/dist/default-pix-config.js +10 -0
- package/dist/markdown-format.js +27 -9
- package/dist/schemas/index.d.ts +1 -0
- package/dist/schemas/index.js +1 -0
- package/dist/schemas/pi-tools-suite-schema.d.ts +106 -71
- package/dist/schemas/pi-tools-suite-schema.js +68 -88
- package/dist/schemas/pix-schema.d.ts +7 -0
- package/dist/schemas/pix-schema.js +14 -0
- package/dist/schemas/tasks-schema.d.ts +18 -0
- package/dist/schemas/tasks-schema.js +41 -0
- package/docs/concurrency.md +6 -0
- package/docs/desktop-mvp.md +12 -1
- package/docs/desktop-task-manager.md +93 -82
- package/external/pi-tools-suite/README.md +192 -72
- package/external/pi-tools-suite/docs/browser-qa-subagent.md +50 -21
- package/external/pi-tools-suite/docs/context-gateway-p00-adr.md +216 -0
- package/external/pi-tools-suite/docs/context-gateway-p01n-gate-review.md +122 -0
- package/external/pi-tools-suite/docs/context-gateway-p01n-measurement.md +133 -0
- package/external/pi-tools-suite/docs/context-gateway-p01r-ra-evidence.md +111 -0
- package/external/pi-tools-suite/docs/context-gateway-p01r-rb-evidence.md +100 -0
- package/external/pi-tools-suite/docs/context-gateway-p01r-rc-evidence.md +69 -0
- package/external/pi-tools-suite/docs/context-gateway-p01r-rd-evidence.md +100 -0
- package/external/pi-tools-suite/docs/context-gateway-p01r-re-evidence.md +74 -0
- package/external/pi-tools-suite/docs/context-gateway-p01r-rf-evidence.md +153 -0
- package/external/pi-tools-suite/docs/context-gateway-p01r-rg-evidence.md +235 -0
- package/external/pi-tools-suite/docs/evals.md +1 -1
- package/external/pi-tools-suite/docs/session-recovery.md +40 -14
- package/external/pi-tools-suite/docs/subagent-model-pools.md +120 -0
- package/external/pi-tools-suite/package.json +3 -0
- package/external/pi-tools-suite/src/async-subagents/{private-skills → agents}/browser-qa/scripts/browser-qa-runner.mjs +82 -1
- package/external/pi-tools-suite/src/async-subagents/{private-skills/browser-qa/SKILL.md → agents/browser-qa.md} +261 -12
- package/external/pi-tools-suite/src/async-subagents/agents/frontier-review.md +23 -0
- package/external/pi-tools-suite/src/async-subagents/agents/implement.md +20 -0
- package/external/pi-tools-suite/src/async-subagents/agents/oracle.md +16 -0
- package/external/pi-tools-suite/src/async-subagents/agents/presets.jsonc +16 -0
- package/external/pi-tools-suite/src/async-subagents/agents/research.md +20 -0
- package/external/pi-tools-suite/src/async-subagents/agents/verify.md +18 -0
- package/external/pi-tools-suite/src/async-subagents/commands.ts +20 -72
- package/external/pi-tools-suite/src/async-subagents/core/activity.ts +33 -0
- package/external/pi-tools-suite/src/async-subagents/core/agent-catalog.ts +42 -0
- package/external/pi-tools-suite/src/async-subagents/core/agent-strategy.ts +13 -93
- package/external/pi-tools-suite/src/async-subagents/core/agents-dir.ts +499 -0
- package/external/pi-tools-suite/src/async-subagents/core/browser-qa.ts +9 -0
- package/external/pi-tools-suite/src/async-subagents/core/config.ts +284 -417
- package/external/pi-tools-suite/src/async-subagents/core/model-fallback.ts +1 -1
- package/external/pi-tools-suite/src/async-subagents/core/model-selection.ts +54 -0
- package/external/pi-tools-suite/src/async-subagents/core/prompt.ts +7 -6
- package/external/pi-tools-suite/src/async-subagents/core/routing.ts +65 -45
- package/external/pi-tools-suite/src/async-subagents/core/spawn.ts +18 -6
- package/external/pi-tools-suite/src/async-subagents/core/state.ts +40 -0
- package/external/pi-tools-suite/src/async-subagents/core/types.ts +7 -0
- package/external/pi-tools-suite/src/async-subagents/index.ts +77 -3
- package/external/pi-tools-suite/src/async-subagents/lib.ts +12 -9
- package/external/pi-tools-suite/src/async-subagents/tools/spawn.ts +54 -22
- package/external/pi-tools-suite/src/async-subagents/tools/subagents.ts +6 -4
- package/external/pi-tools-suite/src/async-subagents/types.ts +3 -0
- package/external/pi-tools-suite/src/config.ts +42 -2
- package/external/pi-tools-suite/src/context-gateway/accounting.ts +151 -0
- package/external/pi-tools-suite/src/context-gateway/config.ts +120 -0
- package/external/pi-tools-suite/src/context-gateway/enforcement.ts +102 -0
- package/external/pi-tools-suite/src/context-gateway/index.ts +214 -0
- package/external/pi-tools-suite/src/context-gateway/metadata-normalization.ts +88 -0
- package/external/pi-tools-suite/src/context-gateway/storeless-capabilities.ts +89 -0
- package/external/pi-tools-suite/src/context-gateway/telemetry.ts +502 -0
- package/external/pi-tools-suite/src/context-gateway/test-output-parser.ts +326 -0
- package/external/pi-tools-suite/src/context-gateway/types.ts +158 -0
- package/external/pi-tools-suite/src/context-inventory.ts +99 -0
- package/external/pi-tools-suite/src/dcp/auto-compress-budget.ts +106 -0
- package/external/pi-tools-suite/src/dcp/auto-compress.ts +892 -136
- package/external/pi-tools-suite/src/dcp/commands.ts +82 -139
- package/external/pi-tools-suite/src/dcp/compress-tool.ts +533 -74
- package/external/pi-tools-suite/src/dcp/compression-blocks.ts +488 -94
- package/external/pi-tools-suite/src/dcp/compression-preview.ts +122 -0
- package/external/pi-tools-suite/src/dcp/compression-progress.ts +70 -0
- package/external/pi-tools-suite/src/dcp/config.ts +86 -68
- package/external/pi-tools-suite/src/dcp/conversation-index.ts +421 -0
- package/external/pi-tools-suite/src/dcp/debug-log.ts +7 -5
- package/external/pi-tools-suite/src/dcp/index.ts +617 -203
- package/external/pi-tools-suite/src/dcp/journal.ts +566 -0
- package/external/pi-tools-suite/src/dcp/progress-controller.ts +244 -0
- package/external/pi-tools-suite/src/dcp/prompts.ts +83 -189
- package/external/pi-tools-suite/src/dcp/protected-continuity.ts +175 -0
- package/external/pi-tools-suite/src/dcp/provider-tool-results.ts +189 -0
- package/external/pi-tools-suite/src/dcp/pruner-candidates.ts +299 -79
- package/external/pi-tools-suite/src/dcp/pruner-compression-blocks.ts +173 -281
- package/external/pi-tools-suite/src/dcp/pruner-emergency.ts +2 -4
- package/external/pi-tools-suite/src/dcp/pruner-message-ids.ts +23 -15
- package/external/pi-tools-suite/src/dcp/pruner-metadata.ts +11 -1
- package/external/pi-tools-suite/src/dcp/pruner-nudge.ts +30 -82
- package/external/pi-tools-suite/src/dcp/pruner-tools.ts +28 -136
- package/external/pi-tools-suite/src/dcp/pruner.ts +18 -33
- package/external/pi-tools-suite/src/dcp/recovery.ts +129 -0
- package/external/pi-tools-suite/src/dcp/shadow-plan.ts +127 -0
- package/external/pi-tools-suite/src/dcp/state-transaction.ts +102 -0
- package/external/pi-tools-suite/src/dcp/state.ts +158 -580
- package/external/pi-tools-suite/src/dcp/ui.ts +1 -0
- package/external/pi-tools-suite/src/default-pi-tools-suite-config.ts +36 -214
- package/external/pi-tools-suite/src/index.ts +16 -1
- package/external/pi-tools-suite/src/model-tools/index.ts +76 -42
- package/external/pi-tools-suite/src/repo-discovery/index.ts +84 -18
- package/external/pi-tools-suite/src/repo-discovery/native-compact.ts +458 -0
- package/external/pi-tools-suite/src/resource-registry/index.ts +2290 -0
- package/external/pi-tools-suite/src/session-recovery/index.ts +189 -43
- package/external/pi-tools-suite/src/shell-command-policy.ts +219 -0
- package/external/pi-tools-suite/src/tool-descriptions.ts +41 -38
- package/external/pi-tools-suite/src/truncation-metadata-normalizer/index.ts +17 -0
- package/package.json +6 -3
- package/schemas/pi-tools-suite.json +540 -312
- package/schemas/pix.json +24 -0
- package/schemas/tasks.json +132 -0
- package/skills/spec-wiki/SKILL.md +55 -0
- package/skills/spec-wiki/evals/evals.json +132 -0
- package/skills/spec-wiki/evals/files/bootstrap/architecture/rfc-007.md +14 -0
- package/skills/spec-wiki/evals/files/bootstrap/docs/how-to-pay.md +4 -0
- package/skills/spec-wiki/evals/files/bootstrap/docs/overview.md +9 -0
- package/skills/spec-wiki/evals/files/bootstrap/requirements/payment-behavior.md +17 -0
- package/skills/spec-wiki/evals/files/bootstrap/src/payments.ts +12 -0
- package/skills/spec-wiki/evals/files/bootstrap/tests/payments.test.ts +11 -0
- package/skills/spec-wiki/evals/files/focused/src/session.ts +5 -0
- package/skills/spec-wiki/evals/files/focused/tests/session.test.ts +17 -0
- package/skills/spec-wiki/evals/files/maintenance/low-signal/incoming/capture.txt +2 -0
- package/skills/spec-wiki/evals/files/maintenance/low-signal/src/capture.ts +3 -0
- package/skills/spec-wiki/evals/files/maintenance/move/docs/old-job-contract.md +18 -0
- package/skills/spec-wiki/evals/files/maintenance/move/src/job.ts +5 -0
- package/skills/spec-wiki/evals/files/maintenance/new-relation/docs/session-refresh.md +24 -0
- package/skills/spec-wiki/evals/files/maintenance/new-relation/incoming/refresh-worker.ts +7 -0
- package/skills/spec-wiki/evals/files/maintenance/new-relation/src/session.ts +7 -0
- package/skills/spec-wiki/evals/files/maintenance/no-impact/docs/auth-contract.md +17 -0
- package/skills/spec-wiki/evals/files/maintenance/no-impact/incoming/telemetry-format.ts +3 -0
- package/skills/spec-wiki/evals/files/maintenance/no-impact/src/auth.ts +3 -0
- package/skills/spec-wiki/evals/files/query/docs/how-to-run-jobs.md +4 -0
- package/skills/spec-wiki/evals/files/query/docs/spec-overview.md +9 -0
- package/skills/spec-wiki/evals/files/query/features/jobs/cancellation-contract.md +15 -0
- package/skills/spec-wiki/evals/files/query/features/jobs/retry-spec.md +6 -0
- package/skills/spec-wiki/evals/maintenance_regression.py +311 -0
- package/skills/spec-wiki/evals/retrieval-eval.md +37 -0
- package/skills/spec-wiki/evals/retrieval-evals.json +37 -0
- package/skills/spec-wiki/evals/trigger-evals.json +94 -0
- package/skills/spec-wiki/references/bootstrap.md +100 -0
- package/skills/spec-wiki/references/focused-spec.md +117 -0
- package/skills/spec-wiki/references/index-schema.md +330 -0
- package/skills/spec-wiki/references/maintenance.md +134 -0
- package/skills/spec-wiki/references/query.md +74 -0
- package/skills/spec-wiki/scripts/spec_wiki.py +2076 -0
- package/docs/desktop-markdown-media.md +0 -77
- package/external/pi-tools-suite/docs/dcp-emergency-current-turn.md +0 -102
- package/external/pi-tools-suite/src/async-subagents/async-subagents.sample.jsonc +0 -270
- package/external/pi-tools-suite/src/async-subagents/private-skills/browser-qa/references/auth-scaffold-spec.md +0 -78
- package/external/pi-tools-suite/src/async-subagents/private-skills/browser-qa/references/qa-design.md +0 -223
- package/external/pi-tools-suite/src/dcp/state-persistence.ts +0 -195
- package/external/pi-tools-suite/src/skill-installer/index.ts +0 -333
- package/skills/spec-lite/SKILL.md +0 -140
- /package/external/pi-tools-suite/src/async-subagents/{private-skills/browser-qa/references → agents/browser-qa/examples}/qa-auth.example.jsonc +0 -0
- /package/external/pi-tools-suite/src/async-subagents/{private-skills/browser-qa/references → agents/browser-qa/examples}/qa-flow.example.jsonc +0 -0
- /package/external/pi-tools-suite/src/async-subagents/{private-skills → agents}/browser-qa/vendor/fflate.LICENSE +0 -0
- /package/external/pi-tools-suite/src/async-subagents/{private-skills → agents}/browser-qa/vendor/fflate.mjs +0 -0
|
@@ -1,15 +1,25 @@
|
|
|
1
1
|
---
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
description: Use for browser-based visual QA - reproduce UI bugs and verify fixes with deterministic assertions, screenshots, video, and traces.
|
|
3
|
+
icon: globe
|
|
4
|
+
models: [zai/glm-5.3-flash, openai-codex/gpt-5.6-luna]
|
|
5
|
+
thinking: low
|
|
6
|
+
timeoutMs: 300000
|
|
7
|
+
tools: [read, grep, bash]
|
|
4
8
|
---
|
|
5
9
|
|
|
6
10
|
# Browser QA
|
|
7
11
|
|
|
8
|
-
Use this
|
|
12
|
+
Use this agent's bundled runner as the only browser interface. It already owns
|
|
9
13
|
Playwright, browser/context lifecycle, tracing, video, screenshots, origin
|
|
10
14
|
isolation, authentication, redaction, and cleanup. Do not invoke another browser
|
|
11
15
|
CLI, create shared/default browser sessions, or generate executable browser code.
|
|
12
16
|
|
|
17
|
+
The launcher sets `PI_BROWSER_QA_RUNNER` to the absolute path of the installed
|
|
18
|
+
runner. Invoke it as `node "$PI_BROWSER_QA_RUNNER"`; do not guess a path from
|
|
19
|
+
the project cwd, override this variable, or copy/reimplement the runner.
|
|
20
|
+
The complete workflow and scenario-design guidance are included below. No
|
|
21
|
+
additional skill or instruction-file discovery is needed.
|
|
22
|
+
|
|
13
23
|
Never read, print, grep, copy, or edit credential values from
|
|
14
24
|
`.pi/qa_auth.jsonc` yourself.
|
|
15
25
|
|
|
@@ -37,7 +47,8 @@ inside the preflight, return a structured `BLOCKED` result immediately. Do not
|
|
|
37
47
|
consume the launcher budget on open-ended source reading, server polling,
|
|
38
48
|
capability probing, or retries.
|
|
39
49
|
|
|
40
|
-
1.
|
|
50
|
+
1. Use the launcher-provided `PI_BROWSER_QA_RUNNER` path. If it is missing,
|
|
51
|
+
report a launcher configuration blocker rather than selecting another runner.
|
|
41
52
|
2. Use the launcher-provided `$PI_SUBAGENT_AGENT_DIR/browser-qa/` workspace.
|
|
42
53
|
The launcher creates its private `flows/` directory and the runner rejects
|
|
43
54
|
flows or evidence destinations outside this owning sub-agent directory. Do
|
|
@@ -48,7 +59,7 @@ capability probing, or retries.
|
|
|
48
59
|
be reached or started, report the concrete blocker instead of switching to a
|
|
49
60
|
mock target or substituting static checks for browser QA.
|
|
50
61
|
4. If the requested behavior requires authentication, run
|
|
51
|
-
`node
|
|
62
|
+
`node "$PI_BROWSER_QA_RUNNER" profiles`. A missing auth config returns an empty
|
|
52
63
|
list without creating `.pi/qa_auth.jsonc`. Otherwise skip profile discovery
|
|
53
64
|
and use public mode. Choose an auth profile only when the task names its id,
|
|
54
65
|
safe profile traits make the choice unambiguous, or a public run proves that
|
|
@@ -61,7 +72,8 @@ capability probing, or retries.
|
|
|
61
72
|
executable JavaScript in it. The `evaluate` action exposes only the safe
|
|
62
73
|
operations documented below; it does not accept expressions or scripts.
|
|
63
74
|
6. Run public QA with
|
|
64
|
-
`node
|
|
75
|
+
`node "$PI_BROWSER_QA_RUNNER" run --base-url <url> --flow <flow.jsonc>`.
|
|
76
|
+
The URL's exact
|
|
65
77
|
origin becomes the fail-closed allowlist. When the real app requires known
|
|
66
78
|
API/CDN origins, add repeatable `--allow-origin <exact-origin>` flags. Each
|
|
67
79
|
value must be an exact `http(s)` origin with no path, credentials, wildcard,
|
|
@@ -128,8 +140,8 @@ capability probing, or retries.
|
|
|
128
140
|
product behavior differs from the expectation, preserve the failure evidence
|
|
129
141
|
and report the mismatch.
|
|
130
142
|
|
|
131
|
-
|
|
132
|
-
ambiguous
|
|
143
|
+
Use the detailed scenario-design guidance below for non-trivial flows,
|
|
144
|
+
ambiguous failures, and decisions about what evidence proves the result.
|
|
133
145
|
|
|
134
146
|
## Flow contract
|
|
135
147
|
|
|
@@ -293,7 +305,7 @@ When a public HTTPS login page (or loopback HTTP page for local development) is
|
|
|
293
305
|
known and there is no usable profile, invoke the trusted runner once:
|
|
294
306
|
|
|
295
307
|
```sh
|
|
296
|
-
node
|
|
308
|
+
node "$PI_BROWSER_QA_RUNNER" auth scaffold \
|
|
297
309
|
--profile <safe-id> \
|
|
298
310
|
--login-url <public-login-url>
|
|
299
311
|
```
|
|
@@ -322,7 +334,7 @@ Do not request credentials merely because `.pi/qa_auth.jsonc` is absent. If the
|
|
|
322
334
|
task explicitly requires authenticated behavior, or a public run reaches the
|
|
323
335
|
flow's `authRejectedIf` check, and `profiles` returned no usable profile, run
|
|
324
336
|
form-auth scaffolding when supported. Otherwise run
|
|
325
|
-
`node
|
|
337
|
+
`node "$PI_BROWSER_QA_RUNNER" profiles --require-auth`. Only these paths
|
|
326
338
|
may create the private auth file.
|
|
327
339
|
|
|
328
340
|
If that command or an authenticated run returns `QA_AUTH_UPDATE_REQUIRED`, stop
|
|
@@ -345,5 +357,242 @@ These links are mandatory so the user can open the evidence directly.
|
|
|
345
357
|
Also include `visualInspection` with `inspected` or `unavailable`; never infer a
|
|
346
358
|
visual pass from a successful runner status alone.
|
|
347
359
|
|
|
348
|
-
|
|
349
|
-
|
|
360
|
+
### Scaffold safety and edge cases
|
|
361
|
+
|
|
362
|
+
The trusted runner discovers the most likely form, fillable fields, submit
|
|
363
|
+
control, and form container on the unauthenticated page. It writes only
|
|
364
|
+
discovered selectors and generated placeholders to the private `0600` config.
|
|
365
|
+
The agent treats that config as opaque and user-owned. Scaffold status exposes
|
|
366
|
+
only the file path, profile id, counts, and action, never inspected DOM text,
|
|
367
|
+
input values, URLs, or selectors.
|
|
368
|
+
|
|
369
|
+
Scaffolding rejects pages without a discoverable fillable field or submit
|
|
370
|
+
control, form-less pages without an explicit success condition, remote HTTP
|
|
371
|
+
login pages, cross-origin base URLs, malformed success options, symlinked or
|
|
372
|
+
permissive auth paths, and invalid or non-empty existing configuration. Report
|
|
373
|
+
these blockers; do not bypass them. No generated profile is usable until the
|
|
374
|
+
user replaces its secret placeholders.
|
|
375
|
+
|
|
376
|
+
## Detailed scenario-design guidance
|
|
377
|
+
|
|
378
|
+
Use the bundled declarative runner throughout. This workflow does not require
|
|
379
|
+
a separate browser CLI or executable Playwright scripts.
|
|
380
|
+
|
|
381
|
+
### Build the proof before the steps
|
|
382
|
+
|
|
383
|
+
Write down three things first:
|
|
384
|
+
|
|
385
|
+
1. **Setup:** the page and state needed to expose the behavior.
|
|
386
|
+
2. **Action:** the smallest user interaction that exercises it.
|
|
387
|
+
3. **Oracle:** the observable state that proves success or reproduces failure.
|
|
388
|
+
|
|
389
|
+
Good oracles are product-visible and specific: an exact URL, a stable status
|
|
390
|
+
message, a field value, item count, enabled/disabled state, or checked state.
|
|
391
|
+
Avoid treating “the click did not throw” or “the screenshot looks plausible” as
|
|
392
|
+
proof.
|
|
393
|
+
|
|
394
|
+
When verifying a fix, prefer a focused regression flow over a broad tour of the
|
|
395
|
+
application. If multiple independent states matter, assert each one explicitly.
|
|
396
|
+
|
|
397
|
+
For explicit exploratory/manual QA, keep exploration bounded rather than turning
|
|
398
|
+
it into an open-ended crawl. Run at most three minimal rounds. Each round should
|
|
399
|
+
start from one concrete hypothesis, produce a deterministic observation plus a
|
|
400
|
+
meaningful screenshot, and use that evidence to decide whether another round is
|
|
401
|
+
justified. Verification tasks remain one browser run per profile.
|
|
402
|
+
|
|
403
|
+
### Choose resilient locators
|
|
404
|
+
|
|
405
|
+
Prefer locators that match how users and accessibility APIs identify controls:
|
|
406
|
+
|
|
407
|
+
1. `testId` when the product exposes a stable test contract.
|
|
408
|
+
2. `role` with accessible `name` for buttons, links, headings, dialogs, and
|
|
409
|
+
similar semantic elements.
|
|
410
|
+
3. `label` for form controls.
|
|
411
|
+
4. `placeholder` or visible `text` when they are stable product copy.
|
|
412
|
+
5. `css` only when no semantic contract exists.
|
|
413
|
+
|
|
414
|
+
Use `exact: true` when duplicate or substring matches are possible. Avoid CSS
|
|
415
|
+
that encodes DOM depth, generated classes, styling details, or element order.
|
|
416
|
+
If a locator is ambiguous, inspect nearby source or rendered copy and choose a
|
|
417
|
+
more specific product contract rather than adding arbitrary delays.
|
|
418
|
+
|
|
419
|
+
### Wait for state, not time
|
|
420
|
+
|
|
421
|
+
Runner interactions inherit Playwright auto-waiting. Usually an action followed
|
|
422
|
+
by an assertion is enough. Use `waitFor` only when the next operation depends on
|
|
423
|
+
a distinct attached/detached/visible/hidden transition.
|
|
424
|
+
|
|
425
|
+
After navigation and visible interactions, the runner also waits for DOM
|
|
426
|
+
readiness, tracks requests causally started by that action through a bounded
|
|
427
|
+
readiness window, waits for common visible
|
|
428
|
+
`aria-busy`/progress/loading/spinner/skeleton markers, and keeps a 500 ms stable
|
|
429
|
+
interval. EventSource/WebSocket traffic is ignored, and a long poll is not
|
|
430
|
+
allowed to pin the entire flow timeout. A visible busy indicator may still hold
|
|
431
|
+
readiness until `timeoutMs`. This is a safe baseline, not an application-specific
|
|
432
|
+
oracle: explicitly wait for a custom loader to become hidden and assert the
|
|
433
|
+
loaded content when the application uses different readiness semantics.
|
|
434
|
+
|
|
435
|
+
`waitForTimeout` is bounded to five seconds and should be exceptional—for a
|
|
436
|
+
known animation, debounce, or externally scheduled transition with no
|
|
437
|
+
observable intermediate state. Sleeping longer hides races instead of proving
|
|
438
|
+
behavior. If a normal operation legitimately needs more time, adjust the flow's
|
|
439
|
+
`timeoutMs` rather than inserting repeated sleeps.
|
|
440
|
+
|
|
441
|
+
All assertion actions retry until that timeout. This makes an action followed
|
|
442
|
+
directly by `assertText`, `assertVisible`, `assertURL`, or another assertion
|
|
443
|
+
safe for asynchronously rendered outcomes. `assertText` requires the locator to
|
|
444
|
+
be visible and matches rendered `innerText`; use `assertTextContent` only when
|
|
445
|
+
hidden/raw DOM text is deliberately part of the oracle. Use `assertAttribute` for
|
|
446
|
+
observable state such as `aria-expanded`, `aria-invalid`, or `data-state`
|
|
447
|
+
instead of reading DOM state through executable JavaScript.
|
|
448
|
+
|
|
449
|
+
### Responsive and scrolling scenarios
|
|
450
|
+
|
|
451
|
+
Set the flow's top-level `viewport` whenever the bug depends on a breakpoint or
|
|
452
|
+
available height. Assert `viewportWidth` or `viewportHeight` with
|
|
453
|
+
`assertDOMMetric` when the dimensions themselves are part of the proof; the
|
|
454
|
+
runner also includes the applied viewport in its result.
|
|
455
|
+
|
|
456
|
+
Use `wheel` to reproduce real pointer-wheel input. Add a locator when the wheel
|
|
457
|
+
must target a nested scrolling container—the runner hovers it before sending
|
|
458
|
+
the input. Because browser scrolling may be scheduled after the wheel event,
|
|
459
|
+
wait only for a short known settling interval when a direct metric assertion is
|
|
460
|
+
otherwise racy.
|
|
461
|
+
|
|
462
|
+
Use safe `evaluate` `scrollTo`/`scrollBy` operations for deterministic setup or
|
|
463
|
+
to distinguish input handling from layout behavior. Use the `metrics` operation
|
|
464
|
+
to retain a named page/element snapshot in result `observations`, and use
|
|
465
|
+
`assertDOMMetric` for pass/fail. Raw JavaScript expressions are intentionally
|
|
466
|
+
excluded: flows remain declarative and cannot inspect authentication storage or
|
|
467
|
+
execute arbitrary same-origin requests.
|
|
468
|
+
|
|
469
|
+
### Deterministic browser environment
|
|
470
|
+
|
|
471
|
+
Set top-level `environment` when locale, timezone, color scheme, or motion
|
|
472
|
+
preferences can change the behavior. The runner otherwise uses stable defaults
|
|
473
|
+
(`en-US`, `UTC`, `light`, `reduce`) instead of inheriting host settings. Prefer
|
|
474
|
+
asserting product-visible copy or state derived from those settings; do not use
|
|
475
|
+
screenshot pixels as the only oracle.
|
|
476
|
+
|
|
477
|
+
### Causal network and dialog expectations
|
|
478
|
+
|
|
479
|
+
Put `expectResponse` or `expectDialog` on the interaction that causes the event.
|
|
480
|
+
The runner arms both listeners before the interaction, avoiding the race in a
|
|
481
|
+
separate “click, then wait” sequence. Response expectations deliberately match
|
|
482
|
+
only an exact allowlisted-origin pathname, HTTP method, and status. This proves
|
|
483
|
+
that a matching request started and received a response within the action
|
|
484
|
+
window without retaining its URL query, headers, or body.
|
|
485
|
+
|
|
486
|
+
Dialog expectations match a fixed dialog type and exact/included message, then
|
|
487
|
+
accept or dismiss it declaratively. A mismatch is dismissed before the step
|
|
488
|
+
fails so the page cannot freeze. Actual event metadata is never included in
|
|
489
|
+
failure diagnostics. Do not place secrets in expected messages or response
|
|
490
|
+
paths even though the runner keeps diagnostics generic.
|
|
491
|
+
|
|
492
|
+
### Drag, upload, and download scenarios
|
|
493
|
+
|
|
494
|
+
Use `dragTo` for native DOM drag/drop and assert the resulting product state.
|
|
495
|
+
Optional source/drop positions are relative bounded coordinates. Canvas-only,
|
|
496
|
+
OS-native, or custom synthetic-event drag protocols remain unsupported; do not
|
|
497
|
+
work around that with executable JavaScript.
|
|
498
|
+
|
|
499
|
+
Uploads are memory-only base64 payloads declared in the flow. This intentionally
|
|
500
|
+
prevents a flow from selecting arbitrary project files, credential config, or
|
|
501
|
+
directories. Keep fixtures minimal and non-secret. An empty file list clears a
|
|
502
|
+
file input.
|
|
503
|
+
|
|
504
|
+
Use the atomic `download` action rather than clicking a download link directly.
|
|
505
|
+
Always match the suggested filename and choose a tight `maxBytes`. Retain a
|
|
506
|
+
download only when its contents are needed as evidence; otherwise the runner
|
|
507
|
+
deletes it after validation. Retained downloads use generated private names,
|
|
508
|
+
not server-provided paths, and are scanned for configured authentication before
|
|
509
|
+
publication. `maxBytes` bounds the runner's private evidence copy and triggers
|
|
510
|
+
cancellation while it grows, but it is not a network-bandwidth guarantee: the
|
|
511
|
+
browser can receive temporary bytes before cancellation.
|
|
512
|
+
|
|
513
|
+
### Same-origin frames and popups
|
|
514
|
+
|
|
515
|
+
Use a scoped `target` for iframe or named popup interactions. The runner checks
|
|
516
|
+
the live frame origin before every scoped step and checks a popup after it loads;
|
|
517
|
+
both must remain in `allowedOrigins`. This supports embedded application UI and
|
|
518
|
+
same-origin auxiliary windows without opening a route around the network guard.
|
|
519
|
+
Cross-origin login, payment, and third-party widgets remain intentionally out of
|
|
520
|
+
scope. Each popup adds a separate private video artifact, so open only the
|
|
521
|
+
windows needed for the proof.
|
|
522
|
+
|
|
523
|
+
### Authentication transitions
|
|
524
|
+
|
|
525
|
+
Add `authRejectedIf` directly after initial navigation and after transitions
|
|
526
|
+
that can redirect to login or display an expired-session marker. This converts
|
|
527
|
+
stale credentials into an explicit update request instead of misreporting a
|
|
528
|
+
product regression.
|
|
529
|
+
|
|
530
|
+
Do not encode credentials, tokens, storage values, or login form secrets in the
|
|
531
|
+
flow. The trusted runner applies the selected profile internally. For form auth,
|
|
532
|
+
video starts on the login page and includes field filling and submission; password
|
|
533
|
+
inputs remain masked, but visible identifiers can appear, so treat the video as
|
|
534
|
+
sensitive private evidence. Tracing starts only after login succeeds and is
|
|
535
|
+
sanitized before retention.
|
|
536
|
+
|
|
537
|
+
### Evidence strategy
|
|
538
|
+
|
|
539
|
+
The runner always attempts a final or failure screenshot, records video from the
|
|
540
|
+
first page, and creates a sanitized post-auth trace. Add named `screenshot`
|
|
541
|
+
steps only at states that materially help explain the result—for example before
|
|
542
|
+
and after a destructive interaction, or when a transient success message is
|
|
543
|
+
the oracle.
|
|
544
|
+
|
|
545
|
+
Use evidence by purpose:
|
|
546
|
+
|
|
547
|
+
- **Screenshot:** quick review of one meaningful visual state.
|
|
548
|
+
- **Video:** chronological confirmation of the complete user flow.
|
|
549
|
+
- **Trace:** action/DOM timing diagnosis for a failed or flaky interaction.
|
|
550
|
+
|
|
551
|
+
Videos automatically show a transient cursor and yellow pulse for clicks and
|
|
552
|
+
double-clicks. After a native `dragTo` gesture completes, its resolved
|
|
553
|
+
source-to-target route is replayed over 450 ms with a large orange cursor and
|
|
554
|
+
progressively drawn high-contrast trail, followed by a green drop marker. These
|
|
555
|
+
annotations are
|
|
556
|
+
runner-owned, pointer-transparent, and accessibility-hidden; they cover the main
|
|
557
|
+
page, same-origin frames, declared popups, and form-auth submission. Their
|
|
558
|
+
bounded animations finish within the normal post-action stable interval, so
|
|
559
|
+
they explain the chronology without becoming screenshot or assertion oracles.
|
|
560
|
+
|
|
561
|
+
Assertions determine pass/fail; evidence explains it. Preserve and link every
|
|
562
|
+
artifact group returned on both passed and failed runs.
|
|
563
|
+
|
|
564
|
+
For visual QA, do not stop at artifact generation. Open at least one meaningful
|
|
565
|
+
PNG with the model's image-capable `read` path and inspect layout, clipping,
|
|
566
|
+
overlap, state styling, and other visual defects relevant to the scenario. If
|
|
567
|
+
the active model cannot read images, explicitly report visual inspection as
|
|
568
|
+
unavailable rather than treating deterministic assertions as a visual pass.
|
|
569
|
+
|
|
570
|
+
### Diagnose failures without weakening the test
|
|
571
|
+
|
|
572
|
+
Classify the first failing step:
|
|
573
|
+
|
|
574
|
+
- wrong target/setup or service unavailable;
|
|
575
|
+
- authentication rejected or expired;
|
|
576
|
+
- locator no longer matches the product contract;
|
|
577
|
+
- expected state never appeared;
|
|
578
|
+
- actual product behavior contradicts the expectation.
|
|
579
|
+
|
|
580
|
+
Fix the flow only when its setup or locator is wrong. Do not replace a precise
|
|
581
|
+
assertion with a vague one, increase timeouts reflexively, or remove the failing
|
|
582
|
+
step to manufacture a pass. Keep the failure artifacts and state the expected
|
|
583
|
+
versus observed behavior.
|
|
584
|
+
|
|
585
|
+
### Cleanup and isolation
|
|
586
|
+
|
|
587
|
+
Each runner invocation owns one isolated context and evidence directory and
|
|
588
|
+
closes its browser resources in a `finally` path. Do not create parallel shared
|
|
589
|
+
or default sessions outside the runner. Test multiple auth profiles with
|
|
590
|
+
separate invocations so cookies, storage, traces, and evidence cannot mix.
|
|
591
|
+
|
|
592
|
+
Keep the declarative flow and every generated screenshot, video, trace, and
|
|
593
|
+
result manifest inside `$PI_SUBAGENT_AGENT_DIR/browser-qa/`. The launcher owns
|
|
594
|
+
that path and the runner validates it before opening a browser. Do not override
|
|
595
|
+
the environment path or copy evidence into shared `.pi/qa-runs`/`.pi/qa-flows`
|
|
596
|
+
directories: the agent-local workspace is intentionally removed by the normal
|
|
597
|
+
sub-agent shutdown and cleanup lifecycle. Authentication config remains a
|
|
598
|
+
separate persistent input under project `.pi/`.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Independent frontier-model code review gate for substantive code changes made by a non-frontier parent. Use after implementation and targeted checks, before finalizing. Read-only review of the actual diff and surrounding code; use research for ordinary evidence gathering and oracle for architecture or high-stakes second opinions.
|
|
3
|
+
icon: eye
|
|
4
|
+
models: [openai-codex/gpt-5.6-sol, zai/glm-5.3]
|
|
5
|
+
notForParentModels: [openai-codex/gpt-5.6-sol*, zai/glm-5.3]
|
|
6
|
+
thinking: high
|
|
7
|
+
tools: [read, grep, bash]
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Frontier code review
|
|
11
|
+
|
|
12
|
+
Review the implementation independently. Inspect the actual diff and the
|
|
13
|
+
surrounding contracts; do not accept the implementer's summary as evidence.
|
|
14
|
+
|
|
15
|
+
Look for correctness bugs, regressions, broken invariants, unsafe edge cases,
|
|
16
|
+
missing error handling, concurrency/state mistakes, security issues, and tests
|
|
17
|
+
that fail to cover a material behavior change. Prefer a small number of
|
|
18
|
+
actionable findings over stylistic commentary or speculative rewrites.
|
|
19
|
+
|
|
20
|
+
Do not edit source or tests. Run narrow read-only checks when they materially
|
|
21
|
+
increase confidence. For each finding, give severity, rationale, and precise
|
|
22
|
+
file/line evidence. If there are no findings, say so explicitly and name any
|
|
23
|
+
important residual risk or verification gap.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Make bounded changes to code, docs, tests, or UI using the parent's requirements and acceptance criteria. Follow local conventions and verify the change. Task-specific discipline belongs in the brief, not a separate role.
|
|
3
|
+
icon: code
|
|
4
|
+
models: [zai/glm-5.3-flash, openai-codex/gpt-5.6-terra, openai-codex/gpt-5.6-luna]
|
|
5
|
+
thinking: medium
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Implement
|
|
9
|
+
|
|
10
|
+
Execute the bounded change, including documentation, tests, or frontend work
|
|
11
|
+
when requested. Inspect nearby conventions, preserve unrelated work, and do
|
|
12
|
+
not broaden scope or make product/architecture decisions for the parent.
|
|
13
|
+
|
|
14
|
+
For UI work, preserve the existing design language and inspect supplied visual
|
|
15
|
+
references with an image-capable model. Report unavailable capabilities instead
|
|
16
|
+
of claiming visual verification. Actual browser QA belongs to browser-qa.
|
|
17
|
+
|
|
18
|
+
Run relevant targeted checks and report changed paths plus their results. If
|
|
19
|
+
requirements conflict or the task exceeds your capabilities, stop with a
|
|
20
|
+
concrete blocker and the evidence already gathered; do not re-plan the project.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Strong independent second opinion for hard or high-stakes uncertainty. Use sparingly to challenge architecture, plans, root-cause hypotheses, or risk decisions. Prefer another provider within the available pool; read-only advice, not routine execution.
|
|
3
|
+
icon: sparkles
|
|
4
|
+
models: [openai-codex/gpt-5.6-sol, zai/glm-5.3]
|
|
5
|
+
thinking: max
|
|
6
|
+
tools: [read, grep, bash]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Oracle agent
|
|
10
|
+
|
|
11
|
+
You are an oracle: a strong model giving an independent second opinion to the
|
|
12
|
+
parent agent. A different provider is preferred within the available pool, but
|
|
13
|
+
not guaranteed; do not claim cross-provider independence without checking.
|
|
14
|
+
Give a concise, decisive recommendation with key
|
|
15
|
+
tradeoffs and risks. Disagree when warranted; do not rubber-stamp. Do not edit
|
|
16
|
+
unless explicitly asked.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
// Presets are available-model pools. Agent candidate order still comes from
|
|
3
|
+
// each agent's Markdown frontmatter; pool order never reorders candidates.
|
|
4
|
+
"cheap": {
|
|
5
|
+
"description": "GLM pool: economical workers plus GLM-5.3 for frontier-review/oracle.",
|
|
6
|
+
"models": ["zai/glm-5-turbo", "zai/glm-5.3-flash", "zai/glm-5.3"]
|
|
7
|
+
},
|
|
8
|
+
"gpt": {
|
|
9
|
+
"description": "GPT pool: Luna/Terra workers; Sol is available to frontier-review/oracle.",
|
|
10
|
+
"models": ["openai-codex/gpt-5.6-luna", "openai-codex/gpt-5.6-terra", "openai-codex/gpt-5.6-sol"]
|
|
11
|
+
},
|
|
12
|
+
"deep": {
|
|
13
|
+
"description": "Mixed pool; workers retain economical candidate order and frontier-review/oracle use strong models.",
|
|
14
|
+
"models": ["zai/glm-5-turbo", "zai/glm-5.3-flash", "openai-codex/gpt-5.6-luna", "openai-codex/gpt-5.6-terra", "openai-codex/gpt-5.6-sol", "zai/glm-5.3"]
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Read-only evidence gathering - search files, trace behavior, investigate hypotheses, or analyze a focused review question. Return findings with paths, not raw source. Use frontier-review for the post-implementation code-review gate when available, verify for running checks, and implement for changes.
|
|
3
|
+
icon: search
|
|
4
|
+
models: [zai/glm-5-turbo, openai-codex/gpt-5.6-luna]
|
|
5
|
+
thinking: low
|
|
6
|
+
tools: [read, grep]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Research
|
|
10
|
+
|
|
11
|
+
Investigate the assigned question within scope. Read and compare evidence; do
|
|
12
|
+
not edit files or invent missing facts. When assigned a review question, make
|
|
13
|
+
it a fresh investigation of the relevant code, not approval based on another
|
|
14
|
+
agent's summary. The broad post-implementation review gate belongs to
|
|
15
|
+
frontier-review when that role is available.
|
|
16
|
+
|
|
17
|
+
Return the answer and supporting file:line references, distinguishing confirmed
|
|
18
|
+
findings from hypotheses. Report gaps or a concrete blocker when the available
|
|
19
|
+
evidence is insufficient. Leave architecture decisions and escalation to the
|
|
20
|
+
parent. Do not dump search results or source files unless explicitly requested.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Run targeted tests, builds, or checks and diagnose their output in an isolated context. Return pass/fail, relevant failure evidence and log paths. Do not fix source code; creating or changing tests belongs to implement.
|
|
3
|
+
icon: flask
|
|
4
|
+
models: [zai/glm-5-turbo, openai-codex/gpt-5.6-luna]
|
|
5
|
+
thinking: low
|
|
6
|
+
tools: [read, grep, bash]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Verify
|
|
10
|
+
|
|
11
|
+
Select and run the smallest checks that establish the requested acceptance
|
|
12
|
+
criteria. Do not edit source or tests, weaken assertions, install dependencies,
|
|
13
|
+
or update snapshots to manufacture a pass. Report missing prerequisites.
|
|
14
|
+
|
|
15
|
+
Keep noisy output in artifacts and return the command, exit status, relevant
|
|
16
|
+
failure excerpt, and log path. Separate environment failures from product
|
|
17
|
+
failures and mark unrun checks explicitly. This is a behavioral no-edit
|
|
18
|
+
contract: the shell is not a read-only filesystem sandbox.
|
|
@@ -3,15 +3,12 @@ import * as fs from "node:fs";
|
|
|
3
3
|
import * as path from "node:path";
|
|
4
4
|
import { ignoreStaleExtensionContextError } from "../context-usage.js";
|
|
5
5
|
import {
|
|
6
|
-
copySubagentConfigSample,
|
|
7
6
|
ensureSessionFileLink,
|
|
8
|
-
existingSubagentConfigFiles,
|
|
9
7
|
findSubagentSessionByFile,
|
|
10
8
|
getActiveSubagentPresetName,
|
|
11
|
-
|
|
9
|
+
getBuiltinSubagentPresetsPath,
|
|
10
|
+
getProjectSubagentPresetsPath,
|
|
12
11
|
getSessionSubagentPresetOverride,
|
|
13
|
-
getSubagentConfigInitTargetPath,
|
|
14
|
-
getSubagentConfigSamplePath,
|
|
15
12
|
getSubagentPresetSelectionPath,
|
|
16
13
|
getRunState,
|
|
17
14
|
listRunDirs,
|
|
@@ -49,17 +46,16 @@ type MessageSender = ExtensionAPI & {
|
|
|
49
46
|
};
|
|
50
47
|
|
|
51
48
|
const CLEAR_ACTIVE_PRESET_LABEL = "Use no active preset";
|
|
52
|
-
const COPY_SAMPLE_CONFIG_LABEL = "Copy sample asyncSubagents config";
|
|
53
49
|
|
|
54
50
|
export const ULTRAWORK_PROMPT = `Run ultrawork mode for the current objective.
|
|
55
51
|
|
|
56
|
-
Use subagents when
|
|
52
|
+
Use subagents when a lower-cost worker or isolation of noisy evidence helps, including one bounded sequential task. Pick subagentType from the effective catalog: research for reading/review, implement for code/docs/tests/UI changes, verify for running checks, browser-qa for real-browser testing, and oracle only for a deliberate strong independent opinion. Prefer an appropriate project-local specialist. Keep decisions and integration in the parent; do not create agents just to assign a discipline.
|
|
57
53
|
|
|
58
54
|
Keep parent context lean: spawn for broad parallel work, read results only when needed, and finish unless genuinely blocked.`;
|
|
59
55
|
|
|
60
56
|
const HYPERPLAN_PROMPT = `Run hyperplan mode for the current objective.
|
|
61
57
|
|
|
62
|
-
Before implementation, use
|
|
58
|
+
Before implementation, use bounded research tasks to gather constraints and independently pressure-test the plan. Use oracle only when a strong second opinion is justified. Synthesize the evidence and objections in the parent before editing.`;
|
|
63
59
|
|
|
64
60
|
export function buildUltraworkPrompt(objective: string): string {
|
|
65
61
|
const trimmed = objective.trim();
|
|
@@ -192,12 +188,10 @@ async function triggerOrchestrationPrompt(
|
|
|
192
188
|
|
|
193
189
|
function registerPresetCommands(pi: ExtensionAPI): void {
|
|
194
190
|
pi.registerCommand("subagent-preset", {
|
|
195
|
-
description: "Select a sub-agent preset
|
|
191
|
+
description: "Select a sub-agent model-pool preset, or run session <name> for a process-only override",
|
|
196
192
|
getArgumentCompletions: (prefix: string) => {
|
|
197
|
-
const names =
|
|
198
|
-
|
|
199
|
-
: [];
|
|
200
|
-
return [...names, ...names.map((name) => `session ${name}`), "list", "path", "config", "init", "clear", "session", "session-clear"]
|
|
193
|
+
const names = sortedPresetNames(loadSubagentConfig(process.cwd()).presets ?? {}, getActiveSubagentPresetName());
|
|
194
|
+
return [...names, ...names.map((name) => `session ${name}`), "list", "path", "clear", "session", "session-clear"]
|
|
201
195
|
.filter((name) => name.startsWith(prefix))
|
|
202
196
|
.map((name) => ({ value: name, label: name }));
|
|
203
197
|
},
|
|
@@ -209,28 +203,19 @@ function registerPresetCommands(pi: ExtensionAPI): void {
|
|
|
209
203
|
if (name === "session-clear") return clearSessionActiveSubagentPreset(ctx);
|
|
210
204
|
if (name === "list") return listSubagentPresets(ctx);
|
|
211
205
|
if (name === "path") return showSubagentPresetPaths(ctx);
|
|
212
|
-
if (name === "config") return showSubagentPresetConfigurator(ctx);
|
|
213
|
-
if (name === "init") return initSubagentConfigSample(ctx);
|
|
214
206
|
if (name === "clear") return clearActiveSubagentPreset(ctx);
|
|
215
|
-
if (existingSubagentConfigFiles(ctx.cwd).length === 0) return ctx.ui.notify(missingSubagentConfigMessage(ctx), "warning");
|
|
216
207
|
|
|
217
208
|
const config = loadSubagentConfig(ctx.cwd);
|
|
218
209
|
const preset = config.presets?.[name];
|
|
219
|
-
if (!preset) return ctx.ui.notify(`Unknown sub-agent preset "${name}".
|
|
210
|
+
if (!preset) return ctx.ui.notify(`Unknown sub-agent preset "${name}". Run /subagent-preset list to see available pools.`, "error");
|
|
220
211
|
setActiveSubagentPreset(name);
|
|
221
212
|
notifyActiveSubagentPreset(ctx, name, preset);
|
|
222
213
|
},
|
|
223
214
|
});
|
|
224
|
-
|
|
225
|
-
pi.registerCommand("subagent-preset-config", {
|
|
226
|
-
description: "Select sub-agent presets defined in asyncSubagents config",
|
|
227
|
-
handler: async (_args: string, ctx: CommandContext) => showSubagentPresetConfigurator(ctx),
|
|
228
|
-
});
|
|
229
215
|
}
|
|
230
216
|
|
|
231
217
|
async function showSubagentPresetSelector(ctx: CommandContext): Promise<void> {
|
|
232
218
|
if (!ctx.hasUI) return ctx.ui.notify("Sub-agent preset selector requires interactive UI. Use /subagent-preset <name>.", "warning");
|
|
233
|
-
if (existingSubagentConfigFiles(ctx.cwd).length === 0) return showMissingSubagentConfigSelector(ctx);
|
|
234
219
|
|
|
235
220
|
const config = loadSubagentConfig(ctx.cwd);
|
|
236
221
|
const activePreset = getActiveSubagentPresetName();
|
|
@@ -240,12 +225,12 @@ async function showSubagentPresetSelector(ctx: CommandContext): Promise<void> {
|
|
|
240
225
|
const labels = [...presetLabels];
|
|
241
226
|
if (activePreset) labels.push(CLEAR_ACTIVE_PRESET_LABEL);
|
|
242
227
|
if (labels.length === 0) {
|
|
243
|
-
ctx.ui.notify("No sub-agent presets are
|
|
228
|
+
ctx.ui.notify("No sub-agent model-pool presets are available.", "warning");
|
|
244
229
|
showSubagentPresetPaths(ctx);
|
|
245
230
|
return;
|
|
246
231
|
}
|
|
247
232
|
const labelToName = new Map(presetLabels.map((label, index) => [label, names[index]]));
|
|
248
|
-
const selected = await ctx.ui.select(
|
|
233
|
+
const selected = await ctx.ui.select("Select active sub-agent preset", labels);
|
|
249
234
|
if (!selected) return;
|
|
250
235
|
if (selected === CLEAR_ACTIVE_PRESET_LABEL) return clearActiveSubagentPreset(ctx);
|
|
251
236
|
|
|
@@ -254,69 +239,29 @@ async function showSubagentPresetSelector(ctx: CommandContext): Promise<void> {
|
|
|
254
239
|
setActiveSubagentPreset(name);
|
|
255
240
|
notifyActiveSubagentPreset(ctx, name, presets[name]);
|
|
256
241
|
}
|
|
257
|
-
|
|
258
|
-
async function showSubagentPresetConfigurator(ctx: CommandContext): Promise<void> {
|
|
259
|
-
if (!ctx.hasUI) return ctx.ui.notify("Sub-agent preset selector requires interactive UI.", "warning");
|
|
260
|
-
return showSubagentPresetSelector(ctx);
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
async function showMissingSubagentConfigSelector(ctx: CommandContext): Promise<void> {
|
|
264
|
-
const selected = await ctx.ui.select("No asyncSubagents config found", [COPY_SAMPLE_CONFIG_LABEL]);
|
|
265
|
-
if (selected === COPY_SAMPLE_CONFIG_LABEL) initSubagentConfigSample(ctx);
|
|
266
|
-
}
|
|
267
|
-
|
|
268
242
|
function listSubagentPresets(ctx: CommandContext): void {
|
|
269
|
-
if (existingSubagentConfigFiles(ctx.cwd).length === 0) {
|
|
270
|
-
ctx.ui.notify(missingSubagentConfigMessage(ctx), "warning");
|
|
271
|
-
return;
|
|
272
|
-
}
|
|
273
243
|
const config = loadSubagentConfig(ctx.cwd);
|
|
274
244
|
const activePreset = getActiveSubagentPresetName();
|
|
275
245
|
const presets = config.presets ?? {};
|
|
276
246
|
const names = sortedPresetNames(presets, activePreset);
|
|
277
|
-
if (names.length === 0) return ctx.ui.notify("No sub-agent presets are
|
|
247
|
+
if (names.length === 0) return ctx.ui.notify("No sub-agent model-pool presets are available.", "warning");
|
|
278
248
|
ctx.ui.notify([
|
|
279
|
-
"Sub-agent presets
|
|
249
|
+
"Sub-agent model-pool presets:",
|
|
280
250
|
...names.map((name) => `- ${subagentPresetLabel(name, presets[name], activePreset)}`),
|
|
281
251
|
].join("\n"), "info");
|
|
282
252
|
}
|
|
283
253
|
|
|
284
254
|
function showSubagentPresetPaths(ctx: CommandContext): void {
|
|
285
255
|
ctx.ui.notify([
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
`Sample config: ${getSubagentConfigSamplePath()}`,
|
|
290
|
-
`Copy sample target: ${getSubagentConfigInitTargetPath(ctx.cwd)}`,
|
|
256
|
+
`Bundled presets: ${getBuiltinSubagentPresetsPath()}`,
|
|
257
|
+
`Project preset override: ${getProjectSubagentPresetsPath(ctx.cwd)}`,
|
|
258
|
+
"Project presets are defined as model pools in .pi/agents/presets.jsonc; agent behavior stays in .pi/agents/*.md.",
|
|
291
259
|
`Active selection state: ${getSubagentPresetSelectionPath()}`,
|
|
292
260
|
`Session override: ${formatSessionPresetOverride()}`,
|
|
293
261
|
"Use /subagent-preset session <name> to override only the current Pi process; use /subagent-preset session-clear to clear that runtime override.",
|
|
294
|
-
"Run /subagent-preset init to copy the bundled sample only when no config exists.",
|
|
295
262
|
].join("\n"), "info");
|
|
296
263
|
}
|
|
297
264
|
|
|
298
|
-
function initSubagentConfigSample(ctx: CommandContext): void {
|
|
299
|
-
try {
|
|
300
|
-
const result = copySubagentConfigSample(ctx.cwd);
|
|
301
|
-
if (result.copied) {
|
|
302
|
-
ctx.ui.notify(`Copied sample asyncSubagents config:\n${result.samplePath}\n→ ${result.targetPath}`, "info");
|
|
303
|
-
return;
|
|
304
|
-
}
|
|
305
|
-
ctx.ui.notify(`AsyncSubagents config already exists; not overwriting:\n${result.existingFiles.join("\n") || result.targetPath}`, "warning");
|
|
306
|
-
} catch (error) {
|
|
307
|
-
ctx.ui.notify(error instanceof Error ? error.message : String(error), "error");
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
function missingSubagentConfigMessage(ctx: CommandContext): string {
|
|
312
|
-
return [
|
|
313
|
-
"No asyncSubagents config found in pi-tools-suite config.",
|
|
314
|
-
`Sample config: ${getSubagentConfigSamplePath()}`,
|
|
315
|
-
`Copy target: ${getSubagentConfigInitTargetPath(ctx.cwd)}`,
|
|
316
|
-
"Run /subagent-preset init to copy the bundled sample into the shared config.",
|
|
317
|
-
].join("\n");
|
|
318
|
-
}
|
|
319
|
-
|
|
320
265
|
function clearActiveSubagentPreset(ctx: CommandContext): void {
|
|
321
266
|
setActiveSubagentPreset(undefined);
|
|
322
267
|
const override = getSessionSubagentPresetOverride();
|
|
@@ -327,10 +272,9 @@ function clearActiveSubagentPreset(ctx: CommandContext): void {
|
|
|
327
272
|
|
|
328
273
|
function setSessionActiveSubagentPreset(ctx: CommandContext, name: string): void {
|
|
329
274
|
if (!name) return ctx.ui.notify("Usage: /subagent-preset session <name>", "warning");
|
|
330
|
-
if (existingSubagentConfigFiles(ctx.cwd).length === 0) return ctx.ui.notify(missingSubagentConfigMessage(ctx), "warning");
|
|
331
275
|
const config = loadSubagentConfig(ctx.cwd);
|
|
332
276
|
const preset = config.presets?.[name];
|
|
333
|
-
if (!preset) return ctx.ui.notify(`Unknown sub-agent preset "${name}".
|
|
277
|
+
if (!preset) return ctx.ui.notify(`Unknown sub-agent preset "${name}". Run /subagent-preset list to see available pools.`, "error");
|
|
334
278
|
setSessionSubagentPresetOverride(name);
|
|
335
279
|
ctx.ui.notify(`Session-only sub-agent preset "${name}": ${subagentPresetDescription(preset)}\nApplies to future sub-agent spawns only until this Pi process exits or /subagent-preset session-clear is run. Saved preset selection is unchanged.`, "info");
|
|
336
280
|
}
|
|
@@ -368,6 +312,10 @@ function sortedPresetNames(presets: Record<string, SubagentPreset>, activePreset
|
|
|
368
312
|
function subagentPresetDescription(preset: SubagentPreset): string {
|
|
369
313
|
const parts: string[] = [];
|
|
370
314
|
if (preset.description) parts.push(preset.description);
|
|
315
|
+
if (preset.models !== undefined) {
|
|
316
|
+
parts.push(`models:${preset.models.join(",") || "(none)"}`);
|
|
317
|
+
return parts.join(", ");
|
|
318
|
+
}
|
|
371
319
|
if (preset.model) parts.push(`model:${preset.model}`);
|
|
372
320
|
if (preset.fallbackModels && preset.fallbackModels.length > 0) parts.push(`fallbacks:${preset.fallbackModels.join(",")}`);
|
|
373
321
|
if (preset.thinking) parts.push(`thinking:${preset.thinking}`);
|