@caupulican/pi-adaptative 0.80.46 → 0.80.48
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 +16 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +1 -0
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +5 -0
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +1 -0
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +3 -0
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/profile-resource-selection.d.ts +9 -0
- package/dist/core/profile-resource-selection.d.ts.map +1 -1
- package/dist/core/profile-resource-selection.js +49 -0
- package/dist/core/profile-resource-selection.js.map +1 -1
- package/dist/core/settings-manager.d.ts +1 -1
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +12 -0
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/modes/interactive/components/profile-resource-editor.d.ts +20 -6
- package/dist/modes/interactive/components/profile-resource-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/profile-resource-editor.js +176 -23
- package/dist/modes/interactive/components/profile-resource-editor.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts +1 -7
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +41 -108
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +16 -2
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +687 -95
- package/dist/modes/interactive/interactive-mode.js.map +1 -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/npm-shrinkwrap.json +12 -12
- package/package.json +4 -4
|
@@ -32,6 +32,7 @@ import { hasProjectTrustInputs, ProjectTrustStore } from "../../core/trust-manag
|
|
|
32
32
|
import { getChangelogPath, getNewEntries, parseChangelog } from "../../utils/changelog.js";
|
|
33
33
|
import { copyToClipboard } from "../../utils/clipboard.js";
|
|
34
34
|
import { readClipboardImage } from "../../utils/clipboard-image.js";
|
|
35
|
+
import { parseFrontmatter } from "../../utils/frontmatter.js";
|
|
35
36
|
import { parseGitUrl } from "../../utils/git.js";
|
|
36
37
|
import { getCwdRelativePath, resolvePath } from "../../utils/paths.js";
|
|
37
38
|
import { getPiUserAgent } from "../../utils/pi-user-agent.js";
|
|
@@ -2541,6 +2542,24 @@ export class InteractiveMode {
|
|
|
2541
2542
|
await this.handleReloadCommand();
|
|
2542
2543
|
return;
|
|
2543
2544
|
}
|
|
2545
|
+
if (text === "/install-resources" || text.startsWith("/install-resources ")) {
|
|
2546
|
+
const args = text.slice("/install-resources".length).trim();
|
|
2547
|
+
this.editor.setText("");
|
|
2548
|
+
await this.handleInstallResourcesCommand(args);
|
|
2549
|
+
return;
|
|
2550
|
+
}
|
|
2551
|
+
if (text === "/config-backup" || text.startsWith("/config-backup ")) {
|
|
2552
|
+
const file = text.slice("/config-backup".length).trim() || undefined;
|
|
2553
|
+
this.editor.setText("");
|
|
2554
|
+
await this.handleConfigBackupCommand(file);
|
|
2555
|
+
return;
|
|
2556
|
+
}
|
|
2557
|
+
if (text === "/config-restore" || text.startsWith("/config-restore ")) {
|
|
2558
|
+
const file = text.slice("/config-restore".length).trim();
|
|
2559
|
+
this.editor.setText("");
|
|
2560
|
+
await this.handleConfigRestoreCommand(file);
|
|
2561
|
+
return;
|
|
2562
|
+
}
|
|
2544
2563
|
if (text === "/debug") {
|
|
2545
2564
|
this.handleDebugCommand();
|
|
2546
2565
|
this.editor.setText("");
|
|
@@ -5070,40 +5089,462 @@ export class InteractiveMode {
|
|
|
5070
5089
|
this.updateAutoLearnFooter();
|
|
5071
5090
|
this.showStatus(`Auto Learn settings saved to ${scope}. Use /auto-learn status or /auto-learn run.`);
|
|
5072
5091
|
},
|
|
5073
|
-
|
|
5092
|
+
onResourcesHubAction: (action) => {
|
|
5074
5093
|
done();
|
|
5075
|
-
void this.
|
|
5094
|
+
void this.handleResourcesHubAction(action);
|
|
5076
5095
|
},
|
|
5077
|
-
|
|
5096
|
+
onCancel: () => {
|
|
5078
5097
|
done();
|
|
5079
|
-
|
|
5098
|
+
this.ui.requestRender();
|
|
5080
5099
|
},
|
|
5081
|
-
|
|
5100
|
+
});
|
|
5101
|
+
return { component: selector, focus: selector.getSettingsList() };
|
|
5102
|
+
});
|
|
5103
|
+
}
|
|
5104
|
+
async handleResourcesHubAction(action) {
|
|
5105
|
+
switch (action) {
|
|
5106
|
+
case "nudge-add-source":
|
|
5107
|
+
void this.addExternalResourceRootFlow().then(() => {
|
|
5108
|
+
void this.showSettingsSelector();
|
|
5109
|
+
});
|
|
5110
|
+
break;
|
|
5111
|
+
case "active-profile":
|
|
5112
|
+
void this.openActiveProfileSelector();
|
|
5113
|
+
break;
|
|
5114
|
+
case "manage-library":
|
|
5115
|
+
void this.openLibraryManagerFlow();
|
|
5116
|
+
break;
|
|
5117
|
+
case "manage-profiles":
|
|
5118
|
+
void this.openManageProfilesFlow();
|
|
5119
|
+
break;
|
|
5120
|
+
case "sources":
|
|
5121
|
+
void this.openSourcesManagerFlow();
|
|
5122
|
+
break;
|
|
5123
|
+
}
|
|
5124
|
+
}
|
|
5125
|
+
async openActiveProfileSelector() {
|
|
5126
|
+
const registry = this.settingsManager.getProfileRegistry();
|
|
5127
|
+
const profiles = registry.listProfiles();
|
|
5128
|
+
const activeNames = this.settingsManager.getActiveResourceProfileNames();
|
|
5129
|
+
const options = [
|
|
5130
|
+
{ value: "(none)", label: "(none)", description: "No active profile (all resources enabled)" },
|
|
5131
|
+
...profiles.map((p) => ({
|
|
5132
|
+
value: p.name,
|
|
5133
|
+
label: p.name,
|
|
5134
|
+
description: p.description || p.source,
|
|
5135
|
+
})),
|
|
5136
|
+
];
|
|
5137
|
+
this.showSelector((done) => {
|
|
5138
|
+
const selector = new SelectSubmenu("Profile / Situation", "Select the active runtime profile for this session. This is session-only unless saved elsewhere.", options, activeNames[0] || "(none)", (value) => {
|
|
5139
|
+
done();
|
|
5140
|
+
void this.applyProfile(value === "(none)" ? "" : value).then(() => {
|
|
5141
|
+
void this.showSettingsSelector();
|
|
5142
|
+
});
|
|
5143
|
+
}, () => {
|
|
5144
|
+
done();
|
|
5145
|
+
void this.showSettingsSelector();
|
|
5146
|
+
});
|
|
5147
|
+
return { component: selector, focus: selector.getSelectList() };
|
|
5148
|
+
});
|
|
5149
|
+
}
|
|
5150
|
+
async openManageProfilesFlow() {
|
|
5151
|
+
const registry = this.settingsManager.getProfileRegistry();
|
|
5152
|
+
const profiles = registry.listProfiles();
|
|
5153
|
+
const editableProfiles = profiles.map((p) => ({
|
|
5154
|
+
value: p.name,
|
|
5155
|
+
label: p.name,
|
|
5156
|
+
description: p.description || p.source,
|
|
5157
|
+
}));
|
|
5158
|
+
const options = [
|
|
5159
|
+
{ value: "create", label: "+ Create profile...", description: "Create a new resource profile definition." },
|
|
5160
|
+
];
|
|
5161
|
+
if (this.settingsManager.getActiveResourceProfileNames().length > 0) {
|
|
5162
|
+
options.push({
|
|
5163
|
+
value: "persist",
|
|
5164
|
+
label: "Persist active profile to...",
|
|
5165
|
+
description: "Save the current active-profile selection so it survives restart.",
|
|
5166
|
+
});
|
|
5167
|
+
}
|
|
5168
|
+
if (editableProfiles.length > 0) {
|
|
5169
|
+
options.push({
|
|
5170
|
+
value: "delete",
|
|
5171
|
+
label: "Delete profile...",
|
|
5172
|
+
description: "Remove a profile definition from where it is stored.",
|
|
5173
|
+
});
|
|
5174
|
+
}
|
|
5175
|
+
this.showSelector((done) => {
|
|
5176
|
+
const selector = new SelectSubmenu("Manage Profiles", "Create, delete, or persist profile definitions.", options, "", (value) => {
|
|
5177
|
+
done();
|
|
5178
|
+
if (value === "create") {
|
|
5179
|
+
void this.createProfileFlow().then(() => {
|
|
5180
|
+
void this.showSettingsSelector();
|
|
5181
|
+
});
|
|
5182
|
+
}
|
|
5183
|
+
else if (value === "persist") {
|
|
5184
|
+
void this.openPersistProfileSelector();
|
|
5185
|
+
}
|
|
5186
|
+
else if (value === "delete") {
|
|
5187
|
+
void this.openDeleteProfileSelector();
|
|
5188
|
+
}
|
|
5189
|
+
}, () => {
|
|
5190
|
+
done();
|
|
5191
|
+
void this.showSettingsSelector();
|
|
5192
|
+
});
|
|
5193
|
+
return { component: selector, focus: selector.getSelectList() };
|
|
5194
|
+
});
|
|
5195
|
+
}
|
|
5196
|
+
async openPersistProfileSelector() {
|
|
5197
|
+
const scopeOptions = [
|
|
5198
|
+
{ value: "session", label: "session", description: "Runtime only (not written to disk)" },
|
|
5199
|
+
{
|
|
5200
|
+
value: "directory",
|
|
5201
|
+
label: "directory",
|
|
5202
|
+
description: "~/.pi/agent/resource-profiles/<hash>/settings.json",
|
|
5203
|
+
},
|
|
5204
|
+
{ value: "project", label: "project", description: ".pi/settings.json" },
|
|
5205
|
+
{ value: "global", label: "global", description: "~/.pi/agent/settings.json" },
|
|
5206
|
+
];
|
|
5207
|
+
this.showSelector((done) => {
|
|
5208
|
+
const selector = new SelectSubmenu("Persist Active Profile", "Choose where to write the active-profile selection.", scopeOptions, "directory", (value) => {
|
|
5209
|
+
done();
|
|
5210
|
+
this.persistActiveProfile(value);
|
|
5211
|
+
void this.showSettingsSelector();
|
|
5212
|
+
}, () => {
|
|
5213
|
+
done();
|
|
5214
|
+
void this.openManageProfilesFlow();
|
|
5215
|
+
});
|
|
5216
|
+
return { component: selector, focus: selector.getSelectList() };
|
|
5217
|
+
});
|
|
5218
|
+
}
|
|
5219
|
+
async openDeleteProfileSelector() {
|
|
5220
|
+
const registry = this.settingsManager.getProfileRegistry();
|
|
5221
|
+
const editableProfiles = registry.listProfiles().map((p) => ({
|
|
5222
|
+
value: p.name,
|
|
5223
|
+
label: p.name,
|
|
5224
|
+
description: p.description || p.source,
|
|
5225
|
+
}));
|
|
5226
|
+
this.showSelector((done) => {
|
|
5227
|
+
const selector = new SelectSubmenu("Delete Profile", "Pick a profile to delete.", editableProfiles, "", (value) => {
|
|
5228
|
+
done();
|
|
5229
|
+
this.deleteProfileFromSource(value);
|
|
5230
|
+
void this.showSettingsSelector();
|
|
5231
|
+
}, () => {
|
|
5232
|
+
done();
|
|
5233
|
+
void this.openManageProfilesFlow();
|
|
5234
|
+
});
|
|
5235
|
+
return { component: selector, focus: selector.getSelectList() };
|
|
5236
|
+
});
|
|
5237
|
+
}
|
|
5238
|
+
async openSourcesManagerFlow() {
|
|
5239
|
+
const externalRoots = this.settingsManager.getExternalResourceRoots();
|
|
5240
|
+
const trustedRoots = this.settingsManager.getTrustedResourceRoots();
|
|
5241
|
+
const options = [
|
|
5242
|
+
{
|
|
5243
|
+
value: "add",
|
|
5244
|
+
label: "+ Add external root...",
|
|
5245
|
+
description: "Register a new external directory root (requires trust)",
|
|
5246
|
+
},
|
|
5247
|
+
];
|
|
5248
|
+
for (const r of externalRoots) {
|
|
5249
|
+
const isTrusted = trustedRoots.includes(r);
|
|
5250
|
+
options.push({
|
|
5251
|
+
value: `remove:${r}`,
|
|
5252
|
+
label: `Remove: ${r}`,
|
|
5253
|
+
description: isTrusted ? "Trusted external root" : "Untrusted external root",
|
|
5254
|
+
});
|
|
5255
|
+
}
|
|
5256
|
+
this.showSelector((done) => {
|
|
5257
|
+
const selector = new SelectSubmenu("Sources", "Manage external resource roots. Adding a root requires trust confirmation.", options, "", (value) => {
|
|
5258
|
+
done();
|
|
5259
|
+
if (value === "add") {
|
|
5260
|
+
void this.addExternalResourceRootFlow().then(() => {
|
|
5261
|
+
void this.showSettingsSelector();
|
|
5262
|
+
});
|
|
5263
|
+
}
|
|
5264
|
+
else if (value.startsWith("remove:")) {
|
|
5265
|
+
const root = value.slice("remove:".length);
|
|
5266
|
+
void this.removeExternalResourceRootFlow(root).then(() => {
|
|
5267
|
+
void this.showSettingsSelector();
|
|
5268
|
+
});
|
|
5269
|
+
}
|
|
5270
|
+
}, () => {
|
|
5271
|
+
done();
|
|
5272
|
+
void this.showSettingsSelector();
|
|
5273
|
+
});
|
|
5274
|
+
return { component: selector, focus: selector.getSelectList() };
|
|
5275
|
+
});
|
|
5276
|
+
}
|
|
5277
|
+
async openLibraryManagerFlow() {
|
|
5278
|
+
const activeNames = this.settingsManager.getActiveResourceProfileNames();
|
|
5279
|
+
const activeName = activeNames[0];
|
|
5280
|
+
if (!activeName || activeName === "(none)") {
|
|
5281
|
+
this.showSelector((done) => {
|
|
5282
|
+
const selector = new SelectSubmenu("No Active Profile", "Select or create a profile to manage the library.", [
|
|
5283
|
+
{
|
|
5284
|
+
value: "select",
|
|
5285
|
+
label: "Select existing profile...",
|
|
5286
|
+
description: "Choose an existing profile to activate.",
|
|
5287
|
+
},
|
|
5288
|
+
{ value: "create", label: "Create new profile...", description: "Create a new profile definition." },
|
|
5289
|
+
], "select", (value) => {
|
|
5082
5290
|
done();
|
|
5083
|
-
|
|
5084
|
-
|
|
5085
|
-
|
|
5291
|
+
if (value === "create") {
|
|
5292
|
+
void this.createProfileAndOpenLibraryFlow();
|
|
5293
|
+
}
|
|
5294
|
+
else {
|
|
5295
|
+
void this.selectProfileAndOpenLibraryFlow();
|
|
5296
|
+
}
|
|
5297
|
+
}, () => {
|
|
5086
5298
|
done();
|
|
5087
|
-
this.
|
|
5088
|
-
}
|
|
5089
|
-
|
|
5299
|
+
void this.showSettingsSelector();
|
|
5300
|
+
});
|
|
5301
|
+
return { component: selector, focus: selector.getSelectList() };
|
|
5302
|
+
});
|
|
5303
|
+
return;
|
|
5304
|
+
}
|
|
5305
|
+
const registry = this.settingsManager.getProfileRegistry();
|
|
5306
|
+
const profile = registry.getProfile(activeName);
|
|
5307
|
+
if (!profile) {
|
|
5308
|
+
this.showError(`Active profile "${activeName}" not found in registry.`);
|
|
5309
|
+
return;
|
|
5310
|
+
}
|
|
5311
|
+
const scope = this.scopeForProfileSource(profile.source);
|
|
5312
|
+
void this.openLibraryEditorForProfile(profile.name, scope);
|
|
5313
|
+
}
|
|
5314
|
+
async createProfileAndOpenLibraryFlow() {
|
|
5315
|
+
const name = await new Promise((resolve) => {
|
|
5316
|
+
this.showSelector((done) => {
|
|
5317
|
+
const input = new ExtensionInputComponent("Create Profile", "Enter profile name", (value) => {
|
|
5090
5318
|
done();
|
|
5091
|
-
|
|
5092
|
-
},
|
|
5093
|
-
onAddExternalResourceRoot: () => {
|
|
5319
|
+
resolve(value);
|
|
5320
|
+
}, () => {
|
|
5094
5321
|
done();
|
|
5095
|
-
|
|
5096
|
-
},
|
|
5097
|
-
|
|
5322
|
+
resolve(undefined);
|
|
5323
|
+
}, { tui: this.ui });
|
|
5324
|
+
return { component: input, focus: input };
|
|
5325
|
+
});
|
|
5326
|
+
});
|
|
5327
|
+
if (name === undefined) {
|
|
5328
|
+
void this.openLibraryManagerFlow();
|
|
5329
|
+
return;
|
|
5330
|
+
}
|
|
5331
|
+
const trimmed = name.trim();
|
|
5332
|
+
if (!trimmed) {
|
|
5333
|
+
this.showWarning("Profile name cannot be empty.");
|
|
5334
|
+
void this.openLibraryManagerFlow();
|
|
5335
|
+
return;
|
|
5336
|
+
}
|
|
5337
|
+
try {
|
|
5338
|
+
this.settingsManager.setProfileDefinition(trimmed, {
|
|
5339
|
+
name: trimmed,
|
|
5340
|
+
resources: {},
|
|
5341
|
+
}, "directory");
|
|
5342
|
+
await this.applyProfile(trimmed);
|
|
5343
|
+
void this.openLibraryEditorForProfile(trimmed, "directory");
|
|
5344
|
+
}
|
|
5345
|
+
catch (error) {
|
|
5346
|
+
this.showError(error instanceof Error ? error.message : String(error));
|
|
5347
|
+
void this.openLibraryManagerFlow();
|
|
5348
|
+
}
|
|
5349
|
+
}
|
|
5350
|
+
async selectProfileAndOpenLibraryFlow() {
|
|
5351
|
+
const registry = this.settingsManager.getProfileRegistry();
|
|
5352
|
+
const profiles = registry.listProfiles();
|
|
5353
|
+
const editableProfiles = profiles.map((p) => ({
|
|
5354
|
+
value: p.name,
|
|
5355
|
+
label: p.name,
|
|
5356
|
+
description: p.description || p.source,
|
|
5357
|
+
}));
|
|
5358
|
+
if (editableProfiles.length === 0) {
|
|
5359
|
+
this.showWarning("No existing profiles to select. Please create one.");
|
|
5360
|
+
void this.createProfileAndOpenLibraryFlow();
|
|
5361
|
+
return;
|
|
5362
|
+
}
|
|
5363
|
+
this.showSelector((done) => {
|
|
5364
|
+
const selector = new SelectSubmenu("Select Profile", "Pick a profile to activate and edit.", editableProfiles, "", (value) => {
|
|
5365
|
+
done();
|
|
5366
|
+
void this.applyProfile(value).then(() => {
|
|
5367
|
+
const profile = registry.getProfile(value);
|
|
5368
|
+
const scope = this.scopeForProfileSource(profile.source);
|
|
5369
|
+
void this.openLibraryEditorForProfile(value, scope);
|
|
5370
|
+
});
|
|
5371
|
+
}, () => {
|
|
5372
|
+
done();
|
|
5373
|
+
void this.openLibraryManagerFlow();
|
|
5374
|
+
});
|
|
5375
|
+
return { component: selector, focus: selector.getSelectList() };
|
|
5376
|
+
});
|
|
5377
|
+
}
|
|
5378
|
+
async getProfileResourceKinds() {
|
|
5379
|
+
const loader = this.session.resourceLoader;
|
|
5380
|
+
const base = (p) => p.split(/[\\/]/).pop() ?? p;
|
|
5381
|
+
const allDiscoverableExtensions = await loader.getDiscoverableExtensionPaths();
|
|
5382
|
+
const skills = loader.getSkills().skills;
|
|
5383
|
+
const prompts = loader.getPrompts().prompts;
|
|
5384
|
+
const themes = getAvailableThemesWithPaths();
|
|
5385
|
+
const agents = loader.getAgentsFiles().agentsFiles;
|
|
5386
|
+
const getAgentDescription = (filePath) => {
|
|
5387
|
+
try {
|
|
5388
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
5389
|
+
const { frontmatter } = parseFrontmatter(content);
|
|
5390
|
+
if (typeof frontmatter.description === "string") {
|
|
5391
|
+
return frontmatter.description;
|
|
5392
|
+
}
|
|
5393
|
+
}
|
|
5394
|
+
catch { }
|
|
5395
|
+
return undefined;
|
|
5396
|
+
};
|
|
5397
|
+
const getExtensionDescription = (filePath) => {
|
|
5398
|
+
try {
|
|
5399
|
+
let dir = filePath;
|
|
5400
|
+
if (fs.existsSync(filePath) && !fs.statSync(filePath).isDirectory()) {
|
|
5401
|
+
dir = path.dirname(filePath);
|
|
5402
|
+
}
|
|
5403
|
+
const pkgPath = path.join(dir, "package.json");
|
|
5404
|
+
if (fs.existsSync(pkgPath)) {
|
|
5405
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
|
|
5406
|
+
if (typeof pkg.description === "string") {
|
|
5407
|
+
return pkg.description;
|
|
5408
|
+
}
|
|
5409
|
+
}
|
|
5410
|
+
}
|
|
5411
|
+
catch { }
|
|
5412
|
+
return undefined;
|
|
5413
|
+
};
|
|
5414
|
+
return [
|
|
5415
|
+
{
|
|
5416
|
+
kind: "tools",
|
|
5417
|
+
label: "Tools",
|
|
5418
|
+
items: Array.from(allToolNames).map((name) => ({ id: name })),
|
|
5419
|
+
},
|
|
5420
|
+
{
|
|
5421
|
+
kind: "skills",
|
|
5422
|
+
label: "Skills",
|
|
5423
|
+
items: skills.map((s) => ({
|
|
5424
|
+
id: s.name,
|
|
5425
|
+
path: s.filePath,
|
|
5426
|
+
description: s.description,
|
|
5427
|
+
})),
|
|
5428
|
+
},
|
|
5429
|
+
{
|
|
5430
|
+
kind: "extensions",
|
|
5431
|
+
label: "Extensions",
|
|
5432
|
+
items: allDiscoverableExtensions.map((e) => ({
|
|
5433
|
+
id: base(e),
|
|
5434
|
+
path: e,
|
|
5435
|
+
description: getExtensionDescription(e),
|
|
5436
|
+
})),
|
|
5437
|
+
},
|
|
5438
|
+
{
|
|
5439
|
+
kind: "agents",
|
|
5440
|
+
label: "Agents",
|
|
5441
|
+
items: agents.map((f) => ({
|
|
5442
|
+
id: base(f.path),
|
|
5443
|
+
path: f.path,
|
|
5444
|
+
description: getAgentDescription(f.path),
|
|
5445
|
+
})),
|
|
5446
|
+
},
|
|
5447
|
+
{
|
|
5448
|
+
kind: "prompts",
|
|
5449
|
+
label: "Prompts",
|
|
5450
|
+
items: prompts.map((p) => ({
|
|
5451
|
+
id: p.name,
|
|
5452
|
+
path: p.filePath,
|
|
5453
|
+
description: p.description,
|
|
5454
|
+
})),
|
|
5455
|
+
},
|
|
5456
|
+
{
|
|
5457
|
+
kind: "themes",
|
|
5458
|
+
label: "Themes",
|
|
5459
|
+
items: themes.map((t) => ({
|
|
5460
|
+
id: t.name,
|
|
5461
|
+
path: t.path,
|
|
5462
|
+
})),
|
|
5463
|
+
},
|
|
5464
|
+
];
|
|
5465
|
+
}
|
|
5466
|
+
async openLibraryEditorForProfile(profileName, initialScope) {
|
|
5467
|
+
const currentScope = initialScope;
|
|
5468
|
+
const registry = this.settingsManager.getProfileRegistry();
|
|
5469
|
+
const profile = registry.getProfile(profileName);
|
|
5470
|
+
if (!profile) {
|
|
5471
|
+
this.showError(`Profile not found: ${profileName}`);
|
|
5472
|
+
return;
|
|
5473
|
+
}
|
|
5474
|
+
const kinds = await this.getProfileResourceKinds();
|
|
5475
|
+
const originalResources = profile.resources;
|
|
5476
|
+
const isActiveProfile = this.settingsManager.getActiveResourceProfileNames().includes(profile.name);
|
|
5477
|
+
this.showSelector((done) => {
|
|
5478
|
+
const editor = new ProfileResourceEditorComponent({
|
|
5479
|
+
profileName: profile.name,
|
|
5480
|
+
profileScope: currentScope,
|
|
5481
|
+
initialResources: profile.resources,
|
|
5482
|
+
kinds,
|
|
5483
|
+
cwd: this.sessionManager.getCwd(),
|
|
5484
|
+
agentDir: getAgentDir(),
|
|
5485
|
+
externalResourceRoots: this.settingsManager.getExternalResourceRoots(),
|
|
5486
|
+
onSave: (resources) => {
|
|
5098
5487
|
done();
|
|
5099
|
-
|
|
5488
|
+
try {
|
|
5489
|
+
this.settingsManager.setProfileDefinition(profileName, {
|
|
5490
|
+
name: profileName,
|
|
5491
|
+
description: profile.description,
|
|
5492
|
+
model: profile.model,
|
|
5493
|
+
thinking: profile.thinking,
|
|
5494
|
+
resources,
|
|
5495
|
+
}, currentScope);
|
|
5496
|
+
this.showStatus(`Saved profile "${profileName}" to ${currentScope}.`);
|
|
5497
|
+
if (isActiveProfile) {
|
|
5498
|
+
const extensionsChanged = originalResources.extensions !== resources.extensions;
|
|
5499
|
+
const otherResourcesChanged = originalResources.tools !== resources.tools ||
|
|
5500
|
+
originalResources.skills !== resources.skills ||
|
|
5501
|
+
originalResources.agents !== resources.agents ||
|
|
5502
|
+
originalResources.prompts !== resources.prompts ||
|
|
5503
|
+
originalResources.themes !== resources.themes;
|
|
5504
|
+
if (extensionsChanged && !otherResourcesChanged) {
|
|
5505
|
+
void this.reconcileExtensionsAndRefreshUI(profileName);
|
|
5506
|
+
}
|
|
5507
|
+
else {
|
|
5508
|
+
void this.refreshAfterProfileMutation(profileName);
|
|
5509
|
+
}
|
|
5510
|
+
}
|
|
5511
|
+
}
|
|
5512
|
+
catch (error) {
|
|
5513
|
+
this.showError(error instanceof Error ? error.message : String(error));
|
|
5514
|
+
}
|
|
5100
5515
|
},
|
|
5101
5516
|
onCancel: () => {
|
|
5102
5517
|
done();
|
|
5103
|
-
this.
|
|
5518
|
+
void this.openLibraryManagerFlow();
|
|
5519
|
+
},
|
|
5520
|
+
onScopeChange: () => {
|
|
5521
|
+
done();
|
|
5522
|
+
void this.promptScopeChangeForProfile(profileName, currentScope);
|
|
5104
5523
|
},
|
|
5105
5524
|
});
|
|
5106
|
-
return { component:
|
|
5525
|
+
return { component: editor, focus: editor };
|
|
5526
|
+
});
|
|
5527
|
+
}
|
|
5528
|
+
async promptScopeChangeForProfile(profileName, currentScope) {
|
|
5529
|
+
const scopeOptions = [
|
|
5530
|
+
{ value: "session", label: "session", description: "Runtime only (not written to disk)" },
|
|
5531
|
+
{
|
|
5532
|
+
value: "directory",
|
|
5533
|
+
label: "directory",
|
|
5534
|
+
description: "~/.pi/agent/resource-profiles/<hash>/settings.json",
|
|
5535
|
+
},
|
|
5536
|
+
{ value: "project", label: "project", description: ".pi/settings.json" },
|
|
5537
|
+
{ value: "global", label: "global", description: "~/.pi/agent/settings.json" },
|
|
5538
|
+
];
|
|
5539
|
+
this.showSelector((done) => {
|
|
5540
|
+
const selector = new SelectSubmenu("Change Profile Scope", `Select new scope for profile "${profileName}".`, scopeOptions, currentScope, (value) => {
|
|
5541
|
+
done();
|
|
5542
|
+
void this.openLibraryEditorForProfile(profileName, value);
|
|
5543
|
+
}, () => {
|
|
5544
|
+
done();
|
|
5545
|
+
void this.openLibraryEditorForProfile(profileName, currentScope);
|
|
5546
|
+
});
|
|
5547
|
+
return { component: selector, focus: selector.getSelectList() };
|
|
5107
5548
|
});
|
|
5108
5549
|
}
|
|
5109
5550
|
async handleProfilesCommand(profileName) {
|
|
@@ -5198,24 +5639,6 @@ export class InteractiveMode {
|
|
|
5198
5639
|
this.showError(error instanceof Error ? error.message : String(error));
|
|
5199
5640
|
}
|
|
5200
5641
|
}
|
|
5201
|
-
async getProfileResourceKinds() {
|
|
5202
|
-
const loader = this.session.resourceLoader;
|
|
5203
|
-
const base = (p) => p.split(/[\\/]/).pop() ?? p;
|
|
5204
|
-
// Get all discoverable extension paths (enabled and disabled) for profile filtering
|
|
5205
|
-
const allDiscoverableExtensions = await loader.getDiscoverableExtensionPaths();
|
|
5206
|
-
return [
|
|
5207
|
-
{ kind: "tools", label: "Tools", allIds: [...allToolNames] },
|
|
5208
|
-
{ kind: "skills", label: "Skills", allIds: loader.getSkills().skills.map((s) => s.name) },
|
|
5209
|
-
{
|
|
5210
|
-
kind: "extensions",
|
|
5211
|
-
label: "Extensions",
|
|
5212
|
-
allIds: allDiscoverableExtensions.map((e) => base(e)),
|
|
5213
|
-
},
|
|
5214
|
-
{ kind: "agents", label: "Agents", allIds: loader.getAgentsFiles().agentsFiles.map((f) => base(f.path)) },
|
|
5215
|
-
{ kind: "prompts", label: "Prompts", allIds: loader.getPrompts().prompts.map((p) => p.name) },
|
|
5216
|
-
{ kind: "themes", label: "Themes", allIds: getAvailableThemes() },
|
|
5217
|
-
];
|
|
5218
|
-
}
|
|
5219
5642
|
/** Map where a profile currently lives to the scope we should write it back to. */
|
|
5220
5643
|
scopeForProfileSource(source) {
|
|
5221
5644
|
switch (source) {
|
|
@@ -5282,8 +5705,12 @@ export class InteractiveMode {
|
|
|
5282
5705
|
this.showSelector((done) => {
|
|
5283
5706
|
const editor = new ProfileResourceEditorComponent({
|
|
5284
5707
|
profileName,
|
|
5708
|
+
profileScope: scope,
|
|
5285
5709
|
initialResources: {},
|
|
5286
5710
|
kinds,
|
|
5711
|
+
cwd: this.sessionManager.getCwd(),
|
|
5712
|
+
agentDir: getAgentDir(),
|
|
5713
|
+
externalResourceRoots: this.settingsManager.getExternalResourceRoots(),
|
|
5287
5714
|
onSave: (resources) => {
|
|
5288
5715
|
done();
|
|
5289
5716
|
try {
|
|
@@ -5306,63 +5733,6 @@ export class InteractiveMode {
|
|
|
5306
5733
|
return { component: editor, focus: editor };
|
|
5307
5734
|
});
|
|
5308
5735
|
}
|
|
5309
|
-
async openProfileResourceEditor(profileName) {
|
|
5310
|
-
const profile = this.settingsManager.getProfileRegistry().getProfile(profileName);
|
|
5311
|
-
if (!profile) {
|
|
5312
|
-
this.showError(`Profile not found: ${profileName}`);
|
|
5313
|
-
return;
|
|
5314
|
-
}
|
|
5315
|
-
const scope = this.scopeForProfileSource(profile.source);
|
|
5316
|
-
const kinds = await this.getProfileResourceKinds();
|
|
5317
|
-
const isActiveProfile = this.settingsManager.getActiveResourceProfileNames().includes(profile.name);
|
|
5318
|
-
const originalResources = profile.resources;
|
|
5319
|
-
this.showSelector((done) => {
|
|
5320
|
-
const editor = new ProfileResourceEditorComponent({
|
|
5321
|
-
profileName: profile.name,
|
|
5322
|
-
initialResources: profile.resources,
|
|
5323
|
-
kinds,
|
|
5324
|
-
onSave: (resources) => {
|
|
5325
|
-
done();
|
|
5326
|
-
try {
|
|
5327
|
-
this.settingsManager.setProfileDefinition(profile.name, {
|
|
5328
|
-
name: profile.name,
|
|
5329
|
-
description: profile.description,
|
|
5330
|
-
model: profile.model,
|
|
5331
|
-
thinking: profile.thinking,
|
|
5332
|
-
resources,
|
|
5333
|
-
}, scope);
|
|
5334
|
-
this.showStatus(`Saved profile "${profile.name}" to ${scope}.`);
|
|
5335
|
-
// For active profiles, detect if only extensions changed to avoid full reload
|
|
5336
|
-
if (isActiveProfile) {
|
|
5337
|
-
const extensionsChanged = originalResources.extensions !== resources.extensions;
|
|
5338
|
-
const otherResourcesChanged = originalResources.tools !== resources.tools ||
|
|
5339
|
-
originalResources.skills !== resources.skills ||
|
|
5340
|
-
originalResources.agents !== resources.agents ||
|
|
5341
|
-
originalResources.prompts !== resources.prompts ||
|
|
5342
|
-
originalResources.themes !== resources.themes;
|
|
5343
|
-
if (extensionsChanged && !otherResourcesChanged) {
|
|
5344
|
-
// Only extensions changed: use live reconciliation
|
|
5345
|
-
void this.reconcileExtensionsAndRefreshUI(profile.name);
|
|
5346
|
-
}
|
|
5347
|
-
else {
|
|
5348
|
-
// Other resources changed or mixed: use full reload
|
|
5349
|
-
void this.refreshAfterProfileMutation(profile.name);
|
|
5350
|
-
}
|
|
5351
|
-
}
|
|
5352
|
-
// Non-active profiles don't need refresh
|
|
5353
|
-
}
|
|
5354
|
-
catch (error) {
|
|
5355
|
-
this.showError(error instanceof Error ? error.message : String(error));
|
|
5356
|
-
}
|
|
5357
|
-
},
|
|
5358
|
-
onCancel: () => {
|
|
5359
|
-
done();
|
|
5360
|
-
this.ui.requestRender();
|
|
5361
|
-
},
|
|
5362
|
-
});
|
|
5363
|
-
return { component: editor, focus: editor };
|
|
5364
|
-
});
|
|
5365
|
-
}
|
|
5366
5736
|
persistActiveProfile(scope) {
|
|
5367
5737
|
const active = this.settingsManager.getActiveResourceProfileNames()[0];
|
|
5368
5738
|
if (!active) {
|
|
@@ -6812,6 +7182,228 @@ export class InteractiveMode {
|
|
|
6812
7182
|
await this.handleFatalRuntimeError("Failed to create session", error);
|
|
6813
7183
|
}
|
|
6814
7184
|
}
|
|
7185
|
+
copyResourcesRecursively(src, dest, force, stats) {
|
|
7186
|
+
if (!fs.existsSync(src))
|
|
7187
|
+
return;
|
|
7188
|
+
const entries = fs.readdirSync(src, { withFileTypes: true });
|
|
7189
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
7190
|
+
for (const entry of entries) {
|
|
7191
|
+
const srcPath = path.join(src, entry.name);
|
|
7192
|
+
const destPath = path.join(dest, entry.name);
|
|
7193
|
+
if (entry.isDirectory()) {
|
|
7194
|
+
this.copyResourcesRecursively(srcPath, destPath, force, stats);
|
|
7195
|
+
}
|
|
7196
|
+
else if (entry.isFile()) {
|
|
7197
|
+
if (fs.existsSync(destPath) && !force) {
|
|
7198
|
+
stats.skipped.push(destPath);
|
|
7199
|
+
}
|
|
7200
|
+
else {
|
|
7201
|
+
fs.copyFileSync(srcPath, destPath);
|
|
7202
|
+
stats.installed.push(destPath);
|
|
7203
|
+
}
|
|
7204
|
+
}
|
|
7205
|
+
}
|
|
7206
|
+
}
|
|
7207
|
+
async handleInstallResourcesCommand(argsString) {
|
|
7208
|
+
try {
|
|
7209
|
+
const tokens = argsString.split(/\s+/).filter(Boolean);
|
|
7210
|
+
let force = false;
|
|
7211
|
+
let dir = "";
|
|
7212
|
+
for (const t of tokens) {
|
|
7213
|
+
if (t === "--force") {
|
|
7214
|
+
force = true;
|
|
7215
|
+
}
|
|
7216
|
+
else {
|
|
7217
|
+
dir = t;
|
|
7218
|
+
}
|
|
7219
|
+
}
|
|
7220
|
+
if (!dir) {
|
|
7221
|
+
this.showError("Usage: /install-resources <dir> [--force]");
|
|
7222
|
+
return;
|
|
7223
|
+
}
|
|
7224
|
+
const canonical = this.settingsManager.canonicalizePath(dir);
|
|
7225
|
+
if (!canonical || !fs.existsSync(canonical)) {
|
|
7226
|
+
this.showError(`Source directory does not exist: ${dir}`);
|
|
7227
|
+
return;
|
|
7228
|
+
}
|
|
7229
|
+
const trustedRoots = this.settingsManager.getTrustedResourceRoots();
|
|
7230
|
+
const trusted = trustedRoots.includes(canonical);
|
|
7231
|
+
if (!trusted) {
|
|
7232
|
+
const trust = await new Promise((resolve) => {
|
|
7233
|
+
this.showSelector((done) => {
|
|
7234
|
+
const submenu = new SelectSubmenu("Trust external source for installation?", `The directory "${canonical}" contains extensions/resources to install. Extensions can execute arbitrary code on your machine. Do you trust it?`, [
|
|
7235
|
+
{
|
|
7236
|
+
value: "yes",
|
|
7237
|
+
label: "Yes",
|
|
7238
|
+
description: "Trust this directory and proceed with installation.",
|
|
7239
|
+
},
|
|
7240
|
+
{ value: "no", label: "No", description: "Do not trust this directory. Abort." },
|
|
7241
|
+
], "no", (value) => {
|
|
7242
|
+
done();
|
|
7243
|
+
resolve(value === "yes");
|
|
7244
|
+
}, () => {
|
|
7245
|
+
done();
|
|
7246
|
+
resolve(false);
|
|
7247
|
+
});
|
|
7248
|
+
return { component: submenu, focus: submenu.getSelectList() };
|
|
7249
|
+
});
|
|
7250
|
+
});
|
|
7251
|
+
if (!trust) {
|
|
7252
|
+
this.showStatus("Installation aborted. Source directory was not trusted.");
|
|
7253
|
+
return;
|
|
7254
|
+
}
|
|
7255
|
+
this.settingsManager.addTrustedResourceRoot(canonical, "global");
|
|
7256
|
+
}
|
|
7257
|
+
const subdirs = ["skills", "extensions", "prompts", "themes", "profiles"];
|
|
7258
|
+
const stats = { installed: [], skipped: [] };
|
|
7259
|
+
const userAgentDir = getAgentDir();
|
|
7260
|
+
for (const sub of subdirs) {
|
|
7261
|
+
const srcSub = path.join(canonical, sub);
|
|
7262
|
+
const destSub = path.join(userAgentDir, sub);
|
|
7263
|
+
if (fs.existsSync(srcSub)) {
|
|
7264
|
+
this.copyResourcesRecursively(srcSub, destSub, force, stats);
|
|
7265
|
+
}
|
|
7266
|
+
}
|
|
7267
|
+
const installedCount = stats.installed.length;
|
|
7268
|
+
const skippedCount = stats.skipped.length;
|
|
7269
|
+
this.showStatus(`Installation complete: ${installedCount} resources installed, ${skippedCount} skipped.`);
|
|
7270
|
+
await this.handleReloadCommand();
|
|
7271
|
+
}
|
|
7272
|
+
catch (error) {
|
|
7273
|
+
this.showError(error instanceof Error ? error.message : String(error));
|
|
7274
|
+
}
|
|
7275
|
+
}
|
|
7276
|
+
async handleConfigBackupCommand(fileArg) {
|
|
7277
|
+
try {
|
|
7278
|
+
const profilesDir = path.join(getAgentDir(), "profiles");
|
|
7279
|
+
const profiles = {};
|
|
7280
|
+
if (fs.existsSync(profilesDir)) {
|
|
7281
|
+
const entries = fs.readdirSync(profilesDir);
|
|
7282
|
+
for (const entry of entries) {
|
|
7283
|
+
if (entry.endsWith(".json")) {
|
|
7284
|
+
const pPath = path.join(profilesDir, entry);
|
|
7285
|
+
try {
|
|
7286
|
+
const content = fs.readFileSync(pPath, "utf-8");
|
|
7287
|
+
profiles[entry] = JSON.parse(content);
|
|
7288
|
+
}
|
|
7289
|
+
catch {
|
|
7290
|
+
// skip
|
|
7291
|
+
}
|
|
7292
|
+
}
|
|
7293
|
+
}
|
|
7294
|
+
}
|
|
7295
|
+
const backupData = {
|
|
7296
|
+
profiles,
|
|
7297
|
+
settings: {
|
|
7298
|
+
resourceProfiles: this.settingsManager.settings.resourceProfiles,
|
|
7299
|
+
activeResourceProfile: this.settingsManager.settings.activeResourceProfile,
|
|
7300
|
+
externalResourceRoots: this.settingsManager.settings.externalResourceRoots,
|
|
7301
|
+
trustedResourceRoots: this.settingsManager.settings.trustedResourceRoots,
|
|
7302
|
+
},
|
|
7303
|
+
};
|
|
7304
|
+
let targetFile = fileArg;
|
|
7305
|
+
if (!targetFile) {
|
|
7306
|
+
const backupsDir = path.join(getAgentDir(), "backups");
|
|
7307
|
+
fs.mkdirSync(backupsDir, { recursive: true });
|
|
7308
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
7309
|
+
targetFile = path.join(backupsDir, `config-${timestamp}.json`);
|
|
7310
|
+
}
|
|
7311
|
+
else {
|
|
7312
|
+
const resolved = this.settingsManager.canonicalizePath(targetFile);
|
|
7313
|
+
if (resolved) {
|
|
7314
|
+
targetFile = resolved;
|
|
7315
|
+
}
|
|
7316
|
+
}
|
|
7317
|
+
fs.mkdirSync(path.dirname(targetFile), { recursive: true });
|
|
7318
|
+
fs.writeFileSync(targetFile, JSON.stringify(backupData, null, 2), "utf-8");
|
|
7319
|
+
this.showStatus(`Configuration backup saved to ${targetFile}`);
|
|
7320
|
+
}
|
|
7321
|
+
catch (error) {
|
|
7322
|
+
this.showError(error instanceof Error ? error.message : String(error));
|
|
7323
|
+
}
|
|
7324
|
+
}
|
|
7325
|
+
async handleConfigRestoreCommand(fileArg) {
|
|
7326
|
+
try {
|
|
7327
|
+
const trimmed = fileArg.trim();
|
|
7328
|
+
if (!trimmed) {
|
|
7329
|
+
this.showError("Usage: /config-restore <file>");
|
|
7330
|
+
return;
|
|
7331
|
+
}
|
|
7332
|
+
const resolved = this.settingsManager.canonicalizePath(trimmed);
|
|
7333
|
+
if (!resolved || !fs.existsSync(resolved)) {
|
|
7334
|
+
this.showError(`Backup file does not exist: ${trimmed}`);
|
|
7335
|
+
return;
|
|
7336
|
+
}
|
|
7337
|
+
let bundle;
|
|
7338
|
+
try {
|
|
7339
|
+
const content = fs.readFileSync(resolved, "utf-8");
|
|
7340
|
+
bundle = JSON.parse(content);
|
|
7341
|
+
}
|
|
7342
|
+
catch (error) {
|
|
7343
|
+
this.showError(`Failed to parse backup file: ${error instanceof Error ? error.message : String(error)}`);
|
|
7344
|
+
return;
|
|
7345
|
+
}
|
|
7346
|
+
if (!bundle || typeof bundle !== "object") {
|
|
7347
|
+
this.showError("Invalid backup file: must be a JSON object");
|
|
7348
|
+
return;
|
|
7349
|
+
}
|
|
7350
|
+
// Confirm before clobbering
|
|
7351
|
+
const confirm = await new Promise((resolve) => {
|
|
7352
|
+
this.showSelector((done) => {
|
|
7353
|
+
const submenu = new SelectSubmenu("Restore configuration?", "This will overwrite existing local profiles and settings with the backup values. Do you want to continue?", [
|
|
7354
|
+
{ value: "yes", label: "Yes", description: "Proceed with restoration." },
|
|
7355
|
+
{ value: "no", label: "No", description: "Cancel and abort." },
|
|
7356
|
+
], "no", (value) => {
|
|
7357
|
+
done();
|
|
7358
|
+
resolve(value === "yes");
|
|
7359
|
+
}, () => {
|
|
7360
|
+
done();
|
|
7361
|
+
resolve(false);
|
|
7362
|
+
});
|
|
7363
|
+
return { component: submenu, focus: submenu.getSelectList() };
|
|
7364
|
+
});
|
|
7365
|
+
});
|
|
7366
|
+
if (!confirm) {
|
|
7367
|
+
this.showStatus("Restore aborted.");
|
|
7368
|
+
return;
|
|
7369
|
+
}
|
|
7370
|
+
// 1. Restore profile files (reusable-file scope)
|
|
7371
|
+
if (bundle.profiles && typeof bundle.profiles === "object") {
|
|
7372
|
+
const profilesDir = path.join(getAgentDir(), "profiles");
|
|
7373
|
+
fs.mkdirSync(profilesDir, { recursive: true });
|
|
7374
|
+
for (const [filename, content] of Object.entries(bundle.profiles)) {
|
|
7375
|
+
const targetPath = path.join(profilesDir, filename);
|
|
7376
|
+
fs.writeFileSync(targetPath, JSON.stringify(content, null, 2), "utf-8");
|
|
7377
|
+
}
|
|
7378
|
+
}
|
|
7379
|
+
// 2. Restore settings
|
|
7380
|
+
if (bundle.settings && typeof bundle.settings === "object") {
|
|
7381
|
+
const bs = bundle.settings;
|
|
7382
|
+
// Global profiles definitions
|
|
7383
|
+
if (bs.resourceProfiles && typeof bs.resourceProfiles === "object") {
|
|
7384
|
+
for (const [name, definition] of Object.entries(bs.resourceProfiles)) {
|
|
7385
|
+
this.settingsManager.setProfileDefinition(name, definition, "global");
|
|
7386
|
+
}
|
|
7387
|
+
}
|
|
7388
|
+
// Active profile selection
|
|
7389
|
+
if (bs.activeResourceProfile) {
|
|
7390
|
+
this.settingsManager.setActiveProfile(bs.activeResourceProfile, "global");
|
|
7391
|
+
}
|
|
7392
|
+
// External roots (trustedRoots are NOT restored, as per SECURITY requirement)
|
|
7393
|
+
if (Array.isArray(bs.externalResourceRoots)) {
|
|
7394
|
+
this.settingsManager.setExternalResourceRoots(bs.externalResourceRoots, "global");
|
|
7395
|
+
const currentTrusted = this.settingsManager.getTrustedResourceRoots();
|
|
7396
|
+
const newTrusted = currentTrusted.filter((r) => !bs.externalResourceRoots.includes(r));
|
|
7397
|
+
this.settingsManager.setTrustedResourceRoots(newTrusted, "global");
|
|
7398
|
+
}
|
|
7399
|
+
}
|
|
7400
|
+
this.showStatus("Configuration restored successfully.");
|
|
7401
|
+
await this.handleReloadCommand();
|
|
7402
|
+
}
|
|
7403
|
+
catch (error) {
|
|
7404
|
+
this.showError(error instanceof Error ? error.message : String(error));
|
|
7405
|
+
}
|
|
7406
|
+
}
|
|
6815
7407
|
handleDebugCommand() {
|
|
6816
7408
|
const width = this.ui.terminal.columns;
|
|
6817
7409
|
const height = this.ui.terminal.rows;
|