@earendil-works/pi-coding-agent 0.78.1 → 0.79.0

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 (129) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/README.md +21 -4
  3. package/dist/cli/args.d.ts +1 -0
  4. package/dist/cli/args.d.ts.map +1 -1
  5. package/dist/cli/args.js +12 -2
  6. package/dist/cli/args.js.map +1 -1
  7. package/dist/core/agent-session-runtime.d.ts +3 -1
  8. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  9. package/dist/core/agent-session-runtime.js +1 -0
  10. package/dist/core/agent-session-runtime.js.map +1 -1
  11. package/dist/core/agent-session-services.d.ts +2 -1
  12. package/dist/core/agent-session-services.d.ts.map +1 -1
  13. package/dist/core/agent-session-services.js +2 -2
  14. package/dist/core/agent-session-services.js.map +1 -1
  15. package/dist/core/compaction/utils.d.ts +1 -1
  16. package/dist/core/compaction/utils.d.ts.map +1 -1
  17. package/dist/core/compaction/utils.js +1 -1
  18. package/dist/core/compaction/utils.js.map +1 -1
  19. package/dist/core/extensions/index.d.ts +1 -1
  20. package/dist/core/extensions/index.d.ts.map +1 -1
  21. package/dist/core/extensions/index.js.map +1 -1
  22. package/dist/core/extensions/loader.d.ts +1 -1
  23. package/dist/core/extensions/loader.d.ts.map +1 -1
  24. package/dist/core/extensions/loader.js +4 -4
  25. package/dist/core/extensions/loader.js.map +1 -1
  26. package/dist/core/extensions/runner.d.ts +6 -2
  27. package/dist/core/extensions/runner.d.ts.map +1 -1
  28. package/dist/core/extensions/runner.js +28 -0
  29. package/dist/core/extensions/runner.js.map +1 -1
  30. package/dist/core/extensions/types.d.ts +18 -1
  31. package/dist/core/extensions/types.d.ts.map +1 -1
  32. package/dist/core/extensions/types.js.map +1 -1
  33. package/dist/core/model-registry.d.ts.map +1 -1
  34. package/dist/core/model-registry.js +1 -0
  35. package/dist/core/model-registry.js.map +1 -1
  36. package/dist/core/package-manager.d.ts +1 -0
  37. package/dist/core/package-manager.d.ts.map +1 -1
  38. package/dist/core/package-manager.js +25 -7
  39. package/dist/core/package-manager.js.map +1 -1
  40. package/dist/core/resource-loader.d.ts +13 -2
  41. package/dist/core/resource-loader.d.ts.map +1 -1
  42. package/dist/core/resource-loader.js +129 -54
  43. package/dist/core/resource-loader.js.map +1 -1
  44. package/dist/core/settings-manager.d.ts +10 -2
  45. package/dist/core/settings-manager.d.ts.map +1 -1
  46. package/dist/core/settings-manager.js +71 -30
  47. package/dist/core/settings-manager.js.map +1 -1
  48. package/dist/core/slash-commands.d.ts.map +1 -1
  49. package/dist/core/slash-commands.js +1 -0
  50. package/dist/core/slash-commands.js.map +1 -1
  51. package/dist/core/tools/bash.d.ts.map +1 -1
  52. package/dist/core/tools/bash.js +1 -1
  53. package/dist/core/tools/bash.js.map +1 -1
  54. package/dist/core/tools/find.d.ts.map +1 -1
  55. package/dist/core/tools/find.js +1 -1
  56. package/dist/core/tools/find.js.map +1 -1
  57. package/dist/core/tools/grep.d.ts.map +1 -1
  58. package/dist/core/tools/grep.js +1 -1
  59. package/dist/core/tools/grep.js.map +1 -1
  60. package/dist/core/tools/ls.d.ts.map +1 -1
  61. package/dist/core/tools/ls.js +1 -1
  62. package/dist/core/tools/ls.js.map +1 -1
  63. package/dist/core/tools/read.d.ts.map +1 -1
  64. package/dist/core/tools/read.js +1 -1
  65. package/dist/core/tools/read.js.map +1 -1
  66. package/dist/core/tools/write.d.ts.map +1 -1
  67. package/dist/core/tools/write.js +1 -1
  68. package/dist/core/tools/write.js.map +1 -1
  69. package/dist/core/trust-manager.d.ts +10 -0
  70. package/dist/core/trust-manager.d.ts.map +1 -0
  71. package/dist/core/trust-manager.js +133 -0
  72. package/dist/core/trust-manager.js.map +1 -0
  73. package/dist/index.d.ts +5 -4
  74. package/dist/index.d.ts.map +1 -1
  75. package/dist/index.js +2 -1
  76. package/dist/index.js.map +1 -1
  77. package/dist/main.d.ts.map +1 -1
  78. package/dist/main.js +195 -6
  79. package/dist/main.js.map +1 -1
  80. package/dist/modes/index.d.ts +1 -1
  81. package/dist/modes/index.d.ts.map +1 -1
  82. package/dist/modes/index.js.map +1 -1
  83. package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
  84. package/dist/modes/interactive/components/bash-execution.js +2 -2
  85. package/dist/modes/interactive/components/bash-execution.js.map +1 -1
  86. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  87. package/dist/modes/interactive/components/footer.js +7 -0
  88. package/dist/modes/interactive/components/footer.js.map +1 -1
  89. package/dist/modes/interactive/components/index.d.ts +1 -0
  90. package/dist/modes/interactive/components/index.d.ts.map +1 -1
  91. package/dist/modes/interactive/components/index.js +1 -0
  92. package/dist/modes/interactive/components/index.js.map +1 -1
  93. package/dist/modes/interactive/components/trust-selector.d.ts +20 -0
  94. package/dist/modes/interactive/components/trust-selector.d.ts.map +1 -0
  95. package/dist/modes/interactive/components/trust-selector.js +86 -0
  96. package/dist/modes/interactive/components/trust-selector.js.map +1 -0
  97. package/dist/modes/interactive/interactive-mode.d.ts +7 -0
  98. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  99. package/dist/modes/interactive/interactive-mode.js +85 -1
  100. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  101. package/dist/package-manager-cli.d.ts.map +1 -1
  102. package/dist/package-manager-cli.js +55 -8
  103. package/dist/package-manager-cli.js.map +1 -1
  104. package/docs/docs.json +4 -0
  105. package/docs/extensions.md +22 -1
  106. package/docs/index.md +1 -0
  107. package/docs/packages.md +3 -1
  108. package/docs/prompt-templates.md +1 -1
  109. package/docs/sdk.md +5 -0
  110. package/docs/security.md +57 -0
  111. package/docs/settings.md +10 -0
  112. package/docs/skills.md +1 -1
  113. package/docs/terminal-setup.md +36 -2
  114. package/docs/themes.md +1 -1
  115. package/docs/tmux.md +4 -2
  116. package/docs/usage.md +15 -3
  117. package/examples/extensions/README.md +1 -0
  118. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  119. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  120. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  121. package/examples/extensions/gondolin/package-lock.json +2 -2
  122. package/examples/extensions/gondolin/package.json +1 -1
  123. package/examples/extensions/project-trust.ts +64 -0
  124. package/examples/extensions/sandbox/package-lock.json +2 -2
  125. package/examples/extensions/sandbox/package.json +1 -1
  126. package/examples/extensions/with-deps/package-lock.json +2 -2
  127. package/examples/extensions/with-deps/package.json +1 -1
  128. package/npm-shrinkwrap.json +12 -12
  129. package/package.json +4 -8
