@oh-my-pi/pi-coding-agent 17.0.1 → 17.0.2
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/CHANGELOG.md +92 -20
- package/dist/cli.js +3485 -3448
- package/dist/types/advisor/config.d.ts +14 -6
- package/dist/types/advisor/runtime.d.ts +20 -11
- package/dist/types/autolearn/controller.d.ts +1 -0
- package/dist/types/config/model-discovery.d.ts +17 -0
- package/dist/types/config/model-resolver.d.ts +6 -2
- package/dist/types/config/settings-schema.d.ts +32 -7
- package/dist/types/config/settings.d.ts +50 -0
- package/dist/types/cursor.d.ts +11 -0
- package/dist/types/discovery/helpers.d.ts +5 -2
- package/dist/types/exec/bash-executor.d.ts +2 -0
- package/dist/types/extensibility/extensions/managed-timers.d.ts +15 -0
- package/dist/types/extensibility/extensions/runner.d.ts +7 -0
- package/dist/types/extensibility/extensions/types.d.ts +18 -0
- package/dist/types/extensibility/legacy-pi-coding-agent-shim.d.ts +40 -0
- package/dist/types/extensibility/shared-events.d.ts +6 -0
- package/dist/types/extensibility/utils.d.ts +2 -2
- package/dist/types/mcp/transports/stdio.d.ts +13 -1
- package/dist/types/modes/components/advisor-config.d.ts +8 -1
- package/dist/types/modes/components/hook-editor.d.ts +7 -0
- package/dist/types/modes/components/model-hub.d.ts +5 -2
- package/dist/types/modes/components/session-selector.d.ts +2 -0
- package/dist/types/modes/controllers/command-controller.d.ts +8 -0
- package/dist/types/modes/controllers/selector-controller.d.ts +3 -1
- package/dist/types/modes/print-mode.d.ts +1 -1
- package/dist/types/modes/warp-events.d.ts +24 -0
- package/dist/types/modes/warp-events.test.d.ts +1 -0
- package/dist/types/plan-mode/model-transition.d.ts +47 -0
- package/dist/types/plan-mode/model-transition.test.d.ts +1 -0
- package/dist/types/registry/agent-lifecycle.d.ts +26 -1
- package/dist/types/sdk.d.ts +13 -2
- package/dist/types/session/agent-session.d.ts +34 -10
- package/dist/types/session/session-history-format.d.ts +10 -0
- package/dist/types/session/session-manager.d.ts +14 -0
- package/dist/types/slash-commands/helpers/active-oauth-account.d.ts +9 -0
- package/dist/types/task/label.d.ts +1 -1
- package/dist/types/telemetry-export.d.ts +34 -9
- package/dist/types/tools/approval.d.ts +8 -0
- package/dist/types/tools/bash.d.ts +2 -0
- package/dist/types/tools/essential-tools.d.ts +29 -0
- package/dist/types/tools/image-gen.d.ts +2 -1
- package/dist/types/tools/index.d.ts +1 -0
- package/dist/types/tools/xdev.d.ts +11 -2
- package/dist/types/utils/title-generator.d.ts +2 -1
- package/dist/types/web/search/providers/kimi.d.ts +4 -1
- package/dist/types/web/search/types.d.ts +1 -1
- package/package.json +21 -16
- package/src/advisor/__tests__/advisor.test.ts +1304 -42
- package/src/advisor/__tests__/config.test.ts +58 -2
- package/src/advisor/config.ts +76 -24
- package/src/advisor/runtime.ts +445 -92
- package/src/autolearn/controller.ts +23 -28
- package/src/cli.ts +5 -1
- package/src/config/model-discovery.ts +81 -21
- package/src/config/model-registry.ts +25 -6
- package/src/config/model-resolver.ts +14 -7
- package/src/config/settings-schema.ts +42 -6
- package/src/config/settings.ts +405 -25
- package/src/cursor.ts +20 -3
- package/src/debug/report-bundle.ts +40 -4
- package/src/discovery/helpers.ts +28 -5
- package/src/exec/bash-executor.ts +14 -5
- package/src/extensibility/custom-tools/loader.ts +3 -3
- package/src/extensibility/custom-tools/wrapper.ts +2 -1
- package/src/extensibility/extensions/loader.ts +3 -3
- package/src/extensibility/extensions/managed-timers.ts +83 -0
- package/src/extensibility/extensions/runner.ts +26 -0
- package/src/extensibility/extensions/types.ts +18 -0
- package/src/extensibility/extensions/wrapper.ts +2 -1
- package/src/extensibility/hooks/loader.ts +3 -3
- package/src/extensibility/legacy-pi-coding-agent-shim.ts +96 -1
- package/src/extensibility/plugins/legacy-pi-compat.ts +225 -22
- package/src/extensibility/plugins/manager.ts +2 -2
- package/src/extensibility/shared-events.ts +6 -0
- package/src/extensibility/utils.ts +91 -25
- package/src/irc/bus.ts +22 -3
- package/src/launch/broker.ts +3 -2
- package/src/launch/client.ts +2 -2
- package/src/launch/presence.ts +2 -2
- package/src/lsp/client.ts +1 -1
- package/src/main.ts +11 -8
- package/src/mcp/manager.ts +9 -3
- package/src/mcp/transports/stdio.ts +103 -23
- package/src/modes/components/advisor-config.ts +65 -3
- package/src/modes/components/ask-dialog.ts +1 -1
- package/src/modes/components/hook-editor.ts +18 -3
- package/src/modes/components/model-hub.ts +138 -42
- package/src/modes/components/session-selector.ts +4 -0
- package/src/modes/components/status-line/component.test.ts +1 -0
- package/src/modes/components/status-line/segments.ts +21 -6
- package/src/modes/controllers/command-controller.ts +167 -47
- package/src/modes/controllers/event-controller.ts +5 -0
- package/src/modes/controllers/extension-ui-controller.ts +4 -22
- package/src/modes/controllers/input-controller.ts +12 -12
- package/src/modes/controllers/selector-controller.ts +191 -31
- package/src/modes/interactive-mode.ts +139 -54
- package/src/modes/print-mode.ts +3 -3
- package/src/modes/rpc/host-tools.ts +2 -1
- package/src/modes/rpc/rpc-mode.ts +19 -4
- package/src/modes/warp-events.test.ts +794 -0
- package/src/modes/warp-events.ts +232 -0
- package/src/plan-mode/model-transition.test.ts +60 -0
- package/src/plan-mode/model-transition.ts +51 -0
- package/src/registry/agent-lifecycle.ts +133 -18
- package/src/sdk.ts +221 -42
- package/src/session/agent-session.ts +1285 -348
- package/src/session/session-history-format.ts +20 -5
- package/src/session/session-manager.ts +48 -0
- package/src/slash-commands/builtin-registry.ts +7 -0
- package/src/slash-commands/helpers/active-oauth-account.ts +16 -0
- package/src/task/executor.ts +1 -1
- package/src/task/label.ts +2 -0
- package/src/telemetry-export.ts +453 -97
- package/src/tools/approval.ts +11 -0
- package/src/tools/bash.ts +71 -38
- package/src/tools/essential-tools.ts +45 -0
- package/src/tools/gh.ts +169 -2
- package/src/tools/image-gen.ts +69 -7
- package/src/tools/index.ts +7 -5
- package/src/tools/read.ts +48 -3
- package/src/tools/write.ts +22 -4
- package/src/tools/xdev.ts +14 -3
- package/src/utils/title-generator.ts +15 -4
- package/src/web/search/providers/kimi.ts +18 -12
- package/src/web/search/types.ts +6 -1
|
@@ -56,8 +56,15 @@ import { reset as resetCapabilities } from "../capability";
|
|
|
56
56
|
import type { CollabGuestLink } from "../collab/guest";
|
|
57
57
|
import type { CollabHost } from "../collab/host";
|
|
58
58
|
import { KeybindingsManager } from "../config/keybindings";
|
|
59
|
+
import type { ResolvedModelRoleValue } from "../config/model-resolver";
|
|
59
60
|
import { applyProviderGlobalsFromSettings } from "../config/provider-globals";
|
|
60
|
-
import {
|
|
61
|
+
import {
|
|
62
|
+
isSettingsInitialized,
|
|
63
|
+
onModelRolesChanged,
|
|
64
|
+
onStatusLineSessionAccentChanged,
|
|
65
|
+
Settings,
|
|
66
|
+
settings,
|
|
67
|
+
} from "../config/settings";
|
|
61
68
|
import { clearClaudePluginRootsCache } from "../discovery/helpers";
|
|
62
69
|
import type {
|
|
63
70
|
AutocompleteProviderFactory,
|
|
@@ -88,6 +95,7 @@ import {
|
|
|
88
95
|
resolveApprovedPlan,
|
|
89
96
|
resolvePlanTitle,
|
|
90
97
|
} from "../plan-mode/approved-plan";
|
|
98
|
+
import { resolvePlanModelTransition } from "../plan-mode/model-transition";
|
|
91
99
|
import planModeApprovedPrompt from "../prompts/system/plan-mode-approved.md" with { type: "text" };
|
|
92
100
|
import planModeCompactInstructionsPrompt from "../prompts/system/plan-mode-compact-instructions.md" with {
|
|
93
101
|
type: "text",
|
|
@@ -539,6 +547,8 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
539
547
|
#goalSuppressNextContinuation = false;
|
|
540
548
|
#planModePreviousModelState: { model: Model; thinkingLevel?: ConfiguredThinkingLevel } | undefined;
|
|
541
549
|
#pendingModelSwitch: { model: Model; thinkingLevel?: ConfiguredThinkingLevel } | undefined;
|
|
550
|
+
/** Whether #pendingModelSwitch was queued by the live plan-role reconciler. */
|
|
551
|
+
#pendingPlanModelSwitch = false;
|
|
542
552
|
#planModeHasEntered = false;
|
|
543
553
|
#planReviewOverlay: PlanReviewOverlay | undefined;
|
|
544
554
|
#planReviewOverlayHandle: OverlayHandle | undefined;
|
|
@@ -1023,6 +1033,11 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
1023
1033
|
this.#handleSessionAccentInputsChanged();
|
|
1024
1034
|
}),
|
|
1025
1035
|
);
|
|
1036
|
+
this.#eventBusUnsubscribers.push(
|
|
1037
|
+
onModelRolesChanged(() => {
|
|
1038
|
+
void this.#reapplyPlanModeModelOnRoleChange();
|
|
1039
|
+
}),
|
|
1040
|
+
);
|
|
1026
1041
|
this.#eventBusUnsubscribers.push(
|
|
1027
1042
|
this.session.subscribeCommandMetadataChanged(() => {
|
|
1028
1043
|
const retainedCommands = this.#pendingSlashCommands.filter(command => !command.name.startsWith("skill:"));
|
|
@@ -2080,35 +2095,81 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
2080
2095
|
if (!resolved.model) return;
|
|
2081
2096
|
|
|
2082
2097
|
const currentModel = this.session.model;
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2098
|
+
// Capture the pre-plan model so #exitPlanMode can restore it. Only the
|
|
2099
|
+
// entry path records this — a mid-planning role change (below) leaves the
|
|
2100
|
+
// active model on the plan role, so overwriting here would restore the old
|
|
2101
|
+
// plan model instead of the user's real pre-plan model.
|
|
2086
2102
|
this.#planModePreviousModelState = currentModel
|
|
2087
2103
|
? { model: currentModel, thinkingLevel: this.session.configuredThinkingLevel() }
|
|
2088
2104
|
: undefined;
|
|
2089
2105
|
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2106
|
+
await this.#applyPlanModelTransition(currentModel, resolved);
|
|
2107
|
+
}
|
|
2108
|
+
|
|
2109
|
+
/**
|
|
2110
|
+
* Re-resolve the `plan` role and move the active model onto it. Fires when
|
|
2111
|
+
* the plan role is reassigned while plan mode is active: the active model IS
|
|
2112
|
+
* the plan model there, so a settings-only change would otherwise leave the
|
|
2113
|
+
* current turn on the model plan mode was entered with (issue #5657). No-op
|
|
2114
|
+
* outside plan mode — role reassignment for an inactive role only touches
|
|
2115
|
+
* settings.
|
|
2116
|
+
*/
|
|
2117
|
+
async #reapplyPlanModeModelOnRoleChange(): Promise<void> {
|
|
2118
|
+
if (!this.planModeEnabled) return;
|
|
2119
|
+
const resolved = this.session.resolveRoleModelWithThinking("plan");
|
|
2120
|
+
if (!resolved.model) {
|
|
2121
|
+
this.#clearPendingPlanModelSwitch();
|
|
2122
|
+
return;
|
|
2123
|
+
}
|
|
2124
|
+
await this.#applyPlanModelTransition(this.session.model, resolved);
|
|
2125
|
+
}
|
|
2126
|
+
|
|
2127
|
+
/**
|
|
2128
|
+
* Drop a stale deferred switch that was queued for a previous plan-role
|
|
2129
|
+
* assignment. Other deferred switches (such as restoring the pre-plan
|
|
2130
|
+
* model) remain intact.
|
|
2131
|
+
*/
|
|
2132
|
+
#clearPendingPlanModelSwitch(): void {
|
|
2133
|
+
if (!this.#pendingPlanModelSwitch) return;
|
|
2134
|
+
this.#pendingModelSwitch = undefined;
|
|
2135
|
+
this.#pendingPlanModelSwitch = false;
|
|
2136
|
+
}
|
|
2137
|
+
|
|
2138
|
+
/** Apply (or defer) the model/thinking change implied by the resolved plan role. */
|
|
2139
|
+
async #applyPlanModelTransition(currentModel: Model | undefined, resolved: ResolvedModelRoleValue): Promise<void> {
|
|
2140
|
+
const transition = resolvePlanModelTransition(currentModel, resolved, this.session.isStreaming);
|
|
2141
|
+
if (transition.kind !== "apply" || !transition.deferred) {
|
|
2142
|
+
this.#clearPendingPlanModelSwitch();
|
|
2143
|
+
}
|
|
2144
|
+
switch (transition.kind) {
|
|
2145
|
+
case "none":
|
|
2146
|
+
return;
|
|
2147
|
+
case "thinking":
|
|
2148
|
+
this.session.setThinkingLevel(transition.thinkingLevel);
|
|
2149
|
+
return;
|
|
2150
|
+
case "apply":
|
|
2151
|
+
if (transition.deferred) {
|
|
2152
|
+
this.#pendingModelSwitch = { model: transition.model, thinkingLevel: transition.thinkingLevel };
|
|
2153
|
+
this.#pendingPlanModelSwitch = true;
|
|
2154
|
+
return;
|
|
2155
|
+
}
|
|
2156
|
+
try {
|
|
2157
|
+
await this.session.setModelTemporary(transition.model, transition.thinkingLevel);
|
|
2158
|
+
} catch (error) {
|
|
2159
|
+
this.showWarning(
|
|
2160
|
+
`Failed to switch to plan model for plan mode: ${error instanceof Error ? error.message : String(error)}`,
|
|
2161
|
+
);
|
|
2162
|
+
}
|
|
2093
2163
|
return;
|
|
2094
|
-
}
|
|
2095
|
-
try {
|
|
2096
|
-
await this.session.setModelTemporary(resolved.model, planThinkingLevel);
|
|
2097
|
-
} catch (error) {
|
|
2098
|
-
this.showWarning(
|
|
2099
|
-
`Failed to switch to plan model for plan mode: ${error instanceof Error ? error.message : String(error)}`,
|
|
2100
|
-
);
|
|
2101
|
-
}
|
|
2102
|
-
} else if (planThinkingLevel) {
|
|
2103
|
-
this.session.setThinkingLevel(planThinkingLevel);
|
|
2104
2164
|
}
|
|
2105
2165
|
}
|
|
2106
2166
|
|
|
2107
2167
|
/** Apply any deferred model switch after the current stream ends. */
|
|
2108
2168
|
async flushPendingModelSwitch(): Promise<void> {
|
|
2109
2169
|
const pending = this.#pendingModelSwitch;
|
|
2110
|
-
if (!pending) return;
|
|
2111
2170
|
this.#pendingModelSwitch = undefined;
|
|
2171
|
+
this.#pendingPlanModelSwitch = false;
|
|
2172
|
+
if (!pending) return;
|
|
2112
2173
|
try {
|
|
2113
2174
|
await this.session.setModelTemporary(pending.model, pending.thinkingLevel);
|
|
2114
2175
|
} catch (error) {
|
|
@@ -2120,19 +2181,23 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
2120
2181
|
|
|
2121
2182
|
async #clearTransientModeState(): Promise<void> {
|
|
2122
2183
|
if (this.planModeEnabled || this.planModePaused) {
|
|
2123
|
-
if (this.#planModePreviousTools !== undefined) {
|
|
2124
|
-
await this.session.setActiveToolsByName(this.#planModePreviousTools);
|
|
2125
|
-
}
|
|
2126
|
-
this.session.setPlanProposalHandler?.(null);
|
|
2127
2184
|
this.session.setPlanModeState(undefined);
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2185
|
+
try {
|
|
2186
|
+
if (this.#planModePreviousTools !== undefined) {
|
|
2187
|
+
await this.session.setActiveToolsByName(this.#planModePreviousTools);
|
|
2188
|
+
}
|
|
2189
|
+
} finally {
|
|
2190
|
+
this.session.setPlanProposalHandler?.(null);
|
|
2191
|
+
this.planModeEnabled = false;
|
|
2192
|
+
this.planModePaused = false;
|
|
2193
|
+
this.planModePlanFilePath = undefined;
|
|
2194
|
+
this.#planModePreviousTools = undefined;
|
|
2195
|
+
this.#planModePreviousModelState = undefined;
|
|
2196
|
+
this.#pendingModelSwitch = undefined;
|
|
2197
|
+
this.#pendingPlanModelSwitch = false;
|
|
2198
|
+
this.#planModeHasEntered = false;
|
|
2199
|
+
this.#updatePlanModeStatus();
|
|
2200
|
+
}
|
|
2136
2201
|
}
|
|
2137
2202
|
|
|
2138
2203
|
if (this.goalModeEnabled || this.goalModePaused) {
|
|
@@ -2314,6 +2379,7 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
2314
2379
|
this.session.setThinkingLevel(prev.thinkingLevel);
|
|
2315
2380
|
} else if (this.session.isStreaming) {
|
|
2316
2381
|
this.#pendingModelSwitch = { model: prev.model, thinkingLevel: prev.thinkingLevel };
|
|
2382
|
+
this.#pendingPlanModelSwitch = false;
|
|
2317
2383
|
} else {
|
|
2318
2384
|
await this.session.setModelTemporary(prev.model, prev.thinkingLevel);
|
|
2319
2385
|
}
|
|
@@ -2345,33 +2411,30 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
2345
2411
|
return;
|
|
2346
2412
|
}
|
|
2347
2413
|
|
|
2348
|
-
const
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
if (!options?.deferModelRestore) {
|
|
2354
|
-
await this.#restorePlanPreviousModel(this.#planModePreviousModelState);
|
|
2414
|
+
const planModeState = this.session.getPlanModeState();
|
|
2415
|
+
this.session.setPlanModeState(undefined);
|
|
2416
|
+
try {
|
|
2417
|
+
if (this.#planModePreviousTools !== undefined) {
|
|
2418
|
+
await this.session.setActiveToolsByName(this.#planModePreviousTools);
|
|
2355
2419
|
}
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
// session on the plan-role model after the user has exited plan mode
|
|
2360
|
-
// (issue #816). This runs even when deferModelRestore is set
|
|
2361
|
-
// (compact-approval path): otherwise the stale plan switch survives and
|
|
2362
|
-
// flushPendingModelSwitch() later clobbers the restored/execution model.
|
|
2363
|
-
// Only clear when the pending target matches the plan-role model — leave
|
|
2364
|
-
// any unrelated user-queued switch intact.
|
|
2365
|
-
const pending = this.#pendingModelSwitch;
|
|
2366
|
-
if (pending) {
|
|
2367
|
-
const planResolution = this.session.resolveRoleModelWithThinking("plan");
|
|
2368
|
-
if (planResolution.model && modelsAreEqual(pending.model, planResolution.model)) {
|
|
2369
|
-
this.#pendingModelSwitch = undefined;
|
|
2420
|
+
if (this.#planModePreviousModelState) {
|
|
2421
|
+
if (!options?.deferModelRestore) {
|
|
2422
|
+
await this.#restorePlanPreviousModel(this.#planModePreviousModelState);
|
|
2370
2423
|
}
|
|
2424
|
+
// If #applyPlanModeModel queued a deferred switch to the plan-role model
|
|
2425
|
+
// (because the session was streaming on entry), drop it now: we are
|
|
2426
|
+
// leaving plan mode, so flushing it on the next agent_end would land the
|
|
2427
|
+
// session on the plan-role model after the user has exited plan mode
|
|
2428
|
+
// (issue #816). This runs even when deferModelRestore is set
|
|
2429
|
+
// (compact-approval path): otherwise the stale plan switch survives and
|
|
2430
|
+
// flushPendingModelSwitch() later clobbers the restored/execution model.
|
|
2431
|
+
this.#clearPendingPlanModelSwitch();
|
|
2371
2432
|
}
|
|
2433
|
+
} catch (error) {
|
|
2434
|
+
this.session.setPlanModeState(planModeState);
|
|
2435
|
+
throw error;
|
|
2372
2436
|
}
|
|
2373
2437
|
this.session.setPlanProposalHandler?.(null);
|
|
2374
|
-
this.session.setPlanModeState(undefined);
|
|
2375
2438
|
this.planModeEnabled = false;
|
|
2376
2439
|
// Suppress cache-miss marker on the next turn: plan exit changes the system
|
|
2377
2440
|
// prompt, which predictably invalidates the cache.
|
|
@@ -2551,6 +2614,7 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
2551
2614
|
maxHeight: "100%",
|
|
2552
2615
|
margin: 0,
|
|
2553
2616
|
fullscreen: true,
|
|
2617
|
+
mouseTracking: false,
|
|
2554
2618
|
});
|
|
2555
2619
|
this.ui.setFocus(overlay);
|
|
2556
2620
|
this.ui.requestRender();
|
|
@@ -2881,6 +2945,18 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
2881
2945
|
planFilePath: options.planFilePath,
|
|
2882
2946
|
contextPreserved: options.preserveContext === true,
|
|
2883
2947
|
});
|
|
2948
|
+
// Close the review overlay only now — after the async title write and plan
|
|
2949
|
+
// prompt are prepared, immediately before the execution turn is queued. The
|
|
2950
|
+
// synthetic prompt below blocks in `session.prompt` for the whole run, so
|
|
2951
|
+
// hiding here (rather than after #approvePlan returns) keeps the operator off
|
|
2952
|
+
// the stale plan-review screen (issue #5688) while #5319's stale-buffer guard
|
|
2953
|
+
// stays intact. Deferring the hide past the awaited `setSessionName` also
|
|
2954
|
+
// prevents restored editor focus from letting operator keystrokes submit a
|
|
2955
|
+
// normal turn ahead of the approved execution turn (PR #5689 review).
|
|
2956
|
+
// `#hidePlanReview` is idempotent, so the caller's trailing `closePlanReview()`
|
|
2957
|
+
// — and the cancelled/error early returns above — stay safe no-ops.
|
|
2958
|
+
this.#hidePlanReview();
|
|
2959
|
+
this.ui.requestRender();
|
|
2884
2960
|
// A user turn queued during compaction was already fired by
|
|
2885
2961
|
// `flushCompactionQueue` before we returned from `handleCompactCommand`; the
|
|
2886
2962
|
// old abort-then-prompt path would have discarded that operator turn AND
|
|
@@ -4310,11 +4386,20 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
4310
4386
|
this.#selectorController.showSessionSelector();
|
|
4311
4387
|
}
|
|
4312
4388
|
|
|
4313
|
-
handleResumeSession(sessionPath: string): Promise<void> {
|
|
4389
|
+
async handleResumeSession(sessionPath: string): Promise<void> {
|
|
4390
|
+
// Flush pending settings writes *before* disposing controllers or resetting
|
|
4391
|
+
// observers: a save failure must leave the session, process project dir,
|
|
4392
|
+
// and Settings in the source scope with all UI intact.
|
|
4393
|
+
try {
|
|
4394
|
+
await this.settings.flush();
|
|
4395
|
+
} catch (err) {
|
|
4396
|
+
this.showError(`Failed to save pending settings: ${err instanceof Error ? err.message : String(err)}`);
|
|
4397
|
+
return;
|
|
4398
|
+
}
|
|
4314
4399
|
this.#btwController.dispose();
|
|
4315
4400
|
this.#omfgController.dispose();
|
|
4316
4401
|
this.resetObserverRegistry();
|
|
4317
|
-
|
|
4402
|
+
await this.#selectorController.handleResumeSession(sessionPath, { settingsFlushed: true });
|
|
4318
4403
|
}
|
|
4319
4404
|
|
|
4320
4405
|
handleSessionDeleteCommand(): Promise<void> {
|
package/src/modes/print-mode.ts
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
import type { AgentMessage } from "@oh-my-pi/pi-agent-core";
|
|
9
9
|
import type { AssistantMessage, ImageContent } from "@oh-my-pi/pi-ai";
|
|
10
10
|
import { logger, sanitizeText } from "@oh-my-pi/pi-utils";
|
|
11
|
-
import type
|
|
11
|
+
import { type AgentSession, type AgentSessionEvent, SHUTDOWN_CONSOLIDATE_BUDGET_MS } from "../session/agent-session";
|
|
12
12
|
import { isSilentAbort } from "../session/messages";
|
|
13
13
|
import { flushTelemetryExport } from "../telemetry-export";
|
|
14
14
|
import { initializeExtensions } from "./runtime-init";
|
|
@@ -152,7 +152,7 @@ export async function runPrintMode(session: AgentSession, options: PrintModeOpti
|
|
|
152
152
|
// OMP-owned Chromium survives this exit (issue #5643). `dispose()`
|
|
153
153
|
// is idempotent, so the unreachable call below is a harmless no-op.
|
|
154
154
|
await flushTelemetryExport();
|
|
155
|
-
await session.dispose();
|
|
155
|
+
await session.dispose({ mnemopiConsolidateTimeoutMs: SHUTDOWN_CONSOLIDATE_BUDGET_MS });
|
|
156
156
|
const flushed = process.stderr.write(`${errorLine}\n`);
|
|
157
157
|
if (flushed) {
|
|
158
158
|
process.exit(1);
|
|
@@ -189,5 +189,5 @@ export async function runPrintMode(session: AgentSession, options: PrintModeOpti
|
|
|
189
189
|
});
|
|
190
190
|
});
|
|
191
191
|
|
|
192
|
-
await session.dispose();
|
|
192
|
+
await session.dispose({ mnemopiConsolidateTimeoutMs: SHUTDOWN_CONSOLIDATE_BUDGET_MS });
|
|
193
193
|
}
|
|
@@ -3,6 +3,7 @@ import type { Static, TSchema } from "@oh-my-pi/pi-ai";
|
|
|
3
3
|
import { Snowflake } from "@oh-my-pi/pi-utils";
|
|
4
4
|
import { applyToolProxy } from "../../extensibility/tool-proxy";
|
|
5
5
|
import type { Theme } from "../../modes/theme/theme";
|
|
6
|
+
import { defaultLoadModeForToolName } from "../../tools/essential-tools";
|
|
6
7
|
import type {
|
|
7
8
|
RpcHostToolCallRequest,
|
|
8
9
|
RpcHostToolCancelRequest,
|
|
@@ -54,7 +55,7 @@ class RpcHostToolAdapter<TParams extends TSchema = TSchema, TTheme extends Theme
|
|
|
54
55
|
this.#definition = definition;
|
|
55
56
|
this.#bridge = bridge;
|
|
56
57
|
applyToolProxy(definition, this);
|
|
57
|
-
this.loadMode = definition.loadMode
|
|
58
|
+
this.loadMode = defaultLoadModeForToolName(definition.name, definition.loadMode);
|
|
58
59
|
}
|
|
59
60
|
|
|
60
61
|
execute(
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
*/
|
|
13
13
|
import { getOAuthProviders } from "@oh-my-pi/pi-ai/oauth";
|
|
14
14
|
import { isZodSchema, zodToWireSchema } from "@oh-my-pi/pi-ai/utils/schema";
|
|
15
|
-
import { $env, isRecord,
|
|
15
|
+
import { $env, isRecord, readLines, Snowflake } from "@oh-my-pi/pi-utils";
|
|
16
16
|
import { reset as resetCapabilities } from "../../capability";
|
|
17
17
|
import { clearPluginRootsAndCaches, resolveActiveProjectRegistryPath } from "../../discovery/helpers";
|
|
18
18
|
import {
|
|
@@ -29,6 +29,7 @@ import type { AgentSession } from "../../session/agent-session";
|
|
|
29
29
|
import { SKILL_PROMPT_MESSAGE_TYPE, USER_INTERRUPT_LABEL } from "../../session/messages";
|
|
30
30
|
import { executeAcpBuiltinSlashCommand } from "../../slash-commands/acp-builtins";
|
|
31
31
|
import { buildAvailableSlashCommands } from "../../slash-commands/available-commands";
|
|
32
|
+
import { defaultLoadModeForToolName } from "../../tools/essential-tools";
|
|
32
33
|
import type { EventBus } from "../../utils/event-bus";
|
|
33
34
|
import { initializeExtensions } from "../runtime-init";
|
|
34
35
|
import { isRpcHostToolResult, isRpcHostToolUpdate, RpcHostToolBridge } from "./host-tools";
|
|
@@ -507,7 +508,7 @@ function normalizeHostToolDefinitions(tools: RpcHostToolDefinition[]): RpcHostTo
|
|
|
507
508
|
description,
|
|
508
509
|
parameters: tool.parameters,
|
|
509
510
|
hidden: tool.hidden === true,
|
|
510
|
-
loadMode: tool.loadMode
|
|
511
|
+
loadMode: defaultLoadModeForToolName(name, tool.loadMode),
|
|
511
512
|
};
|
|
512
513
|
});
|
|
513
514
|
}
|
|
@@ -1375,8 +1376,22 @@ export async function runRpcMode(
|
|
|
1375
1376
|
|
|
1376
1377
|
// Keep the stdin reader moving: side-channel frames dispatch immediately,
|
|
1377
1378
|
// ordinary commands serialize through inputDispatcher, and bash remains
|
|
1378
|
-
// background-dispatched so abort_bash can overtake it.
|
|
1379
|
-
|
|
1379
|
+
// background-dispatched so abort_bash can overtake it. Frames are read
|
|
1380
|
+
// line-by-line and parsed here (not via readJsonl) so a single malformed
|
|
1381
|
+
// line is reported as an error frame and the loop keeps running instead of
|
|
1382
|
+
// throwing out of the generator and killing the whole process (issue #5194).
|
|
1383
|
+
const decoder = new TextDecoder();
|
|
1384
|
+
for await (const line of readLines(Bun.stdin.stream())) {
|
|
1385
|
+
const text = decoder.decode(line).trim();
|
|
1386
|
+
if (!text) continue;
|
|
1387
|
+
let parsed: unknown;
|
|
1388
|
+
try {
|
|
1389
|
+
parsed = JSON.parse(text);
|
|
1390
|
+
} catch (e: unknown) {
|
|
1391
|
+
const message = e instanceof Error ? e.message : String(e);
|
|
1392
|
+
output(error(undefined, "parse", `Failed to parse command: ${message}`));
|
|
1393
|
+
continue;
|
|
1394
|
+
}
|
|
1380
1395
|
inputDispatcher.dispatch(parsed);
|
|
1381
1396
|
}
|
|
1382
1397
|
|