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
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
getRunState,
|
|
8
8
|
getRunRoot,
|
|
9
9
|
getSubagentRegistryPath,
|
|
10
|
+
filterSubagentConfigForParentModel,
|
|
10
11
|
isBlindModelRef,
|
|
11
12
|
loadSubagentConfig,
|
|
12
13
|
listSubagentSessionRecords,
|
|
@@ -14,9 +15,11 @@ import {
|
|
|
14
15
|
removeSubagentRunsFromRegistry,
|
|
15
16
|
stopAgents,
|
|
16
17
|
type AgentCompletionHandler,
|
|
18
|
+
type RpcEventRecord,
|
|
17
19
|
type StopSignal,
|
|
18
20
|
type SubagentSessionRecord,
|
|
19
21
|
} from "./lib.js";
|
|
22
|
+
import { activityFromRpcEvent } from "./core/activity.js";
|
|
20
23
|
import { buildUltraworkPrompt, isUltraworkEnvEnabled, registerCommands } from "./commands.js";
|
|
21
24
|
import { agentStrategyPrompt, appendAgentStrategyPrompt } from "./core/agent-strategy.js";
|
|
22
25
|
import { buildSubagentCatalogPrompt } from "./core/agent-catalog.js";
|
|
@@ -41,6 +44,7 @@ function isTerminalAgentStatus(status: AgentState["status"]): boolean {
|
|
|
41
44
|
|
|
42
45
|
const SUBAGENTS_LIVE_COUNT_EVENT = "pi-tools-suite:async-subagents:live-count";
|
|
43
46
|
const SUBAGENTS_LIVE_STATE_EVENT = "pi-tools-suite:async-subagents:live-state";
|
|
47
|
+
export const SUBAGENTS_CATALOG_STATE_EVENT = "pi-tools-suite:async-subagents:catalog";
|
|
44
48
|
const SESSION_SHUTDOWN_KILL_GRACE_MS = 500;
|
|
45
49
|
const COMPLETION_WATCH_INTERVAL_MS = 2_000;
|
|
46
50
|
|
|
@@ -54,6 +58,14 @@ interface ShutdownPlan {
|
|
|
54
58
|
runDirsToDelete: string[];
|
|
55
59
|
}
|
|
56
60
|
|
|
61
|
+
interface SubagentCatalogStateEvent {
|
|
62
|
+
version: 1;
|
|
63
|
+
sessionId?: string;
|
|
64
|
+
sessionFile?: string;
|
|
65
|
+
model?: string;
|
|
66
|
+
types: string[];
|
|
67
|
+
}
|
|
68
|
+
|
|
57
69
|
function createLiveStatePayload(
|
|
58
70
|
liveAgents: Map<string, Map<string, LiveAgent>>,
|
|
59
71
|
sessionFile: string | undefined,
|
|
@@ -65,7 +77,13 @@ function createLiveStatePayload(
|
|
|
65
77
|
if (matchingLiveAgents.length === 0) continue;
|
|
66
78
|
const agentIds = matchingLiveAgents.map((agent) => agent.agentId);
|
|
67
79
|
const state = getRunState(runDir, agentIds, { includeLineCounts: false, checkRpcPromptFailure: false });
|
|
68
|
-
const
|
|
80
|
+
const liveAgentsById = new Map(matchingLiveAgents.map((agent) => [agent.agentId, agent]));
|
|
81
|
+
const activeAgents = state.agents
|
|
82
|
+
.filter((agent) => !isTerminalAgentStatus(agent.status))
|
|
83
|
+
.map((agent) => {
|
|
84
|
+
const lastActivity = liveAgentsById.get(agent.id)?.lastActivity;
|
|
85
|
+
return lastActivity ? { ...agent, lastActivity } : agent;
|
|
86
|
+
});
|
|
69
87
|
if (activeAgents.length === 0) continue;
|
|
70
88
|
count += activeAgents.length;
|
|
71
89
|
const tasks = matchingLiveAgents.map((agent) => agent.preview).filter((preview): preview is NonNullable<typeof preview> => Boolean(preview));
|
|
@@ -84,6 +102,25 @@ function createLiveStatePayload(
|
|
|
84
102
|
};
|
|
85
103
|
}
|
|
86
104
|
|
|
105
|
+
function createSubagentCatalogState(ctx: unknown): SubagentCatalogStateEvent {
|
|
106
|
+
const cwd = (ctx as { cwd?: string } | undefined)?.cwd ?? process.cwd();
|
|
107
|
+
const model = modelRefFromContext(ctx);
|
|
108
|
+
const config = safeLoadSubagentConfig(cwd);
|
|
109
|
+
const effective = config ? filterSubagentConfigForParentModel(config, model) : undefined;
|
|
110
|
+
const sessionManager = (ctx as {
|
|
111
|
+
sessionManager?: { getSessionId?: () => string; getSessionFile?: () => string | undefined };
|
|
112
|
+
} | undefined)?.sessionManager;
|
|
113
|
+
const sessionId = typeof sessionManager?.getSessionId === "function" ? sessionManager.getSessionId() : undefined;
|
|
114
|
+
const sessionFile = typeof sessionManager?.getSessionFile === "function" ? sessionManager.getSessionFile() : undefined;
|
|
115
|
+
return {
|
|
116
|
+
version: 1,
|
|
117
|
+
...(sessionId ? { sessionId } : {}),
|
|
118
|
+
...(sessionFile ? { sessionFile } : {}),
|
|
119
|
+
...(model ? { model } : {}),
|
|
120
|
+
types: Object.keys(effective?.types ?? {}).sort(),
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
87
124
|
function agentMatchesSession(agent: LiveAgent, sessionFile: string | undefined): boolean {
|
|
88
125
|
if (!sessionFile) return true;
|
|
89
126
|
return agent.parentSession !== undefined && pathsEqual(sessionFile, agent.parentSession);
|
|
@@ -106,6 +143,12 @@ export default function (pi: ExtensionAPI) {
|
|
|
106
143
|
let completionWatchTimer: ReturnType<typeof setInterval> | undefined;
|
|
107
144
|
publishSubagentPresetsStartupSection();
|
|
108
145
|
|
|
146
|
+
function publishSubagentCatalogState(ctx: unknown): void {
|
|
147
|
+
const state = createSubagentCatalogState(ctx);
|
|
148
|
+
pi.events?.emit?.(SUBAGENTS_CATALOG_STATE_EVENT, state);
|
|
149
|
+
publishRpcSessionState(ctx as Parameters<typeof publishRpcSessionState>[0], SUBAGENTS_CATALOG_STATE_EVENT, state);
|
|
150
|
+
}
|
|
151
|
+
|
|
109
152
|
function refreshSubagentOverlay(): void {
|
|
110
153
|
try {
|
|
111
154
|
reconcileLiveAgentCompletions();
|
|
@@ -165,7 +208,16 @@ export default function (pi: ExtensionAPI) {
|
|
|
165
208
|
refreshSubagentOverlay();
|
|
166
209
|
};
|
|
167
210
|
|
|
168
|
-
|
|
211
|
+
function handleAgentRpcEvent(runDir: string, agentId: string, event: RpcEventRecord): void {
|
|
212
|
+
const activity = activityFromRpcEvent(event);
|
|
213
|
+
if (!activity) return;
|
|
214
|
+
const liveAgent = liveAgents.get(runDir)?.get(agentId);
|
|
215
|
+
if (!liveAgent) return;
|
|
216
|
+
liveAgent.lastActivity = activity;
|
|
217
|
+
refreshSubagentOverlay();
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
registerSubagentsTool(pi, liveAgents, handleAgentCompletion, refreshSubagentOverlay, handleAgentRpcEvent);
|
|
169
221
|
registerCommands(pi);
|
|
170
222
|
|
|
171
223
|
pi.on("session_start", async (_event, ctx) => {
|
|
@@ -173,6 +225,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
173
225
|
sawAutoUltraworkCandidate = false;
|
|
174
226
|
currentSessionFile = sessionFileFromContext(ctx);
|
|
175
227
|
currentSessionStateContext = ctx;
|
|
228
|
+
publishSubagentCatalogState(ctx);
|
|
176
229
|
subagentOverlay.restoreRunningAgents(ctx.cwd, currentSessionFile);
|
|
177
230
|
refreshSubagentOverlay();
|
|
178
231
|
} catch (error) {
|
|
@@ -180,6 +233,14 @@ export default function (pi: ExtensionAPI) {
|
|
|
180
233
|
}
|
|
181
234
|
});
|
|
182
235
|
|
|
236
|
+
pi.on("model_select", (_event, ctx) => {
|
|
237
|
+
try {
|
|
238
|
+
publishSubagentCatalogState(ctx);
|
|
239
|
+
} catch (error) {
|
|
240
|
+
ignoreStaleExtensionContextError(error);
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
|
|
183
244
|
pi.on("tool_execution_end", async (event) => {
|
|
184
245
|
if (event.toolName !== "subagents" && !event.toolName.startsWith("async_subagents_")) return;
|
|
185
246
|
refreshSubagentOverlay();
|
|
@@ -192,7 +253,10 @@ export default function (pi: ExtensionAPI) {
|
|
|
192
253
|
});
|
|
193
254
|
const visionPrompt = visionCapabilityPrompt(event, ctx);
|
|
194
255
|
const catalogPrompt = selectedToolsInclude(event, "subagents")
|
|
195
|
-
? subagentCatalogPrompt(
|
|
256
|
+
? subagentCatalogPrompt(
|
|
257
|
+
(ctx as { cwd?: string } | undefined)?.cwd ?? process.cwd(),
|
|
258
|
+
modelRefFromContext(ctx),
|
|
259
|
+
)
|
|
196
260
|
: undefined;
|
|
197
261
|
if (!strategyPrompt && !visionPrompt && !catalogPrompt) return undefined;
|
|
198
262
|
let systemPrompt = event.systemPrompt ?? "";
|
|
@@ -286,9 +350,9 @@ function safeLoadSubagentConfig(cwd: string) {
|
|
|
286
350
|
}
|
|
287
351
|
}
|
|
288
352
|
|
|
289
|
-
function subagentCatalogPrompt(cwd: string): string | undefined {
|
|
353
|
+
function subagentCatalogPrompt(cwd: string, parentModelRef?: string): string | undefined {
|
|
290
354
|
const config = safeLoadSubagentConfig(cwd);
|
|
291
|
-
return config ? buildSubagentCatalogPrompt(config) : undefined;
|
|
355
|
+
return config ? buildSubagentCatalogPrompt(config, parentModelRef) : undefined;
|
|
292
356
|
}
|
|
293
357
|
|
|
294
358
|
function startupSubagentPresetList(cwd = process.cwd()): string {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export type {
|
|
2
|
+
AgentActivity,
|
|
2
3
|
AgentCompletionHandler,
|
|
3
4
|
AgentResult,
|
|
4
5
|
AgentState,
|
|
@@ -12,21 +13,19 @@ export type {
|
|
|
12
13
|
} from "./core/types.js";
|
|
13
14
|
|
|
14
15
|
export { createRunDir, getRunRoot, hasAgentPrompt, hasLaunchedAgentPrompt, hasQueuedAgentPrompt, resolveRunDir, validateBasename } from "./core/paths.js";
|
|
15
|
-
export type {
|
|
16
|
+
export type { ModelByParentEntry, ResolvedAgentTaskConfig, ResolvedSubagentRoutingConfig, ResolveAgentTaskOptions, SubagentConfig, SubagentPreset, SubagentRoutingConfig, SubagentTypeConfig, SubagentVisionConfig } from "./core/config.js";
|
|
16
17
|
export {
|
|
17
|
-
configFiles,
|
|
18
|
-
copySubagentConfigSample,
|
|
19
18
|
currentModelRef,
|
|
20
19
|
defaultSubagentType,
|
|
21
20
|
DEFAULT_MAX_CONCURRENT,
|
|
22
21
|
DEFAULT_RETRY_CONFIG,
|
|
23
22
|
DEFAULT_ROUTING_CONFIG,
|
|
24
|
-
|
|
25
|
-
getDefaultSubagentConfigPath,
|
|
23
|
+
filterSubagentConfigForParentModel,
|
|
26
24
|
getBuiltinSubagentDefinitionsDir,
|
|
27
|
-
|
|
28
|
-
|
|
25
|
+
getBuiltinSubagentPresetsPath,
|
|
26
|
+
getProjectSubagentPresetsPath,
|
|
29
27
|
isBlindModelRef,
|
|
28
|
+
isSubagentTypeAvailableForParent,
|
|
30
29
|
loadSubagentConfig,
|
|
31
30
|
resolveAgentTaskConfig,
|
|
32
31
|
resolveRetryConfig,
|
|
@@ -35,9 +34,17 @@ export {
|
|
|
35
34
|
shouldForceCurrentSubagentModel,
|
|
36
35
|
} from "./core/config.js";
|
|
37
36
|
export { routeSubagentTasks, SubagentRoutingError } from "./core/routing.js";
|
|
38
|
-
export {
|
|
37
|
+
export {
|
|
38
|
+
BROWSER_QA_RUNNER_ENV,
|
|
39
|
+
UI_QA_RUNNER_ENV,
|
|
40
|
+
LEGACY_BROWSER_QA_TYPE,
|
|
41
|
+
UI_QA_TYPE,
|
|
42
|
+
getBrowserQaRunnerPath,
|
|
43
|
+
getUiQaRunnerPath,
|
|
44
|
+
isUiQaType,
|
|
45
|
+
} from "./core/browser-qa.js";
|
|
39
46
|
export type { RoutedSubagentTasks, SubagentRoutingContext } from "./core/routing.js";
|
|
40
|
-
export { agentDefinitionFiles, agentNameFromFilename, parseAgentMarkdown, projectAgentDefinitionFiles, readAgentDefinitionsFromDir, readProjectAgentDefinitions } from "./core/agents-dir.js";
|
|
47
|
+
export { agentDefinitionFiles, agentNameFromFilename, parseAgentMarkdown, projectAgentDefinitionFiles, projectAgentsDir, readAgentDefinitionsFromDir, readProjectAgentDefinitions } from "./core/agents-dir.js";
|
|
41
48
|
export type { AgentDefinition, ProjectAgentDefinition } from "./core/agents-dir.js";
|
|
42
49
|
export { buildSubagentCatalogPrompt } from "./core/agent-catalog.js";
|
|
43
50
|
export type { SubagentPresetSelectionState } from "./core/presets.js";
|
|
@@ -7,7 +7,7 @@ import { ASYNC_SUBAGENT_TOOL_DESCRIPTIONS } from "../../tool-descriptions.js";
|
|
|
7
7
|
import { SUBAGENT_TYPE_SELECTION_GUIDANCE } from "../core/agent-catalog.js";
|
|
8
8
|
import { selectAvailableAgentModels } from "../core/model-selection.js";
|
|
9
9
|
import { SubagentModelSelectionError } from "../core/config.js";
|
|
10
|
-
import type { AgentCompletionHandler, AgentTask, ResolvedAgentTaskConfig, Semaphore, SpawnedAgent } from "../lib.js";
|
|
10
|
+
import type { AgentCompletionHandler, AgentTask, ResolvedAgentTaskConfig, RpcEventRecord, Semaphore, SpawnedAgent } from "../lib.js";
|
|
11
11
|
import {
|
|
12
12
|
createRunDir,
|
|
13
13
|
createSemaphore,
|
|
@@ -52,6 +52,7 @@ interface LaunchQueuedAgentOptions {
|
|
|
52
52
|
onCancelled: (reason: string) => void;
|
|
53
53
|
onLaunchError: (error: unknown) => void;
|
|
54
54
|
onUpdate: () => void;
|
|
55
|
+
onRpcEvent?: (event: RpcEventRecord) => void;
|
|
55
56
|
}
|
|
56
57
|
|
|
57
58
|
const PROJECT_SEMAPHORES = new Map<string, Semaphore>();
|
|
@@ -71,7 +72,7 @@ function normalizedLimit(limit: number): number {
|
|
|
71
72
|
}
|
|
72
73
|
|
|
73
74
|
async function launchQueuedAgent(options: LaunchQueuedAgentOptions): Promise<void> {
|
|
74
|
-
const { resolved, runDir, cwd, parentSession, semaphore, signal, onResult, onComplete, onCancelled, onLaunchError, onUpdate } = options;
|
|
75
|
+
const { resolved, runDir, cwd, parentSession, semaphore, signal, onResult, onComplete, onCancelled, onLaunchError, onUpdate, onRpcEvent } = options;
|
|
75
76
|
let slotAcquired = false;
|
|
76
77
|
try {
|
|
77
78
|
await semaphore.acquire(signal);
|
|
@@ -98,7 +99,6 @@ async function launchQueuedAgent(options: LaunchQueuedAgentOptions): Promise<voi
|
|
|
98
99
|
parentSession,
|
|
99
100
|
maxResultBytes: resolved.maxResultBytes,
|
|
100
101
|
timeoutMs: resolved.timeoutMs,
|
|
101
|
-
isolatedSkills: resolved.isolatedSkills,
|
|
102
102
|
};
|
|
103
103
|
if (resolved.retry.maxRetries > 0 || resolved.fallbackModels.length > 0) {
|
|
104
104
|
const retryResult = spawnAgentWithRetry(
|
|
@@ -111,13 +111,14 @@ async function launchQueuedAgent(options: LaunchQueuedAgentOptions): Promise<voi
|
|
|
111
111
|
extraArgs: resolved.extraArgs,
|
|
112
112
|
fallbackModels: resolved.fallbackModels,
|
|
113
113
|
signal,
|
|
114
|
+
onRpcEvent,
|
|
114
115
|
...spawnOptions,
|
|
115
116
|
},
|
|
116
117
|
);
|
|
117
118
|
onResult(retryResult.initial);
|
|
118
119
|
retryResult.done.catch(onLaunchError);
|
|
119
120
|
} else {
|
|
120
|
-
const result = spawnAgent(runDir, resolved.task, cwd, resolved.extraArgs,
|
|
121
|
+
const result = spawnAgent(runDir, resolved.task, cwd, resolved.extraArgs, onRpcEvent, completionHandler, spawnOptions);
|
|
121
122
|
onResult(result);
|
|
122
123
|
}
|
|
123
124
|
onUpdate();
|
|
@@ -195,6 +196,7 @@ export function registerSpawnTool(
|
|
|
195
196
|
liveAgents: Map<string, Map<string, LiveAgent>>,
|
|
196
197
|
handleAgentCompletion: AgentCompletionHandler,
|
|
197
198
|
onLiveAgentsChange?: () => void,
|
|
199
|
+
onAgentRpcEvent?: (runDir: string, agentId: string, event: RpcEventRecord) => void,
|
|
198
200
|
): void {
|
|
199
201
|
pi.registerTool({
|
|
200
202
|
...ASYNC_SUBAGENT_TOOL_DESCRIPTIONS.spawnAction,
|
|
@@ -226,7 +228,7 @@ export function registerSpawnTool(
|
|
|
226
228
|
const activePreset = activePresetName ? config.presets?.[activePresetName] : undefined;
|
|
227
229
|
if (getSessionSubagentPresetOverride() && !activePreset) {
|
|
228
230
|
return {
|
|
229
|
-
content: [{ type: "text", text: `AGENTS_PRESET=${activePresetName} does not match any
|
|
231
|
+
content: [{ type: "text", text: `AGENTS_PRESET=${activePresetName} does not match any available sub-agent preset.` }],
|
|
230
232
|
details: {},
|
|
231
233
|
isError: true,
|
|
232
234
|
};
|
|
@@ -342,6 +344,7 @@ export function registerSpawnTool(
|
|
|
342
344
|
details: partialDetails,
|
|
343
345
|
});
|
|
344
346
|
},
|
|
347
|
+
onRpcEvent: (event) => onAgentRpcEvent?.(runDir, task.id, event),
|
|
345
348
|
});
|
|
346
349
|
}
|
|
347
350
|
|
|
@@ -3,8 +3,8 @@ import { Type } from "@earendil-works/pi-ai";
|
|
|
3
3
|
import { Text } from "@earendil-works/pi-tui";
|
|
4
4
|
import { asyncSubagentToolDescriptions } from "../../tool-descriptions.js";
|
|
5
5
|
import { SUBAGENT_TYPE_SELECTION_GUIDANCE } from "../core/agent-catalog.js";
|
|
6
|
-
import {
|
|
7
|
-
import type { AgentCompletionHandler } from "../lib.js";
|
|
6
|
+
import { hasAvailableIndexedProjectRoot } from "../../lib/project.js";
|
|
7
|
+
import type { AgentCompletionHandler, RpcEventRecord } from "../lib.js";
|
|
8
8
|
import { DEFAULT_SPAWN_WATCH_SECONDS, INLINE_RENDERING } from "../constants.js";
|
|
9
9
|
import { renderSubagentSpawnPrompts } from "../render.js";
|
|
10
10
|
import { emptyToolSlot } from "../ui.js";
|
|
@@ -73,10 +73,11 @@ export function registerSubagentsTool(
|
|
|
73
73
|
liveAgents: Map<string, Map<string, LiveAgent>>,
|
|
74
74
|
handleAgentCompletion: AgentCompletionHandler,
|
|
75
75
|
onLiveAgentsChange?: () => void,
|
|
76
|
+
onAgentRpcEvent?: (runDir: string, agentId: string, event: RpcEventRecord) => void,
|
|
76
77
|
): void {
|
|
77
|
-
const toolDescriptions = asyncSubagentToolDescriptions(
|
|
78
|
+
const toolDescriptions = asyncSubagentToolDescriptions(hasAvailableIndexedProjectRoot());
|
|
78
79
|
const collector = new ToolCollector();
|
|
79
|
-
registerSpawnTool(collector as any, liveAgents, handleAgentCompletion, onLiveAgentsChange);
|
|
80
|
+
registerSpawnTool(collector as any, liveAgents, handleAgentCompletion, onLiveAgentsChange, onAgentRpcEvent);
|
|
80
81
|
registerStatusTool(collector as any);
|
|
81
82
|
registerStopTool(collector as any, liveAgents, onLiveAgentsChange);
|
|
82
83
|
registerWaitTool(collector as any);
|
|
@@ -22,6 +22,11 @@ type LookupDetails = {
|
|
|
22
22
|
contextChars: number;
|
|
23
23
|
stopReason?: string;
|
|
24
24
|
error?: string;
|
|
25
|
+
attempts?: Array<{
|
|
26
|
+
ref: string;
|
|
27
|
+
outcome: "ok" | "unavailable" | "error" | "empty";
|
|
28
|
+
error?: string;
|
|
29
|
+
}>;
|
|
25
30
|
};
|
|
26
31
|
|
|
27
32
|
type ResolvedLookupModel = {
|
|
@@ -473,8 +478,9 @@ function createLookupTool() {
|
|
|
473
478
|
executionMode: "sequential" as const,
|
|
474
479
|
async execute(_toolCallId: string, params: LookupParams, signal: AbortSignal | undefined, _onUpdate: unknown, ctx: unknown) {
|
|
475
480
|
const cwd = contextCwd(ctx) ?? process.cwd();
|
|
476
|
-
const
|
|
477
|
-
|
|
481
|
+
const lookupModelRefs = lookupModelRefsFromConfig(cwd);
|
|
482
|
+
const primaryLookupModelRef = lookupModelRefs[0];
|
|
483
|
+
if (!primaryLookupModelRef) {
|
|
478
484
|
return lookupToolTextResult("lookupModel is not configured in pi-tools-suite config; lookup is disabled.", {
|
|
479
485
|
model: "",
|
|
480
486
|
imageCount: 0,
|
|
@@ -484,69 +490,86 @@ function createLookupTool() {
|
|
|
484
490
|
});
|
|
485
491
|
}
|
|
486
492
|
|
|
487
|
-
const resolved = await resolveLookupModel(ctx, lookupModelRef);
|
|
488
|
-
if (!resolved) {
|
|
489
|
-
return lookupToolTextResult(`Lookup model is unavailable or unauthenticated: ${lookupModelRef}`, {
|
|
490
|
-
model: lookupModelRef,
|
|
491
|
-
imageCount: 0,
|
|
492
|
-
imagePathCount: params.imagePaths?.length ?? 0,
|
|
493
|
-
contextChars: 0,
|
|
494
|
-
error: "lookup model unavailable",
|
|
495
|
-
});
|
|
496
|
-
}
|
|
497
|
-
|
|
498
493
|
const recentContext = buildRecentSessionContext(ctx, DEFAULT_LOOKUP_MAX_CONTEXT_CHARS);
|
|
499
494
|
const sessionImages = extractRecentSessionImages(ctx, DEFAULT_LOOKUP_MAX_IMAGES);
|
|
500
495
|
const pathImages = readImagePathContents(cwd, params.imagePaths ?? [], Math.max(0, DEFAULT_LOOKUP_MAX_IMAGES - sessionImages.length));
|
|
501
496
|
const images = [...sessionImages, ...pathImages.images].slice(0, DEFAULT_LOOKUP_MAX_IMAGES);
|
|
502
497
|
const promptText = buildLookupPrompt(params, recentContext, images.length, pathImages.warnings);
|
|
498
|
+
const attempts: NonNullable<LookupDetails["attempts"]> = [];
|
|
499
|
+
|
|
500
|
+
for (const lookupModelRef of lookupModelRefs) {
|
|
501
|
+
if (signal?.aborted) throw signal.reason ?? new Error("Lookup aborted");
|
|
502
|
+
let resolved: ResolvedLookupModel | undefined;
|
|
503
|
+
try {
|
|
504
|
+
resolved = await resolveLookupModel(ctx, lookupModelRef);
|
|
505
|
+
} catch (error) {
|
|
506
|
+
if (signal?.aborted || isAbortError(error)) throw error;
|
|
507
|
+
attempts.push({ ref: lookupModelRef, outcome: "error", error: error instanceof Error ? error.message : String(error) });
|
|
508
|
+
continue;
|
|
509
|
+
}
|
|
510
|
+
if (!resolved) {
|
|
511
|
+
attempts.push({ ref: lookupModelRef, outcome: "unavailable" });
|
|
512
|
+
continue;
|
|
513
|
+
}
|
|
503
514
|
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
})
|
|
515
|
+
try {
|
|
516
|
+
const response = await completeWithModelRegistry(
|
|
517
|
+
resolved.modelRegistry,
|
|
518
|
+
resolved.model,
|
|
519
|
+
{
|
|
520
|
+
systemPrompt: LOOKUP_SYSTEM_PROMPT,
|
|
521
|
+
messages: [
|
|
522
|
+
{
|
|
523
|
+
role: "user" as const,
|
|
524
|
+
content: [{ type: "text" as const, text: promptText }, ...images],
|
|
525
|
+
timestamp: Date.now(),
|
|
526
|
+
},
|
|
527
|
+
],
|
|
528
|
+
},
|
|
529
|
+
{
|
|
530
|
+
apiKey: resolved.apiKey,
|
|
531
|
+
headers: resolved.headers,
|
|
532
|
+
env: resolved.env,
|
|
533
|
+
cacheRetention: "none",
|
|
534
|
+
maxRetries: 1,
|
|
535
|
+
maxTokens: DEFAULT_LOOKUP_MAX_TOKENS,
|
|
536
|
+
signal,
|
|
537
|
+
timeoutMs: DEFAULT_LOOKUP_TIMEOUT_MS,
|
|
538
|
+
},
|
|
539
|
+
);
|
|
540
|
+
if (signal?.aborted || response.stopReason === "aborted") throw signal?.reason ?? new Error("Lookup aborted");
|
|
541
|
+
if (response.stopReason === "error") {
|
|
542
|
+
attempts.push({ ref: lookupModelRef, outcome: "error", ...(response.errorMessage ? { error: response.errorMessage } : {}) });
|
|
543
|
+
continue;
|
|
544
|
+
}
|
|
545
|
+
const text = responseText(response).trim();
|
|
546
|
+
if (!text) {
|
|
547
|
+
attempts.push({ ref: lookupModelRef, outcome: "empty" });
|
|
548
|
+
continue;
|
|
549
|
+
}
|
|
550
|
+
attempts.push({ ref: lookupModelRef, outcome: "ok" });
|
|
551
|
+
return lookupToolTextResult(text, {
|
|
552
|
+
model: lookupModelRef,
|
|
553
|
+
imageCount: images.length,
|
|
554
|
+
imagePathCount: pathImages.images.length,
|
|
555
|
+
contextChars: recentContext.length,
|
|
556
|
+
stopReason: response.stopReason,
|
|
557
|
+
attempts,
|
|
558
|
+
});
|
|
559
|
+
} catch (error) {
|
|
560
|
+
if (signal?.aborted || isAbortError(error)) throw error;
|
|
561
|
+
attempts.push({ ref: lookupModelRef, outcome: "error", error: error instanceof Error ? error.message : String(error) });
|
|
562
|
+
}
|
|
549
563
|
}
|
|
564
|
+
|
|
565
|
+
return lookupToolTextResult("Lookup failed across configured models.", {
|
|
566
|
+
model: primaryLookupModelRef,
|
|
567
|
+
imageCount: images.length,
|
|
568
|
+
imagePathCount: pathImages.images.length,
|
|
569
|
+
contextChars: recentContext.length,
|
|
570
|
+
error: "all lookup models failed",
|
|
571
|
+
attempts,
|
|
572
|
+
});
|
|
550
573
|
},
|
|
551
574
|
};
|
|
552
575
|
}
|
|
@@ -585,7 +608,15 @@ function isInstructionMessage(message: unknown): boolean {
|
|
|
585
608
|
}
|
|
586
609
|
|
|
587
610
|
function lookupModelFromConfig(cwd?: string): string | undefined {
|
|
588
|
-
return
|
|
611
|
+
return lookupModelRefsFromConfig(cwd)[0];
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
function lookupModelRefsFromConfig(cwd?: string): string[] {
|
|
615
|
+
const config = loadPiToolsSuiteConfig(["coding-discipline"], { cwd: cwd ?? process.cwd() });
|
|
616
|
+
if (!config.lookupModel) return [];
|
|
617
|
+
return [...new Set([config.lookupModel, ...config.lookupFallbackModels]
|
|
618
|
+
.map((modelRef) => modelRef.trim())
|
|
619
|
+
.filter(Boolean))];
|
|
589
620
|
}
|
|
590
621
|
|
|
591
622
|
function buildLookupPrompt(params: LookupParams, recentContext: string, imageCount: number, warnings: string[]): string {
|
|
@@ -12,6 +12,18 @@ export interface PiToolsSuiteConfig {
|
|
|
12
12
|
todoThinkingOverrides: Record<string, TodoThinkingLevel>;
|
|
13
13
|
/** Vision-capable model used by the coding-discipline lookup tool; unset disables lookup. */
|
|
14
14
|
lookupModel?: string;
|
|
15
|
+
/** Ordered lookup fallbacks tried after lookupModel. Always present, even when empty. */
|
|
16
|
+
lookupFallbackModels: string[];
|
|
17
|
+
resourceRegistry: ResourceRegistryConfig;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface ResourceRegistryConfig {
|
|
21
|
+
/** Git remote containing reusable skills/agents and project-scoped state under projects/. */
|
|
22
|
+
remote?: string;
|
|
23
|
+
/** Branch used for installs, updates, and pushes. */
|
|
24
|
+
branch: string;
|
|
25
|
+
/** Optional explicit project key for project-scoped registry state when Git remote discovery is unavailable or should be overridden. */
|
|
26
|
+
projectKey?: string;
|
|
15
27
|
}
|
|
16
28
|
|
|
17
29
|
type MutableConfig = {
|
|
@@ -20,6 +32,8 @@ type MutableConfig = {
|
|
|
20
32
|
todoThinking: boolean;
|
|
21
33
|
todoThinkingOverrides: Map<string, TodoThinkingLevel>;
|
|
22
34
|
lookupModel: string | undefined;
|
|
35
|
+
lookupFallbackModels: string[];
|
|
36
|
+
resourceRegistry: ResourceRegistryConfig;
|
|
23
37
|
};
|
|
24
38
|
|
|
25
39
|
const TODO_THINKING_OVERRIDE_LEVELS = ["off", "minimal", "low", "medium", "high", "xhigh", "max"] as const;
|
|
@@ -35,8 +49,9 @@ const ENABLED_LIST_KEYS = ["enabledModules", "enabledExtensions"];
|
|
|
35
49
|
const MODULE_MAP_KEYS = ["modules", "extensions"];
|
|
36
50
|
const DEFAULT_DISABLED_MODULES = new Set<string>(["credential-firewall", "truncation-metadata-normalizer"]);
|
|
37
51
|
const DEFAULT_TODO_THINKING_OVERRIDES = new Map<string, TodoThinkingLevel>([["zai/glm-5.3", "max"]]);
|
|
52
|
+
const DEFAULT_RESOURCE_REGISTRY_BRANCH = "main";
|
|
38
53
|
|
|
39
|
-
export function getPiToolsSuiteUserConfigPath(homeDir = homedir()): string {
|
|
54
|
+
export function getPiToolsSuiteUserConfigPath(homeDir = process.env.HOME?.trim() || homedir()): string {
|
|
40
55
|
return join(homeDir, ".config", "pi", "pi-tools-suite.jsonc");
|
|
41
56
|
}
|
|
42
57
|
|
|
@@ -68,6 +83,32 @@ function normalizeLookupModel(raw: unknown): string | undefined {
|
|
|
68
83
|
return trimmed ? trimmed : undefined;
|
|
69
84
|
}
|
|
70
85
|
|
|
86
|
+
function normalizeModelList(raw: unknown): string[] {
|
|
87
|
+
if (!Array.isArray(raw)) return [];
|
|
88
|
+
return [...new Set(raw
|
|
89
|
+
.filter((value): value is string => typeof value === "string")
|
|
90
|
+
.map((value) => value.trim())
|
|
91
|
+
.filter(Boolean))];
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function normalizeNonEmptyString(raw: unknown): string | undefined {
|
|
95
|
+
if (typeof raw !== "string") return undefined;
|
|
96
|
+
const trimmed = raw.trim();
|
|
97
|
+
return trimmed ? trimmed : undefined;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function mergeResourceRegistry(config: MutableConfig, raw: unknown): void {
|
|
101
|
+
if (!isRecord(raw)) return;
|
|
102
|
+
if (Object.prototype.hasOwnProperty.call(raw, "remote")) {
|
|
103
|
+
config.resourceRegistry.remote = normalizeNonEmptyString(raw.remote);
|
|
104
|
+
}
|
|
105
|
+
const branch = normalizeNonEmptyString(raw.branch);
|
|
106
|
+
if (branch) config.resourceRegistry.branch = branch;
|
|
107
|
+
if (Object.prototype.hasOwnProperty.call(raw, "projectKey")) {
|
|
108
|
+
config.resourceRegistry.projectKey = normalizeNonEmptyString(raw.projectKey);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
71
112
|
function isTodoThinkingLevel(raw: unknown): raw is TodoThinkingLevel {
|
|
72
113
|
return TODO_THINKING_OVERRIDE_LEVELS.includes(raw as TodoThinkingLevel);
|
|
73
114
|
}
|
|
@@ -145,6 +186,8 @@ function mergeConfigLayer(config: MutableConfig, raw: Record<string, unknown>, k
|
|
|
145
186
|
if (typeof raw.todoThinking === "boolean") config.todoThinking = raw.todoThinking;
|
|
146
187
|
mergeTodoThinkingOverrides(config, raw.todoThinkingOverrides);
|
|
147
188
|
if (Object.prototype.hasOwnProperty.call(raw, "lookupModel")) config.lookupModel = normalizeLookupModel(raw.lookupModel);
|
|
189
|
+
if (Object.prototype.hasOwnProperty.call(raw, "lookupFallbackModels")) config.lookupFallbackModels = normalizeModelList(raw.lookupFallbackModels);
|
|
190
|
+
mergeResourceRegistry(config, raw.resourceRegistry);
|
|
148
191
|
|
|
149
192
|
for (const key of DISABLED_LIST_KEYS) addDisabled(config, raw[key], knownModules);
|
|
150
193
|
for (const key of ENABLED_LIST_KEYS) removeDisabled(config, raw[key], knownModules);
|
|
@@ -191,6 +234,13 @@ function applyEnv(config: MutableConfig, env: Env, knownModules: ReadonlySet<str
|
|
|
191
234
|
const todoThinking = boolFromEnv(env.PI_TOOLS_SUITE_TODO_THINKING);
|
|
192
235
|
if (todoThinking !== undefined) config.todoThinking = todoThinking;
|
|
193
236
|
|
|
237
|
+
const registryRemote = normalizeNonEmptyString(env.PI_RESOURCE_REGISTRY_REMOTE);
|
|
238
|
+
if (registryRemote) config.resourceRegistry.remote = registryRemote;
|
|
239
|
+
const registryBranch = normalizeNonEmptyString(env.PI_RESOURCE_REGISTRY_BRANCH);
|
|
240
|
+
if (registryBranch) config.resourceRegistry.branch = registryBranch;
|
|
241
|
+
const registryProjectKey = normalizeNonEmptyString(env.PI_RESOURCE_REGISTRY_PROJECT_KEY);
|
|
242
|
+
if (registryProjectKey) config.resourceRegistry.projectKey = registryProjectKey;
|
|
243
|
+
|
|
194
244
|
return config;
|
|
195
245
|
}
|
|
196
246
|
|
|
@@ -203,6 +253,8 @@ export function loadPiToolsSuiteConfig(moduleNames: readonly string[], options:
|
|
|
203
253
|
todoThinking: false,
|
|
204
254
|
todoThinkingOverrides: new Map(DEFAULT_TODO_THINKING_OVERRIDES),
|
|
205
255
|
lookupModel: undefined,
|
|
256
|
+
lookupFallbackModels: [],
|
|
257
|
+
resourceRegistry: { branch: DEFAULT_RESOURCE_REGISTRY_BRANCH },
|
|
206
258
|
};
|
|
207
259
|
const userConfigPath = getPiToolsSuiteUserConfigPath(options.homeDir);
|
|
208
260
|
|
|
@@ -223,5 +275,7 @@ export function loadPiToolsSuiteConfig(moduleNames: readonly string[], options:
|
|
|
223
275
|
todoThinking: config.todoThinking,
|
|
224
276
|
todoThinkingOverrides: Object.fromEntries(config.todoThinkingOverrides),
|
|
225
277
|
...(config.lookupModel ? { lookupModel: config.lookupModel } : {}),
|
|
278
|
+
lookupFallbackModels: [...config.lookupFallbackModels],
|
|
279
|
+
resourceRegistry: { ...config.resourceRegistry },
|
|
226
280
|
};
|
|
227
281
|
}
|