@caupulican/pi-adaptative 0.80.45 → 0.80.47

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.
Files changed (44) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/dist/core/agent-session.d.ts.map +1 -1
  3. package/dist/core/agent-session.js +1 -0
  4. package/dist/core/agent-session.js.map +1 -1
  5. package/dist/core/extensions/loader.d.ts.map +1 -1
  6. package/dist/core/extensions/loader.js +5 -0
  7. package/dist/core/extensions/loader.js.map +1 -1
  8. package/dist/core/extensions/runner.d.ts.map +1 -1
  9. package/dist/core/extensions/runner.js +1 -0
  10. package/dist/core/extensions/runner.js.map +1 -1
  11. package/dist/core/extensions/types.d.ts +3 -0
  12. package/dist/core/extensions/types.d.ts.map +1 -1
  13. package/dist/core/extensions/types.js.map +1 -1
  14. package/dist/core/profile-registry.d.ts +1 -0
  15. package/dist/core/profile-registry.d.ts.map +1 -1
  16. package/dist/core/profile-registry.js +40 -20
  17. package/dist/core/profile-registry.js.map +1 -1
  18. package/dist/core/resource-loader.d.ts.map +1 -1
  19. package/dist/core/resource-loader.js +133 -4
  20. package/dist/core/resource-loader.js.map +1 -1
  21. package/dist/core/settings-manager.d.ts +10 -1
  22. package/dist/core/settings-manager.d.ts.map +1 -1
  23. package/dist/core/settings-manager.js +67 -1
  24. package/dist/core/settings-manager.js.map +1 -1
  25. package/dist/core/slash-commands.d.ts.map +1 -1
  26. package/dist/core/slash-commands.js +12 -0
  27. package/dist/core/slash-commands.js.map +1 -1
  28. package/dist/modes/interactive/components/settings-selector.d.ts +11 -1
  29. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  30. package/dist/modes/interactive/components/settings-selector.js +39 -1
  31. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  32. package/dist/modes/interactive/interactive-mode.d.ts +6 -0
  33. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  34. package/dist/modes/interactive/interactive-mode.js +326 -1
  35. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  36. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  37. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  38. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  39. package/examples/extensions/sandbox/package-lock.json +2 -2
  40. package/examples/extensions/sandbox/package.json +1 -1
  41. package/examples/extensions/with-deps/package-lock.json +2 -2
  42. package/examples/extensions/with-deps/package.json +1 -1
  43. package/npm-shrinkwrap.json +12 -12
  44. package/package.json +4 -4
@@ -62,7 +62,7 @@ import { ProfileResourceEditorComponent, } from "./components/profile-resource-e
62
62
  import { ProfileSelectorComponent } from "./components/profile-selector.js";
63
63
  import { ScopedModelsSelectorComponent } from "./components/scoped-models-selector.js";
64
64
  import { SessionSelectorComponent } from "./components/session-selector.js";
65
- import { SettingsSelectorComponent } from "./components/settings-selector.js";
65
+ import { SelectSubmenu, SettingsSelectorComponent } from "./components/settings-selector.js";
66
66
  import { SkillInvocationMessageComponent } from "./components/skill-invocation-message.js";
67
67
  import { ToolExecutionComponent } from "./components/tool-execution.js";
68
68
  import { ToolGroupComponent } from "./components/tool-group.js";
@@ -2541,6 +2541,24 @@ export class InteractiveMode {
2541
2541
  await this.handleReloadCommand();
2542
2542
  return;
2543
2543
  }
