@psnext/slingcli 2.5.20260607-2 → 2.5.20260615-2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (205) hide show
  1. package/node_modules/@aws-sdk/core/dist-cjs/index.js +47 -2297
  2. package/node_modules/@aws-sdk/core/dist-es/index.js +3 -3
  3. package/node_modules/@aws-sdk/core/dist-types/index.d.ts +5 -5
  4. package/node_modules/@aws-sdk/core/dist-types/ts3.4/index.d.ts +5 -5
  5. package/node_modules/@aws-sdk/core/package.json +8 -8
  6. package/node_modules/@aws-sdk/credential-provider-env/package.json +4 -4
  7. package/node_modules/@aws-sdk/credential-provider-http/node_modules/@smithy/node-http-handler/package.json +7 -7
  8. package/node_modules/@aws-sdk/credential-provider-http/package.json +6 -5
  9. package/node_modules/@aws-sdk/credential-provider-ini/package.json +11 -11
  10. package/node_modules/@aws-sdk/credential-provider-login/package.json +5 -5
  11. package/node_modules/@aws-sdk/credential-provider-node/package.json +9 -9
  12. package/node_modules/@aws-sdk/credential-provider-process/package.json +4 -4
  13. package/node_modules/@aws-sdk/credential-provider-sso/dist-cjs/index.js +4 -1
  14. package/node_modules/@aws-sdk/credential-provider-sso/dist-es/resolveSSOCredentials.js +4 -1
  15. package/node_modules/@aws-sdk/credential-provider-sso/node_modules/@aws-sdk/token-providers/package.json +5 -5
  16. package/node_modules/@aws-sdk/credential-provider-sso/package.json +9 -7
  17. package/node_modules/@aws-sdk/credential-provider-web-identity/package.json +5 -5
  18. package/node_modules/@aws-sdk/eventstream-handler-node/package.json +3 -3
  19. package/node_modules/@aws-sdk/middleware-eventstream/package.json +3 -3
  20. package/node_modules/@aws-sdk/middleware-websocket/package.json +5 -5
  21. package/node_modules/@aws-sdk/nested-clients/dist-cjs/submodules/cognito-identity/index.js +1 -1
  22. package/node_modules/@aws-sdk/nested-clients/dist-cjs/submodules/signin/index.js +1 -1
  23. package/node_modules/@aws-sdk/nested-clients/dist-cjs/submodules/sso/index.js +1 -1
  24. package/node_modules/@aws-sdk/nested-clients/dist-cjs/submodules/sso-oidc/index.js +1 -1
  25. package/node_modules/@aws-sdk/nested-clients/dist-cjs/submodules/sts/index.js +1 -1
  26. package/node_modules/@aws-sdk/nested-clients/node_modules/@smithy/node-http-handler/package.json +7 -7
  27. package/node_modules/@aws-sdk/nested-clients/package.json +6 -6
  28. package/node_modules/@aws-sdk/signature-v4-multi-region/package.json +7 -6
  29. package/node_modules/@aws-sdk/types/package.json +2 -2
  30. package/node_modules/@aws-sdk/util-locate-window/package.json +2 -2
  31. package/node_modules/@aws-sdk/xml-builder/package.json +2 -2
  32. package/node_modules/@earendil-works/pi-agent-core/dist/agent-loop.js +8 -0
  33. package/node_modules/@earendil-works/pi-agent-core/dist/harness/compaction/compaction.js +1 -1
  34. package/node_modules/@earendil-works/pi-agent-core/package.json +2 -2
  35. package/node_modules/@earendil-works/pi-ai/dist/image-models.generated.js +6 -6
  36. package/node_modules/@earendil-works/pi-ai/dist/models.generated.js +906 -873
  37. package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.js +25 -8
  38. package/node_modules/@earendil-works/pi-ai/dist/providers/anthropic.js +19 -12
  39. package/node_modules/@earendil-works/pi-ai/dist/providers/azure-openai-responses.js +1 -0
  40. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-codex-responses.js +8 -4
  41. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-completions.js +2 -1
  42. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses-shared.js +2 -1
  43. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses.js +1 -0
  44. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/openai-codex.js +1 -1
  45. package/node_modules/@earendil-works/pi-ai/dist/utils/overflow.js +3 -2
  46. package/node_modules/@earendil-works/pi-ai/package.json +1 -1
  47. package/node_modules/@earendil-works/pi-coding-agent/dist/cli/args.js +3 -5
  48. package/node_modules/@earendil-works/pi-coding-agent/dist/cli/project-trust.js +48 -0
  49. package/node_modules/@earendil-works/pi-coding-agent/dist/cli/startup-ui.js +133 -0
  50. package/node_modules/@earendil-works/pi-coding-agent/dist/config.js +14 -3
  51. package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session-runtime.js +4 -1
  52. package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session-services.js +2 -2
  53. package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session.js +9 -2
  54. package/node_modules/@earendil-works/pi-coding-agent/dist/core/compaction/utils.js +1 -1
  55. package/node_modules/@earendil-works/pi-coding-agent/dist/core/experimental.js +4 -0
  56. package/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/loader.js +4 -4
  57. package/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/runner.js +34 -0
  58. package/node_modules/@earendil-works/pi-coding-agent/dist/core/index.js +1 -0
  59. package/node_modules/@earendil-works/pi-coding-agent/dist/core/model-registry.js +5 -57
  60. package/node_modules/@earendil-works/pi-coding-agent/dist/core/model-resolver.js +41 -5
  61. package/node_modules/@earendil-works/pi-coding-agent/dist/core/package-manager.js +31 -17
  62. package/node_modules/@earendil-works/pi-coding-agent/dist/core/project-trust.js +58 -0
  63. package/node_modules/@earendil-works/pi-coding-agent/dist/core/prompt-templates.js +24 -26
  64. package/node_modules/@earendil-works/pi-coding-agent/dist/core/resolve-config-value.js +0 -4
  65. package/node_modules/@earendil-works/pi-coding-agent/dist/core/resource-loader.js +121 -54
  66. package/node_modules/@earendil-works/pi-coding-agent/dist/core/session-manager.js +11 -2
  67. package/node_modules/@earendil-works/pi-coding-agent/dist/core/settings-manager.js +26 -0
  68. package/node_modules/@earendil-works/pi-coding-agent/dist/core/trust-manager.js +89 -17
  69. package/node_modules/@earendil-works/pi-coding-agent/dist/index.js +2 -2
  70. package/node_modules/@earendil-works/pi-coding-agent/dist/main.js +65 -76
  71. package/node_modules/@earendil-works/pi-coding-agent/dist/migrations.js +1 -118
  72. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/first-time-setup.js +103 -0
  73. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/index.js +1 -0
  74. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/login-dialog.js +7 -1
  75. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/settings-selector.js +20 -0
  76. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/tree-selector.js +87 -12
  77. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/trust-selector.js +23 -18
  78. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/interactive-mode.js +104 -30
  79. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/theme/theme.js +19 -41
  80. package/node_modules/@earendil-works/pi-coding-agent/dist/package-manager-cli.js +72 -18
  81. package/node_modules/@earendil-works/pi-coding-agent/dist/utils/changelog.js +78 -0
  82. package/node_modules/@earendil-works/pi-coding-agent/dist/utils/version-check.js +4 -27
  83. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/LICENSE +15 -0
  84. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/bin/semver.js +195 -0
  85. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/classes/comparator.js +143 -0
  86. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/classes/index.js +7 -0
  87. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/classes/range.js +557 -0
  88. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/classes/semver.js +333 -0
  89. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/functions/clean.js +8 -0
  90. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/functions/cmp.js +54 -0
  91. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/functions/coerce.js +62 -0
  92. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/functions/compare-build.js +9 -0
  93. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/functions/compare-loose.js +5 -0
  94. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/functions/compare.js +7 -0
  95. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/functions/diff.js +60 -0
  96. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/functions/eq.js +5 -0
  97. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/functions/gt.js +5 -0
  98. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/functions/gte.js +5 -0
  99. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/functions/inc.js +21 -0
  100. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/functions/lt.js +5 -0
  101. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/functions/lte.js +5 -0
  102. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/functions/major.js +5 -0
  103. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/functions/minor.js +5 -0
  104. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/functions/neq.js +5 -0
  105. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/functions/parse.js +18 -0
  106. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/functions/patch.js +5 -0
  107. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/functions/prerelease.js +8 -0
  108. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/functions/rcompare.js +5 -0
  109. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/functions/rsort.js +5 -0
  110. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/functions/satisfies.js +12 -0
  111. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/functions/sort.js +5 -0
  112. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/functions/truncate.js +48 -0
  113. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/functions/valid.js +8 -0
  114. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/index.js +93 -0
  115. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/internal/constants.js +37 -0
  116. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/internal/debug.js +11 -0
  117. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/internal/identifiers.js +29 -0
  118. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/internal/lrucache.js +42 -0
  119. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/internal/parse-options.js +17 -0
  120. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/internal/re.js +223 -0
  121. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/package.json +78 -0
  122. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/preload.js +4 -0
  123. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/range.bnf +17 -0
  124. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/ranges/gtr.js +6 -0
  125. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/ranges/intersects.js +9 -0
  126. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/ranges/ltr.js +6 -0
  127. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/ranges/max-satisfying.js +27 -0
  128. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/ranges/min-satisfying.js +26 -0
  129. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/ranges/min-version.js +63 -0
  130. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/ranges/outside.js +82 -0
  131. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/ranges/simplify.js +49 -0
  132. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/ranges/subset.js +249 -0
  133. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/ranges/to-comparators.js +10 -0
  134. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/ranges/valid.js +13 -0
  135. package/node_modules/@earendil-works/pi-coding-agent/npm-shrinkwrap.json +25 -12
  136. package/node_modules/@earendil-works/pi-coding-agent/package.json +6 -8
  137. package/node_modules/@earendil-works/pi-tui/dist/components/editor.js +102 -43
  138. package/node_modules/@earendil-works/pi-tui/dist/components/markdown.js +11 -1
  139. package/node_modules/@earendil-works/pi-tui/dist/fuzzy.js +2 -2
  140. package/node_modules/@earendil-works/pi-tui/dist/index.js +2 -0
  141. package/node_modules/@earendil-works/pi-tui/dist/terminal-colors.js +51 -0
  142. package/node_modules/@earendil-works/pi-tui/dist/terminal.js +38 -77
  143. package/node_modules/@earendil-works/pi-tui/dist/tui.js +145 -21
  144. package/node_modules/@earendil-works/pi-tui/dist/utils.js +44 -16
  145. package/node_modules/@earendil-works/pi-tui/package.json +1 -1
  146. package/node_modules/@nodable/entities/package.json +4 -1
  147. package/node_modules/@nodable/entities/src/EntityDecoder.js +104 -3
  148. package/node_modules/@nodable/entities/src/index.d.ts +77 -0
  149. package/node_modules/@nodable/entities/src/index.js +1 -1
  150. package/node_modules/@smithy/core/dist-cjs/submodules/retry/index.browser.js +3 -3
  151. package/node_modules/@smithy/core/dist-cjs/submodules/retry/index.js +3 -3
  152. package/node_modules/@smithy/core/dist-es/submodules/retry/middleware-retry/retry-pre-sra-deprecated/StandardRetryStrategy.js +2 -2
  153. package/node_modules/@smithy/core/dist-es/submodules/retry/util-retry/DefaultRateLimiter.js +1 -1
  154. package/node_modules/@smithy/core/package.json +17 -17
  155. package/node_modules/@smithy/credential-provider-imds/package.json +6 -6
  156. package/node_modules/@smithy/fetch-http-handler/package.json +9 -9
  157. package/node_modules/@smithy/signature-v4/package.json +6 -6
  158. package/node_modules/@smithy/types/package.json +9 -9
  159. package/node_modules/@types/node/README.md +1 -1
  160. package/node_modules/@types/node/http2.d.ts +1 -0
  161. package/node_modules/@types/node/package.json +2 -2
  162. package/node_modules/anynum/LICENSE +21 -0
  163. package/node_modules/anynum/README.md +142 -0
  164. package/node_modules/anynum/anynum.js +135 -0
  165. package/node_modules/anynum/digitTable.js +116 -0
  166. package/node_modules/anynum/package.json +42 -0
  167. package/node_modules/protobufjs/dist/light/protobuf.js +161 -203
  168. package/node_modules/protobufjs/dist/light/protobuf.js.map +1 -1
  169. package/node_modules/protobufjs/dist/light/protobuf.min.js +3 -3
  170. package/node_modules/protobufjs/dist/light/protobuf.min.js.map +1 -1
  171. package/node_modules/protobufjs/dist/minimal/protobuf.js +34 -77
  172. package/node_modules/protobufjs/dist/minimal/protobuf.js.map +1 -1
  173. package/node_modules/protobufjs/dist/minimal/protobuf.min.js +3 -3
  174. package/node_modules/protobufjs/dist/minimal/protobuf.min.js.map +1 -1
  175. package/node_modules/protobufjs/dist/protobuf.js +181 -223
  176. package/node_modules/protobufjs/dist/protobuf.js.map +1 -1
  177. package/node_modules/protobufjs/dist/protobuf.min.js +3 -3
  178. package/node_modules/protobufjs/dist/protobuf.min.js.map +1 -1
  179. package/node_modules/protobufjs/index.d.ts +0 -8
  180. package/node_modules/protobufjs/package.json +2 -3
  181. package/node_modules/protobufjs/src/converter.js +5 -4
  182. package/node_modules/protobufjs/src/decoder.js +1 -1
  183. package/node_modules/protobufjs/src/service.js +5 -7
  184. package/node_modules/protobufjs/src/type.js +3 -1
  185. package/node_modules/protobufjs/src/util/minimal.js +1 -4
  186. package/node_modules/protobufjs/src/verifier.js +1 -1
  187. package/node_modules/semver/classes/range.js +11 -2
  188. package/node_modules/semver/package.json +2 -2
  189. package/node_modules/strnum/CHANGELOG.md +8 -0
  190. package/node_modules/strnum/README.md +9 -0
  191. package/node_modules/strnum/package.json +4 -1
  192. package/node_modules/strnum/strnum.js +9 -1
  193. package/package.json +6 -6
  194. package/slingshot/index.js +260 -258
  195. package/node_modules/@protobufjs/inquire/CHANGELOG.md +0 -8
  196. package/node_modules/@protobufjs/inquire/LICENSE +0 -26
  197. package/node_modules/@protobufjs/inquire/README.md +0 -13
  198. package/node_modules/@protobufjs/inquire/index.d.ts +0 -10
  199. package/node_modules/@protobufjs/inquire/index.js +0 -38
  200. package/node_modules/@protobufjs/inquire/package.json +0 -21
  201. package/node_modules/@protobufjs/inquire/tests/data/array.js +0 -1
  202. package/node_modules/@protobufjs/inquire/tests/data/emptyArray.js +0 -1
  203. package/node_modules/@protobufjs/inquire/tests/data/emptyObject.js +0 -1
  204. package/node_modules/@protobufjs/inquire/tests/data/object.js +0 -1
  205. package/node_modules/@protobufjs/inquire/tests/index.js +0 -20
