@caupulican/pi-adaptative 0.80.42 → 0.80.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/CHANGELOG.md +24 -0
- package/dist/bundled-resources/prompts/extensionify.md +20 -0
- package/dist/bundled-resources/prompts/learn.md +27 -0
- package/dist/bundled-resources/prompts/skillify.md +21 -0
- package/dist/bundled-resources/skills/pi-harness-learning/SKILL.md +217 -0
- package/dist/bundled-resources/skills/skill-architect/SKILL.md +162 -0
- package/dist/config.d.ts +17 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +30 -0
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session.d.ts +37 -2
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +215 -9
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/context-gc.d.ts.map +1 -1
- package/dist/core/context-gc.js +27 -5
- package/dist/core/context-gc.js.map +1 -1
- package/dist/core/extensions/loader.d.ts +10 -3
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +38 -7
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +6 -0
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +53 -6
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +16 -2
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/profile-registry.d.ts +39 -0
- package/dist/core/profile-registry.d.ts.map +1 -0
- package/dist/core/profile-registry.js +230 -0
- package/dist/core/profile-registry.js.map +1 -0
- package/dist/core/profile-resource-selection.d.ts +19 -0
- package/dist/core/profile-resource-selection.d.ts.map +1 -0
- package/dist/core/profile-resource-selection.js +84 -0
- package/dist/core/profile-resource-selection.js.map +1 -0
- package/dist/core/resource-loader.d.ts +33 -3
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +68 -11
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/settings-manager.d.ts +44 -2
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +557 -27
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/skills.d.ts +5 -0
- package/dist/core/skills.d.ts.map +1 -1
- package/dist/core/skills.js +2 -2
- package/dist/core/skills.js.map +1 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +1 -0
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +5 -17
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/tools/extensionify.d.ts +33 -0
- package/dist/core/tools/extensionify.d.ts.map +1 -0
- package/dist/core/tools/extensionify.js +146 -0
- package/dist/core/tools/extensionify.js.map +1 -0
- package/dist/core/tools/index.d.ts +10 -1
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/core/tools/index.js +36 -1
- package/dist/core/tools/index.js.map +1 -1
- package/dist/core/tools/skill-audit.d.ts +63 -0
- package/dist/core/tools/skill-audit.d.ts.map +1 -0
- package/dist/core/tools/skill-audit.js +175 -0
- package/dist/core/tools/skill-audit.js.map +1 -0
- package/dist/core/tools/skillify.d.ts +30 -0
- package/dist/core/tools/skillify.d.ts.map +1 -0
- package/dist/core/tools/skillify.js +91 -0
- package/dist/core/tools/skillify.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/modes/interactive/components/profile-resource-editor.d.ts +50 -0
- package/dist/modes/interactive/components/profile-resource-editor.d.ts.map +1 -0
- package/dist/modes/interactive/components/profile-resource-editor.js +232 -0
- package/dist/modes/interactive/components/profile-resource-editor.js.map +1 -0
- package/dist/modes/interactive/components/profile-selector.d.ts +8 -0
- package/dist/modes/interactive/components/profile-selector.d.ts.map +1 -0
- package/dist/modes/interactive/components/profile-selector.js +77 -0
- package/dist/modes/interactive/components/profile-selector.js.map +1 -0
- package/dist/modes/interactive/components/settings-selector.d.ts +8 -0
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +75 -0
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +14 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +434 -24
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/docs/settings.md +20 -1
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/examples/sdk/12-full-control.ts +4 -0
- package/npm-shrinkwrap.json +12 -12
- package/package.json +6 -6
|
@@ -18,14 +18,16 @@ import { FooterDataProvider } from "../../core/footer-data-provider.js";
|
|
|
18
18
|
import { configureHttpDispatcher, formatHttpIdleTimeoutMs } from "../../core/http-dispatcher.js";
|
|
19
19
|
import { KeybindingsManager } from "../../core/keybindings.js";
|
|
20
20
|
import { createCompactionSummaryMessage } from "../../core/messages.js";
|
|
21
|
-
import { cliProviderAliases, defaultModelPerProvider, findExactModelReferenceMatch, resolveModelScope, } from "../../core/model-resolver.js";
|
|
21
|
+
import { cliProviderAliases, defaultModelPerProvider, findExactModelReferenceMatch, resolveCliModel, resolveModelScope, } from "../../core/model-resolver.js";
|
|
22
22
|
import { DefaultPackageManager } from "../../core/package-manager.js";
|
|
23
23
|
import { BUILT_IN_PROVIDER_DISPLAY_NAMES } from "../../core/provider-display-names.js";
|
|
24
24
|
import { getPendingReloadBlockers } from "../../core/reload-blockers.js";
|
|
25
25
|
import { formatMissingSessionCwdPrompt, MissingSessionCwdError } from "../../core/session-cwd.js";
|
|
26
26
|
import { isAutoLearnSessionId, SessionManager } from "../../core/session-manager.js";
|
|
27
|
+
import { validateSkillName } from "../../core/skills.js";
|
|
27
28
|
import { BUILTIN_SLASH_COMMANDS } from "../../core/slash-commands.js";
|
|
28
29
|
import { isInstallTelemetryEnabled } from "../../core/telemetry.js";
|
|
30
|
+
import { allToolNames } from "../../core/tools/index.js";
|
|
29
31
|
import { hasProjectTrustInputs, ProjectTrustStore } from "../../core/trust-manager.js";
|
|
30
32
|
import { getChangelogPath, getNewEntries, parseChangelog } from "../../utils/changelog.js";
|
|
31
33
|
import { copyToClipboard } from "../../utils/clipboard.js";
|
|
@@ -56,6 +58,8 @@ import { formatKeyText, keyDisplayText, keyHint, keyText, rawKeyHint } from "./c
|
|
|
56
58
|
import { LoginDialogComponent } from "./components/login-dialog.js";
|
|
57
59
|
import { ModelSelectorComponent } from "./components/model-selector.js";
|
|
58
60
|
import { OAuthSelectorComponent } from "./components/oauth-selector.js";
|
|
61
|
+
import { ProfileResourceEditorComponent, } from "./components/profile-resource-editor.js";
|
|
62
|
+
import { ProfileSelectorComponent } from "./components/profile-selector.js";
|
|
59
63
|
import { ScopedModelsSelectorComponent } from "./components/scoped-models-selector.js";
|
|
60
64
|
import { SessionSelectorComponent } from "./components/session-selector.js";
|
|
61
65
|
import { SettingsSelectorComponent } from "./components/settings-selector.js";
|
|
@@ -101,6 +105,7 @@ const ANTHROPIC_SUBSCRIPTION_AUTH_WARNING = "Anthropic subscription auth is acti
|
|
|
101
105
|
const AUTO_LEARN_DEFAULTS = {
|
|
102
106
|
enabled: false,
|
|
103
107
|
model: "active",
|
|
108
|
+
thinkingLevel: "low",
|
|
104
109
|
longSessionMessages: 32,
|
|
105
110
|
longSessionContextPercent: 70,
|
|
106
111
|
cooldownMinutes: 24 * 60,
|
|
@@ -108,36 +113,39 @@ const AUTO_LEARN_DEFAULTS = {
|
|
|
108
113
|
maxConcurrentLearners: 1,
|
|
109
114
|
applyHighConfidence: false,
|
|
110
115
|
reflectionReview: true,
|
|
111
|
-
reflectionMinToolCalls:
|
|
116
|
+
reflectionMinToolCalls: 12,
|
|
112
117
|
reflectionCooldownMinutes: 24 * 60,
|
|
118
|
+
complexTaskToolCalls: 12,
|
|
113
119
|
};
|
|
114
120
|
const AUTONOMY_AUTO_LEARN_PRESETS = {
|
|
115
121
|
off: { ...AUTO_LEARN_DEFAULTS, enabled: false, reflectionReview: false },
|
|
116
122
|
safe: {
|
|
117
123
|
...AUTO_LEARN_DEFAULTS,
|
|
118
|
-
enabled:
|
|
124
|
+
enabled: false,
|
|
119
125
|
longSessionMessages: 64,
|
|
120
126
|
longSessionContextPercent: 85,
|
|
121
127
|
cooldownMinutes: 24 * 60,
|
|
122
128
|
leaseMinutes: 60,
|
|
123
129
|
maxConcurrentLearners: 1,
|
|
124
130
|
applyHighConfidence: false,
|
|
125
|
-
reflectionReview:
|
|
126
|
-
reflectionMinToolCalls:
|
|
131
|
+
reflectionReview: false,
|
|
132
|
+
reflectionMinToolCalls: 12,
|
|
127
133
|
reflectionCooldownMinutes: 24 * 60,
|
|
134
|
+
complexTaskToolCalls: 12,
|
|
128
135
|
},
|
|
129
136
|
balanced: {
|
|
130
137
|
...AUTO_LEARN_DEFAULTS,
|
|
131
|
-
enabled:
|
|
138
|
+
enabled: false,
|
|
132
139
|
longSessionMessages: 64,
|
|
133
140
|
longSessionContextPercent: 85,
|
|
134
141
|
cooldownMinutes: 24 * 60,
|
|
135
142
|
leaseMinutes: 90,
|
|
136
143
|
maxConcurrentLearners: 1,
|
|
137
144
|
applyHighConfidence: false,
|
|
138
|
-
reflectionReview:
|
|
139
|
-
reflectionMinToolCalls:
|
|
145
|
+
reflectionReview: false,
|
|
146
|
+
reflectionMinToolCalls: 12,
|
|
140
147
|
reflectionCooldownMinutes: 24 * 60,
|
|
148
|
+
complexTaskToolCalls: 12,
|
|
141
149
|
},
|
|
142
150
|
full: {
|
|
143
151
|
...AUTO_LEARN_DEFAULTS,
|
|
@@ -149,14 +157,13 @@ const AUTONOMY_AUTO_LEARN_PRESETS = {
|
|
|
149
157
|
maxConcurrentLearners: 1,
|
|
150
158
|
applyHighConfidence: true,
|
|
151
159
|
reflectionReview: true,
|
|
152
|
-
reflectionMinToolCalls:
|
|
160
|
+
reflectionMinToolCalls: 12,
|
|
153
161
|
reflectionCooldownMinutes: 24 * 60,
|
|
162
|
+
complexTaskToolCalls: 12,
|
|
154
163
|
},
|
|
155
164
|
};
|
|
156
165
|
const AUTONOMY_MODES = ["off", "safe", "balanced", "full"];
|
|
157
166
|
const AUTO_LEARN_RESERVATION_MS = 2 * 60 * 1000;
|
|
158
|
-
const AUTO_LEARN_THINKING_LEVEL = "xhigh";
|
|
159
|
-
const AUTO_LEARN_COMPLEX_TASK_TOOL_CALLS = 5;
|
|
160
167
|
export const AUTO_LEARN_HISTORY_RETENTION_MS = 7 * 24 * 60 * 60 * 1000;
|
|
161
168
|
function definedStringSet(values) {
|
|
162
169
|
const set = new Set();
|
|
@@ -434,6 +441,7 @@ export class InteractiveMode {
|
|
|
434
441
|
skillCommands = new Map();
|
|
435
442
|
// Agent subscription unsubscribe function
|
|
436
443
|
unsubscribe;
|
|
444
|
+
unsubscribeExtensionsChanged;
|
|
437
445
|
signalCleanupHandlers = [];
|
|
438
446
|
// Track if editor is in bash mode (text starts with !)
|
|
439
447
|
isBashMode = false;
|
|
@@ -750,6 +758,10 @@ export class InteractiveMode {
|
|
|
750
758
|
this.isInitialized = true;
|
|
751
759
|
// Initialize extensions first so resources are shown before messages
|
|
752
760
|
await this.rebindCurrentSession();
|
|
761
|
+
// Register extensions-changed listener for live reload UI refresh
|
|
762
|
+
this.unsubscribeExtensionsChanged = this.session.onExtensionsChanged(() => {
|
|
763
|
+
this.refreshUIAfterExtensionsChanged();
|
|
764
|
+
});
|
|
753
765
|
// Render initial messages AFTER showing loaded resources
|
|
754
766
|
await this.renderInitialMessages();
|
|
755
767
|
this.renderProjectTrustWarningIfNeeded();
|
|
@@ -2437,6 +2449,12 @@ export class InteractiveMode {
|
|
|
2437
2449
|
await this.handleModelCommand(searchTerm);
|
|
2438
2450
|
return;
|
|
2439
2451
|
}
|
|
2452
|
+
if (text === "/profiles" || text.startsWith("/profiles ")) {
|
|
2453
|
+
const rawProfileName = text.startsWith("/profiles ") ? text.slice(10).trim() : undefined;
|
|
2454
|
+
this.editor.setText("");
|
|
2455
|
+
await this.handleProfilesCommand(rawProfileName?.length ? rawProfileName : undefined);
|
|
2456
|
+
return;
|
|
2457
|
+
}
|
|
2440
2458
|
if (text === "/export" || text.startsWith("/export ")) {
|
|
2441
2459
|
await this.handleExportCommand(text);
|
|
2442
2460
|
this.editor.setText("");
|
|
@@ -4134,6 +4152,8 @@ export class InteractiveMode {
|
|
|
4134
4152
|
reflectionReview: settings.reflectionReview ?? preset.reflectionReview,
|
|
4135
4153
|
reflectionMinToolCalls: settings.reflectionMinToolCalls ?? preset.reflectionMinToolCalls,
|
|
4136
4154
|
reflectionCooldownMinutes: settings.reflectionCooldownMinutes ?? preset.reflectionCooldownMinutes,
|
|
4155
|
+
complexTaskToolCalls: settings.complexTaskToolCalls ?? preset.complexTaskToolCalls,
|
|
4156
|
+
thinkingLevel: settings.thinkingLevel ?? preset.thinkingLevel,
|
|
4137
4157
|
};
|
|
4138
4158
|
}
|
|
4139
4159
|
getAutoLearnTenantKey() {
|
|
@@ -4338,7 +4358,7 @@ export class InteractiveMode {
|
|
|
4338
4358
|
const objective = options.kind === "reflection"
|
|
4339
4359
|
? "review the latest completed turn for durable memory, skill, validation, tooling, and code-baked self-improvement cues, then run one bounded continuous-learning pass if the learning tools are available"
|
|
4340
4360
|
: "run one bounded continuous-learning pass for this Pi tenant";
|
|
4341
|
-
return `You are Pi Auto Learn running as a background learner.\n\nObjective: ${objective}.\nTrigger: ${reason}.\n\n${authorityBlock}\n\nRequired workflow:\n1. Query existing durable memory/rules first when tools allow it. Memory confrontation is mandatory before accepting, merging, upgrading, or rejecting learning candidates.\n2. Run the available Auto Learn tooling, preferably learning_run_auto, with applyHighConfidence=${settings.applyHighConfidence}. Process candidate validation in vectorized chunks/batches; avoid scalar per-candidate memory queries except for final selected writes.\n3. Apply the learning validation tree to each candidate chunk: (a) Why is this good for the user? (b) Is it unique, or similar to existing memory/skills/agents so it should merge or upgrade existing knowledge? (c) Will this make Pi a better agent? Candidates that cannot answer all three are noise.\n4. Hermes-style learning cycle: after a complex task (${
|
|
4361
|
+
return `You are Pi Auto Learn running as a background learner.\n\nObjective: ${objective}.\nTrigger: ${reason}.\n\n${authorityBlock}\n\nRequired workflow:\n1. Query existing durable memory/rules first when tools allow it. Memory confrontation is mandatory before accepting, merging, upgrading, or rejecting learning candidates.\n2. Run the available Auto Learn tooling, preferably learning_run_auto, with applyHighConfidence=${settings.applyHighConfidence}. Process candidate validation in vectorized chunks/batches; avoid scalar per-candidate memory queries except for final selected writes.\n3. Apply the learning validation tree to each candidate chunk: (a) Why is this good for the user? (b) Is it unique, or similar to existing memory/skills/agents so it should merge or upgrade existing knowledge? (c) Will this make Pi a better agent? Candidates that cannot answer all three are noise.\n4. Hermes-style learning cycle: after a complex task (${settings.complexTaskToolCalls}+ tool calls), user correction, repeated steering pattern, non-trivial fix/workaround/debugging path, loaded-skill defect, trigger gap, tool gap, or harness workflow defect, actively create or update durable learning artifacts. Memory stores compact facts/preferences/state; skills/prompts/agents/extensions/source store procedural behavior. When a lesson changes how Pi should act on a future class of task, memory alone is not completion.\n5. Skill update preference order: (1) patch the currently loaded or consulted skill that governed the task; (2) patch an existing class-level umbrella skill/agent/prompt; (3) add a support file under references/, templates/, or scripts/ and add a SKILL.md pointer; (4) create a new class-level umbrella skill only when no existing artifact fits. Never create one-off PR/error/codename/session skills.\n6. Behavioral self-improvement is code-baked by default: prefer the lowest durable executable layer that fixes the behavior — patch an existing skill/prompt/agent/extension/tool, tune an approved setting, or edit the authorized Pi source when source authority is available. Use Automata only for concise facts/evidence pointers that support the baked change.\n7. Do not harden transient or environment-dependent failures into durable behavior: missing binaries, fresh-install package gaps, credentials not configured, path mismatches, one-off task narratives, or negative tool-broken claims should become setup/troubleshooting fixes only when the fix itself is reusable.\n8. Treat the latest-turn digest as current-session evidence only; do not auto-commit one-off cues unless deterministic tooling and memory confrontation corroborate them.\n9. In mode=full, apply safe memory/skill/user-extension/authorized-source improvements under the standing grant above; otherwise keep them proposal-gated.\n10. Never cross hard-stop boundaries from the authority policy.\n11. If the learning tools are unavailable, report BLOCKED with the missing tool names and do not improvise.\n12. Finish with PASS, BLOCKED, or FAIL and concise evidence, including chunk counts, merge/upgrade/code-bake decisions, changed paths/settings, validation, and cleanup/purge status.${reflectionBlock}`;
|
|
4342
4362
|
}
|
|
4343
4363
|
reserveAutoLearnRun(params) {
|
|
4344
4364
|
return this.withAutoLearnStateLock((current) => {
|
|
@@ -4468,7 +4488,7 @@ export class InteractiveMode {
|
|
|
4468
4488
|
const args = buildAutoLearnSpawnArgs(spawnTarget, {
|
|
4469
4489
|
name: `Auto Learn ${runId}`,
|
|
4470
4490
|
modelPattern,
|
|
4471
|
-
thinkingLevel:
|
|
4491
|
+
thinkingLevel: settings.thinkingLevel ?? "low",
|
|
4472
4492
|
sessionDir,
|
|
4473
4493
|
sessionId,
|
|
4474
4494
|
promptPath,
|
|
@@ -4630,7 +4650,6 @@ export class InteractiveMode {
|
|
|
4630
4650
|
}
|
|
4631
4651
|
evaluateAutonomyReview(messages) {
|
|
4632
4652
|
const settings = this.getEffectiveAutoLearnSettings();
|
|
4633
|
-
const autonomy = this.settingsManager.getAutonomySettings();
|
|
4634
4653
|
const state = this.withAutoLearnStateLock((current) => {
|
|
4635
4654
|
const pruned = this.pruneAutoLearnHistoryFromState(current);
|
|
4636
4655
|
return { result: pruned, next: pruned };
|
|
@@ -4651,7 +4670,8 @@ export class InteractiveMode {
|
|
|
4651
4670
|
const correctionSignal = /\b(next time|for future|from now on|remember this|don't|do not|avoid|instead|you should|should have|you forgot|you missed|not what i asked|wrong again)\b/i.test(userText);
|
|
4652
4671
|
const behavioralSelfImprovementSignal = /\b(harness|pi|agent|autonomy|autonomous|self[- ]?improv(?:e|ement|ing)?|steer(?:ing)?|trigger(?:s)?|skill(?:s)?|code[- ]?bak(?:e|ed)|bake(?:d)? into code|not (?:automata|memory)|reference agent|hermes)\b/i.test(userText) &&
|
|
4653
4672
|
/\b(improve|automatic(?:ally)?|autonomous|trigger|fire|skill|steer|self[- ]?improv(?:e|ement|ing)?|code[- ]?bak(?:e|ed)|bake(?:d)?|too much|less)\b/i.test(userText);
|
|
4654
|
-
const
|
|
4673
|
+
const complexTaskThreshold = Math.max(1, settings.complexTaskToolCalls ?? 12);
|
|
4674
|
+
const complexTaskSignal = toolCalls >= complexTaskThreshold;
|
|
4655
4675
|
const bypassCooldown = correctionSignal || behavioralSelfImprovementSignal || complexTaskSignal;
|
|
4656
4676
|
const base = { messageCount, contextPercent, cooldownRemainingMs, runningCount, toolCalls };
|
|
4657
4677
|
if (!settings.enabled)
|
|
@@ -4690,19 +4710,12 @@ export class InteractiveMode {
|
|
|
4690
4710
|
return {
|
|
4691
4711
|
...base,
|
|
4692
4712
|
shouldRun: true,
|
|
4693
|
-
reason: `reflection complex task learning signal (${toolCalls}/${
|
|
4713
|
+
reason: `reflection complex task learning signal (${toolCalls}/${complexTaskThreshold} tool calls)`,
|
|
4694
4714
|
digest: this.buildAutonomyReviewDigest(messages),
|
|
4695
4715
|
bypassCooldown: true,
|
|
4696
4716
|
};
|
|
4697
4717
|
}
|
|
4698
|
-
|
|
4699
|
-
return {
|
|
4700
|
-
...base,
|
|
4701
|
-
shouldRun: true,
|
|
4702
|
-
reason: "full autonomy post-turn review",
|
|
4703
|
-
digest: this.buildAutonomyReviewDigest(messages),
|
|
4704
|
-
};
|
|
4705
|
-
}
|
|
4718
|
+
// Full autonomy expands allowed action scope for triggered reviews; it does not make every turn a review trigger.
|
|
4706
4719
|
if (toolCalls >= settings.reflectionMinToolCalls) {
|
|
4707
4720
|
return {
|
|
4708
4721
|
...base,
|
|
@@ -4859,6 +4872,21 @@ export class InteractiveMode {
|
|
|
4859
4872
|
showSettingsSelector() {
|
|
4860
4873
|
this.showSelector((done) => {
|
|
4861
4874
|
const projectSettings = this.settingsManager.getProjectSettings();
|
|
4875
|
+
const profileOptions = [
|
|
4876
|
+
{
|
|
4877
|
+
value: "(none)",
|
|
4878
|
+
label: "(none)",
|
|
4879
|
+
description: "Use configured profile selection (session default)",
|
|
4880
|
+
},
|
|
4881
|
+
...this.settingsManager
|
|
4882
|
+
.getProfileRegistry()
|
|
4883
|
+
.listProfiles()
|
|
4884
|
+
.map((profile) => ({
|
|
4885
|
+
value: profile.name,
|
|
4886
|
+
label: profile.name,
|
|
4887
|
+
description: profile.description ?? profile.source,
|
|
4888
|
+
})),
|
|
4889
|
+
];
|
|
4862
4890
|
const selector = new SettingsSelectorComponent({
|
|
4863
4891
|
autoCompact: this.session.autoCompactionEnabled,
|
|
4864
4892
|
showImages: this.settingsManager.getShowImages(),
|
|
@@ -4896,6 +4924,8 @@ export class InteractiveMode {
|
|
|
4896
4924
|
currentModelPattern: this.session.model
|
|
4897
4925
|
? `${this.session.model.provider}/${this.session.model.id}`
|
|
4898
4926
|
: undefined,
|
|
4927
|
+
activeProfileName: this.settingsManager.getActiveResourceProfileNames()[0],
|
|
4928
|
+
profileOptions,
|
|
4899
4929
|
}, {
|
|
4900
4930
|
onAutoCompactChange: (enabled) => {
|
|
4901
4931
|
this.session.setAutoCompactionEnabled(enabled);
|
|
@@ -5038,6 +5068,26 @@ export class InteractiveMode {
|
|
|
5038
5068
|
this.updateAutoLearnFooter();
|
|
5039
5069
|
this.showStatus(`Auto Learn settings saved to ${scope}. Use /auto-learn status or /auto-learn run.`);
|
|
5040
5070
|
},
|
|
5071
|
+
onProfileChange: (profile) => {
|
|
5072
|
+
done();
|
|
5073
|
+
void this.applyProfile(profile);
|
|
5074
|
+
},
|
|
5075
|
+
onProfileCreate: () => {
|
|
5076
|
+
done();
|
|
5077
|
+
void this.createProfileFlow();
|
|
5078
|
+
},
|
|
5079
|
+
onProfileEdit: (profileName) => {
|
|
5080
|
+
done();
|
|
5081
|
+
void this.openProfileResourceEditor(profileName);
|
|
5082
|
+
},
|
|
5083
|
+
onProfilePersistActive: (scope) => {
|
|
5084
|
+
done();
|
|
5085
|
+
this.persistActiveProfile(scope);
|
|
5086
|
+
},
|
|
5087
|
+
onProfileDelete: (profileName) => {
|
|
5088
|
+
done();
|
|
5089
|
+
this.deleteProfileFromSource(profileName);
|
|
5090
|
+
},
|
|
5041
5091
|
onCancel: () => {
|
|
5042
5092
|
done();
|
|
5043
5093
|
this.ui.requestRender();
|
|
@@ -5046,6 +5096,298 @@ export class InteractiveMode {
|
|
|
5046
5096
|
return { component: selector, focus: selector.getSettingsList() };
|
|
5047
5097
|
});
|
|
5048
5098
|
}
|
|
5099
|
+
async handleProfilesCommand(profileName) {
|
|
5100
|
+
if (profileName) {
|
|
5101
|
+
await this.applyProfile(profileName);
|
|
5102
|
+
return;
|
|
5103
|
+
}
|
|
5104
|
+
const registry = this.settingsManager.getProfileRegistry();
|
|
5105
|
+
const profiles = registry.listProfiles();
|
|
5106
|
+
if (profiles.length === 0) {
|
|
5107
|
+
this.showWarning("No profiles found. Add resourceProfiles to settings or JSON files under ~/.pi/agent/profiles/.");
|
|
5108
|
+
return;
|
|
5109
|
+
}
|
|
5110
|
+
this.showSelector((done) => {
|
|
5111
|
+
const selector = new ProfileSelectorComponent(profiles, this.settingsManager.getActiveResourceProfileNames(), (profile) => {
|
|
5112
|
+
done();
|
|
5113
|
+
void this.applyProfile(profile);
|
|
5114
|
+
}, () => {
|
|
5115
|
+
done();
|
|
5116
|
+
this.ui.requestRender();
|
|
5117
|
+
});
|
|
5118
|
+
return { component: selector, focus: selector.getSelectList() };
|
|
5119
|
+
});
|
|
5120
|
+
}
|
|
5121
|
+
async applyProfile(profileName) {
|
|
5122
|
+
const normalizedName = profileName.trim();
|
|
5123
|
+
const normalizedLower = normalizedName.toLowerCase();
|
|
5124
|
+
if (normalizedName.length === 0 || normalizedLower === "none" || normalizedLower === "(none)") {
|
|
5125
|
+
try {
|
|
5126
|
+
this.settingsManager.setRuntimeResourceProfiles([]);
|
|
5127
|
+
this.session.sessionManager.appendCustomEntry("pi.activeResourceProfiles", {
|
|
5128
|
+
profiles: [],
|
|
5129
|
+
});
|
|
5130
|
+
await this.handleReloadCommand();
|
|
5131
|
+
const activeProfileName = this.settingsManager.getActiveResourceProfileNames()[0] ?? "(none)";
|
|
5132
|
+
this.footerDataProvider.setExtensionStatus("profile", activeProfileName);
|
|
5133
|
+
this.footer.invalidate();
|
|
5134
|
+
this.updateEditorBorderColor();
|
|
5135
|
+
this.showStatus(`Profile: ${activeProfileName}`);
|
|
5136
|
+
}
|
|
5137
|
+
catch (error) {
|
|
5138
|
+
this.showError(error instanceof Error ? error.message : String(error));
|
|
5139
|
+
}
|
|
5140
|
+
return;
|
|
5141
|
+
}
|
|
5142
|
+
const registry = this.settingsManager.getProfileRegistry();
|
|
5143
|
+
const profile = normalizedName.startsWith("./") || normalizedName.startsWith("../")
|
|
5144
|
+
? registry.resolveProfileRef(normalizedName, this.sessionManager.getCwd())
|
|
5145
|
+
: registry.getProfile(normalizedName);
|
|
5146
|
+
if (!profile) {
|
|
5147
|
+
this.showError(`Profile not found: ${profileName}`);
|
|
5148
|
+
return;
|
|
5149
|
+
}
|
|
5150
|
+
try {
|
|
5151
|
+
let appliedModel;
|
|
5152
|
+
if (profile.model) {
|
|
5153
|
+
this.session.modelRegistry.refresh();
|
|
5154
|
+
const resolved = resolveCliModel({ cliModel: profile.model, modelRegistry: this.session.modelRegistry });
|
|
5155
|
+
if (resolved.error) {
|
|
5156
|
+
this.showError(resolved.error);
|
|
5157
|
+
return;
|
|
5158
|
+
}
|
|
5159
|
+
if (resolved.warning) {
|
|
5160
|
+
this.showWarning(resolved.warning);
|
|
5161
|
+
}
|
|
5162
|
+
if (resolved.model) {
|
|
5163
|
+
await this.session.setModel(resolved.model, { persistSettings: false });
|
|
5164
|
+
appliedModel = resolved.model;
|
|
5165
|
+
}
|
|
5166
|
+
if (resolved.thinkingLevel && !profile.thinking) {
|
|
5167
|
+
this.session.setThinkingLevel(resolved.thinkingLevel, { persistSettings: false });
|
|
5168
|
+
}
|
|
5169
|
+
}
|
|
5170
|
+
if (profile.thinking) {
|
|
5171
|
+
this.session.setThinkingLevel(profile.thinking, { persistSettings: false });
|
|
5172
|
+
}
|
|
5173
|
+
this.settingsManager.setRuntimeResourceProfiles([profile.name]);
|
|
5174
|
+
this.session.sessionManager.appendCustomEntry("pi.activeResourceProfiles", {
|
|
5175
|
+
profiles: [profile.name],
|
|
5176
|
+
});
|
|
5177
|
+
await this.handleReloadCommand();
|
|
5178
|
+
this.footerDataProvider.setExtensionStatus("profile", profile.name);
|
|
5179
|
+
this.footer.invalidate();
|
|
5180
|
+
this.updateEditorBorderColor();
|
|
5181
|
+
this.showStatus(`Profile: ${profile.name}`);
|
|
5182
|
+
if (appliedModel) {
|
|
5183
|
+
void this.maybeWarnAboutAnthropicSubscriptionAuth(appliedModel);
|
|
5184
|
+
this.checkDaxnutsEasterEgg(appliedModel);
|
|
5185
|
+
}
|
|
5186
|
+
}
|
|
5187
|
+
catch (error) {
|
|
5188
|
+
this.showError(error instanceof Error ? error.message : String(error));
|
|
5189
|
+
}
|
|
5190
|
+
}
|
|
5191
|
+
async getProfileResourceKinds() {
|
|
5192
|
+
const loader = this.session.resourceLoader;
|
|
5193
|
+
const base = (p) => p.split(/[\\/]/).pop() ?? p;
|
|
5194
|
+
// Get all discoverable extension paths (enabled and disabled) for profile filtering
|
|
5195
|
+
const allDiscoverableExtensions = await loader.getDiscoverableExtensionPaths();
|
|
5196
|
+
return [
|
|
5197
|
+
{ kind: "tools", label: "Tools", allIds: [...allToolNames] },
|
|
5198
|
+
{ kind: "skills", label: "Skills", allIds: loader.getSkills().skills.map((s) => s.name) },
|
|
5199
|
+
{
|
|
5200
|
+
kind: "extensions",
|
|
5201
|
+
label: "Extensions",
|
|
5202
|
+
allIds: allDiscoverableExtensions.map((e) => base(e)),
|
|
5203
|
+
},
|
|
5204
|
+
{ kind: "agents", label: "Agents", allIds: loader.getAgentsFiles().agentsFiles.map((f) => base(f.path)) },
|
|
5205
|
+
{ kind: "prompts", label: "Prompts", allIds: loader.getPrompts().prompts.map((p) => p.name) },
|
|
5206
|
+
{ kind: "themes", label: "Themes", allIds: getAvailableThemes() },
|
|
5207
|
+
];
|
|
5208
|
+
}
|
|
5209
|
+
/** Map where a profile currently lives to the scope we should write it back to. */
|
|
5210
|
+
scopeForProfileSource(source) {
|
|
5211
|
+
switch (source) {
|
|
5212
|
+
case "profile-file":
|
|
5213
|
+
return "reusable-file";
|
|
5214
|
+
case "directory-overlay":
|
|
5215
|
+
case "embedded":
|
|
5216
|
+
return "directory";
|
|
5217
|
+
case "inline":
|
|
5218
|
+
return "session";
|
|
5219
|
+
default:
|
|
5220
|
+
return "global"; // "settings"
|
|
5221
|
+
}
|
|
5222
|
+
}
|
|
5223
|
+
async refreshAfterProfileMutation(profileName) {
|
|
5224
|
+
if (this.settingsManager.getActiveResourceProfileNames().includes(profileName)) {
|
|
5225
|
+
await this.handleReloadCommand();
|
|
5226
|
+
const active = this.settingsManager.getActiveResourceProfileNames()[0] ?? "(none)";
|
|
5227
|
+
this.footerDataProvider.setExtensionStatus("profile", active);
|
|
5228
|
+
this.footer.invalidate();
|
|
5229
|
+
this.updateEditorBorderColor();
|
|
5230
|
+
}
|
|
5231
|
+
}
|
|
5232
|
+
async createProfileFlow() {
|
|
5233
|
+
const name = await new Promise((resolve) => {
|
|
5234
|
+
this.showSelector((done) => {
|
|
5235
|
+
const input = new ExtensionInputComponent("Create Profile", "Enter profile name", (value) => {
|
|
5236
|
+
done();
|
|
5237
|
+
resolve(value);
|
|
5238
|
+
}, () => {
|
|
5239
|
+
done();
|
|
5240
|
+
resolve(undefined);
|
|
5241
|
+
}, { tui: this.ui });
|
|
5242
|
+
return { component: input, focus: input };
|
|
5243
|
+
});
|
|
5244
|
+
});
|
|
5245
|
+
if (name === undefined) {
|
|
5246
|
+
this.ui.requestRender();
|
|
5247
|
+
return;
|
|
5248
|
+
}
|
|
5249
|
+
const trimmed = name.trim();
|
|
5250
|
+
if (!trimmed) {
|
|
5251
|
+
this.showError("Profile name cannot be empty");
|
|
5252
|
+
return this.createProfileFlow();
|
|
5253
|
+
}
|
|
5254
|
+
// Validate name rules using validateSkillName
|
|
5255
|
+
const errors = validateSkillName(trimmed);
|
|
5256
|
+
if (errors.length > 0) {
|
|
5257
|
+
this.showError(`Invalid profile name: ${errors.join(", ")}`);
|
|
5258
|
+
return this.createProfileFlow();
|
|
5259
|
+
}
|
|
5260
|
+
// Collision check
|
|
5261
|
+
const existing = this.settingsManager.getProfileRegistry().getProfile(trimmed);
|
|
5262
|
+
if (existing) {
|
|
5263
|
+
this.showError(`Profile "${trimmed}" already exists`);
|
|
5264
|
+
return this.createProfileFlow();
|
|
5265
|
+
}
|
|
5266
|
+
// Open the resource editor on the NEW profile
|
|
5267
|
+
void this.openNewProfileEditor(trimmed);
|
|
5268
|
+
}
|
|
5269
|
+
async openNewProfileEditor(profileName) {
|
|
5270
|
+
const scope = "reusable-file";
|
|
5271
|
+
const kinds = await this.getProfileResourceKinds();
|
|
5272
|
+
this.showSelector((done) => {
|
|
5273
|
+
const editor = new ProfileResourceEditorComponent({
|
|
5274
|
+
profileName,
|
|
5275
|
+
initialResources: {},
|
|
5276
|
+
kinds,
|
|
5277
|
+
onSave: (resources) => {
|
|
5278
|
+
done();
|
|
5279
|
+
try {
|
|
5280
|
+
this.settingsManager.setProfileDefinition(profileName, {
|
|
5281
|
+
name: profileName,
|
|
5282
|
+
resources,
|
|
5283
|
+
}, scope);
|
|
5284
|
+
this.showStatus(`Saved profile "${profileName}" to ${scope}.`);
|
|
5285
|
+
this.ui.requestRender();
|
|
5286
|
+
}
|
|
5287
|
+
catch (error) {
|
|
5288
|
+
this.showError(error instanceof Error ? error.message : String(error));
|
|
5289
|
+
}
|
|
5290
|
+
},
|
|
5291
|
+
onCancel: () => {
|
|
5292
|
+
done();
|
|
5293
|
+
this.ui.requestRender();
|
|
5294
|
+
},
|
|
5295
|
+
});
|
|
5296
|
+
return { component: editor, focus: editor };
|
|
5297
|
+
});
|
|
5298
|
+
}
|
|
5299
|
+
async openProfileResourceEditor(profileName) {
|
|
5300
|
+
const profile = this.settingsManager.getProfileRegistry().getProfile(profileName);
|
|
5301
|
+
if (!profile) {
|
|
5302
|
+
this.showError(`Profile not found: ${profileName}`);
|
|
5303
|
+
return;
|
|
5304
|
+
}
|
|
5305
|
+
const scope = this.scopeForProfileSource(profile.source);
|
|
5306
|
+
const kinds = await this.getProfileResourceKinds();
|
|
5307
|
+
const isActiveProfile = this.settingsManager.getActiveResourceProfileNames().includes(profile.name);
|
|
5308
|
+
const originalResources = profile.resources;
|
|
5309
|
+
this.showSelector((done) => {
|
|
5310
|
+
const editor = new ProfileResourceEditorComponent({
|
|
5311
|
+
profileName: profile.name,
|
|
5312
|
+
initialResources: profile.resources,
|
|
5313
|
+
kinds,
|
|
5314
|
+
onSave: (resources) => {
|
|
5315
|
+
done();
|
|
5316
|
+
try {
|
|
5317
|
+
this.settingsManager.setProfileDefinition(profile.name, {
|
|
5318
|
+
name: profile.name,
|
|
5319
|
+
description: profile.description,
|
|
5320
|
+
model: profile.model,
|
|
5321
|
+
thinking: profile.thinking,
|
|
5322
|
+
resources,
|
|
5323
|
+
}, scope);
|
|
5324
|
+
this.showStatus(`Saved profile "${profile.name}" to ${scope}.`);
|
|
5325
|
+
// For active profiles, detect if only extensions changed to avoid full reload
|
|
5326
|
+
if (isActiveProfile) {
|
|
5327
|
+
const extensionsChanged = originalResources.extensions !== resources.extensions;
|
|
5328
|
+
const otherResourcesChanged = originalResources.tools !== resources.tools ||
|
|
5329
|
+
originalResources.skills !== resources.skills ||
|
|
5330
|
+
originalResources.agents !== resources.agents ||
|
|
5331
|
+
originalResources.prompts !== resources.prompts ||
|
|
5332
|
+
originalResources.themes !== resources.themes;
|
|
5333
|
+
if (extensionsChanged && !otherResourcesChanged) {
|
|
5334
|
+
// Only extensions changed: use live reconciliation
|
|
5335
|
+
void this.reconcileExtensionsAndRefreshUI(profile.name);
|
|
5336
|
+
}
|
|
5337
|
+
else {
|
|
5338
|
+
// Other resources changed or mixed: use full reload
|
|
5339
|
+
void this.refreshAfterProfileMutation(profile.name);
|
|
5340
|
+
}
|
|
5341
|
+
}
|
|
5342
|
+
// Non-active profiles don't need refresh
|
|
5343
|
+
}
|
|
5344
|
+
catch (error) {
|
|
5345
|
+
this.showError(error instanceof Error ? error.message : String(error));
|
|
5346
|
+
}
|
|
5347
|
+
},
|
|
5348
|
+
onCancel: () => {
|
|
5349
|
+
done();
|
|
5350
|
+
this.ui.requestRender();
|
|
5351
|
+
},
|
|
5352
|
+
});
|
|
5353
|
+
return { component: editor, focus: editor };
|
|
5354
|
+
});
|
|
5355
|
+
}
|
|
5356
|
+
persistActiveProfile(scope) {
|
|
5357
|
+
const active = this.settingsManager.getActiveResourceProfileNames()[0];
|
|
5358
|
+
if (!active) {
|
|
5359
|
+
this.showError("No active profile to persist. Select one with /profiles first.");
|
|
5360
|
+
return;
|
|
5361
|
+
}
|
|
5362
|
+
try {
|
|
5363
|
+
if (scope === "session") {
|
|
5364
|
+
this.settingsManager.setRuntimeResourceProfiles([active]);
|
|
5365
|
+
}
|
|
5366
|
+
else {
|
|
5367
|
+
this.settingsManager.setActiveProfile(active, scope);
|
|
5368
|
+
}
|
|
5369
|
+
this.showStatus(`Active profile "${active}" persisted to ${scope}.`);
|
|
5370
|
+
}
|
|
5371
|
+
catch (error) {
|
|
5372
|
+
this.showError(error instanceof Error ? error.message : String(error));
|
|
5373
|
+
}
|
|
5374
|
+
}
|
|
5375
|
+
deleteProfileFromSource(profileName) {
|
|
5376
|
+
const profile = this.settingsManager.getProfileRegistry().getProfile(profileName);
|
|
5377
|
+
if (!profile) {
|
|
5378
|
+
this.showError(`Profile not found: ${profileName}`);
|
|
5379
|
+
return;
|
|
5380
|
+
}
|
|
5381
|
+
const scope = this.scopeForProfileSource(profile.source);
|
|
5382
|
+
try {
|
|
5383
|
+
this.settingsManager.deleteProfile(profileName, scope);
|
|
5384
|
+
this.showStatus(`Deleted profile "${profileName}" from ${scope}.`);
|
|
5385
|
+
void this.refreshAfterProfileMutation(profileName);
|
|
5386
|
+
}
|
|
5387
|
+
catch (error) {
|
|
5388
|
+
this.showError(error instanceof Error ? error.message : String(error));
|
|
5389
|
+
}
|
|
5390
|
+
}
|
|
5049
5391
|
async handleModelCommand(searchTerm) {
|
|
5050
5392
|
if (!searchTerm) {
|
|
5051
5393
|
await this.showModelSelector();
|
|
@@ -5916,6 +6258,71 @@ export class InteractiveMode {
|
|
|
5916
6258
|
this.showError(`Reload failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
5917
6259
|
}
|
|
5918
6260
|
}
|
|
6261
|
+
/**
|
|
6262
|
+
* Refresh UI after extensions are loaded/unloaded live.
|
|
6263
|
+
* Performs the same refresh calls as handleReloadCommand but without the full reload.
|
|
6264
|
+
*/
|
|
6265
|
+
async refreshUIAfterExtensionsChanged() {
|
|
6266
|
+
try {
|
|
6267
|
+
// Refresh keybindings and autocomplete
|
|
6268
|
+
this.keybindings.reload();
|
|
6269
|
+
this.setupAutocompleteProvider();
|
|
6270
|
+
// Refresh themes
|
|
6271
|
+
const activeHeader = this.customHeader ?? this.builtInHeader;
|
|
6272
|
+
if (isExpandable(activeHeader)) {
|
|
6273
|
+
activeHeader.setExpanded(this.toolOutputExpanded);
|
|
6274
|
+
}
|
|
6275
|
+
setRegisteredThemes(this.session.resourceLoader.getThemes().themes);
|
|
6276
|
+
this.hideThinkingBlock = this.settingsManager.getHideThinkingBlock();
|
|
6277
|
+
const themeName = this.settingsManager.getTheme();
|
|
6278
|
+
const themeResult = themeName ? setTheme(themeName, true) : { success: true };
|
|
6279
|
+
if (!themeResult.success) {
|
|
6280
|
+
this.showError(`Failed to load theme "${themeName}": ${themeResult.error}\nFell back to dark theme.`);
|
|
6281
|
+
}
|
|
6282
|
+
// Refresh editor settings
|
|
6283
|
+
const editorPaddingX = this.settingsManager.getEditorPaddingX();
|
|
6284
|
+
const autocompleteMaxVisible = this.settingsManager.getAutocompleteMaxVisible();
|
|
6285
|
+
this.defaultEditor.setPaddingX(editorPaddingX);
|
|
6286
|
+
this.defaultEditor.setAutocompleteMaxVisible(autocompleteMaxVisible);
|
|
6287
|
+
if (this.editor !== this.defaultEditor) {
|
|
6288
|
+
this.editor.setPaddingX?.(editorPaddingX);
|
|
6289
|
+
this.editor.setAutocompleteMaxVisible?.(autocompleteMaxVisible);
|
|
6290
|
+
}
|
|
6291
|
+
// Refresh extension shortcuts
|
|
6292
|
+
const runner = this.session.extensionRunner;
|
|
6293
|
+
this.setupExtensionShortcuts(runner);
|
|
6294
|
+
// Refresh chat and UI
|
|
6295
|
+
await this.rebuildChatFromMessages();
|
|
6296
|
+
this.footer.invalidate();
|
|
6297
|
+
this.ui.requestRender();
|
|
6298
|
+
}
|
|
6299
|
+
catch (error) {
|
|
6300
|
+
this.showError(`Extension refresh failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
6301
|
+
}
|
|
6302
|
+
}
|
|
6303
|
+
/**
|
|
6304
|
+
* Reconcile extensions for the active profile and refresh UI.
|
|
6305
|
+
* Used when only extensions change in the active profile to avoid full reload.
|
|
6306
|
+
*/
|
|
6307
|
+
async reconcileExtensionsAndRefreshUI(profileName) {
|
|
6308
|
+
try {
|
|
6309
|
+
await this.session.reconcileLoadedExtensions();
|
|
6310
|
+
const active = this.settingsManager.getActiveResourceProfileNames()[0] ?? "(none)";
|
|
6311
|
+
this.footerDataProvider.setExtensionStatus("profile", active);
|
|
6312
|
+
this.footer.invalidate();
|
|
6313
|
+
this.updateEditorBorderColor();
|
|
6314
|
+
}
|
|
6315
|
+
catch (error) {
|
|
6316
|
+
// On error, fall back to full reload
|
|
6317
|
+
try {
|
|
6318
|
+
await this.refreshAfterProfileMutation(profileName);
|
|
6319
|
+
}
|
|
6320
|
+
catch {
|
|
6321
|
+
// If full reload also fails, show error
|
|
6322
|
+
this.showError(`Failed to reconcile extensions: ${error instanceof Error ? error.message : String(error)}`);
|
|
6323
|
+
}
|
|
6324
|
+
}
|
|
6325
|
+
}
|
|
5919
6326
|
async handleExportCommand(text) {
|
|
5920
6327
|
const outputPath = this.getPathCommandArgument(text, "/export");
|
|
5921
6328
|
try {
|
|
@@ -6466,6 +6873,9 @@ export class InteractiveMode {
|
|
|
6466
6873
|
if (this.unsubscribe) {
|
|
6467
6874
|
this.unsubscribe();
|
|
6468
6875
|
}
|
|
6876
|
+
if (this.unsubscribeExtensionsChanged) {
|
|
6877
|
+
this.unsubscribeExtensionsChanged();
|
|
6878
|
+
}
|
|
6469
6879
|
if (this.isInitialized) {
|
|
6470
6880
|
this.ui.stop();
|
|
6471
6881
|
this.isInitialized = false;
|