@@ -24,6 +24,7 @@ import { formatMissingSessionCwdPrompt, MissingSessionCwdError } from "../../cor
24
24
  import { SessionManager } from "../../core/session-manager.js";
25
25
  import { BUILTIN_SLASH_COMMANDS } from "../../core/slash-commands.js";
26
26
  import { isInstallTelemetryEnabled } from "../../core/telemetry.js";
27
+ import { hasProjectConfigDir, hasProjectTrustInputs, ProjectTrustStore } from "../../core/trust-manager.js";
27
28
  import { getChangelogPath, getNewEntries, parseChangelog } from "../../utils/changelog.js";
28
29
  import { copyToClipboard } from "../../utils/clipboard.js";
29
30
  import { extensionForImageMimeType, readClipboardImage } from "../../utils/clipboard-image.js";
@@ -59,6 +60,7 @@ import { SettingsSelectorComponent } from "./components/settings-selector.js";
59
60
  import { SkillInvocationMessageComponent } from "./components/skill-invocation-message.js";
60
61
  import { ToolExecutionComponent } from "./components/tool-execution.js";
61
62
  import { TreeSelectorComponent } from "./components/tree-selector.js";
63
+ import { TrustSelectorComponent } from "./components/trust-selector.js";
62
64
  import { UserMessageComponent } from "./components/user-message.js";