2544
+ if (text === "/install-resources" || text.startsWith("/install-resources ")) {
2545
+ const args = text.slice("/install-resources".length).trim();
2546
+ this.editor.setText("");
2547
+ await this.handleInstallResourcesCommand(args);
2548
+ return;
2549
+ }
2550
+ if (text === "/config-backup" || text.startsWith("/config-backup ")) {
2551
+ const file = text.slice("/config-backup".length).trim() || undefined;
2552
+ this.editor.setText("");
2553
+ await this.handleConfigBackupCommand(file);
2554
+ return;
2555
+ }
2556
+ if (text === "/config-restore" || text.startsWith("/config-restore ")) {
2557
+ const file = text.slice("/config-restore".length).trim();
2558
+ this.editor.setText("");
2559
+ await this.handleConfigRestoreCommand(file);
2560
+ return;
2561
+ }
2544
2562
  if (text === "/debug") {
2545
2563
  this.handleDebugCommand();
2546
2564
  this.editor.setText("");
@@ -4926,6 +4944,8 @@ export class InteractiveMode {
4926
4944
  : undefined,
4927
4945
  activeProfileName: this.settingsManager.getActiveResourceProfileNames()[0],
4928
4946
  profileOptions,
4947
+ externalResourceRoots: this.settingsManager.getExternalResourceRoots(),
4948
+ trustedResourceRoots: this.settingsManager.getTrustedResourceRoots(),
4929
4949
  }, {
4930
4950
  onAutoCompactChange: (enabled) => {
4931
4951
  this.session.setAutoCompactionEnabled(enabled);
@@ -5088,6 +5108,14 @@ export class InteractiveMode {
5088
5108
  done();
5089
5109
  this.deleteProfileFromSource(profileName);
5090
5110
  },
5111
+ onAddExternalResourceRoot: () => {
5112
+ done();
5113
+ void this.addExternalResourceRootFlow();
5114
+ },
5115
+ onRemoveExternalResourceRoot: (root) => {
5116
+ done();
5117
+ void this.removeExternalResourceRootFlow(root);
5118
+ },
5091
5119
  onCancel: () => {
5092
5120
  done();
5093
5121
  this.ui.requestRender();
@@ -5388,6 +5416,81 @@ export class InteractiveMode {
5388
5416
  this.showError(error instanceof Error ? error.message : String(error));
5389
5417
  }
5390
5418
  }
5419
+ async addExternalResourceRootFlow() {
5420
+ const rootPath = await new Promise((resolve) => {
5421
+ this.showSelector((done) => {
5422
+ const input = new ExtensionInputComponent("Add External Root", "Enter external root directory path", (value) => {
5423
+ done();
5424
+ resolve(value);
5425
+ }, () => {
5426
+ done();
5427
+ resolve(undefined);
5428
+ }, { tui: this.ui });
5429
+ return { component: input, focus: input };
5430
+ });
5431
+ });
5432
+ if (rootPath === undefined) {
5433
+ this.ui.requestRender();
5434
+ return;
5435
+ }
5436
+ const trimmed = rootPath.trim();
5437
+ if (!trimmed) {
5438
+ this.showError("Directory path cannot be empty");
5439
+ return;
5440
+ }
5441
+ const canonical = this.settingsManager.canonicalizePath(trimmed);
5442
+ if (!canonical) {
5443
+ this.showError(`Invalid path: ${trimmed}`);
5444
+ return;
5445
+ }
5446
+ // Prompt for trust confirmation (Yes/No)
5447
+ const trust = await new Promise((resolve) => {
5448
+ this.showSelector((done) => {
5449
+ const submenu = new SelectSubmenu("Trust external source?", "This directory can load custom extensions that execute arbitrary code on your machine.", [
5450
+ { value: "yes", label: "Yes", description: "Trust this directory and enable loading resources." },
5451
+ { value: "no", label: "No", description: "Do not trust this directory. Skip loading resources." },
5452
+ ], "no", (value) => {
5453
+ done();
5454
+ resolve(value === "yes");
5455
+ }, () => {
5456
+ done();
5457
+ resolve(false);
5458
+ });
5459
+ return { component: submenu, focus: submenu.getSelectList() };
5460
+ });
5461
+ });
5462
+ if (!trust) {
5463
+ this.showStatus("Aborted. External root was not trusted.");
5464
+ return;
5465
+ }
5466
+ try {
5467
+ const currentRoots = this.settingsManager.getExternalResourceRoots();
5468
+ if (!currentRoots.includes(canonical)) {
5469
+ this.settingsManager.setExternalResourceRoots([...currentRoots, canonical], "global");
5470
+ }
5471
+ this.settingsManager.addTrustedResourceRoot(canonical, "global");
5472
+ this.showStatus(`Added trusted external root: ${canonical}`);
5473
+ await this.handleReloadCommand();
5474
+ }
5475
+ catch (error) {
5476
+ this.showError(error instanceof Error ? error.message : String(error));
5477
+ }
5478
+ }
5479
+ async removeExternalResourceRootFlow(root) {
5480
+ try {
5481
+ const currentRoots = this.settingsManager.getExternalResourceRoots();
5482
+ const currentTrusted = this.settingsManager.getTrustedResourceRoots();
5483
+ const newRoots = currentRoots.filter((r) => r !== root);
5484
+ const newTrusted = currentTrusted.filter((r) => r !== root);
5485
+ this.settingsManager.setExternalResourceRoots(newRoots, "global");
5486
+ this.settingsManager.setTrustedResourceRoots(newTrusted, "global");
5487
+ this.showStatus(`Removed external root: ${root}`);
5488
+ await this.handleReloadCommand();
5489
+ }
5490
+ catch (error) {
5491
+ this.showError(error instanceof Error ? error.message : String(error));
5492
+ }
5493
+ }
5391
5494
  async handleModelCommand(searchTerm) {
5392
5495
  if (!searchTerm) {
5393
5496
  await this.showModelSelector();
@@ -6727,6 +6830,228 @@ export class InteractiveMode {
6727
6830
  await this.handleFatalRuntimeError("Failed to create session", error);
6728
6831
  }
6729
6832
  }
6833
+ copyResourcesRecursively(src, dest, force, stats) {
6834
+ if (!fs.existsSync(src))
6835
+ return;
6836
+ const entries = fs.readdirSync(src, { withFileTypes: true });
6837
+ fs.mkdirSync(dest, { recursive: true });
6838
+ for (const entry of entries) {
6839
+ const srcPath = path.join(src, entry.name);
6840
+ const destPath = path.join(dest, entry.name);
6841
+ if (entry.isDirectory()) {
6842
+ this.copyResourcesRecursively(srcPath, destPath, force, stats);
6843
+ }
6844
+ else if (entry.isFile()) {
6845
+ if (fs.existsSync(destPath) && !force) {
6846
+ stats.skipped.push(destPath);
6847
+ }
6848
+ else {
6849
+ fs.copyFileSync(srcPath, destPath);
6850
+ stats.installed.push(destPath);
6851
+ }
6852
+ }
6853
+ }
6854
+ }
6855
+ async handleInstallResourcesCommand(argsString) {
6856
+ try {
6857
+ const tokens = argsString.split(/\s+/).filter(Boolean);
6858
+ let force = false;
6859
+ let dir = "";
6860
+ for (const t of tokens) {
6861
+ if (t === "--force") {
6862
+ force = true;
6863
+ }
6864
+ else {
6865
+ dir = t;
6866
+ }
6867
+ }
6868
+ if (!dir) {
6869
+ this.showError("Usage: /install-resources <dir> [--force]");
6870
+ return;
6871
+ }
6872
+ const canonical = this.settingsManager.canonicalizePath(dir);
6873
+ if (!canonical || !fs.existsSync(canonical)) {
6874
+ this.showError(`Source directory does not exist: ${dir}`);
6875
+ return;
6876
+ }
6877
+ const trustedRoots = this.settingsManager.getTrustedResourceRoots();
6878
+ const trusted = trustedRoots.includes(canonical);
6879
+ if (!trusted) {
6880
+ const trust = await new Promise((resolve) => {
6881
+ this.showSelector((done) => {
6882
+ 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?`, [
6883
+ {
6884
+ value: "yes",
6885
+ label: "Yes",
6886
+ description: "Trust this directory and proceed with installation.",
6887
+ },
6888
+ { value: "no", label: "No", description: "Do not trust this directory. Abort." },
6889
+ ], "no", (value) => {
6890
+ done();
6891
+ resolve(value === "yes");
6892
+ }, () => {
6893
+ done();
6894
+ resolve(false);
6895
+ });
6896
+ return { component: submenu, focus: submenu.getSelectList() };
6897
+ });
6898
+ });
6899
+ if (!trust) {
6900
+ this.showStatus("Installation aborted. Source directory was not trusted.");
6901
+ return;
6902
+ }
6903
+ this.settingsManager.addTrustedResourceRoot(canonical, "global");
6904
+ }
6905
+ const subdirs = ["skills", "extensions", "prompts", "themes", "profiles"];
6906
+ const stats = { installed: [], skipped: [] };
6907
+ const userAgentDir = getAgentDir();
6908
+ for (const sub of subdirs) {
6909
+ const srcSub = path.join(canonical, sub);
6910
+ const destSub = path.join(userAgentDir, sub);
6911
+ if (fs.existsSync(srcSub)) {
6912
+ this.copyResourcesRecursively(srcSub, destSub, force, stats);
6913
+ }
6914
+ }
6915
+ const installedCount = stats.installed.length;
6916
+ const skippedCount = stats.skipped.length;
6917
+ this.showStatus(`Installation complete: ${installedCount} resources installed, ${skippedCount} skipped.`);
6918
+ await this.handleReloadCommand();
6919
+ }
6920
+ catch (error) {
6921
+ this.showError(error instanceof Error ? error.message : String(error));
6922
+ }
6923
+ }
6924
+ async handleConfigBackupCommand(fileArg) {
6925
+ try {
6926
+ const profilesDir = path.join(getAgentDir(), "profiles");
6927
+ const profiles = {};
6928
+ if (fs.existsSync(profilesDir)) {
6929
+ const entries = fs.readdirSync(profilesDir);
6930
+ for (const entry of entries) {
6931
+ if (entry.endsWith(".json")) {
6932
+ const pPath = path.join(profilesDir, entry);
6933
+ try {
6934
+ const content = fs.readFileSync(pPath, "utf-8");
6935
+ profiles[entry] = JSON.parse(content);
6936
+ }
6937
+ catch {
6938
+ // skip
6939
+ }
6940
+ }
6941
+ }
6942
+ }
6943
+ const backupData = {
6944
+ profiles,
6945
+ settings: {
6946
+ resourceProfiles: this.settingsManager.settings.resourceProfiles,
6947
+ activeResourceProfile: this.settingsManager.settings.activeResourceProfile,
6948
+ externalResourceRoots: this.settingsManager.settings.externalResourceRoots,
6949
+ trustedResourceRoots: this.settingsManager.settings.trustedResourceRoots,
6950
+ },
6951
+ };
6952
+ let targetFile = fileArg;
6953
+ if (!targetFile) {
6954
+ const backupsDir = path.join(getAgentDir(), "backups");
6955
+ fs.mkdirSync(backupsDir, { recursive: true });
6956
+ const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
6957
+ targetFile = path.join(backupsDir, `config-${timestamp}.json`);
6958
+ }
6959
+ else {
6960
+ const resolved = this.settingsManager.canonicalizePath(targetFile);
6961
+ if (resolved) {
6962
+ targetFile = resolved;
6963
+ }
6964
+ }
6965
+ fs.mkdirSync(path.dirname(targetFile), { recursive: true });
6966
+ fs.writeFileSync(targetFile, JSON.stringify(backupData, null, 2), "utf-8");
6967
+ this.showStatus(`Configuration backup saved to ${targetFile}`);
6968
+ }
6969
+ catch (error) {
6970
+ this.showError(error instanceof Error ? error.message : String(error));
6971
+ }
6972
+ }
6973
+ async handleConfigRestoreCommand(fileArg) {
6974
+ try {
6975
+ const trimmed = fileArg.trim();
6976
+ if (!trimmed) {
6977
+ this.showError("Usage: /config-restore <file>");
6978
+ return;
6979
+ }
6980
+ const resolved = this.settingsManager.canonicalizePath(trimmed);
6981
+ if (!resolved || !fs.existsSync(resolved)) {
6982
+ this.showError(`Backup file does not exist: ${trimmed}`);
6983
+ return;
6984
+ }
6985
+ let bundle;
6986
+ try {
6987
+ const content = fs.readFileSync(resolved, "utf-8");
6988
+ bundle = JSON.parse(content);
6989
+ }
6990
+ catch (error) {
6991
+ this.showError(`Failed to parse backup file: ${error instanceof Error ? error.message : String(error)}`);
6992
+ return;
6993
+ }
6994
+ if (!bundle || typeof bundle !== "object") {
6995
+ this.showError("Invalid backup file: must be a JSON object");
6996
+ return;
6997
+ }
6998
+ // Confirm before clobbering
6999
+ const confirm = await new Promise((resolve) => {
7000
+ this.showSelector((done) => {
7001
+ const submenu = new SelectSubmenu("Restore configuration?", "This will overwrite existing local profiles and settings with the backup values. Do you want to continue?", [
7002
+ { value: "yes", label: "Yes", description: "Proceed with restoration." },
7003
+ { value: "no", label: "No", description: "Cancel and abort." },
7004
+ ], "no", (value) => {
7005
+ done();
7006
+ resolve(value === "yes");
7007
+ }, () => {
7008
+ done();
7009
+ resolve(false);
7010
+ });
7011
+ return { component: submenu, focus: submenu.getSelectList() };
7012
+ });
7013
+ });
7014
+ if (!confirm) {
7015
+ this.showStatus("Restore aborted.");
7016
+ return;
7017
+ }
7018
+ // 1. Restore profile files (reusable-file scope)
7019
+ if (bundle.profiles && typeof bundle.profiles === "object") {
7020
+ const profilesDir = path.join(getAgentDir(), "profiles");
7021
+ fs.mkdirSync(profilesDir, { recursive: true });
7022
+ for (const [filename, content] of Object.entries(bundle.profiles)) {
7023
+ const targetPath = path.join(profilesDir, filename);
7024
+ fs.writeFileSync(targetPath, JSON.stringify(content, null, 2), "utf-8");
7025
+ }
7026
+ }
7027
+ // 2. Restore settings
7028
+ if (bundle.settings && typeof bundle.settings === "object") {
7029
+ const bs = bundle.settings;
7030
+ // Global profiles definitions
7031
+ if (bs.resourceProfiles && typeof bs.resourceProfiles === "object") {
7032
+ for (const [name, definition] of Object.entries(bs.resourceProfiles)) {
7033
+ this.settingsManager.setProfileDefinition(name, definition, "global");
7034
+ }
7035
+ }
7036
+ // Active profile selection
7037
+ if (bs.activeResourceProfile) {
7038
+ this.settingsManager.setActiveProfile(bs.activeResourceProfile, "global");
7039
+ }
7040
+ // External roots (trustedRoots are NOT restored, as per SECURITY requirement)
7041
+ if (Array.isArray(bs.externalResourceRoots)) {
7042
+ this.settingsManager.setExternalResourceRoots(bs.externalResourceRoots, "global");
7043
+ const currentTrusted = this.settingsManager.getTrustedResourceRoots();
7044
+ const newTrusted = currentTrusted.filter((r) => !bs.externalResourceRoots.includes(r));
7045
+ this.settingsManager.setTrustedResourceRoots(newTrusted, "global");
7046
+ }
7047
+ }
7048
+ this.showStatus("Configuration restored successfully.");
7049
+ await this.handleReloadCommand();
7050
+ }
7051
+ catch (error) {
7052
+ this.showError(error instanceof Error ? error.message : String(error));
7053
+ }
7054
+ }
6730
7055
  handleDebugCommand() {
6731
7056
  const width = this.ui.terminal.columns;
6732
7057
  const height = this.ui.terminal.rows;