pi-ui-extend 1.0.23 → 1.0.28
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 +5 -1
- package/dist/app/app.d.ts +1 -0
- package/dist/app/app.js +12 -0
- package/dist/app/constants.d.ts +1 -1
- package/dist/app/constants.js +1 -1
- package/dist/app/icons.d.ts +1 -0
- package/dist/app/icons.js +2 -0
- package/dist/app/input/input-controller.d.ts +2 -0
- package/dist/app/input/input-controller.js +8 -5
- package/dist/app/rendering/render-controller.js +2 -0
- package/dist/app/rendering/status-line-renderer.d.ts +4 -1
- package/dist/app/rendering/status-line-renderer.js +12 -0
- package/dist/app/runtime.d.ts +1 -8
- package/dist/app/runtime.js +0 -39
- package/dist/app/screen/mouse-controller.d.ts +4 -1
- package/dist/app/screen/mouse-controller.js +9 -0
- package/dist/app/session/agent-pause-controller.d.ts +30 -0
- package/dist/app/session/agent-pause-controller.js +178 -0
- package/dist/app/session/session-event-controller.d.ts +1 -0
- package/dist/app/session/session-event-controller.js +22 -15
- package/dist/app/session/session-lifecycle-controller.d.ts +1 -0
- package/dist/app/session/session-lifecycle-controller.js +1 -0
- package/dist/app/types.d.ts +10 -0
- package/dist/config.js +1 -1
- package/dist/default-pix-config.js +2 -2
- package/external/pi-tools-suite/README.md +1 -1
- package/external/pi-tools-suite/docs/browser-qa-subagent.md +34 -2
- package/external/pi-tools-suite/package.json +3 -3
- package/external/pi-tools-suite/src/async-subagents/async-subagents.sample.jsonc +24 -18
- package/external/pi-tools-suite/src/async-subagents/core/config.ts +14 -3
- package/external/pi-tools-suite/src/async-subagents/core/process.ts +19 -0
- package/external/pi-tools-suite/src/async-subagents/core/spawn.ts +97 -17
- package/external/pi-tools-suite/src/async-subagents/core/stop.ts +4 -2
- package/external/pi-tools-suite/src/async-subagents/private-skills/browser-qa/SKILL.md +108 -13
- package/external/pi-tools-suite/src/async-subagents/private-skills/browser-qa/references/qa-design.md +80 -0
- package/external/pi-tools-suite/src/async-subagents/private-skills/browser-qa/references/qa-flow.example.jsonc +54 -1
- package/external/pi-tools-suite/src/async-subagents/private-skills/browser-qa/scripts/browser-qa-runner.mjs +952 -76
- package/external/pi-tools-suite/src/coding-discipline/index.ts +2 -94
- package/external/pi-tools-suite/src/dcp/index.ts +21 -0
- package/external/pi-tools-suite/src/dcp/pruner-compression-blocks.ts +92 -0
- package/external/pi-tools-suite/src/default-pi-tools-suite-config.ts +21 -16
- package/external/pi-tools-suite/src/todo/index.ts +86 -46
- package/external/pi-tools-suite/src/todo/todo.ts +1 -1
- package/package.json +4 -4
|
@@ -134,7 +134,8 @@ export class AppSessionEventController {
|
|
|
134
134
|
this.historyEntries = [];
|
|
135
135
|
this.historyWindowStart = 0;
|
|
136
136
|
const lazyOlderHistory = options.lazyOlderHistory === true;
|
|
137
|
-
const historyEntries =
|
|
137
|
+
const historyEntries = [];
|
|
138
|
+
let historyAttached = false;
|
|
138
139
|
const messages = lazyOlderHistory
|
|
139
140
|
? sessionHistoryDisplayMessages(runtime.session)
|
|
140
141
|
: sessionHistoryDisplayMessagesFromEntries(await sessionHistoryFullBranchEntries(runtime.session));
|
|
@@ -142,24 +143,22 @@ export class AppSessionEventController {
|
|
|
142
143
|
return false;
|
|
143
144
|
const loaded = await loadSessionHistoryEntriesAsync({
|
|
144
145
|
messages,
|
|
145
|
-
addEntry: (entry) =>
|
|
146
|
-
if (historyEntries)
|
|
147
|
-
historyEntries.push(entry);
|
|
148
|
-
else
|
|
149
|
-
this.addEntry(entry);
|
|
150
|
-
},
|
|
146
|
+
addEntry: (entry) => historyEntries.push(entry),
|
|
151
147
|
prependEntries: (entries) => {
|
|
152
|
-
if (
|
|
153
|
-
|
|
148
|
+
if (historyAttached)
|
|
149
|
+
this.prependLoadedHistoryEntries(entries);
|
|
154
150
|
else
|
|
155
|
-
|
|
151
|
+
historyEntries.unshift(...entries);
|
|
156
152
|
},
|
|
157
153
|
setToolEntryId: (toolCallId, entryId) => this.toolEntryIdsByCallId.set(toolCallId, entryId),
|
|
158
154
|
toolDefaultExpanded: (toolName) => this.host.toolDefaultExpanded(toolName),
|
|
159
155
|
observeSubagentsToolResult: (toolName, details, options) => this.host.observeSubagentsToolResult(toolName, details, options),
|
|
160
156
|
observeTodoToolResult: (toolName, details, isError) => this.host.observeTodoToolResult(toolName, details, isError),
|
|
161
157
|
isCancelled: options.isCancelled,
|
|
162
|
-
render:
|
|
158
|
+
render: () => {
|
|
159
|
+
if (historyAttached)
|
|
160
|
+
options.render();
|
|
161
|
+
},
|
|
163
162
|
lazyOlderHistory,
|
|
164
163
|
olderMessagesReader: lazyOlderHistory ? sessionHistoryOlderMessagesReader(runtime.session) : undefined,
|
|
165
164
|
onOlderLoaderReady: (loader) => {
|
|
@@ -169,24 +168,24 @@ export class AppSessionEventController {
|
|
|
169
168
|
});
|
|
170
169
|
if (!loaded)
|
|
171
170
|
return false;
|
|
172
|
-
if (!historyEntries)
|
|
173
|
-
return !options.isCancelled();
|
|
174
171
|
this.historyEntries = historyEntries;
|
|
172
|
+
historyAttached = true;
|
|
175
173
|
this.setHistoryWindowStart(this.maxHistoryWindowStart());
|
|
176
174
|
options.render();
|
|
177
175
|
return !options.isCancelled();
|
|
178
176
|
}
|
|
179
177
|
hasOlderSessionHistory() {
|
|
180
178
|
if (this.historyEntries.length > 0)
|
|
181
|
-
return this.historyWindowStart > 0;
|
|
179
|
+
return this.historyWindowStart > 0 || this.olderHistoryLoader?.hasOlder() === true;
|
|
182
180
|
return this.olderHistoryLoader?.hasOlder() === true;
|
|
183
181
|
}
|
|
184
182
|
isLoadingOlderSessionHistory() {
|
|
185
183
|
return this.olderHistoryLoader?.isLoading() === true;
|
|
186
184
|
}
|
|
187
185
|
async loadOlderSessionHistory(options = {}) {
|
|
188
|
-
if (this.historyEntries.length > 0)
|
|
186
|
+
if (this.historyEntries.length > 0 && this.historyWindowStart > 0) {
|
|
189
187
|
return this.shiftHistoryWindow(-HISTORY_WINDOW_SHIFT_ENTRIES, options);
|
|
188
|
+
}
|
|
190
189
|
return this.olderHistoryLoader?.loadOlder(options) ?? false;
|
|
191
190
|
}
|
|
192
191
|
/**
|
|
@@ -447,6 +446,14 @@ export class AppSessionEventController {
|
|
|
447
446
|
this.registerEntry(entry);
|
|
448
447
|
this.pruneHistoryWindow("bottom");
|
|
449
448
|
}
|
|
449
|
+
prependLoadedHistoryEntries(entries) {
|
|
450
|
+
if (entries.length === 0)
|
|
451
|
+
return;
|
|
452
|
+
const previousStart = this.historyWindowStart;
|
|
453
|
+
this.historyEntries.unshift(...entries);
|
|
454
|
+
const nextStart = previousStart === 0 ? 0 : previousStart + entries.length;
|
|
455
|
+
this.setHistoryWindowStart(nextStart);
|
|
456
|
+
}
|
|
450
457
|
shiftHistoryWindow(delta, options = {}) {
|
|
451
458
|
if (this.historyEntries.length === 0)
|
|
452
459
|
return false;
|
|
@@ -26,6 +26,7 @@ export type AppSessionLifecycleHost = {
|
|
|
26
26
|
createExtensionCommandContextActions(runtime: AgentSessionRuntime): ExtensionCommandContextActions;
|
|
27
27
|
handleExtensionError(error: ExtensionError): void;
|
|
28
28
|
handleSessionEvent(event: AgentSessionEvent): void;
|
|
29
|
+
bindAgentPause(session: AgentSession): void;
|
|
29
30
|
addEntry(entry: Entry): void;
|
|
30
31
|
setStatus(status: string): void;
|
|
31
32
|
showToast(message: string, kind: "success" | "error" | "warning" | "info"): void;
|
|
@@ -73,6 +73,7 @@ export class AppSessionLifecycleController {
|
|
|
73
73
|
async bindCurrentSession(options = {}) {
|
|
74
74
|
const runtime = this.requireRuntime();
|
|
75
75
|
const session = runtime.session;
|
|
76
|
+
this.host.bindAgentPause(session);
|
|
76
77
|
const ownershipGeneration = this.advanceOwnership(runtime, session);
|
|
77
78
|
const subscriptionGeneration = ++this.subscriptionGeneration;
|
|
78
79
|
this.replacementHistoryGeneration += 1;
|
package/dist/app/types.d.ts
CHANGED
|
@@ -284,6 +284,7 @@ export type StatusLineLayout = {
|
|
|
284
284
|
compactToolsWidget?: StatusCompactToolsWidgetLayout;
|
|
285
285
|
terminalBellSoundWidget?: StatusTerminalBellSoundWidgetLayout;
|
|
286
286
|
promptEnhancerWidget?: StatusPromptEnhancerWidgetLayout;
|
|
287
|
+
agentPauseWidget?: StatusAgentPauseWidgetLayout;
|
|
287
288
|
voiceWidget?: StatusVoiceWidgetLayout;
|
|
288
289
|
};
|
|
289
290
|
export type StatusQuickScrollWidgetLayout = {
|
|
@@ -318,6 +319,10 @@ export type StatusPromptEnhancerWidgetLayout = {
|
|
|
318
319
|
startColumn: number;
|
|
319
320
|
endColumn: number;
|
|
320
321
|
};
|
|
322
|
+
export type StatusAgentPauseWidgetLayout = {
|
|
323
|
+
startColumn: number;
|
|
324
|
+
endColumn: number;
|
|
325
|
+
};
|
|
321
326
|
export type StatusTerminalBellSoundTarget = {
|
|
322
327
|
row: number;
|
|
323
328
|
startColumn: number;
|
|
@@ -589,6 +594,11 @@ export type StatusPromptEnhancerTarget = {
|
|
|
589
594
|
startColumn: number;
|
|
590
595
|
endColumn: number;
|
|
591
596
|
};
|
|
597
|
+
export type StatusAgentPauseTarget = {
|
|
598
|
+
row: number;
|
|
599
|
+
startColumn: number;
|
|
600
|
+
endColumn: number;
|
|
601
|
+
};
|
|
592
602
|
export type StatusUserJumpTarget = {
|
|
593
603
|
row: number;
|
|
594
604
|
startColumn: number;
|
package/dist/config.js
CHANGED
|
@@ -55,7 +55,7 @@ const DEFAULT_OUTPUT_FILTERS = {
|
|
|
55
55
|
};
|
|
56
56
|
const THINKING_LEVELS = ["off", "minimal", "low", "medium", "high", "xhigh", "max"];
|
|
57
57
|
const DEFAULT_PROMPT_ENHANCER = {
|
|
58
|
-
modelRef: "
|
|
58
|
+
modelRef: "openai-codex/gpt-5.6-luna",
|
|
59
59
|
};
|
|
60
60
|
const DEFAULT_AUTOCOMPLETE = {
|
|
61
61
|
modelRef: "zai/glm-5-turbo",
|
|
@@ -52,9 +52,9 @@ export const DEFAULT_PIX_CONFIG_JSONC = String.raw `{
|
|
|
52
52
|
"antigravity/antigravity-claude-*": "error"
|
|
53
53
|
},
|
|
54
54
|
|
|
55
|
-
"promptEnhancer": { "modelRef": "
|
|
55
|
+
"promptEnhancer": { "modelRef": "openai-codex/gpt-5.6-luna" },
|
|
56
56
|
"autocomplete": { "modelRef": "zai/glm-5-turbo", "debounceMs": 350, "timeoutMs": 3000, "maxTokens": 48, "maxPromptTokens": 1200, "includeRecentMessages": 0 },
|
|
57
|
-
"sessionTitle": { "modelRef": "
|
|
57
|
+
"sessionTitle": { "modelRef": "openai-codex/gpt-5.6-luna", "fallbackModels": ["zai/glm-5-turbo"] },
|
|
58
58
|
"dictation": {
|
|
59
59
|
"language": "en",
|
|
60
60
|
"languages": {
|
|
@@ -247,7 +247,7 @@ For an oh-my-openagent-style workflow, run `/ultrawork` or `/ulw` to ask the par
|
|
|
247
247
|
|
|
248
248
|
### Private browser QA and project auth
|
|
249
249
|
|
|
250
|
-
The built-in `browser-qa` role runs on `openai-codex/gpt-5.
|
|
250
|
+
The built-in `browser-qa` role runs on `openai-codex/gpt-5.6-luna`, with
|
|
251
251
|
`antigravity/gemini-3-flash-preview` and then `zai/glm-5.3` as fallbacks. Its browser
|
|
252
252
|
workflow is an explicit private skill under `src/async-subagents/private-skills/`,
|
|
253
253
|
outside normal Pi skill discovery. The role's first-class `isolatedSkills` setting launches the child with
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
Provide a cheap, fast `browser-qa` async-subagent that reproduces browser bugs
|
|
6
6
|
and proves fixes with deterministic assertions plus screenshot, video, and trace
|
|
7
|
-
evidence. The role uses `openai-codex/gpt-5.
|
|
7
|
+
evidence. The role uses `openai-codex/gpt-5.6-luna`, falling back to
|
|
8
8
|
`antigravity/gemini-3-flash-preview` and then `zai/glm-5.3`.
|
|
9
9
|
|
|
10
10
|
## Private skill isolation
|
|
@@ -62,6 +62,9 @@ evidence. The role uses `openai-codex/gpt-5.4-mini`, falling back to
|
|
|
62
62
|
trusted runner implements a bounded set of navigation, interaction,
|
|
63
63
|
assertion, screenshot, and auth-rejection actions and never gives the flow a
|
|
64
64
|
Playwright context or credential values.
|
|
65
|
+
- Target discovery is a bounded preflight, not an open-ended research task. The
|
|
66
|
+
sub-agent invokes the runner within 45 seconds or returns `BLOCKED`; it does
|
|
67
|
+
not spend the full launcher budget reading source or probing prerequisites.
|
|
65
68
|
- The launcher injects `PI_SUBAGENT_AGENT_DIR`, pre-creates a private
|
|
66
69
|
`browser-qa/flows/` workspace, and clears stale browser QA files when an agent
|
|
67
70
|
id is reused. The runner validates the directory's project/type metadata and
|
|
@@ -79,6 +82,32 @@ evidence. The role uses `openai-codex/gpt-5.4-mini`, falling back to
|
|
|
79
82
|
- Auth rejection discovered by a QA flow is reported through the
|
|
80
83
|
`authRejectedIf` action so the parent gets an update-required status.
|
|
81
84
|
|
|
85
|
+
## Reliability and shutdown contract
|
|
86
|
+
|
|
87
|
+
- The built-in `browser-qa` profile has a 120-second wall-clock budget unless
|
|
88
|
+
the caller explicitly supplies a task or spawn timeout. This bounds model
|
|
89
|
+
stalls as well as browser work.
|
|
90
|
+
- The trusted runner has its own bounded lifecycle. Browser launch, context
|
|
91
|
+
setup, auth, flow execution, evidence finalization, and browser shutdown must
|
|
92
|
+
not wait forever; a timeout reports the last started stage without exposing
|
|
93
|
+
flow contents or credentials.
|
|
94
|
+
- Trace sanitization runs in a memory-limited worker that can be terminated at
|
|
95
|
+
the cleanup deadline; synchronous archive work cannot defeat the watchdog.
|
|
96
|
+
- The launcher always writes a small sanitized `progress.jsonl` journal in the
|
|
97
|
+
agent directory. It records lifecycle/RPC event types and tool names, but not
|
|
98
|
+
prompts, tool arguments, tool results, model text, or secrets. The browser
|
|
99
|
+
runner writes similarly sanitized stage entries under its private workspace.
|
|
100
|
+
- On POSIX, newly launched agents own a process group. Settled, timed-out, and
|
|
101
|
+
explicitly stopped agents signal that group rather than only the Pi process;
|
|
102
|
+
timeout/settled shutdown escalates to `SIGKILL` after its grace period. On
|
|
103
|
+
Windows the existing recursive `taskkill /T /F` behavior remains in force.
|
|
104
|
+
- Process-tree cleanup is scoped to a launcher-created process-group marker so
|
|
105
|
+
an old or externally-created PID is never treated as an owned process group.
|
|
106
|
+
User browser sessions outside that group must not be signalled.
|
|
107
|
+
- Playwright can launch Chromium in its own POSIX process group. On runner
|
|
108
|
+
failure the runner snapshots and kills only its own descendants before it
|
|
109
|
+
exits, covering that detached browser tree without touching a user's browser.
|
|
110
|
+
|
|
82
111
|
## Acceptance criteria
|
|
83
112
|
|
|
84
113
|
1. `browser-qa` resolves to the intended model/fallback and its self-contained
|
|
@@ -96,7 +125,10 @@ evidence. The role uses `openai-codex/gpt-5.4-mini`, falling back to
|
|
|
96
125
|
deleting the run removes them while persistent auth config/state remains.
|
|
97
126
|
6. Completed test runs report clickable screenshot, video, and trace links
|
|
98
127
|
whenever those artifacts exist.
|
|
99
|
-
7.
|
|
128
|
+
7. Timeout tests identify the last browser stage, launcher progress remains
|
|
129
|
+
available when full RPC logging is disabled, and process-tree tests prove a
|
|
130
|
+
descendant is terminated without signalling unrelated processes.
|
|
131
|
+
8. Suite tests/typecheck, host checks, and suite sync pass.
|
|
100
132
|
|
|
101
133
|
## Real-browser regression test
|
|
102
134
|
|
|
@@ -44,9 +44,9 @@
|
|
|
44
44
|
"vscode-languageserver-protocol": "^3.17.5"
|
|
45
45
|
},
|
|
46
46
|
"peerDependencies": {
|
|
47
|
-
"@earendil-works/pi-ai": "0.84.
|
|
48
|
-
"@earendil-works/pi-coding-agent": "0.84.
|
|
49
|
-
"@earendil-works/pi-tui": "0.84.
|
|
47
|
+
"@earendil-works/pi-ai": "0.84.3",
|
|
48
|
+
"@earendil-works/pi-coding-agent": "0.84.3",
|
|
49
|
+
"@earendil-works/pi-tui": "0.84.3",
|
|
50
50
|
"typebox": "*"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
@@ -71,7 +71,7 @@
|
|
|
71
71
|
"model": "zai/glm-4.5-air",
|
|
72
72
|
// Ordered router model fallbacks tried when the primary routing model is
|
|
73
73
|
// unavailable or fails. The current parent model is always tried last.
|
|
74
|
-
"fallbackModels": ["openai-codex/gpt-5.
|
|
74
|
+
"fallbackModels": ["openai-codex/gpt-5.6-luna"],
|
|
75
75
|
"maxTaskChars": 1200,
|
|
76
76
|
"maxTokens": 512,
|
|
77
77
|
"maxRetries": 3,
|
|
@@ -116,7 +116,7 @@
|
|
|
116
116
|
"research": { "model": "zai/glm-5-turbo", "thinking": "low" },
|
|
117
117
|
"docs": { "model": "zai/glm-4.5-air", "thinking": "low" },
|
|
118
118
|
"frontend": { "model": "antigravity/gemini-3-flash-preview", "fallbackModels": ["zai/glm-5.3"], "thinking": "medium" },
|
|
119
|
-
"browser-qa": { "model": "openai-codex/gpt-5.
|
|
119
|
+
"browser-qa": { "model": "openai-codex/gpt-5.6-luna", "fallbackModels": ["antigravity/gemini-3-flash-preview", "zai/glm-5.3"], "thinking": "low" },
|
|
120
120
|
"tests": { "model": "zai/glm-5-turbo", "thinking": "medium" },
|
|
121
121
|
"review": { "model": "zai/glm-5.3", "thinking": "high" },
|
|
122
122
|
"implement": { "model": "zai/glm-5.3", "thinking": "high" },
|
|
@@ -132,7 +132,7 @@
|
|
|
132
132
|
"research": { "model": "openai-codex/gpt-5.6-terra", "fallbackModels": ["zai/glm-5-turbo"], "thinking": "low" },
|
|
133
133
|
"docs": { "model": "openai-codex/gpt-5.6-luna", "fallbackModels": ["zai/glm-4.5-air"], "thinking": "low" },
|
|
134
134
|
"frontend": { "model": "openai-codex/gpt-5.6-terra", "fallbackModels": ["antigravity/gemini-3-flash-preview", "zai/glm-5.3"], "thinking": "medium" },
|
|
135
|
-
"browser-qa": { "model": "openai-codex/gpt-5.
|
|
135
|
+
"browser-qa": { "model": "openai-codex/gpt-5.6-luna", "fallbackModels": ["antigravity/gemini-3-flash-preview", "zai/glm-5.3"], "thinking": "low" },
|
|
136
136
|
"tests": { "model": "openai-codex/gpt-5.6-terra", "fallbackModels": ["zai/glm-5-turbo"], "thinking": "medium" },
|
|
137
137
|
"review": { "model": "openai-codex/gpt-5.6-sol", "fallbackModels": ["zai/glm-5.3"], "thinking": "high" },
|
|
138
138
|
"implement": { "model": "openai-codex/gpt-5.6-sol", "fallbackModels": ["zai/glm-5.3"], "thinking": "high" },
|
|
@@ -143,13 +143,13 @@
|
|
|
143
143
|
"deep": {
|
|
144
144
|
"description": "Use only enabled strong models, mixing GPT, Claude, and Gemini by role.",
|
|
145
145
|
"types": {
|
|
146
|
-
"quick": { "model": "openai-codex/gpt-5.
|
|
147
|
-
"scan": { "model": "antigravity/gemini-3-flash-preview", "fallbackModels": ["openai-codex/gpt-5.
|
|
148
|
-
"research": { "model": "antigravity/gemini-3.1-pro-preview", "fallbackModels": ["openai-codex/gpt-5.
|
|
149
|
-
"docs": { "model": "antigravity/gemini-2.5-flash", "fallbackModels": ["openai-codex/gpt-5.
|
|
150
|
-
"frontend": { "model": "antigravity/gemini-3.1-pro-preview-customtools", "fallbackModels": ["openai-codex/gpt-5.
|
|
151
|
-
"browser-qa": { "model": "openai-codex/gpt-5.
|
|
152
|
-
"tests": { "model": "antigravity/antigravity-claude-sonnet-4-6", "fallbackModels": ["openai-codex/gpt-5.
|
|
146
|
+
"quick": { "model": "openai-codex/gpt-5.6-luna", "fallbackModels": ["zai/glm-4.5-air"], "thinking": "low" },
|
|
147
|
+
"scan": { "model": "antigravity/gemini-3-flash-preview", "fallbackModels": ["openai-codex/gpt-5.6-luna", "zai/glm-4.5-air"], "thinking": "off" },
|
|
148
|
+
"research": { "model": "antigravity/gemini-3.1-pro-preview", "fallbackModels": ["openai-codex/gpt-5.6-luna", "zai/glm-5-turbo"], "thinking": "medium" },
|
|
149
|
+
"docs": { "model": "antigravity/gemini-2.5-flash", "fallbackModels": ["openai-codex/gpt-5.6-luna", "zai/glm-4.5-air"], "thinking": "medium" },
|
|
150
|
+
"frontend": { "model": "antigravity/gemini-3.1-pro-preview-customtools", "fallbackModels": ["openai-codex/gpt-5.6-luna", "zai/glm-5.3"], "thinking": "low" },
|
|
151
|
+
"browser-qa": { "model": "openai-codex/gpt-5.6-luna", "fallbackModels": ["antigravity/gemini-3-flash-preview", "zai/glm-5.3"], "thinking": "low" },
|
|
152
|
+
"tests": { "model": "antigravity/antigravity-claude-sonnet-4-6", "fallbackModels": ["openai-codex/gpt-5.6-luna", "zai/glm-5-turbo"], "thinking": "high" },
|
|
153
153
|
"review": { "model": "antigravity/antigravity-claude-sonnet-4-6", "fallbackModels": ["openai-codex/gpt-5.6-sol", "zai/glm-5.3"], "thinking": "high" },
|
|
154
154
|
"implement": { "model": "openai-codex/gpt-5.6-sol", "fallbackModels": ["zai/glm-5.3"], "thinking": "high" },
|
|
155
155
|
"deep": { "model": "antigravity/antigravity-claude-opus-4-6-thinking", "fallbackModels": ["openai-codex/gpt-5.6-sol", "zai/glm-5.3"], "thinking": "high" }
|
|
@@ -160,34 +160,38 @@
|
|
|
160
160
|
"types": {
|
|
161
161
|
"quick": {
|
|
162
162
|
"description": "Use for tiny cheap tasks: answer a simple question, inspect one known file, or verify one fact. Not for broad repo search.",
|
|
163
|
-
"model": "
|
|
163
|
+
"model": "openai-codex/gpt-5.6-luna",
|
|
164
|
+
"fallbackModels": ["zai/glm-4.5-air"],
|
|
164
165
|
"thinking": "off"
|
|
165
166
|
},
|
|
166
167
|
|
|
167
168
|
"scan": {
|
|
168
169
|
"description": "Use for finding files, symbols, text, or inventory across a repo. Return paths/facts; do not judge code quality.",
|
|
169
|
-
"model": "
|
|
170
|
+
"model": "openai-codex/gpt-5.6-luna",
|
|
171
|
+
"fallbackModels": ["zai/glm-4.5-air"],
|
|
170
172
|
"thinking": "off",
|
|
171
173
|
"tools": ["read", "grep"]
|
|
172
174
|
},
|
|
173
175
|
|
|
174
176
|
"research": {
|
|
175
177
|
"description": "Use for multi-file codebase research: read several files and explain how something works. No edits.",
|
|
176
|
-
"model": "
|
|
178
|
+
"model": "openai-codex/gpt-5.6-terra",
|
|
179
|
+
"fallbackModels": ["zai/glm-5-turbo"],
|
|
177
180
|
"thinking": "low",
|
|
178
181
|
"tools": ["read", "grep"]
|
|
179
182
|
},
|
|
180
183
|
|
|
181
184
|
"docs": {
|
|
182
185
|
"description": "Use for documentation work: README/API docs review, docs gaps, changelog, migration notes, examples.",
|
|
183
|
-
"model": "
|
|
186
|
+
"model": "openai-codex/gpt-5.6-luna",
|
|
187
|
+
"fallbackModels": ["zai/glm-4.5-air"],
|
|
184
188
|
"thinking": "low"
|
|
185
189
|
},
|
|
186
190
|
|
|
187
191
|
"frontend": {
|
|
188
192
|
"description": "Use for frontend UI/UX visual work: styling, layout, typography, animation, responsive states, component polish, accessibility. Avoid backend/business logic unless needed for UI behavior.",
|
|
189
193
|
"model": "antigravity/gemini-3-flash-preview",
|
|
190
|
-
"fallbackModels": ["openai-codex/gpt-5.
|
|
194
|
+
"fallbackModels": ["openai-codex/gpt-5.6-luna", "zai/glm-5.3"],
|
|
191
195
|
"thinking": "medium",
|
|
192
196
|
"promptAppend": [
|
|
193
197
|
"Act as a frontend UI/UX engineer for visual and product-facing work.",
|
|
@@ -199,15 +203,17 @@
|
|
|
199
203
|
|
|
200
204
|
"browser-qa": {
|
|
201
205
|
"description": "Use for browser-based visual QA: reproduce UI bugs and verify fixes with deterministic assertions, screenshots, video, and traces.",
|
|
202
|
-
"model": "openai-codex/gpt-5.
|
|
206
|
+
"model": "openai-codex/gpt-5.6-luna",
|
|
203
207
|
"fallbackModels": ["antigravity/gemini-3-flash-preview", "zai/glm-5.3"],
|
|
204
|
-
"thinking": "
|
|
208
|
+
"thinking": "low",
|
|
209
|
+
"timeoutMs": 120000,
|
|
205
210
|
"tools": ["read", "grep", "bash"]
|
|
206
211
|
},
|
|
207
212
|
|
|
208
213
|
"tests": {
|
|
209
214
|
"description": "Use for tests: locate coverage, find gaps, run/check targeted test commands, diagnose failing tests.",
|
|
210
|
-
"model": "
|
|
215
|
+
"model": "openai-codex/gpt-5.6-terra",
|
|
216
|
+
"fallbackModels": ["zai/glm-5-turbo"],
|
|
211
217
|
"thinking": "medium",
|
|
212
218
|
"tools": ["read", "grep", "bash"]
|
|
213
219
|
},
|
|
@@ -167,7 +167,7 @@ export const DEFAULT_MAX_CONCURRENT = 5;
|
|
|
167
167
|
export const DEFAULT_ROUTING_CONFIG: ResolvedSubagentRoutingConfig = {
|
|
168
168
|
enabled: true,
|
|
169
169
|
model: "zai/glm-4.5-air",
|
|
170
|
-
fallbackModels: ["openai-codex/gpt-5.
|
|
170
|
+
fallbackModels: ["openai-codex/gpt-5.6-luna"],
|
|
171
171
|
maxTaskChars: 1200,
|
|
172
172
|
maxTokens: 512,
|
|
173
173
|
maxRetries: 3,
|
|
@@ -181,18 +181,26 @@ const BUILTIN_CONFIG: SubagentConfig = {
|
|
|
181
181
|
types: {
|
|
182
182
|
quick: {
|
|
183
183
|
description: "Use for tiny cheap tasks: answer a simple question, inspect one known file, or verify one fact. Not for broad repo search.",
|
|
184
|
+
model: "openai-codex/gpt-5.6-luna",
|
|
185
|
+
fallbackModels: ["zai/glm-4.5-air"],
|
|
184
186
|
thinking: "off",
|
|
185
187
|
},
|
|
186
188
|
scan: {
|
|
187
189
|
description: "Use for finding files, symbols, text, or inventory across a repo. Return paths/facts; do not judge code quality.",
|
|
190
|
+
model: "openai-codex/gpt-5.6-luna",
|
|
191
|
+
fallbackModels: ["zai/glm-4.5-air"],
|
|
188
192
|
thinking: "off",
|
|
189
193
|
},
|
|
190
194
|
research: {
|
|
191
195
|
description: "Use for multi-file codebase research: read several files and explain how something works. No edits.",
|
|
196
|
+
model: "openai-codex/gpt-5.6-terra",
|
|
197
|
+
fallbackModels: ["zai/glm-5-turbo"],
|
|
192
198
|
thinking: "low",
|
|
193
199
|
},
|
|
194
200
|
docs: {
|
|
195
201
|
description: "Use for documentation work: README/API docs review, docs gaps, changelog, migration notes, examples.",
|
|
202
|
+
model: "openai-codex/gpt-5.6-luna",
|
|
203
|
+
fallbackModels: ["zai/glm-4.5-air"],
|
|
196
204
|
thinking: "low",
|
|
197
205
|
},
|
|
198
206
|
frontend: {
|
|
@@ -207,9 +215,10 @@ const BUILTIN_CONFIG: SubagentConfig = {
|
|
|
207
215
|
},
|
|
208
216
|
"browser-qa": {
|
|
209
217
|
description: "Use for browser-based visual QA: reproduce UI bugs and verify fixes with deterministic assertions, screenshots, video, and traces.",
|
|
210
|
-
model: "openai-codex/gpt-5.
|
|
218
|
+
model: "openai-codex/gpt-5.6-luna",
|
|
211
219
|
fallbackModels: ["antigravity/gemini-3-flash-preview", "zai/glm-5.3"],
|
|
212
|
-
thinking: "
|
|
220
|
+
thinking: "low",
|
|
221
|
+
timeoutMs: 120_000,
|
|
213
222
|
tools: ["read", "grep", "bash"],
|
|
214
223
|
isolatedSkills: [getBrowserQaSkillPath()],
|
|
215
224
|
},
|
|
@@ -219,6 +228,8 @@ const BUILTIN_CONFIG: SubagentConfig = {
|
|
|
219
228
|
},
|
|
220
229
|
tests: {
|
|
221
230
|
description: "Use for tests: locate coverage, find gaps, run/check targeted test commands, diagnose failing tests.",
|
|
231
|
+
model: "openai-codex/gpt-5.6-terra",
|
|
232
|
+
fallbackModels: ["zai/glm-5-turbo"],
|
|
222
233
|
thinking: "medium",
|
|
223
234
|
},
|
|
224
235
|
review: {
|
|
@@ -13,3 +13,22 @@ export function terminateProcess(pid: number, signal: ProcessSignal): void {
|
|
|
13
13
|
}
|
|
14
14
|
process.kill(pid, signal);
|
|
15
15
|
}
|
|
16
|
+
|
|
17
|
+
/** Signal a launcher-owned process tree. POSIX callers must create the child as
|
|
18
|
+
* a process-group leader before using this helper. */
|
|
19
|
+
export function terminateProcessTree(pid: number, signal: ProcessSignal): void {
|
|
20
|
+
if (process.platform === "win32") {
|
|
21
|
+
terminateProcess(pid, signal);
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
try {
|
|
26
|
+
process.kill(-pid, signal);
|
|
27
|
+
} catch (error) {
|
|
28
|
+
const code = typeof error === "object" && error && "code" in error
|
|
29
|
+
? String((error as { code?: unknown }).code)
|
|
30
|
+
: undefined;
|
|
31
|
+
if (code !== "ESRCH") throw error;
|
|
32
|
+
// The owned group is already gone. Never fall back to a possibly reused PID.
|
|
33
|
+
}
|
|
34
|
+
}
|