63
65
  import { UserMessageSelectorComponent } from "./components/user-message-selector.js";
64
66
  import { getAvailableThemes, getAvailableThemesWithPaths, getEditorTheme, getMarkdownTheme, getThemeByName, initTheme, onThemeChange, setRegisteredThemes, setTheme, setThemeInstance, stopThemeWatcher, Theme, theme, } from "./theme/theme.js";
@@ -213,6 +215,7 @@ export class InteractiveMode {
213
215
  // Custom header from extension (undefined = use built-in header)
214
216
  customHeader = undefined;
215
217
  options;
218
+ autoTrustOnReloadCwd;
216
219
  // Convenience accessors
217
220
  get session() {
218
221
  return this.runtimeHost.session;
@@ -229,6 +232,7 @@ export class InteractiveMode {
229
232
  constructor(runtimeHost, options = {}) {
230
233
  this.runtimeHost = runtimeHost;
231
234
  this.options = options;
235
+ this.autoTrustOnReloadCwd = options.autoTrustOnReloadCwd;
232
236
  this.runtimeHost.setBeforeSessionInvalidate(() => {
233
237
  this.resetExtensionUI();
234
238
  });
@@ -1555,6 +1559,20 @@ export class InteractiveMode {
1555
1559
  /**
1556
1560
  * Create the ExtensionUIContext for extensions.
1557
1561
  */
1562
+ createProjectTrustContext(cwd) {
1563
+ const ui = this.createExtensionUIContext();
1564
+ return {
1565
+ cwd,
1566
+ mode: "tui",
1567
+ hasUI: true,
1568
+ ui: {
1569
+ select: ui.select,
1570
+ confirm: ui.confirm,
1571
+ input: ui.input,
1572
+ notify: ui.notify,
1573
+ },
1574
+ };
1575
+ }
1558
1576
  createExtensionUIContext() {
1559
1577
  return {
1560
1578
  select: (title, options, opts) => this.showExtensionSelector(title, options, opts),
@@ -2059,6 +2077,11 @@ export class InteractiveMode {
2059
2077
  this.editor.setText("");
2060
2078
  return;
2061
2079
  }
2080
+ if (text === "/trust") {
2081
+ this.showTrustSelector();
2082
+ this.editor.setText("");
2083
+ return;
2084
+ }
2062
2085
  if (text === "/login") {
2063
2086
  this.showOAuthSelector("login");
2064
2087
  this.editor.setText("");
@@ -2528,6 +2551,7 @@ export class InteractiveMode {
2528
2551
  this.chatContainer.addChild(component);
2529
2552
  // Render user message separately if present
2530
2553
  if (skillBlock.userMessage) {
2554
+ this.chatContainer.addChild(new Spacer(1));
2531
2555
  const userComponent = new UserMessageComponent(skillBlock.userMessage, this.getMarkdownThemeWithSettings());
2532
2556
  this.chatContainer.addChild(userComponent);
2533
2557
  }
@@ -2627,6 +2651,7 @@ export class InteractiveMode {
2627
2651
  updateFooter: true,
2628
2652
  populateHistory: true,
2629
2653
  });
2654
+ this.renderProjectTrustWarningIfNeeded();
2630
2655
  // Show compaction info if session was compacted
2631
2656
  const allEntries = this.sessionManager.getEntries();
2632
2657
  const compactionCount = allEntries.filter((e) => e.type === "compaction").length;
@@ -2635,6 +2660,15 @@ export class InteractiveMode {
2635
2660
  this.showStatus(`Session compacted ${times}`);
2636
2661
  }
2637
2662
  }
2663
+ renderProjectTrustWarningIfNeeded() {
2664
+ if (this.settingsManager.isProjectTrusted() || !hasProjectTrustInputs(this.sessionManager.getCwd())) {
2665
+ return;
2666
+ }
2667
+ if (this.chatContainer.children.length > 0) {
2668
+ this.chatContainer.addChild(new Spacer(1));
2669
+ }
2670
+ this.chatContainer.addChild(new Text(theme.fg("warning", "This project is not trusted. Project instructions (AGENTS.md/CLAUDE.md), .pi resources, and project packages are ignored. Use /trust to save a trust decision, then restart pi."), 1, 0));
2671
+ }
2638
2672
  async getUserInput() {
2639
2673
  const queuedInput = this.pendingUserInputs.shift();
2640
2674
  if (queuedInput !== undefined) {
@@ -3450,6 +3484,51 @@ export class InteractiveMode {
3450
3484
  // Ignore auth lookup failures for warning-only checks.
3451
3485
  }
3452
3486
  }
3487
+ maybeSaveImplicitProjectTrustAfterReload() {
3488
+ const cwd = this.sessionManager.getCwd();
3489
+ if (this.autoTrustOnReloadCwd !== cwd) {
3490
+ return false;
3491
+ }
3492
+ if (!this.settingsManager.isProjectTrusted() || !hasProjectConfigDir(cwd)) {
3493
+ return false;
3494
+ }
3495
+ const trustStore = new ProjectTrustStore(this.runtimeHost.services.agentDir);
3496
+ try {
3497
+ if (trustStore.get(cwd) !== null) {
3498
+ this.autoTrustOnReloadCwd = undefined;
3499
+ return false;
3500
+ }
3501
+ trustStore.set(cwd, true);
3502
+ this.autoTrustOnReloadCwd = undefined;
3503
+ return true;
3504
+ }
3505
+ catch (error) {
3506
+ this.showWarning(`Could not save project trust after reload: ${error instanceof Error ? error.message : String(error)}`);
3507
+ return false;
3508
+ }
3509
+ }
3510
+ showTrustSelector() {
3511
+ const cwd = this.sessionManager.getCwd();
3512
+ const trustStore = new ProjectTrustStore(this.runtimeHost.services.agentDir);
3513
+ const savedDecision = trustStore.get(cwd);
3514
+ this.showSelector((done) => {
3515
+ const selector = new TrustSelectorComponent({
3516
+ cwd,
3517
+ savedDecision,
3518
+ projectTrusted: this.settingsManager.isProjectTrusted(),
3519
+ onSelect: (trusted) => {
3520
+ trustStore.set(cwd, trusted);
3521
+ done();
3522
+ this.showStatus(`Saved trust decision: ${trusted ? "trusted" : "untrusted"}. Restart pi for this to take effect.`);
3523
+ },
3524
+ onCancel: () => {
3525
+ done();
3526
+ this.ui.requestRender();
3527
+ },
3528
+ });
3529
+ return { component: selector, focus: selector };
3530
+ });
3531
+ }
3453
3532
  showModelSelector(initialSearchInput) {
3454
3533
  this.showSelector((done) => {
3455
3534
  const selector = new ModelSelectorComponent(this.ui, this.session.model, this.settingsManager, this.session.modelRegistry, this.session.scopedModels, async (model) => {
@@ -3728,6 +3807,7 @@ export class InteractiveMode {
3728
3807
  try {
3729
3808
  const result = await this.runtimeHost.switchSession(sessionPath, {
3730
3809
  withSession: options?.withSession,
3810
+ projectTrustContextFactory: (cwd) => this.createProjectTrustContext(cwd),
3731
3811
  });
3732
3812
  if (result.cancelled) {
3733
3813
  return result;
@@ -3746,6 +3826,7 @@ export class InteractiveMode {
3746
3826
  const result = await this.runtimeHost.switchSession(sessionPath, {
3747
3827
  cwdOverride: selectedCwd,
3748
3828
  withSession: options?.withSession,
3829
+ projectTrustContextFactory: (cwd) => this.createProjectTrustContext(cwd),
3749
3830
  });
3750
3831
  if (result.cancelled) {
3751
3832
  return result;
@@ -4144,11 +4225,14 @@ export class InteractiveMode {
4144
4225
  force: false,
4145
4226
  showDiagnosticsWhenQuiet: true,
4146
4227
  });
4228
+ const savedImplicitProjectTrust = this.maybeSaveImplicitProjectTrustAfterReload();
4147
4229
  const modelsJsonError = this.session.modelRegistry.getError();
4148
4230
  if (modelsJsonError) {
4149
4231
  this.showError(`models.json error: ${modelsJsonError}`);
4150
4232
  }
4151
- this.showStatus("Reloaded keybindings, extensions, skills, prompts, themes");
4233
+ this.showStatus(savedImplicitProjectTrust
4234
+ ? "Reloaded keybindings, extensions, skills, prompts, themes; saved project trust"
4235
+ : "Reloaded keybindings, extensions, skills, prompts, themes");
4152
4236
  }
4153
4237
  catch (error) {
4154
4238
  dismissReloadBox(previousEditor);