pi-ui-extend 1.0.41 → 1.0.45
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 +50 -13
- package/dist/app/app.d.ts +13 -0
- package/dist/app/app.js +158 -8
- package/dist/app/cli/install.js +2 -2
- package/dist/app/commands/command-controller.d.ts +4 -0
- package/dist/app/commands/command-controller.js +11 -0
- package/dist/app/commands/command-git-actions.d.ts +25 -0
- package/dist/app/commands/command-git-actions.js +381 -0
- package/dist/app/commands/command-host.d.ts +4 -0
- package/dist/app/commands/command-host.js +5 -2
- package/dist/app/commands/command-model-actions.d.ts +1 -0
- package/dist/app/commands/command-model-actions.js +57 -35
- package/dist/app/commands/command-navigation-actions.d.ts +1 -0
- package/dist/app/commands/command-navigation-actions.js +16 -3
- package/dist/app/commands/command-registry.d.ts +2 -0
- package/dist/app/commands/command-registry.js +15 -1
- package/dist/app/commands/command-session-actions.js +9 -3
- package/dist/app/commands/reload-context-inventory.d.ts +11 -0
- package/dist/app/commands/reload-context-inventory.js +70 -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/input/autocomplete-controller.js +61 -34
- package/dist/app/input/input-action-controller.d.ts +2 -0
- package/dist/app/input/input-action-controller.js +8 -1
- package/dist/app/input/input-controller.d.ts +2 -1
- package/dist/app/input/input-controller.js +7 -2
- package/dist/app/input/prompt-enhancer-controller.js +53 -35
- package/dist/app/input/voice-controller.d.ts +41 -45
- package/dist/app/input/voice-controller.js +351 -419
- package/dist/app/model/model-usage-controller.js +17 -7
- package/dist/app/model/model-usage-status.d.ts +4 -1
- package/dist/app/model/model-usage-status.js +270 -46
- package/dist/app/popup/menu-items-controller.d.ts +13 -3
- package/dist/app/popup/menu-items-controller.js +37 -21
- package/dist/app/popup/popup-action-controller.d.ts +12 -2
- package/dist/app/popup/popup-action-controller.js +77 -24
- package/dist/app/popup/popup-menu-controller.d.ts +36 -14
- package/dist/app/popup/popup-menu-controller.js +239 -69
- package/dist/app/rendering/dcp-stats.d.ts +9 -4
- package/dist/app/rendering/dcp-stats.js +40 -425
- package/dist/app/rendering/editor-panels.js +10 -4
- package/dist/app/rendering/popup-menu-renderer.d.ts +3 -5
- package/dist/app/rendering/popup-menu-renderer.js +42 -37
- package/dist/app/rendering/render-controller.js +23 -2
- package/dist/app/rendering/status-line-renderer.d.ts +5 -0
- package/dist/app/rendering/status-line-renderer.js +41 -5
- package/dist/app/rendering/tab-line-renderer.js +26 -20
- package/dist/app/runtime.d.ts +12 -1
- package/dist/app/runtime.js +120 -12
- package/dist/app/screen/mouse-controller.d.ts +2 -0
- package/dist/app/screen/mouse-controller.js +17 -7
- package/dist/app/screen/status-controller.d.ts +4 -0
- package/dist/app/screen/status-controller.js +5 -0
- package/dist/app/session/lazy-session-manager.js +34 -0
- package/dist/app/session/session-event-controller.d.ts +1 -0
- package/dist/app/session/session-event-controller.js +10 -1
- package/dist/app/session/session-history.d.ts +1 -0
- package/dist/app/session/session-history.js +12 -1
- package/dist/app/session/session-lifecycle-controller.d.ts +7 -1
- package/dist/app/session/session-lifecycle-controller.js +16 -1
- package/dist/app/session/tabs-controller.d.ts +26 -1
- package/dist/app/session/tabs-controller.js +454 -147
- package/dist/app/subagents/subagents-files.js +60 -1
- package/dist/app/subagents/subagents-model.d.ts +1 -0
- package/dist/app/subagents/subagents-model.js +18 -2
- package/dist/app/subagents/subagents-widget-controller.d.ts +1 -0
- package/dist/app/subagents/subagents-widget-controller.js +6 -0
- package/dist/app/types.d.ts +16 -1
- package/dist/app/workspace/workspace-actions-controller.js +10 -2
- package/dist/app/workspace/workspace-undo.d.ts +1 -0
- package/dist/app/workspace/workspace-undo.js +1 -0
- package/dist/bundled-extensions/question/index.js +9 -1
- package/dist/bundled-extensions/question/remote.d.ts +4 -0
- package/dist/bundled-extensions/question/remote.js +33 -0
- package/dist/bundled-extensions/telegram-connector/bot.d.ts +43 -0
- package/dist/bundled-extensions/telegram-connector/bot.js +166 -0
- package/dist/bundled-extensions/telegram-connector/config.d.ts +8 -0
- package/dist/bundled-extensions/telegram-connector/config.js +87 -0
- package/dist/bundled-extensions/telegram-connector/coordinator.d.ts +66 -0
- package/dist/bundled-extensions/telegram-connector/coordinator.js +413 -0
- package/dist/bundled-extensions/telegram-connector/index.d.ts +3 -0
- package/dist/bundled-extensions/telegram-connector/index.js +195 -0
- package/dist/bundled-extensions/terminal-bell/index.d.ts +0 -8
- package/dist/bundled-extensions/terminal-bell/index.js +0 -76
- package/dist/bundled-extensions/workspace-undo/index.d.ts +26 -0
- package/dist/bundled-extensions/workspace-undo/index.js +191 -0
- package/dist/config.d.ts +21 -2
- package/dist/config.js +159 -32
- package/dist/default-pix-config.js +25 -5
- package/dist/schemas/index.d.ts +1 -0
- package/dist/schemas/index.js +1 -0
- package/dist/schemas/pi-tools-suite-schema.d.ts +88 -62
- package/dist/schemas/pi-tools-suite-schema.js +54 -83
- package/dist/schemas/pix-schema.d.ts +19 -2
- package/dist/schemas/pix-schema.js +47 -5
- package/dist/schemas/tasks-schema.d.ts +18 -0
- package/dist/schemas/tasks-schema.js +41 -0
- package/docs/concurrency.md +9 -1
- package/docs/desktop-mvp.md +22 -6
- package/docs/desktop-task-manager.md +148 -84
- package/docs/release.md +30 -6
- package/external/pi-tools-suite/README.md +197 -84
- package/external/pi-tools-suite/docs/evals.md +1 -1
- package/external/pi-tools-suite/docs/session-recovery.md +47 -14
- package/external/pi-tools-suite/docs/subagent-model-pools.md +48 -30
- package/external/pi-tools-suite/docs/ui-qa-subagent.md +440 -0
- package/external/pi-tools-suite/package.json +6 -1
- package/external/pi-tools-suite/src/antigravity-auth/auth-store.ts +2 -1
- package/external/pi-tools-suite/src/antigravity-auth/constants.ts +9 -3
- package/external/pi-tools-suite/src/antigravity-auth/headers.ts +41 -3
- package/external/pi-tools-suite/src/antigravity-auth/models.ts +94 -21
- package/external/pi-tools-suite/src/antigravity-auth/oauth.ts +5 -17
- package/external/pi-tools-suite/src/antigravity-auth/payload.ts +72 -7
- package/external/pi-tools-suite/src/antigravity-auth/stream.ts +13 -1
- 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 +1 -1
- package/external/pi-tools-suite/src/async-subagents/agents/presets.jsonc +16 -0
- package/external/pi-tools-suite/src/async-subagents/agents/research.md +5 -3
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/backends/browser.mjs +346 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/backends/desktop.mjs +1038 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/backends/tui.mjs +759 -0
- package/external/pi-tools-suite/src/async-subagents/agents/{browser-qa → ui-qa/browser}/scripts/browser-qa-runner.mjs +32 -23
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/drivers/chrome-devtools/chrome-devtools-provider.mjs +895 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/drivers/linux/linux-atspi.py +494 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/drivers/macos/macos-accessibility.swift +1085 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/drivers/native-terminal/bridge-client.mjs +50 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/drivers/native-terminal/native-terminal-host.mjs +501 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/drivers/windows/windows-uia.ps1 +454 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/browser-auth.md +114 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/browser-chrome-devtools.md +91 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/browser-playwright.md +145 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/browser.md +82 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/desktop-linux.md +26 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/desktop-macos.md +29 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/desktop-windows.md +23 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/desktop.md +54 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/tui-native-terminal.md +59 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/tui-pty.md +37 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/tui.md +60 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/scripts/ui-qa-runner.mjs +535 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa.md +75 -0
- package/external/pi-tools-suite/src/async-subagents/commands.ts +15 -71
- 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 +5 -4
- package/external/pi-tools-suite/src/async-subagents/core/agent-strategy.ts +1 -1
- package/external/pi-tools-suite/src/async-subagents/core/agents-dir.ts +8 -5
- package/external/pi-tools-suite/src/async-subagents/core/browser-qa.ts +16 -2
- package/external/pi-tools-suite/src/async-subagents/core/config.ts +160 -327
- package/external/pi-tools-suite/src/async-subagents/core/model-selection.ts +2 -1
- package/external/pi-tools-suite/src/async-subagents/core/registry.ts +158 -33
- package/external/pi-tools-suite/src/async-subagents/core/routing.ts +21 -5
- package/external/pi-tools-suite/src/async-subagents/core/spawn.ts +40 -26
- 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/core/ultrawork-auto.ts +51 -45
- package/external/pi-tools-suite/src/async-subagents/index.ts +69 -5
- package/external/pi-tools-suite/src/async-subagents/lib.ts +16 -9
- package/external/pi-tools-suite/src/async-subagents/tools/spawn.ts +8 -5
- package/external/pi-tools-suite/src/async-subagents/tools/subagents.ts +5 -4
- package/external/pi-tools-suite/src/async-subagents/types.ts +1 -0
- package/external/pi-tools-suite/src/coding-discipline/index.ts +90 -59
- package/external/pi-tools-suite/src/config.ts +55 -1
- package/external/pi-tools-suite/src/context-gateway/accounting-log.ts +282 -0
- package/external/pi-tools-suite/src/context-gateway/config.ts +77 -3
- package/external/pi-tools-suite/src/context-gateway/efficiency.ts +414 -0
- package/external/pi-tools-suite/src/context-gateway/enforcement.ts +222 -0
- package/external/pi-tools-suite/src/context-gateway/index.ts +206 -19
- package/external/pi-tools-suite/src/context-gateway/storeless-capabilities.ts +7 -7
- package/external/pi-tools-suite/src/context-gateway/telemetry.ts +101 -28
- package/external/pi-tools-suite/src/context-gateway/types.ts +16 -3
- package/external/pi-tools-suite/src/context-inventory.ts +99 -0
- package/external/pi-tools-suite/src/dcp/auto-compress-budget.ts +39 -4
- package/external/pi-tools-suite/src/dcp/auto-compress.ts +128 -49
- package/external/pi-tools-suite/src/dcp/commands.ts +32 -156
- package/external/pi-tools-suite/src/dcp/compress-tool.ts +177 -46
- package/external/pi-tools-suite/src/dcp/compression-blocks.ts +6 -58
- package/external/pi-tools-suite/src/dcp/compression-preview.ts +9 -0
- package/external/pi-tools-suite/src/dcp/compression-progress.ts +22 -0
- package/external/pi-tools-suite/src/dcp/config.ts +114 -17
- package/external/pi-tools-suite/src/dcp/conversation-index.ts +36 -9
- package/external/pi-tools-suite/src/dcp/diagnostics.ts +41 -0
- package/external/pi-tools-suite/src/dcp/fresh-tool-results.ts +38 -0
- package/external/pi-tools-suite/src/dcp/index.ts +338 -66
- package/external/pi-tools-suite/src/dcp/journal.ts +126 -4
- package/external/pi-tools-suite/src/dcp/progress-controller.ts +2 -1
- package/external/pi-tools-suite/src/dcp/prompts.ts +83 -192
- package/external/pi-tools-suite/src/dcp/protected-continuity.ts +175 -0
- package/external/pi-tools-suite/src/dcp/pruner-candidates.ts +93 -3
- package/external/pi-tools-suite/src/dcp/pruner-message-ids.ts +6 -10
- package/external/pi-tools-suite/src/dcp/pruner-nudge.ts +36 -33
- package/external/pi-tools-suite/src/dcp/pruner-tools.ts +6 -3
- package/external/pi-tools-suite/src/dcp/pruner.ts +1 -0
- package/external/pi-tools-suite/src/dcp/routine-pressure.ts +86 -0
- package/external/pi-tools-suite/src/dcp/state.ts +9 -0
- package/external/pi-tools-suite/src/dcp/statistics.d.ts +8 -0
- package/external/pi-tools-suite/src/dcp/statistics.js +156 -0
- package/external/pi-tools-suite/src/default-pi-tools-suite-config.ts +78 -22
- package/external/pi-tools-suite/src/index.ts +7 -1
- package/external/pi-tools-suite/src/lib/project.ts +36 -1
- package/external/pi-tools-suite/src/model-tools/index.ts +10 -7
- package/external/pi-tools-suite/src/repo-discovery/index.ts +304 -4
- package/external/pi-tools-suite/src/resource-registry/index.ts +2551 -0
- package/external/pi-tools-suite/src/session-recovery/index.ts +17 -0
- package/external/pi-tools-suite/src/shell-command-policy.ts +219 -0
- package/external/pi-tools-suite/src/todo/index.ts +21 -0
- package/external/pi-tools-suite/src/todo/todo.ts +19 -1
- package/external/pi-tools-suite/src/tool-descriptions.ts +47 -19
- package/package.json +10 -9
- package/schemas/pi-tools-suite.json +466 -287
- package/schemas/pix.json +129 -11
- package/schemas/tasks.json +131 -0
- package/skills/simplify/SKILL.md +33 -5
- package/docs/desktop-markdown-media.md +0 -77
- package/external/pi-tools-suite/docs/browser-qa-subagent.md +0 -177
- package/external/pi-tools-suite/docs/dcp-emergency-current-turn.md +0 -102
- package/external/pi-tools-suite/src/async-subagents/agents/browser-qa.md +0 -598
- package/external/pi-tools-suite/src/async-subagents/async-subagents.sample.jsonc +0 -54
- package/external/pi-tools-suite/src/skill-installer/index.ts +0 -333
- package/skills/playwright-cli/SKILL.md +0 -420
- package/skills/playwright-cli/references/element-attributes.md +0 -23
- package/skills/playwright-cli/references/playwright-tests.md +0 -50
- package/skills/playwright-cli/references/request-mocking.md +0 -87
- package/skills/playwright-cli/references/running-code.md +0 -241
- package/skills/playwright-cli/references/session-management.md +0 -273
- package/skills/playwright-cli/references/spec-driven-testing.md +0 -311
- package/skills/playwright-cli/references/storage-state.md +0 -290
- package/skills/playwright-cli/references/test-generation.md +0 -142
- package/skills/playwright-cli/references/tracing.md +0 -154
- package/skills/playwright-cli/references/video-recording.md +0 -147
- package/skills/spec-lite/SKILL.md +0 -140
- /package/external/pi-tools-suite/src/async-subagents/agents/{browser-qa → ui-qa/browser}/examples/qa-auth.example.jsonc +0 -0
- /package/external/pi-tools-suite/src/async-subagents/agents/{browser-qa → ui-qa/browser}/examples/qa-flow.example.jsonc +0 -0
- /package/external/pi-tools-suite/src/async-subagents/agents/{browser-qa → ui-qa/browser}/vendor/fflate.LICENSE +0 -0
- /package/external/pi-tools-suite/src/async-subagents/agents/{browser-qa → ui-qa/browser}/vendor/fflate.mjs +0 -0
|
@@ -201,6 +201,14 @@ function toolResultFrom(entry: EntryLike): UnknownRecord | undefined {
|
|
|
201
201
|
return message?.role === "toolResult" ? message : undefined;
|
|
202
202
|
}
|
|
203
203
|
|
|
204
|
+
function recoverableGatewayDetails(message: UnknownRecord): UnknownRecord | undefined {
|
|
205
|
+
const toolName = typeof message.toolName === "string" ? message.toolName.toLowerCase() : "";
|
|
206
|
+
if (toolName !== "web_search" && toolName !== "web_fetch") return undefined;
|
|
207
|
+
if (!isRecord(message.details) || !isRecord(message.details.contextGateway)) return undefined;
|
|
208
|
+
if (message.details.contextGateway.representation !== "web-recoverable-compact") return undefined;
|
|
209
|
+
return message.details;
|
|
210
|
+
}
|
|
211
|
+
|
|
204
212
|
function summaryFrom(entry: EntryLike): string {
|
|
205
213
|
if ((entry.type === "compaction" || entry.type === "branch_summary") && typeof entry.summary === "string") {
|
|
206
214
|
return entry.summary;
|
|
@@ -218,6 +226,11 @@ function entryText(entry: EntryLike): string {
|
|
|
218
226
|
for (const call of toolCallsFrom(entry)) {
|
|
219
227
|
chunks.push(call.name, serializeJson(call.arguments));
|
|
220
228
|
}
|
|
229
|
+
if (message.role === "toolResult") {
|
|
230
|
+
const toolName = typeof message.toolName === "string" ? message.toolName : "unknown";
|
|
231
|
+
const callId = typeof message.toolCallId === "string" ? message.toolCallId : "unknown";
|
|
232
|
+
chunks.push(`tool_result ${toolName}#${callId}`);
|
|
233
|
+
}
|
|
221
234
|
} else if (entry.type === "custom_message") {
|
|
222
235
|
const text = textFromContent(entry.content);
|
|
223
236
|
if (text) chunks.push(text);
|
|
@@ -416,6 +429,10 @@ function renderEntryFull(entry: EntryLike): string {
|
|
|
416
429
|
const toolName = typeof message.toolName === "string" ? message.toolName : "unknown";
|
|
417
430
|
const callId = typeof message.toolCallId === "string" ? message.toolCallId : "unknown";
|
|
418
431
|
lines.push(`tool_result ${toolName}#${callId}${message.isError === true ? " error" : ""}`);
|
|
432
|
+
const recoverableDetails = recoverableGatewayDetails(message);
|
|
433
|
+
if (recoverableDetails) {
|
|
434
|
+
lines.push("recoverable_raw_details:", serializeJson(recoverableDetails));
|
|
435
|
+
}
|
|
419
436
|
}
|
|
420
437
|
} else if (entry.type === "compaction") {
|
|
421
438
|
lines.push(summaryFrom(entry));
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
export type ShellCommandScope = "simple" | "compound" | "unknown";
|
|
2
|
+
export type ShellCommandKind = "inspection" | "test-build" | "mutation" | "unknown";
|
|
3
|
+
|
|
4
|
+
export interface ShellCommandClassification {
|
|
5
|
+
scope: ShellCommandScope;
|
|
6
|
+
kind: ShellCommandKind;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const ENV_ASSIGNMENT_RE = /^[A-Za-z_][A-Za-z0-9_]*=.*$/;
|
|
10
|
+
const SAFE_EPHEMERAL_WRITE_RE = /^\/(?:private\/)?tmp\/[^\0\r\n]+$/;
|
|
11
|
+
const COMMAND_SEPARATORS = new Set([";", "&&", "||", "|"]);
|
|
12
|
+
const REDIRECT_OPERATORS = new Set([">", ">>", "<"]);
|
|
13
|
+
|
|
14
|
+
interface ShellScan {
|
|
15
|
+
scope: ShellCommandScope;
|
|
16
|
+
commands: string[][];
|
|
17
|
+
unsafeWrite: boolean;
|
|
18
|
+
unsupported: boolean;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function safeEphemeralWriteTarget(target: string): boolean {
|
|
22
|
+
return target === "/dev/null" || SAFE_EPHEMERAL_WRITE_RE.test(target);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Minimal conservative shell lexer. It understands quoting only well enough to
|
|
27
|
+
* keep metacharacters inside quotes literal and to prove a small allowlisted
|
|
28
|
+
* inspection pipeline safe. Unsupported shell syntax remains unknown.
|
|
29
|
+
*/
|
|
30
|
+
function scanShell(command: string): ShellScan {
|
|
31
|
+
const tokens: string[] = [];
|
|
32
|
+
let current = "";
|
|
33
|
+
let quote: "'" | '"' | undefined;
|
|
34
|
+
let unsupported = false;
|
|
35
|
+
const flush = () => {
|
|
36
|
+
if (current.length > 0) tokens.push(current);
|
|
37
|
+
current = "";
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
for (let index = 0; index < command.length; index++) {
|
|
41
|
+
const char = command[index]!;
|
|
42
|
+
const next = command[index + 1];
|
|
43
|
+
if (quote) {
|
|
44
|
+
if (char === quote) {
|
|
45
|
+
quote = undefined;
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
if (quote === '"' && char === "\\" && next !== undefined) {
|
|
49
|
+
current += next;
|
|
50
|
+
index++;
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
if (quote === '"' && (char === "`" || (char === "$" && next === "("))) unsupported = true;
|
|
54
|
+
current += char;
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (char === "'" || char === '"') {
|
|
59
|
+
quote = char;
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
if (char === "\\" && next !== undefined) {
|
|
63
|
+
current += next;
|
|
64
|
+
index++;
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
if (char === "`" || (char === "$" && next === "(") || ((char === "<" || char === ">") && next === "(")) {
|
|
68
|
+
unsupported = true;
|
|
69
|
+
}
|
|
70
|
+
if (char === "\r" || char === "\n" || char === "&" && next !== "&" || char === "(" || char === ")") {
|
|
71
|
+
unsupported = true;
|
|
72
|
+
}
|
|
73
|
+
if (/\s/.test(char)) {
|
|
74
|
+
flush();
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
if (char === ";" || char === "|" || char === ">" || char === "<" || (char === "&" && next === "&")) {
|
|
78
|
+
flush();
|
|
79
|
+
let operator = char;
|
|
80
|
+
if ((char === "&" && next === "&") || (char === "|" && next === "|") || (char === ">" && next === ">") || (char === "<" && next === "<")) {
|
|
81
|
+
operator += next;
|
|
82
|
+
index++;
|
|
83
|
+
}
|
|
84
|
+
if (operator === "<<") unsupported = true;
|
|
85
|
+
tokens.push(operator);
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
current += char;
|
|
89
|
+
}
|
|
90
|
+
flush();
|
|
91
|
+
if (quote) unsupported = true;
|
|
92
|
+
|
|
93
|
+
const commands: string[][] = [];
|
|
94
|
+
let currentCommand: string[] = [];
|
|
95
|
+
let unsafeWrite = false;
|
|
96
|
+
let compound = false;
|
|
97
|
+
for (let index = 0; index < tokens.length; index++) {
|
|
98
|
+
const token = tokens[index]!;
|
|
99
|
+
if (COMMAND_SEPARATORS.has(token)) {
|
|
100
|
+
compound = true;
|
|
101
|
+
if (currentCommand.length === 0) unsupported = true;
|
|
102
|
+
else commands.push(currentCommand);
|
|
103
|
+
currentCommand = [];
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
if (REDIRECT_OPERATORS.has(token)) {
|
|
107
|
+
compound = true;
|
|
108
|
+
const target = tokens[++index];
|
|
109
|
+
if (!target || COMMAND_SEPARATORS.has(target) || REDIRECT_OPERATORS.has(target)) {
|
|
110
|
+
unsupported = true;
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
if ((token === ">" || token === ">>") && !safeEphemeralWriteTarget(target)) unsafeWrite = true;
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
currentCommand.push(token);
|
|
117
|
+
}
|
|
118
|
+
if (currentCommand.length > 0) commands.push(currentCommand);
|
|
119
|
+
else if (tokens.length > 0 && COMMAND_SEPARATORS.has(tokens.at(-1)!)) unsupported = true;
|
|
120
|
+
|
|
121
|
+
for (const words of commands) {
|
|
122
|
+
while (words.length > 0 && (ENV_ASSIGNMENT_RE.test(words[0]!) || /^\d+$/.test(words[0]!))) words.shift();
|
|
123
|
+
if (words.length === 0) unsupported = true;
|
|
124
|
+
}
|
|
125
|
+
return {
|
|
126
|
+
scope: unsupported ? "unknown" : compound ? "compound" : "simple",
|
|
127
|
+
commands,
|
|
128
|
+
unsafeWrite,
|
|
129
|
+
unsupported,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function baseName(value: string): string {
|
|
134
|
+
return value.replace(/\\/g, "/").split("/").at(-1)?.toLowerCase() ?? "";
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function isKnownInspection(words: readonly string[]): boolean {
|
|
138
|
+
const exe = baseName(words[0]!);
|
|
139
|
+
if (["pwd", "ls", "grep", "cat", "head", "tail", "wc", "stat", "du", "which", "sort", "uniq", "cut", "tr", "printf", "echo", "basename", "dirname"].includes(exe)) {
|
|
140
|
+
return true;
|
|
141
|
+
}
|
|
142
|
+
if (exe === "find") {
|
|
143
|
+
return !words.some((word) => ["-delete", "-exec", "-execdir", "-ok", "-okdir"].includes(word));
|
|
144
|
+
}
|
|
145
|
+
if (exe === "fd") {
|
|
146
|
+
return !words.some((word) => ["-x", "--exec", "-X", "--exec-batch"].includes(word));
|
|
147
|
+
}
|
|
148
|
+
if (exe === "rg") {
|
|
149
|
+
return !words.some((word) => word === "--pre" || word.startsWith("--pre="));
|
|
150
|
+
}
|
|
151
|
+
if (exe === "command" && words[1] === "-v") return true;
|
|
152
|
+
if (exe === "sed") return words.includes("-n") && !words.some((word) => /^-.*i/.test(word));
|
|
153
|
+
if (exe === "jq") return !words.some((word) => word === "-i" || word === "--in-place");
|
|
154
|
+
if (exe !== "git") return false;
|
|
155
|
+
const sub = words[1]?.toLowerCase();
|
|
156
|
+
if (["status", "diff", "log", "show", "grep", "rev-parse", "ls-files", "ls-tree"].includes(sub ?? "")) return true;
|
|
157
|
+
if (sub === "branch") return words.includes("--show-current");
|
|
158
|
+
if (sub === "remote") {
|
|
159
|
+
const action = words[2]?.toLowerCase();
|
|
160
|
+
return action === undefined || action === "-v" || action === "--verbose" || action === "get-url";
|
|
161
|
+
}
|
|
162
|
+
return false;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function isKnownTestBuild(words: readonly string[]): boolean {
|
|
166
|
+
const exe = baseName(words[0]!);
|
|
167
|
+
const first = words[1]?.toLowerCase();
|
|
168
|
+
if (["pytest", "vitest", "jest", "tsc", "eslint", "stylelint"].includes(exe)) return true;
|
|
169
|
+
if (exe === "biome") return first === "check" || first === "lint";
|
|
170
|
+
if (exe === "cargo") return ["test", "check", "build", "clippy", "fmt"].includes(first ?? "");
|
|
171
|
+
if (exe === "go") return first === "test" || first === "vet";
|
|
172
|
+
if (exe === "bun") {
|
|
173
|
+
if (first === "test") return true;
|
|
174
|
+
if (first === "run") return /^(test|check|lint|typecheck|build)(:|$)/.test(words[2]?.toLowerCase() ?? "");
|
|
175
|
+
}
|
|
176
|
+
if (["npm", "pnpm", "yarn"].includes(exe)) {
|
|
177
|
+
if (first === "test") return true;
|
|
178
|
+
if (first === "run") return /^(test|check|lint|typecheck|build)(:|$)/.test(words[2]?.toLowerCase() ?? "");
|
|
179
|
+
}
|
|
180
|
+
return false;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function isKnownMutation(words: readonly string[]): boolean {
|
|
184
|
+
const exe = baseName(words[0]!);
|
|
185
|
+
if (["rm", "mv", "cp", "mkdir", "rmdir", "touch", "chmod", "chown", "ln", "install"].includes(exe)) return true;
|
|
186
|
+
if (exe === "sed" && words.some((word) => /^-.*i/.test(word))) return true;
|
|
187
|
+
if (exe === "git") {
|
|
188
|
+
return [
|
|
189
|
+
"add", "commit", "reset", "checkout", "switch", "restore", "clean", "merge", "rebase",
|
|
190
|
+
"cherry-pick", "revert", "tag", "push", "pull", "fetch", "stash", "worktree",
|
|
191
|
+
].includes(words[1]?.toLowerCase() ?? "");
|
|
192
|
+
}
|
|
193
|
+
if (["npm", "pnpm", "yarn", "bun"].includes(exe)) {
|
|
194
|
+
return ["install", "add", "remove", "uninstall", "update", "upgrade", "link", "publish"].includes(words[1]?.toLowerCase() ?? "");
|
|
195
|
+
}
|
|
196
|
+
return false;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
export function shellCommandText(input: unknown): string | undefined {
|
|
200
|
+
if (!input || typeof input !== "object" || Array.isArray(input)) return undefined;
|
|
201
|
+
const command = (input as Record<string, unknown>).command;
|
|
202
|
+
return typeof command === "string" && command.trim().length > 0 ? command.trim() : undefined;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Conservative, non-executing shell classifier. A command is considered
|
|
207
|
+
* inspection/test-build only when both its structure and executable/subcommand
|
|
208
|
+
* are allowlisted. Everything ambiguous fails closed to unknown.
|
|
209
|
+
*/
|
|
210
|
+
export function classifyShellCommand(input: unknown): ShellCommandClassification {
|
|
211
|
+
const command = shellCommandText(input);
|
|
212
|
+
if (!command) return { scope: "unknown", kind: "unknown" };
|
|
213
|
+
const scan = scanShell(command);
|
|
214
|
+
if (scan.unsupported || scan.commands.length === 0) return { scope: "unknown", kind: "unknown" };
|
|
215
|
+
if (scan.unsafeWrite || scan.commands.some(isKnownMutation)) return { scope: scan.scope, kind: "mutation" };
|
|
216
|
+
if (scan.commands.length === 1 && isKnownTestBuild(scan.commands[0]!)) return { scope: scan.scope, kind: "test-build" };
|
|
217
|
+
if (scan.commands.every(isKnownInspection)) return { scope: scan.scope, kind: "inspection" };
|
|
218
|
+
return { scope: scan.scope, kind: "unknown" };
|
|
219
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
2
2
|
import { loadPiToolsSuiteConfig, type TodoThinkingLevel as ConfigTodoThinkingLevel } from "../config.js";
|
|
3
3
|
import { isAgentBusyRaceError } from "../context-usage.js";
|
|
4
|
+
import { hasAvailableIndexedProjectRoot } from "../lib/project.js";
|
|
4
5
|
import { autoClearCompletedTodos } from "./state/auto-clear.js";
|
|
5
6
|
import { loadPersistedPlan, syncPersistedPlan } from "./state/persistence.js";
|
|
6
7
|
import { replayFromBranch } from "./state/replay.js";
|
|
@@ -32,6 +33,25 @@ const TODO_NUDGE_IDLE_RETRY_DELAY_MS = 100;
|
|
|
32
33
|
const TODO_NUDGE_MAX_IDLE_ATTEMPTS = 40;
|
|
33
34
|
const ASK_USER_TOOL_NAMES = new Set(["ask_user", "ask_user_question", "question"]);
|
|
34
35
|
const TODO_THINKING_RESTORE_METADATA_KEY = "__piTodoRestoreThinking";
|
|
36
|
+
const REPO_KNOWLEDGE_FINALIZATION_REMINDER =
|
|
37
|
+
"📚 Before completing the final todo: if behavior/contracts changed, reconcile affected specs and repo knowledge; skip for mechanical changes.";
|
|
38
|
+
|
|
39
|
+
function completesTodo(info: { action: string; params: TaskMutationParams }): boolean {
|
|
40
|
+
if (info.action === "update") return info.params.status === "completed";
|
|
41
|
+
if (info.action !== "batch_update") return false;
|
|
42
|
+
return (info.params.items ?? []).some((item) => item.status === "completed");
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function repoKnowledgeFinalizationReminder(
|
|
46
|
+
state: ReturnType<typeof getState>,
|
|
47
|
+
ctx: ExtensionContext,
|
|
48
|
+
info: { action: string; params: TaskMutationParams },
|
|
49
|
+
): string | undefined {
|
|
50
|
+
if (!hasAvailableIndexedProjectRoot(ctx.cwd)) return undefined;
|
|
51
|
+
if (!completesTodo(info)) return undefined;
|
|
52
|
+
const remainingActive = selectVisibleTasks(state).filter((task) => ACTIVE_STATUSES.has(task.status));
|
|
53
|
+
return remainingActive.length === 1 ? REPO_KNOWLEDGE_FINALIZATION_REMINDER : undefined;
|
|
54
|
+
}
|
|
35
55
|
|
|
36
56
|
function isStaleExtensionContextError(error: unknown): boolean {
|
|
37
57
|
return error instanceof Error && /ctx is stale|stale ctx|stale after session replacement|stale after.*reload/i.test(error.message);
|
|
@@ -241,6 +261,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
241
261
|
registerTodoTool(pi, {
|
|
242
262
|
...thinkingPrompt,
|
|
243
263
|
...(availableThinkingLevels ? { parameters: todoParamsSchemaForThinkingLevels(availableThinkingLevels) } : {}),
|
|
264
|
+
resultReminder: repoKnowledgeFinalizationReminder,
|
|
244
265
|
prepareMutation: (state, ctx, info) => {
|
|
245
266
|
if (!todoThinkingEnabled) return info.params;
|
|
246
267
|
if (info.action === "create" || info.action === "update") return prepareTodoThinkingMutation(state, ctx, info.params);
|
|
@@ -84,6 +84,11 @@ interface TodoToolHooks {
|
|
|
84
84
|
ctx: ExtensionContext,
|
|
85
85
|
info: { action: TaskAction; params: TaskMutationParams },
|
|
86
86
|
) => TaskMutationParams | Promise<TaskMutationParams>;
|
|
87
|
+
resultReminder?: (
|
|
88
|
+
state: ReturnType<typeof getState>,
|
|
89
|
+
ctx: ExtensionContext,
|
|
90
|
+
info: { action: TaskAction; params: TaskMutationParams },
|
|
91
|
+
) => string | undefined | Promise<string | undefined>;
|
|
87
92
|
afterCommit?: (
|
|
88
93
|
state: ReturnType<typeof getState>,
|
|
89
94
|
ctx: ExtensionContext,
|
|
@@ -448,7 +453,20 @@ export function registerTodoTool(pi: ExtensionAPI, hooks: TodoToolRegistrationOp
|
|
|
448
453
|
params: preparedParams,
|
|
449
454
|
committedState: autoClear.state,
|
|
450
455
|
});
|
|
451
|
-
|
|
456
|
+
let toolResult = buildToolResult(params.action, preparedParams, autoClear.state, result.op);
|
|
457
|
+
const resultReminder = await hooks.resultReminder?.(result.state, _ctx as ExtensionContext, {
|
|
458
|
+
action: params.action,
|
|
459
|
+
params: preparedParams,
|
|
460
|
+
});
|
|
461
|
+
if (resultReminder?.trim()) {
|
|
462
|
+
toolResult = {
|
|
463
|
+
...toolResult,
|
|
464
|
+
content: [{
|
|
465
|
+
type: "text" as const,
|
|
466
|
+
text: `${toolResult.content[0]?.text ?? ""}\n\n${resultReminder.trim()}`.trim(),
|
|
467
|
+
}],
|
|
468
|
+
};
|
|
469
|
+
}
|
|
452
470
|
if (!autoClear.cleared) return toolResult;
|
|
453
471
|
return {
|
|
454
472
|
...toolResult,
|
|
@@ -17,6 +17,8 @@ export type RepoDiscoveryToolDescription = ToolDescription & Required<Pick<ToolD
|
|
|
17
17
|
targetDescription?: string;
|
|
18
18
|
};
|
|
19
19
|
|
|
20
|
+
export type RepoKnowledgeToolDescription = ToolDescription & Required<Pick<ToolDescription, "promptSnippet" | "promptGuidelines">>;
|
|
21
|
+
|
|
20
22
|
export type ToolDescriptionSetOptions = {
|
|
21
23
|
repoDiscovery?: boolean;
|
|
22
24
|
};
|
|
@@ -29,10 +31,9 @@ export const COMPRESS_TOOL_DESCRIPTION: ToolDescription = {
|
|
|
29
31
|
name: "compress",
|
|
30
32
|
label: "Compress Context",
|
|
31
33
|
description: COMPRESS_RANGE_DESCRIPTION,
|
|
32
|
-
promptSnippet: "
|
|
34
|
+
promptSnippet: "Compress only closed, high-yield stale context when pressure/reminders justify it; keep active or still-needed raw context. Omit summary for DCP summarizer.",
|
|
33
35
|
promptGuidelines: [
|
|
34
|
-
"
|
|
35
|
-
"Summarize large stale shell/read/repo/web outputs, diffs, and passing logs once exact text is no longer useful; keep active or still-needed context raw.",
|
|
36
|
+
"Prefer completed work and understood large tool/log output; low context alone is not a trigger.",
|
|
36
37
|
],
|
|
37
38
|
};
|
|
38
39
|
|
|
@@ -70,11 +71,11 @@ export function asyncSubagentToolDescriptions(options: ToolDescriptionSetOptions
|
|
|
70
71
|
name: "subagents",
|
|
71
72
|
label: "Subagents",
|
|
72
73
|
description: [
|
|
73
|
-
"For every real-
|
|
74
|
-
"If
|
|
75
|
-
"After
|
|
74
|
+
"For every real user-interface QA request (browser, terminal/TUI, or desktop GUI), immediately spawn subagentType='ui-qa' before checking files, URLs, servers, launch commands, or other prerequisites; the QA sub-agent owns feasibility checks and blocked reports, so the parent must not substitute static checks for requested UI QA.",
|
|
75
|
+
"If ui-qa browser testing reports that credentials are required, it must identify the generated project-local template and explicitly ask the user to fill it; the parent relays that request without reading or editing the credential file.",
|
|
76
|
+
"After UI testing, ui-qa must return clickable links for every available screenshot, terminal capture, video, trace, or other retained evidence; the parent must preserve those links in its user-facing report.",
|
|
76
77
|
SUBAGENT_DELEGATION_GUIDANCE,
|
|
77
|
-
"Presets declare available models; each agent's ordered models selects the first usable model in that pool. AGENTS_PRESET or /subagent-preset session <name> selects the current session pool
|
|
78
|
+
"Presets declare available models; each agent's ordered models selects the first usable model in that pool. AGENTS_PRESET or /subagent-preset session <name> selects the current session pool. Bundled pools live with agent files, and projects can override/add pools in .pi/agents/presets.jsonc. Do not override the model merely to choose a role.",
|
|
78
79
|
SUBAGENT_TYPE_SELECTION_GUIDANCE,
|
|
79
80
|
repoDiscovery
|
|
80
81
|
? "Use for broad independent tracks, review axes, or hypotheses even though repo_* tools are available."
|
|
@@ -83,18 +84,18 @@ export function asyncSubagentToolDescriptions(options: ToolDescriptionSetOptions
|
|
|
83
84
|
"Results are compact with artifact links. Agents run isolated pi processes with extensions disabled to prevent recursive spawning; spawn/task timeoutSeconds can shorten the default 30m watchdog, project concurrency queues excess agents, and retry backoff/fallback models/Antigravity account rotation are config-driven.",
|
|
84
85
|
].join(" "),
|
|
85
86
|
promptSnippet:
|
|
86
|
-
"For every
|
|
87
|
-
"Give
|
|
87
|
+
"For every real UI QA, UI bug reproduction, or user-facing fix-verification request across browser, terminal/TUI, or desktop GUI, immediately spawn subagentType='ui-qa' even for a single track and before inspecting files or checking prerequisites. The ui-qa sub-agent must discover the actual target/control path and report missing prerequisites; do not preflight, perform, or substitute requested UI QA in the parent agent. " +
|
|
88
|
+
"Give ui-qa a concise acceptance brief: the known target URL/app/command, user-visible flow, expected observable result, and required artifacts. Do not prescribe repository files, searches, commands, server setup, or mock/synthetic substitutes; unknown setup belongs to the QA sub-agent's discovery. " +
|
|
88
89
|
"For other work, use subagents action='spawn' for economical execution or context isolation, including one bounded sequential task or explicit delegate/parallelize/split work requests. " +
|
|
89
90
|
SUBAGENT_TYPE_SELECTION_GUIDANCE + " Avoid trivial reads/edits and do not call status/wait immediately after spawn just for progress. " +
|
|
90
91
|
(repoDiscovery
|
|
91
92
|
? "For one semantic code-discovery question, use repo_search; for independent tracks/hypotheses/review axes, delegate even when repo_* tools exist. Read result only after completion when findings are needed."
|
|
92
93
|
: "For one focused code-discovery question, use direct read/grep. Without repo_* tools, delegate bounded research tracks for broad discovery rather than flooding parent context. Read result only after completion when findings are needed."),
|
|
93
94
|
promptGuidelines: [
|
|
94
|
-
"Treat every real
|
|
95
|
-
"Keep the
|
|
96
|
-
"When
|
|
97
|
-
"After
|
|
95
|
+
"Treat every real UI QA request as a mandatory delegation trigger and an explicit exception to the large/parallel threshold: immediately spawn with `subagentType: \"ui-qa\"` before checking prerequisites. The QA sub-agent owns target discovery, feasibility checks, UI automation, evidence, and blocked reports; the parent must not inspect the project first or substitute non-UI checks.",
|
|
96
|
+
"Keep the ui-qa task payload at the user-visible acceptance level: known target URL/app/command, actions to perform, expected observable outcome, and requested evidence. Do not turn it into a repository investigation plan, name internal files or commands, dictate setup, or invent a mock/synthetic target. Leave unknown prerequisites to the QA sub-agent.",
|
|
97
|
+
"When ui-qa browser testing reports missing credentials, relay its explicit request and generated `.pi/qa_auth.jsonc` template path; never inspect, populate, or edit that credential file in the parent.",
|
|
98
|
+
"After ui-qa completes a test, preserve its clickable screenshot, terminal capture, video, trace, and other evidence links in the final user-facing response whenever those artifacts exist.",
|
|
98
99
|
SUBAGENT_DELEGATION_GUIDANCE,
|
|
99
100
|
repoDiscovery
|
|
100
101
|
? "For one discovery question, use repo_search; spawn for independent tracks/hypotheses/review axes, and do not let repo_* availability suppress delegation."
|
|
@@ -222,7 +223,24 @@ export const REPO_DISCOVERY_TOOLS: RepoDiscoveryToolDescription[] = [
|
|
|
222
223
|
},
|
|
223
224
|
];
|
|
224
225
|
|
|
225
|
-
export const
|
|
226
|
+
export const REPO_KNOWLEDGE_TOOL_DESCRIPTION: RepoKnowledgeToolDescription = {
|
|
227
|
+
name: "repo_knowledge",
|
|
228
|
+
label: "Repo Knowledge",
|
|
229
|
+
description:
|
|
230
|
+
"Project behavioral knowledge/spec maintenance backed by idx. Query contracts with context/search/show/status, review task-scoped impact after material behavior changes, discover new/moved docs, and explicitly record/relate/verify metadata only after semantic evidence review. This tool is exposed only when idx is available and the project is indexed.",
|
|
231
|
+
promptSnippet:
|
|
232
|
+
"Use repo_knowledge for project behavior/contracts and their maintenance. For a behavior/contract question that also needs implementation/tests/freshness, prefer action=context; use action=search when only the relevant specs/contracts are needed. Before a material behavior change, find the current primary contract; after implementation, run action=impact on this task's changed paths. Update the existing spec, or create a focused new spec with Edit/Write/apply_patch when no suitable contract exists, then record/relate and verify only after checking code/tests. Skip this lifecycle for mechanical/non-behavioral edits.",
|
|
233
|
+
promptGuidelines: [
|
|
234
|
+
"Primary specs/contracts are authoritative; catalog/search summaries, embeddings, graph proximity and semantic candidates are routing evidence only. record is classification, not verification; non-fresh status requires review before presenting behavior as current.",
|
|
235
|
+
"For material externally visible or project-contract behavior changes: query existing knowledge before/while implementing, keep the authoritative spec aligned in the same task, create a focused primary spec when no suitable contract exists, then run task-scoped impact and reconcile uncovered/new/moved docs before finishing.",
|
|
236
|
+
"Never persist a relation from similarity alone and never add one just to make coverage non-empty. A reviewed no-impact outcome is valid. verify only after reading the primary source and checking relevant implementation/tests; changed code never auto-rewrites spec semantics.",
|
|
237
|
+
],
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
export const REPO_DISCOVERY_TOOL_NAMES = [
|
|
241
|
+
...REPO_DISCOVERY_TOOLS.map((tool) => tool.name),
|
|
242
|
+
REPO_KNOWLEDGE_TOOL_DESCRIPTION.name,
|
|
243
|
+
];
|
|
226
244
|
|
|
227
245
|
export const TODO_TOOL_DESCRIPTION: ToolDescription = {
|
|
228
246
|
name: "todo",
|
|
@@ -333,12 +351,16 @@ export function claudeAliasToolDescriptions(options: ToolDescriptionSetOptions |
|
|
|
333
351
|
Edit: {
|
|
334
352
|
name: "Edit",
|
|
335
353
|
label: "Edit",
|
|
336
|
-
description:
|
|
354
|
+
description: repoDiscovery
|
|
355
|
+
? "Replace exact text in an existing file. Use for surgical edits; use Write only for whole-file replacement. After a material behavior change, do not finish until repo_knowledge impact reviews this task's changed paths and the authoritative spec is updated or created and verified; skip that lifecycle for mechanical/non-behavioral edits."
|
|
356
|
+
: "Replace exact text in an existing file. Use for surgical edits; use Write only for intentional whole-file replacement.",
|
|
337
357
|
},
|
|
338
358
|
Write: {
|
|
339
359
|
name: "Write",
|
|
340
360
|
label: "Write",
|
|
341
|
-
description:
|
|
361
|
+
description: repoDiscovery
|
|
362
|
+
? "Create or overwrite a file with complete contents. Use only for intentional whole-file writes. When creating/changing material project behavior, keep or create the primary spec in the same task and finish with task-scoped repo_knowledge impact + semantic verification; mechanical/non-behavioral writes do not require it."
|
|
363
|
+
: "Create or overwrite a file with complete contents. Use only when replacing the whole file is intended.",
|
|
342
364
|
},
|
|
343
365
|
Bash: {
|
|
344
366
|
name: "Bash",
|
|
@@ -365,7 +387,9 @@ export function claudeAliasToolDescriptions(options: ToolDescriptionSetOptions |
|
|
|
365
387
|
export const CLAUDE_ALIAS_TOOL_DESCRIPTIONS = claudeAliasToolDescriptions(false);
|
|
366
388
|
export const CLAUDE_ALIAS_TOOL_DESCRIPTIONS_WITH_REPO = claudeAliasToolDescriptions(true);
|
|
367
389
|
|
|
368
|
-
export
|
|
390
|
+
export function codexAliasToolDescriptions(options: ToolDescriptionSetOptions | boolean = false) {
|
|
391
|
+
const repoDiscovery = hasRepoDiscovery(options);
|
|
392
|
+
return {
|
|
369
393
|
shellCommand: {
|
|
370
394
|
name: "shell",
|
|
371
395
|
label: "shell",
|
|
@@ -374,7 +398,7 @@ export const CODEX_ALIAS_TOOL_DESCRIPTIONS = {
|
|
|
374
398
|
applyPatch: {
|
|
375
399
|
name: "apply_patch",
|
|
376
400
|
label: "apply_patch",
|
|
377
|
-
description: `Apply file edits with a relative-path patch or standard unified diff. Use for creating, updating, moving, or deleting files; keep each patch focused.
|
|
401
|
+
description: `Apply file edits with a relative-path patch or standard unified diff. Use for creating, updating, moving, or deleting files; keep each patch focused.${repoDiscovery ? " After a material behavior change, keep/create the authoritative primary spec in the same task and finish with task-scoped repo_knowledge impact plus semantic verification; skip this for mechanical/non-behavioral edits." : ""}
|
|
378
402
|
|
|
379
403
|
Begin-patch format:
|
|
380
404
|
*** Begin Patch
|
|
@@ -388,4 +412,8 @@ Sections: *** Add File (new lines start with +), *** Update File (optionally ***
|
|
|
388
412
|
|
|
389
413
|
Unified diff with ---/+++ headers is also supported. Paths must be workspace-relative, never absolute. Provide the complete patch in input.`,
|
|
390
414
|
},
|
|
391
|
-
} satisfies Record<string, ToolDescription>;
|
|
415
|
+
} satisfies Record<string, ToolDescription>;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
export const CODEX_ALIAS_TOOL_DESCRIPTIONS = codexAliasToolDescriptions(false);
|
|
419
|
+
export const CODEX_ALIAS_TOOL_DESCRIPTIONS_WITH_REPO = codexAliasToolDescriptions(true);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-ui-extend",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.45",
|
|
4
4
|
"description": "Pix: a workspace-first terminal UI for Pi with tabs, readable tool activity, voice input, and bundled agent tools.",
|
|
5
5
|
"private": false,
|
|
6
6
|
"repository": {
|
|
@@ -26,7 +26,8 @@
|
|
|
26
26
|
"import": "./dist/sdk.js"
|
|
27
27
|
},
|
|
28
28
|
"./schemas/pix.json": "./schemas/pix.json",
|
|
29
|
-
"./schemas/pi-tools-suite.json": "./schemas/pi-tools-suite.json"
|
|
29
|
+
"./schemas/pi-tools-suite.json": "./schemas/pi-tools-suite.json",
|
|
30
|
+
"./schemas/tasks.json": "./schemas/tasks.json"
|
|
30
31
|
},
|
|
31
32
|
"files": [
|
|
32
33
|
"assets/screenshots",
|
|
@@ -54,6 +55,7 @@
|
|
|
54
55
|
"prelink:pix": "npm run build:pix --silent",
|
|
55
56
|
"link:pix": "mise exec node@24.16.0 -- npm link --silent",
|
|
56
57
|
"watch:pix": "npm run link:pix --silent && mise exec node@24.16.0 -- node scripts/watch-pix.mjs",
|
|
58
|
+
"watch:all": "mise exec node@24.16.0 -- node scripts/watch-all.mjs",
|
|
57
59
|
"rebuild:all": "npm run build:desktop",
|
|
58
60
|
"check": "mise exec node@24.16.0 -- npm run check:inner",
|
|
59
61
|
"precheck:inner": "npm run generate-schemas --silent",
|
|
@@ -61,6 +63,8 @@
|
|
|
61
63
|
"test": "mise exec node@24.16.0 -- npm run test:inner",
|
|
62
64
|
"test:inner": "node --import tsx --test \"tests/**/*.test.ts\"",
|
|
63
65
|
"test:tools-suite": "npm --prefix external/pi-tools-suite test",
|
|
66
|
+
"test:dcp-session-sim": "npm --prefix external/pi-tools-suite run test:dcp-session-sim",
|
|
67
|
+
"test:dcp-reminder-e2e": "npm --prefix external/pi-tools-suite run test:dcp-reminder-e2e",
|
|
64
68
|
"build:acp": "npm --prefix acp run build",
|
|
65
69
|
"check:acp": "npm --prefix acp run check",
|
|
66
70
|
"dev:desktop": "npm --prefix desktop run dev",
|
|
@@ -76,6 +80,7 @@
|
|
|
76
80
|
"prepack": "npm run generate-schemas --silent",
|
|
77
81
|
"pack:dry-run": "npm pack --dry-run",
|
|
78
82
|
"smoke-test": "mise exec node@24.16.0 -- bash scripts/smoke-test-package.sh",
|
|
83
|
+
"smoke-test:cli": "mise exec node@24.16.0 -- node scripts/smoke-test-package-cli.mjs",
|
|
79
84
|
"release:check": "npm run check && npm run build:pix && npm run pack:dry-run",
|
|
80
85
|
"publish-npm": "bash scripts/publish.sh",
|
|
81
86
|
"generate-schemas": "tsx scripts/generate-schemas.ts",
|
|
@@ -84,10 +89,13 @@
|
|
|
84
89
|
"prepublishOnly": "npm run check && npm run build:pix && npm run generate-schemas"
|
|
85
90
|
},
|
|
86
91
|
"dependencies": {
|
|
92
|
+
"@cortexkit/antigravity-auth-core": "2.2.1",
|
|
87
93
|
"@earendil-works/pi-ai": "0.85.1",
|
|
88
94
|
"@earendil-works/pi-coding-agent": "0.85.1",
|
|
89
95
|
"@earendil-works/pi-tui": "0.85.1",
|
|
96
|
+
"@lydell/node-pty": "1.1.0",
|
|
90
97
|
"@mariozechner/clipboard": "^0.3.9",
|
|
98
|
+
"@xterm/headless": "^6.0.0",
|
|
91
99
|
"grok-mermaid": "0.2.2",
|
|
92
100
|
"jsonc-parser": "3.3.1",
|
|
93
101
|
"typebox": "1.1.38",
|
|
@@ -103,13 +111,6 @@
|
|
|
103
111
|
"engines": {
|
|
104
112
|
"node": ">=22.19.0 <25"
|
|
105
113
|
},
|
|
106
|
-
"overrides": {
|
|
107
|
-
"get-uv-event-loop-napi-h": "1.0.6",
|
|
108
|
-
"node-addon-api": "8.8.0"
|
|
109
|
-
},
|
|
110
|
-
"optionalDependencies": {
|
|
111
|
-
"vosk": "0.3.39"
|
|
112
|
-
},
|
|
113
114
|
"keywords": [
|
|
114
115
|
"pi",
|
|
115
116
|
"pix",
|