@@ -6,13 +6,14 @@
6
6
  */
7
7
  import { createInterface } from "node:readline";
8
8
  import { modelsAreEqual } from "@earendil-works/pi-ai";
9
- import { ProcessTerminal, setKeybindings, TUI } from "@earendil-works/pi-tui";
10
9
  import chalk from "chalk";
11
10
  import { parseArgs, printHelp } from "./cli/args.js";
12
11
  import { processFileArguments } from "./cli/file-processor.js";
13
12
  import { buildInitialMessage } from "./cli/initial-message.js";
14
13
  import { listModels } from "./cli/list-models.js";
14
+ import { createProjectTrustContext } from "./cli/project-trust.js";
15
15
  import { selectSession } from "./cli/session-picker.js";
16
+ import { shouldRunFirstTimeSetup, showFirstTimeSetup, showStartupSelector } from "./cli/startup-ui.js";
16
17
  import { ENV_SESSION_DIR, expandTildePath, getAgentDir, getPackageDir, VERSION } from "./config.js";
17
18
  import { createAgentSessionRuntime } from "./core/agent-session-runtime.js";
18
19
  import { createAgentSessionFromServices, createAgentSessionServices, } from "./core/agent-session-services.js";
@@ -20,17 +21,16 @@ import { formatNoModelsAvailableMessage } from "./core/auth-guidance.js";
20
21
  import { AuthStorage } from "./core/auth-storage.js";
21
22
  import { exportFromFile } from "./core/export-html/index.js";
22
23
  import { configureHttpDispatcher } from "./core/http-dispatcher.js";
23
- import { KeybindingsManager } from "./core/keybindings.js";
24
24
  import { resolveCliModel, resolveModelScope } from "./core/model-resolver.js";
25
25
  import { restoreStdout, takeOverStdout } from "./core/output-guard.js";
26
+ import { resolveProjectTrusted } from "./core/project-trust.js";
26
27
  import { formatMissingSessionCwdPrompt, getMissingSessionCwdIssue, MissingSessionCwdError, } from "./core/session-cwd.js";
27
28
  import { assertValidSessionId, SessionManager } from "./core/session-manager.js";
28
29
  import { SettingsManager } from "./core/settings-manager.js";
29
30
  import { printTimings, resetTimings, time } from "./core/timings.js";
30
- import { hasProjectTrustInputs, ProjectTrustStore } from "./core/trust-manager.js";
31
+ import { hasTrustRequiringProjectResources, ProjectTrustStore } from "./core/trust-manager.js";
31
32
  import { runMigrations, showDeprecationWarnings } from "./migrations.js";
32
33
  import { InteractiveMode, runPrintMode, runRpcMode } from "./modes/index.js";
33
- import { ExtensionSelectorComponent } from "./modes/interactive/components/extension-selector.js";
34
34
  import { initTheme, stopThemeWatcher } from "./modes/interactive/theme/theme.js";
35
35
  import { handleConfigCommand, handlePackageCommand } from "./package-manager-cli.js";
36
36
  import { isLocalPath, normalizePath, resolvePath } from "./utils/paths.js";
@@ -74,14 +74,14 @@ function isTruthyEnvFlag(value) {
74
74
  return false;
75
75
  return value === "1" || value.toLowerCase() === "true" || value.toLowerCase() === "yes";
76
76
  }
77
- function resolveAppMode(parsed, stdinIsTTY) {
77
+ function resolveAppMode(parsed, stdinIsTTY, stdoutIsTTY) {
78
78
  if (parsed.mode === "rpc") {
79
79
  return "rpc";
80
80
  }
81
81
  if (parsed.mode === "json") {
82
82
  return "json";
83
83
  }
84
- if (parsed.print || !stdinIsTTY) {
84
+ if (parsed.print || !stdinIsTTY || !stdoutIsTTY) {
85
85
  return "print";
86
86
  }
87
87
  return "interactive";
@@ -89,6 +89,9 @@ function resolveAppMode(parsed, stdinIsTTY) {
89
89
  function toPrintOutputMode(appMode) {
90
90
  return appMode === "json" ? "json" : "text";
91
91
  }
92
+ function isPlainRuntimeMetadataCommand(parsed) {
93
+ return !parsed.print && parsed.mode === undefined && (parsed.help === true || parsed.listModels !== undefined);
94
+ }
92
95
  async function prepareInitialMessage(parsed, autoResizeImages, stdinContent) {
93
96
  if (parsed.fileArgs.length === 0) {
94
97
  return buildInitialMessage({ parsed, stdinContent });
@@ -268,6 +271,7 @@ function buildSessionOptions(parsed, scopedModels, hasExistingSession, modelRegi
268
271
  const resolved = resolveCliModel({
269
272
  cliProvider: parsed.provider,
270
273
  cliModel: parsed.model,
274
+ cliThinking: parsed.thinking,
271
275
  modelRegistry,
272
276
  });
273
277
  if (resolved.warning) {
@@ -340,64 +344,12 @@ function buildSessionOptions(parsed, scopedModels, hasExistingSession, modelRegi
340
344
  function resolveCliPaths(cwd, paths) {
341
345
  return paths?.map((value) => (isLocalPath(value) ? resolvePath(value, cwd) : value));
342
346
  }
343
- async function showStartupSelector(settingsManager, title, options) {
344
- initTheme(settingsManager.getTheme());
345
- setKeybindings(KeybindingsManager.create());
346
- return new Promise((resolve) => {
347
- const ui = new TUI(new ProcessTerminal(), settingsManager.getShowHardwareCursor());
348
- ui.setClearOnShrink(settingsManager.getClearOnShrink());
349
- let settled = false;
350
- const finish = (result) => {
351
- if (settled) {
352
- return;
353
- }
354
- settled = true;
355
- ui.stop();
356
- resolve(result);
357
- };
358
- const selector = new ExtensionSelectorComponent(title, options.map((option) => option.label), (option) => finish(options.find((entry) => entry.label === option)?.value), () => finish(undefined), { tui: ui });
359
- ui.addChild(selector);
360
- ui.setFocus(selector);
361
- ui.start();
362
- });
363
- }
364
347
  async function promptForMissingSessionCwd(issue, settingsManager) {
365
348
  return showStartupSelector(settingsManager, formatMissingSessionCwdPrompt(issue), [
366
349
  { label: "Continue", value: issue.fallbackCwd },
367
350
  { label: "Cancel", value: undefined },
368
351
  ]);
369
352
  }
370
- async function promptForProjectTrust(cwd, settingsManager) {
371
- return showStartupSelector(settingsManager, `Trust project folder?\n${cwd}\n\nThis allows sling to read project instructions (AGENTS.md/CLAUDE.md), load .sling settings and resources, install missing project packages, and execute project extensions.`, [
372
- { label: "Trust", value: { trusted: true, remember: true } },
373
- { label: "Trust (this session only)", value: { trusted: true, remember: false } },
374
- { label: "Do not trust", value: { trusted: false, remember: true } },
375
- { label: "Do not trust (this session only)", value: { trusted: false, remember: false } },
376
- ]);
377
- }
378
- async function resolveProjectTrusted(options) {
379
- if (options.trustOverride !== undefined) {
380
- return options.trustOverride;
381
- }
382
- if (!hasProjectTrustInputs(options.cwd)) {
383
- return true;
384
- }
385
- const decision = options.trustStore.get(options.cwd);
386
- if (decision !== null) {
387
- return decision;
388
- }
389
- if (options.appMode !== "interactive") {
390
- return false;
391
- }
392
- const selected = await promptForProjectTrust(options.cwd, options.settingsManagerForPrompt);
393
- if (selected !== undefined) {
394
- if (selected.remember) {
395
- options.trustStore.set(options.cwd, selected.trusted);
396
- }
397
- return selected.trusted;
398
- }
399
- return false;
400
- }
401
353
  export async function main(args, options) {
402
354
  resetTimings();
403
355
  const offlineMode = args.includes("--offline") || isTruthyEnvFlag(process.env.PI_OFFLINE);
@@ -408,10 +360,11 @@ export async function main(args, options) {
408
360
  if (process.platform === "win32") {
409
361
  cleanupWindowsSelfUpdateQuarantine(getPackageDir());
410
362
  }
411
- if (await handlePackageCommand(args)) {
363
+ if (await handlePackageCommand(args, { extensionFactories: options?.extensionFactories })) {
364
+ process.exit(process.exitCode ?? 0);
412
365
  return;
413
366
  }
414
- if (await handleConfigCommand(args)) {
367
+ if (await handleConfigCommand(args, { extensionFactories: options?.extensionFactories })) {
415
368
  return;
416
369
  }
417
370
  const parsed = parseArgs(args);
@@ -425,11 +378,6 @@ export async function main(args, options) {
425
378
  }
426
379
  }
427
380
  time("parseArgs");
428
- let appMode = resolveAppMode(parsed, process.stdin.isTTY);
429
- const shouldTakeOverStdout = appMode !== "interactive";
430
- if (shouldTakeOverStdout) {
431
- takeOverStdout();
432
- }
433
381
  if (parsed.version) {
434
382
  console.log(VERSION);
435
383
  process.exit(0);
@@ -448,6 +396,11 @@ export async function main(args, options) {
448
396
  console.log(`Exported to: ${result}`);
449
397
  process.exit(0);
450
398
  }
399
+ let appMode = resolveAppMode(parsed, process.stdin.isTTY, process.stdout.isTTY);
400
+ const shouldTakeOverStdout = appMode !== "interactive" && !isPlainRuntimeMetadataCommand(parsed);
401
+ if (shouldTakeOverStdout) {
402
+ takeOverStdout();
403
+ }
451
404
  if (parsed.mode === "rpc" && parsed.fileArgs.length > 0) {
452
405
  console.error(chalk.red("Error: @file arguments are not supported in RPC mode"));
453
406
  process.exit(1);
@@ -461,6 +414,12 @@ export async function main(args, options) {
461
414
  const agentDir = getAgentDir();
462
415
  const startupSettingsManager = SettingsManager.create(cwd, agentDir);
463
416
  reportDiagnostics(collectSettingsDiagnostics(startupSettingsManager, "startup session lookup"));
417
+ // Experimental first-time setup: theme choice and analytics opt-in.
418
+ // Runs before any runtime services are created so the chosen settings apply everywhere.
419
+ if (appMode === "interactive" && !parsed.help && parsed.listModels === undefined && shouldRunFirstTimeSetup()) {
420
+ await showFirstTimeSetup(startupSettingsManager);
421
+ time("firstTimeSetup");
422
+ }
464
423
  // Decide the final runtime cwd before creating cwd-bound runtime services.
465
424
  // --session and --resume may select a session from another project, so project-local
466
425
  // settings, resources, provider registrations, and models must be resolved only after
@@ -495,23 +454,28 @@ export async function main(args, options) {
495
454
  }
496
455
  time("createSessionManager");
497
456
  const trustStore = new ProjectTrustStore(agentDir);
457
+ const sessionCwd = sessionManager.getCwd();
458
+ const autoTrustOnReloadCwd = parsed.projectTrustOverride === undefined && !hasTrustRequiringProjectResources(sessionCwd)
459
+ ? sessionCwd
460
+ : undefined;
498
461
  const trustPromptMode = parsed.help || parsed.listModels !== undefined ? "print" : appMode;
499
- const projectTrustedForSession = await resolveProjectTrusted({
500
- cwd: sessionManager.getCwd(),
501
- trustStore,
502
- trustOverride: parsed.projectTrustOverride,
503
- appMode: trustPromptMode,
504
- settingsManagerForPrompt: startupSettingsManager,
505
- });
462
+ const projectTrustByCwd = new Map();
506
463
  const resolvedExtensionPaths = resolveCliPaths(cwd, parsed.extensions);
507
464
  const resolvedSkillPaths = resolveCliPaths(cwd, parsed.skills);
508
465
  const resolvedPromptTemplatePaths = resolveCliPaths(cwd, parsed.promptTemplates);
509
466
  const resolvedThemePaths = resolveCliPaths(cwd, parsed.themes);
510
467
  const authStorage = AuthStorage.create();
511
- const createRuntime = async ({ cwd, agentDir, sessionManager, sessionStartEvent, }) => {
512
- const projectTrusted = cwd === sessionManager.getCwd()
513
- ? projectTrustedForSession
514
- : (parsed.projectTrustOverride ?? (!hasProjectTrustInputs(cwd) || trustStore.get(cwd) === true));
468
+ const createRuntime = async ({ cwd, agentDir, sessionManager, sessionStartEvent, projectTrustContext, }) => {
469
+ const isInitialRuntime = sessionStartEvent === undefined;
470
+ const projectTrustDiagnostics = [];
471
+ const cachedProjectTrust = projectTrustByCwd.get(cwd);
472
+ const hasTrustRequiringResources = hasTrustRequiringProjectResources(cwd);
473
+ const shouldResolveProjectTrust = parsed.projectTrustOverride === undefined && cachedProjectTrust === undefined && hasTrustRequiringResources;
474
+ const projectTrusted = shouldResolveProjectTrust
475
+ ? false
476
+ : (cachedProjectTrust ??
477
+ parsed.projectTrustOverride ??
478
+ (!hasTrustRequiringResources || trustStore.get(cwd) === true));
515
479
  const runtimeSettingsManager = SettingsManager.create(cwd, agentDir, { projectTrusted });
516
480
  const services = await createAgentSessionServices({
517
481
  cwd,
@@ -519,6 +483,29 @@ export async function main(args, options) {
519
483
  authStorage,
520
484
  settingsManager: runtimeSettingsManager,
521
485
  extensionFlagValues: parsed.unknownFlags,
486
+ resourceLoaderReloadOptions: shouldResolveProjectTrust
487
+ ? {
488
+ resolveProjectTrust: async ({ extensionsResult }) => {
489
+ const trusted = await resolveProjectTrusted({
490
+ cwd,
491
+ trustStore,
492
+ trustOverride: parsed.projectTrustOverride,
493
+ defaultProjectTrust: startupSettingsManager.getDefaultProjectTrust(),
494
+ extensionsResult,
495
+ projectTrustContext: projectTrustContext ??
496
+ createProjectTrustContext({
497
+ cwd,
498
+ mode: isInitialRuntime ? trustPromptMode : appMode,
499
+ settingsManager: startupSettingsManager,
500
+ hasUI: isInitialRuntime && trustPromptMode === "interactive",
501
+ }),
502
+ onExtensionError: (message) => projectTrustDiagnostics.push({ type: "warning", message }),
503
+ });
504
+ projectTrustByCwd.set(cwd, trusted);
505
+ return trusted;
506
+ },
507
+ }
508
+ : undefined,
522
509
  resourceLoaderOptions: {
523
510
  additionalExtensionPaths: resolvedExtensionPaths,
524
511
  additionalSkillPaths: resolvedSkillPaths,
@@ -536,6 +523,7 @@ export async function main(args, options) {
536
523
  });
537
524
  const { settingsManager, modelRegistry, resourceLoader } = services;
538
525
  const diagnostics = [
526
+ ...projectTrustDiagnostics,
539
527
  ...services.diagnostics,
540
528
  ...collectSettingsDiagnostics(settingsManager, "runtime creation"),
541
529
  ...resourceLoader.getExtensions().errors.map(({ path, error }) => ({
@@ -642,6 +630,7 @@ export async function main(args, options) {
642
630
  const interactiveMode = new InteractiveMode(runtime, {
643
631
  migratedProviders,
644
632
  modelFallbackMessage,
633
+ autoTrustOnReloadCwd,
645
634
  initialMessage,
646
635
  initialImages,
647
636
  initialMessages: parsed.messages,
@@ -2,12 +2,10 @@
2
2
  * One-time migrations that run on startup.
3
3
  */
4
4
  import chalk from "chalk";
5
- import { chmodSync, existsSync, mkdirSync, readdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "fs";
5
+ import { existsSync, mkdirSync, readdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "fs";
6
6
  import { dirname, join } from "path";
7
7
  import { CONFIG_DIR_NAME, getAgentDir, getBinDir } from "./config.js";
8
8
  import { migrateKeybindingsConfig } from "./core/keybindings.js";
9
- import { isLegacyEnvVarNameConfigValue } from "./core/resolve-config-value.js";
10
- import { stripJsonComments } from "./utils/json.js";
11
9
  const MIGRATION_GUIDE_URL = "https://github.com/earendil-works/pi-mono/blob/main/packages/coding-agent/CHANGELOG.md#extensions-migration";
12
10
  const EXTENSIONS_DOC_URL = "https://github.com/earendil-works/pi-mono/blob/main/packages/coding-agent/docs/extensions.md";
13
11
  /**
@@ -65,120 +63,6 @@ export function migrateAuthToAuthJson() {
65
63
  }
66
64
  return providers;
67
65
  }
68
- function migrateLegacyEnvVarString(value) {
69
- return isLegacyEnvVarNameConfigValue(value) ? `$${value}` : undefined;
70
- }
71
- function migrateStringProperty(record, key, location, migrations) {
72
- const value = record[key];
73
- if (typeof value !== "string")
74
- return false;
75
- const migrated = migrateLegacyEnvVarString(value);
76
- if (migrated === undefined)
77
- return false;
78
- record[key] = migrated;
79
- migrations.push({ location, from: value, to: migrated });
80
- return true;
81
- }
82
- function migrateHeadersConfig(headers, location, migrations) {
83
- if (typeof headers !== "object" || headers === null || Array.isArray(headers))
84
- return false;
85
- const headerRecord = headers;
86
- let migrated = false;
87
- for (const [key, value] of Object.entries(headerRecord)) {
88
- if (typeof value !== "string")
89
- continue;
90
- const migratedValue = migrateLegacyEnvVarString(value);
91
- if (migratedValue === undefined)
92
- continue;
93
- headerRecord[key] = migratedValue;
94
- migrations.push({ location: `${location}[${JSON.stringify(key)}]`, from: value, to: migratedValue });
95
- migrated = true;
96
- }
97
- return migrated;
98
- }
99
- function migrateAuthJsonConfigValues(agentDir) {
100
- const authPath = join(agentDir, "auth.json");
101
- if (!existsSync(authPath))
102
- return [];
103
- try {
104
- const parsed = JSON.parse(readFileSync(authPath, "utf-8"));
105
- if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed))
106
- return [];
107
- const authData = parsed;
108
- const migrations = [];
109
- for (const [provider, credential] of Object.entries(authData)) {
110
- if (typeof credential !== "object" || credential === null || Array.isArray(credential))
111
- continue;
112
- const credentialRecord = credential;
113
- if (credentialRecord.type !== "api_key")
114
- continue;
115
- migrateStringProperty(credentialRecord, "key", `auth.json[${JSON.stringify(provider)}].key`, migrations);
116
- }
117
- if (migrations.length === 0)
118
- return [];
119
- writeFileSync(authPath, `${JSON.stringify(parsed, null, 2)}\n`, "utf-8");
120
- chmodSync(authPath, 0o600);
121
- return migrations;
122
- }
123
- catch {
124
- return [];
125
- }
126
- }
127
- function migrateModelsJsonConfigValues(agentDir) {
128
- const modelsPath = join(agentDir, "models.json");
129
- if (!existsSync(modelsPath))
130
- return [];
131
- const parsed = JSON.parse(stripJsonComments(readFileSync(modelsPath, "utf-8")));
132
- if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed))
133
- return [];
134
- const modelsData = parsed;
135
- const providers = modelsData.providers;
136
- if (typeof providers !== "object" || providers === null || Array.isArray(providers))
137
- return [];
138
- const migrations = [];
139
- for (const [provider, providerConfig] of Object.entries(providers)) {
140
- if (typeof providerConfig !== "object" || providerConfig === null || Array.isArray(providerConfig))
141
- continue;
142
- const providerRecord = providerConfig;
143
- const providerLocation = `models.json.providers[${JSON.stringify(provider)}]`;
144
- migrateStringProperty(providerRecord, "apiKey", `${providerLocation}.apiKey`, migrations);
145
- migrateHeadersConfig(providerRecord.headers, `${providerLocation}.headers`, migrations);
146
- if (Array.isArray(providerRecord.models)) {
147
- for (let index = 0; index < providerRecord.models.length; index++) {
148
- const modelConfig = providerRecord.models[index];
149
- if (typeof modelConfig !== "object" || modelConfig === null || Array.isArray(modelConfig))
150
- continue;
151
- const modelRecord = modelConfig;
152
- const modelKey = typeof modelRecord.id === "string" ? JSON.stringify(modelRecord.id) : String(index);
153
- migrateHeadersConfig(modelRecord.headers, `${providerLocation}.models[${modelKey}].headers`, migrations);
154
- }
155
- }
156
- const modelOverrides = providerRecord.modelOverrides;
157
- if (typeof modelOverrides === "object" && modelOverrides !== null && !Array.isArray(modelOverrides)) {
158
- for (const [modelId, modelOverride] of Object.entries(modelOverrides)) {
159
- if (typeof modelOverride !== "object" || modelOverride === null || Array.isArray(modelOverride))
160
- continue;
161
- const modelOverrideRecord = modelOverride;
162
- migrateHeadersConfig(modelOverrideRecord.headers, `${providerLocation}.modelOverrides[${JSON.stringify(modelId)}].headers`, migrations);
163
- }
164
- }
165
- }
166
- if (migrations.length === 0)
167
- return [];
168
- writeFileSync(modelsPath, `${JSON.stringify(parsed, null, 2)}\n`, "utf-8");
169
- return migrations;
170
- }
171
- function migrateExplicitEnvVarConfigValues() {
172
- const agentDir = getAgentDir();
173
- const migrations = [...migrateAuthJsonConfigValues(agentDir), ...migrateModelsJsonConfigValues(agentDir)];
174
- if (migrations.length === 0)
175
- return;
176
- const details = migrations.map((migration) => ` - ${migration.location}: ${migration.from} -> ${migration.to}`);
177
- console.log(chalk.yellow([
178
- "Warning: Migrated API key/header environment references to explicit $ENV_VAR syntax. Plain strings will be treated as literals.",
179
- ...details,
180
- ].join("\n")));
181
- }
182
66
  /**
183
67
  * Migrate sessions from ~/.pi/agent/*.jsonl to proper session directories.
184
68
  *
@@ -388,7 +272,6 @@ export async function showDeprecationWarnings(warnings) {
388
272
  */
389
273
  export function runMigrations(cwd) {
390
274
  const migratedAuthProviders = migrateAuthToAuthJson();
391
- migrateExplicitEnvVarConfigValues();
392
275
  migrateSessionsFromAgentRoot();
393
276
  migrateToolsToBin();
394
277
  migrateKeybindingsConfigFile();
@@ -0,0 +1,103 @@
1
+ import { Container, getKeybindings, Spacer, Text } from "@earendil-works/pi-tui";
2
+ import { APP_NAME } from "../../../config.js";
3
+ import { theme } from "../theme/theme.js";
4
+ import { DynamicBorder } from "./dynamic-border.js";
5
+ import { keyHint, rawKeyHint } from "./keybinding-hints.js";
6
+ const THEME_OPTIONS = [
7
+ { value: "dark", label: "Dark" },
8
+ { value: "light", label: "Light" },
9
+ ];
10
+ const ANALYTICS_OPTIONS = [
11
+ { value: true, label: "Share anonymous usage data" },
12
+ { value: false, label: "Don't share" },
13
+ ];
14
+ const SETUP_LOGO_LINES = ["██████", "██ ██", "████ ██", "██ ██"];
15
+ /** First-time setup dialog: theme choice and analytics opt-in. */
16
+ export class FirstTimeSetupComponent extends Container {
17
+ step = "theme";
18
+ themeIndex;
19
+ analyticsIndex = 0;
20
+ options;
21
+ constructor(options) {
22
+ super();
23
+ this.options = options;
24
+ this.themeIndex = Math.max(0, THEME_OPTIONS.findIndex((option) => option.value === options.detectedTheme));
25
+ this.update();
26
+ }
27
+ // Rebuild the whole dialog on every change so theme previews recolor all text.
28
+ update() {
29
+ this.clear();
30
+ this.addChild(new DynamicBorder());
31
+ this.addChild(new Spacer(1));
32
+ this.addChild(new Text(theme.fg("accent", SETUP_LOGO_LINES.join("\n")), 1, 0));
33
+ this.addChild(new Spacer(1));
34
+ this.addChild(new Text(theme.fg("accent", theme.bold(`Welcome to ${APP_NAME}, the minimal coding agent.`)), 1, 0));
35
+ this.addChild(new Spacer(1));
36
+ if (this.step === "theme") {
37
+ this.addChild(new Text(theme.fg("text", "Pick a theme."), 1, 0));
38
+ this.addChild(new Text(theme.fg("muted", `Detected system appearance: ${this.options.detectedTheme}`), 1, 0));
39
+ this.addChild(new Spacer(1));
40
+ this.addOptionList(THEME_OPTIONS.map((option) => option.label), this.themeIndex);
41
+ }
42
+ else {
43
+ this.addChild(new Text(theme.fg("text", "Opt-in to anonymous usage data sharing?"), 1, 0));
44
+ this.addChild(new Text(theme.fg("muted", "Opting in stores a tracking identifier in settings.json and enables anonymous\nusage analytics. This helps us to better debug, reproduce, and resolve issues\nand bugs within Pi. You can observe what is shared using /privacy and make\nchanges anytime in settings.json."), 1, 0));
45
+ this.addChild(new Spacer(1));
46
+ this.addOptionList(ANALYTICS_OPTIONS.map((option) => option.label), this.analyticsIndex);
47
+ }
48
+ this.addChild(new Spacer(1));
49
+ this.addChild(new Text(rawKeyHint("↑↓", "navigate") +
50
+ " " +
51
+ keyHint("tui.select.confirm", this.step === "theme" ? "continue" : "finish") +
52
+ " " +
53
+ keyHint("tui.select.cancel", "skip setup"), 1, 0));
54
+ this.addChild(new Spacer(1));
55
+ this.addChild(new DynamicBorder());
56
+ }
57
+ addOptionList(labels, selectedIndex) {
58
+ for (let i = 0; i < labels.length; i++) {
59
+ const isSelected = i === selectedIndex;
60
+ const prefix = isSelected ? theme.fg("accent", "→ ") : " ";
61
+ const label = isSelected ? theme.fg("accent", labels[i]) : theme.fg("text", labels[i]);
62
+ this.addChild(new Text(`${prefix}${label}`, 1, 0));
63
+ }
64
+ }
65
+ moveSelection(delta) {
66
+ if (this.step === "theme") {
67
+ const next = Math.max(0, Math.min(THEME_OPTIONS.length - 1, this.themeIndex + delta));
68
+ if (next !== this.themeIndex) {
69
+ this.themeIndex = next;
70
+ this.options.onThemePreview(THEME_OPTIONS[this.themeIndex].value);
71
+ }
72
+ }
73
+ else {
74
+ this.analyticsIndex = Math.max(0, Math.min(ANALYTICS_OPTIONS.length - 1, this.analyticsIndex + delta));
75
+ }
76
+ this.update();
77
+ }
78
+ handleInput(keyData) {
79
+ const kb = getKeybindings();
80
+ if (kb.matches(keyData, "tui.select.up") || keyData === "k") {
81
+ this.moveSelection(-1);
82
+ }
83
+ else if (kb.matches(keyData, "tui.select.down") || keyData === "j") {
84
+ this.moveSelection(1);
85
+ }
86
+ else if (kb.matches(keyData, "tui.select.confirm") || keyData === "\n") {
87
+ if (this.step === "theme") {
88
+ this.step = "analytics";
89
+ this.update();
90
+ }
91
+ else {
92
+ this.options.onSubmit({
93
+ theme: THEME_OPTIONS[this.themeIndex].value,
94
+ shareAnalytics: ANALYTICS_OPTIONS[this.analyticsIndex].value,
95
+ });
96
+ }
97
+ }
98
+ else if (kb.matches(keyData, "tui.select.cancel")) {
99
+ this.options.onCancel();
100
+ }
101
+ }
102
+ }
103
+ //# sourceMappingURL=first-time-setup.js.map
@@ -13,6 +13,7 @@ export { DynamicBorder } from "./dynamic-border.js";
13
13
  export { ExtensionEditorComponent } from "./extension-editor.js";
14
14
  export { ExtensionInputComponent } from "./extension-input.js";
15
15
  export { ExtensionSelectorComponent } from "./extension-selector.js";
16
+ export { FirstTimeSetupComponent, } from "./first-time-setup.js";
16
17
  export { FooterComponent } from "./footer.js";
17
18
  export { keyHint, keyText, rawKeyHint } from "./keybinding-hints.js";
18
19
  export { LoginDialogComponent } from "./login-dialog.js";
@@ -42,7 +42,9 @@ export class LoginDialogComponent extends Container {
42
42
  this.input = new Input();
43
43
  this.input.onSubmit = () => {
44
44
  if (this.inputResolver) {
45
- this.inputResolver(this.input.getValue());
45
+ const value = this.input.getValue();
46
+ this.replaceInputWithSubmittedText(value);
47
+ this.inputResolver(value);
46
48
  this.inputResolver = undefined;
47
49
  this.inputRejecter = undefined;
48
50
  }
@@ -56,6 +58,9 @@ export class LoginDialogComponent extends Container {
56
58
  get signal() {
57
59
  return this.abortController.signal;
58
60
  }
61
+ replaceInputWithSubmittedText(value) {
62
+ this.contentContainer.children = this.contentContainer.children.map((child) => child === this.input ? new Text(`> ${value}`, 0, 0) : child);
63
+ }
59
64
  cancel() {
60
65
  this.abortController.abort();
61
66
  if (this.inputRejecter) {
@@ -103,6 +108,7 @@ export class LoginDialogComponent extends Container {
103
108
  * Show input for manual code/URL entry (for callback server providers)
104
109
  */
105
110
  showManualInput(prompt) {
111
+ this.input.setValue("");
106
112
  this.contentContainer.addChild(new Spacer(1));
107
113
  this.contentContainer.addChild(new Text(theme.fg("dim", prompt), 1, 0));
108
114
  this.contentContainer.addChild(this.input);
@@ -15,6 +15,12 @@ const THINKING_DESCRIPTIONS = {
15
15
  high: "Deep reasoning (~16k tokens)",
16
16
  xhigh: "Maximum reasoning (~32k tokens)",
17
17
  };
18
+ const DEFAULT_PROJECT_TRUST_LABELS = {
19
+ ask: "Ask",
20
+ always: "Always trust",
21
+ never: "Never trust",
22
+ };
23
+ const DEFAULT_PROJECT_TRUST_BY_LABEL = new Map(Object.entries(DEFAULT_PROJECT_TRUST_LABELS).map(([value, label]) => [label, value]));
18
24
  /**
19
25
  * A submenu component for selecting from a list of options.
20
26
  */
@@ -159,6 +165,13 @@ export class SettingsSelectorComponent extends Container {
159
165
  currentValue: config.enableInstallTelemetry ? "true" : "false",
160
166
  values: ["true", "false"],
161
167
  },
168
+ {
169
+ id: "default-project-trust",
170
+ label: "Default project trust",
171
+ description: "Fallback behavior when no extension or saved trust decision decides project trust",
172
+ currentValue: DEFAULT_PROJECT_TRUST_LABELS[config.defaultProjectTrust],
173
+ values: Object.values(DEFAULT_PROJECT_TRUST_LABELS),
174
+ },
162
175
  {
163
176
  id: "double-escape-action",
164
177
  label: "Double-escape action",
@@ -357,6 +370,13 @@ export class SettingsSelectorComponent extends Container {
357
370
  case "install-telemetry":
358
371
  callbacks.onEnableInstallTelemetryChange(newValue === "true");
359
372
  break;
373
+ case "default-project-trust": {
374
+ const defaultProjectTrust = DEFAULT_PROJECT_TRUST_BY_LABEL.get(newValue);
375
+ if (defaultProjectTrust) {
376
+ callbacks.onDefaultProjectTrustChange(defaultProjectTrust);
377
+ }
378
+ break;
379
+ }
360
380
  case "double-escape-action":
361
381
  callbacks.onDoubleEscapeActionChange(newValue);
362
382
  break;