gentle-pi 4.1.0 → 4.3.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 (249) hide show
  1. package/README.md +352 -128
  2. package/assets/agents/gentle-ai-explore.md +1 -0
  3. package/assets/agents/gentle-ai-verify.md +6 -4
  4. package/assets/agents/gentle-ai-worker.md +7 -1
  5. package/assets/orchestrator-delegation-reference.md +163 -0
  6. package/assets/orchestrator-delegation.md +25 -176
  7. package/assets/orchestrator-tracking.md +1 -1
  8. package/assets/orchestrator-verification.md +14 -8
  9. package/assets/orchestrator-writer.md +5 -1
  10. package/assets/orchestrator.md +9 -9
  11. package/bin/engram-guard +1 -1
  12. package/bin/gentle-shell.mjs +188 -35
  13. package/contracts/review-provider-contract-mirror/provider-contract.lock.json +8 -7
  14. package/contracts/review-provider-contract-mirror/{v1.3.0 → v1.4.0}/bundle/README.md +7 -0
  15. package/contracts/review-provider-contract-mirror/{v1.3.0 → v1.4.0}/bundle/manifest.json +11 -2
  16. package/contracts/review-provider-contract-mirror/v1.4.0/bundle/routing/pi.md +92 -0
  17. package/contracts/review-provider-contract-mirror/{v1.3.0 → v1.4.0}/generated/provider-capabilities.baseline.json +8 -1
  18. package/contracts/review-provider-contract-mirror/{v1.3.0 → v1.4.0}/generated/provider-roles.baseline.json +1 -1
  19. package/docs/assets/diagrams/agent-orchestration.svg +54 -15
  20. package/docs/assets/diagrams/gentleman-workflow.svg +69 -11
  21. package/docs/assets/diagrams/measured-routing.svg +49 -0
  22. package/docs/assets/diagrams/native-review.svg +52 -12
  23. package/docs/assets/diagrams/odd-workflow.svg +128 -66
  24. package/docs/assets/diagrams/permission-modes.svg +51 -0
  25. package/docs/assets/features/audio-notifications.png +0 -0
  26. package/docs/assets/features/command-palette.png +0 -0
  27. package/docs/auto-permission-answers.md +25 -0
  28. package/docs/auto-permission-evidence.md +39 -0
  29. package/docs/bundled-install.md +40 -8
  30. package/docs/delegated-verification.md +10 -8
  31. package/docs/gentle-agents-activity.md +11 -5
  32. package/docs/gentle-shell-uninstall.md +8 -1
  33. package/docs/gentle-shell.md +20 -12
  34. package/docs/install-wizard.md +17 -10
  35. package/docs/permission-modes.md +51 -6
  36. package/docs/readme-reference.md +155 -31
  37. package/docs/session-profile-format.md +39 -0
  38. package/docs/yolo-mode.md +21 -7
  39. package/extensions/ask-user-choice.ts +4 -0
  40. package/extensions/ask-user-question.ts +6 -1
  41. package/extensions/codegraph-tools.ts +68 -6
  42. package/extensions/gentle-agents.ts +146 -28
  43. package/extensions/gentle-ai.ts +380 -68
  44. package/extensions/gentle-herdr-activity.ts +2 -3
  45. package/extensions/gentle-shell.ts +53 -43
  46. package/extensions/gentle-todo.ts +62 -18
  47. package/extensions/quiet-tools.ts +1 -1
  48. package/extensions/session-scratch.ts +365 -0
  49. package/extensions/startup-banner.ts +2 -3
  50. package/lib/agent-home.ts +8 -3
  51. package/lib/agents-protocol.ts +3 -0
  52. package/lib/agents-runner.ts +55 -6
  53. package/lib/agents-view.ts +3 -1
  54. package/lib/auto-permission-answers.ts +133 -0
  55. package/lib/auto-permission-classifier.ts +215 -36
  56. package/lib/auto-permission-evidence.ts +88 -0
  57. package/lib/auto-permission-memory.ts +69 -0
  58. package/lib/auto-permission-runtime.ts +251 -35
  59. package/lib/auto-permission-tool-context.ts +61 -0
  60. package/lib/bounded-writer-admission.ts +51 -0
  61. package/lib/command-palette-catalog.ts +0 -4
  62. package/lib/commit-slice-signal.ts +100 -0
  63. package/lib/context-backstop.ts +84 -0
  64. package/lib/delivered-test-lint.ts +80 -0
  65. package/lib/destructive-command-guard.ts +215 -28
  66. package/lib/gauge-theme.ts +146 -0
  67. package/lib/gentle-ai-binary.ts +28 -7
  68. package/lib/gentle-shell-bundled.ts +62 -8
  69. package/lib/gentle-shell-import-pi.ts +233 -0
  70. package/lib/gentle-shell-launcher.ts +146 -12
  71. package/lib/gentle-shell-uninstall.ts +18 -1
  72. package/lib/herdr-activity.ts +24 -0
  73. package/lib/model-routing-authority.ts +6 -1
  74. package/lib/native-review-cli.ts +9 -1
  75. package/lib/orchestrator-discovery.ts +5 -1
  76. package/lib/orchestrator-presence.ts +9 -0
  77. package/lib/orchestrator-scope.ts +21 -3
  78. package/lib/provider-contract-bundle.ts +99 -53
  79. package/lib/review-candidate-view-owner.ts +29 -19
  80. package/lib/review-candidate-view.ts +36 -2
  81. package/lib/review-risk-assessment.ts +43 -38
  82. package/lib/review-session-standing-permission.ts +3 -1
  83. package/lib/selection-engine.ts +4 -1
  84. package/lib/session-profile-freeze.ts +40 -16
  85. package/lib/session-profile-persistence.ts +187 -0
  86. package/lib/session-scratch.ts +474 -0
  87. package/lib/shell-bar.ts +25 -25
  88. package/lib/shell-changes-view.ts +80 -13
  89. package/lib/shell-changes.ts +2 -0
  90. package/lib/shell-gauge.ts +49 -6
  91. package/lib/shell-prompt.ts +6 -4
  92. package/lib/shell-todo.ts +39 -8
  93. package/lib/shell-usage-view.ts +5 -1
  94. package/lib/shell-usage.ts +7 -7
  95. package/lib/verifier-admission.ts +29 -0
  96. package/lib/vim-editor-adapter.ts +22 -4
  97. package/lib/yolo-temp-scratch.ts +69 -0
  98. package/package.json +5 -6
  99. package/runtime/gentle-ai-binary.mjs +28 -7
  100. package/runtime/gentle-shell-bundled.mjs +61 -7
  101. package/runtime/gentle-shell-import-pi.mjs +234 -0
  102. package/runtime/gentle-shell-launcher.mjs +144 -10
  103. package/runtime/gentle-shell-uninstall.mjs +18 -1
  104. package/runtime/native-review-cli.mjs +8 -0
  105. package/runtime/review-risk-assessment.mjs +43 -38
  106. package/scripts/build-runtime-modules.mjs +1 -0
  107. package/scripts/bundled-engram-migration.mjs +125 -0
  108. package/scripts/gentle-ai-installer.mjs +10 -10
  109. package/scripts/install-wizard-preview.mjs +2 -2
  110. package/scripts/installer-downloads.mjs +7 -7
  111. package/scripts/installer-preflight.mjs +1 -1
  112. package/scripts/installer-server.mjs +14 -4
  113. package/scripts/main-channel.mjs +3 -2
  114. package/scripts/pi-update.mjs +223 -0
  115. package/scripts/run-test-suite.mjs +5 -0
  116. package/scripts/verify-package-files.mjs +19 -13
  117. package/skills/gentle-ai/SKILL.md +3 -3
  118. package/skills/work-unit-commits/SKILL.md +5 -3
  119. package/tests/agent-risk-escalation.test.ts +37 -10
  120. package/tests/agents-runner.test.ts +260 -3
  121. package/tests/append-system-prompt-route.test.ts +18 -1
  122. package/tests/auto-mode-human-answers.test.ts +68 -0
  123. package/tests/auto-mode-invariants.test.ts +23 -5
  124. package/tests/auto-mode-sdk.test.ts +29 -2
  125. package/tests/auto-permission-answers.test.ts +170 -0
  126. package/tests/auto-permission-classifier.test.ts +353 -2
  127. package/tests/auto-permission-compound.test.ts +24 -0
  128. package/tests/auto-permission-evidence.test.ts +88 -0
  129. package/tests/auto-permission-memory.test.ts +46 -0
  130. package/tests/auto-permission-public-regressions.test.ts +111 -0
  131. package/tests/auto-permission-runtime.test.ts +270 -12
  132. package/tests/autonomous-guard.test.ts +208 -16
  133. package/tests/bounded-writer-admission.test.ts +11 -3
  134. package/tests/bundled-install.test.ts +3 -3
  135. package/tests/card-content-policy.test.ts +19 -9
  136. package/tests/child-safety.test.ts +39 -0
  137. package/tests/codegraph-tools.test.ts +123 -2
  138. package/tests/command-palette.test.ts +14 -4
  139. package/tests/commit-slice-signal.test.ts +162 -0
  140. package/tests/context-backstop.test.ts +159 -0
  141. package/tests/delegate-for-reason-contract.test.ts +91 -24
  142. package/tests/delivered-test-lint.test.ts +105 -0
  143. package/tests/destructive-command-guard.test.ts +85 -1
  144. package/tests/engram-safety.test.ts +35 -7
  145. package/tests/fixtures/primary-session-prompt/gentleman.golden.md +143 -0
  146. package/tests/fixtures/provider-contract-bundle/v1.4.0/README.md +29 -0
  147. package/tests/fixtures/provider-contract-bundle/v1.4.0/manifest.json +83 -0
  148. package/tests/fixtures/provider-contract-bundle/v1.4.0/orchestration/pi.md +70 -0
  149. package/tests/fixtures/provider-contract-bundle/v1.4.0/routing/pi.md +92 -0
  150. package/tests/fixtures/provider-contract-bundle/v1.4.0/schemas/lens.schema.json +16 -0
  151. package/tests/fixtures/provider-contract-bundle/v1.4.0/schemas/refuter.schema.json +1 -0
  152. package/tests/fixtures/provider-contract-bundle/v1.4.0/schemas/targeted-validator.schema.json +1 -0
  153. package/tests/fixtures/provider-contract-bundle/v1.4.0/vectors/lens.json +1 -0
  154. package/tests/fixtures/provider-contract-bundle/v1.4.0/vectors/refuter.json +1 -0
  155. package/tests/fixtures/provider-contract-bundle/v1.4.0/vectors/targeted-validator.json +1 -0
  156. package/tests/gauge-theme.test.ts +120 -0
  157. package/tests/gentle-agents.test.ts +443 -8
  158. package/tests/gentle-ai-binary.test.ts +1 -1
  159. package/tests/gentle-ai-child-guards.test.ts +61 -0
  160. package/tests/gentle-ai-doctor-herdr.test.ts +94 -0
  161. package/tests/gentle-ai-installer.test.ts +51 -51
  162. package/tests/gentle-shell-bin.test.ts +180 -17
  163. package/tests/gentle-shell-bundled.test.ts +235 -38
  164. package/tests/gentle-shell-import-pi.test.ts +262 -0
  165. package/tests/gentle-shell-launcher.test.ts +97 -13
  166. package/tests/gentle-shell-uninstall.test.ts +30 -0
  167. package/tests/gentle-shell.test.ts +113 -14
  168. package/tests/gentle-todo.test.ts +258 -27
  169. package/tests/headless-delivery-question.test.ts +58 -0
  170. package/tests/herdr-activity.test.ts +34 -1
  171. package/tests/install-wizard.test.ts +2 -2
  172. package/tests/installer-posix-bootstrap.test.ts +8 -8
  173. package/tests/installer-preflight.test.ts +3 -3
  174. package/tests/installer-probes.test.ts +8 -8
  175. package/tests/installer-runner.test.ts +14 -13
  176. package/tests/installer-server.test.ts +13 -5
  177. package/tests/installer-windows-bootstrap.test.ts +33 -4
  178. package/tests/main-channel-upgrade.test.ts +7 -1
  179. package/tests/native-review-capability-contract.test.ts +7 -1
  180. package/tests/native-review-parity.test.ts +22 -1
  181. package/tests/no-self-pause-contract.test.ts +5 -2
  182. package/tests/odd-integration.test.ts +5 -1
  183. package/tests/odd-routing-canonical-ratchet.test.ts +127 -162
  184. package/tests/odd-routing-contract.test.ts +115 -30
  185. package/tests/odd-runtime-delegation-gate.test.ts +4 -1
  186. package/tests/orchestrator-budget.test.ts +19 -8
  187. package/tests/orchestrator-discovery.test.ts +29 -0
  188. package/tests/orchestrator-rdd-ownership.test.ts +3 -1
  189. package/tests/orchestrator-scope.test.ts +66 -0
  190. package/tests/orchestrator-status-publication-contract.test.ts +12 -8
  191. package/tests/package-manifest.test.ts +28 -24
  192. package/tests/pi-update-launcher.test.ts +106 -0
  193. package/tests/pi-update.test.ts +186 -0
  194. package/tests/primary-session-prompt.test.ts +101 -0
  195. package/tests/provider-contract-bundle.test.ts +118 -0
  196. package/tests/provider-contract-mirror.test.ts +24 -0
  197. package/tests/quiet-tool-rendering.test.ts +23 -0
  198. package/tests/rdd-aware-verification-contract.test.ts +29 -11
  199. package/tests/rdd-status-line.test.ts +131 -0
  200. package/tests/review-agent-end-preflight.test.ts +6 -0
  201. package/tests/review-candidate-view.test.ts +49 -0
  202. package/tests/review-contract-prompt.test.ts +5 -2
  203. package/tests/review-controller-native-routing.test.ts +14 -1
  204. package/tests/review-controller.test.ts +1 -1
  205. package/tests/review-host-relay-routing.test.ts +59 -2
  206. package/tests/review-loadout-rdd-off-sdk.test.ts +237 -0
  207. package/tests/review-owner-identity.test.ts +132 -0
  208. package/tests/review-risk-assessment.test.ts +163 -76
  209. package/tests/review-session-standing-permission-controller.test.ts +14 -1
  210. package/tests/review-session-standing-permission.test.ts +27 -1
  211. package/tests/run-test-suite.test.ts +15 -0
  212. package/tests/runtime-harness.mjs +16 -6
  213. package/tests/selection-engine.test.ts +35 -5
  214. package/tests/session-changes-shell.test.ts +1 -1
  215. package/tests/session-profile-freeze.test.ts +37 -1
  216. package/tests/session-profile-persistence.test.ts +334 -0
  217. package/tests/session-scratch.test.ts +945 -0
  218. package/tests/session-subject-routing-contract.test.ts +2 -1
  219. package/tests/shell-bar.test.ts +7 -0
  220. package/tests/shell-changes-view.test.ts +137 -1
  221. package/tests/shell-changes.test.ts +18 -0
  222. package/tests/shell-gauge.test.ts +42 -0
  223. package/tests/shell-todo.test.ts +15 -12
  224. package/tests/small-task-inline-contract.test.ts +37 -0
  225. package/tests/standalone-config-home.test.ts +324 -0
  226. package/tests/startup-banner.test.ts +5 -4
  227. package/tests/startup-home-repo.test.ts +34 -0
  228. package/tests/support/orchestrator-modules.ts +1 -0
  229. package/tests/task-size-routing-contract.test.ts +69 -9
  230. package/tests/test-scratch-contract.test.ts +102 -0
  231. package/tests/test-strength-contract.test.ts +36 -1
  232. package/tests/tool-batching-contract.test.ts +64 -0
  233. package/tests/verification-proportionality.test.ts +46 -0
  234. package/tests/verifier-admission.test.ts +137 -0
  235. package/tests/verify-agent-contract.test.ts +8 -8
  236. package/tests/vim-editor-adapter.test.ts +41 -15
  237. package/tests/windows-hidden-processes.test.ts +5 -0
  238. package/tests/writer-edit-surface-scope.test.ts +3 -0
  239. package/tests/writer-feature-document-admission.test.ts +156 -0
  240. package/tests/yolo-mode.test.ts +24 -1
  241. package/tests/yolo-temp-scratch.test.ts +71 -0
  242. package/scripts/mirror-odd-routing.mjs +0 -242
  243. /package/contracts/review-provider-contract-mirror/{v1.3.0 → v1.4.0}/bundle/orchestration/pi.md +0 -0
  244. /package/contracts/review-provider-contract-mirror/{v1.3.0 → v1.4.0}/bundle/schemas/lens.schema.json +0 -0
  245. /package/contracts/review-provider-contract-mirror/{v1.3.0 → v1.4.0}/bundle/schemas/refuter.schema.json +0 -0
  246. /package/contracts/review-provider-contract-mirror/{v1.3.0 → v1.4.0}/bundle/schemas/targeted-validator.schema.json +0 -0
  247. /package/contracts/review-provider-contract-mirror/{v1.3.0 → v1.4.0}/bundle/vectors/lens.json +0 -0
  248. /package/contracts/review-provider-contract-mirror/{v1.3.0 → v1.4.0}/bundle/vectors/refuter.json +0 -0
  249. /package/contracts/review-provider-contract-mirror/{v1.3.0 → v1.4.0}/bundle/vectors/targeted-validator.json +0 -0
@@ -1,6 +1,7 @@
1
1
  // Generated by scripts/build-runtime-modules.mjs. Do not edit.
2
- import { isAbsolute, join, resolve as resolvePath } from "node:path";
2
+ import { basename, dirname, isAbsolute, join, resolve as resolvePath } from "node:path";
3
3
  import { CHILD_PACKAGE_INJECTION_ENV, encodeChildPackageInjection, } from "./child-package-injection.mjs";
4
+ import { GENTLE_SHELL_CONFIG_HOME_ENV } from "./gentle-shell-bundled.mjs";
4
5
 
5
6
  // The gentle-shell launcher: pure, side-effect-free functions over injected
6
7
  // env/fs/exec. `bin/gentle-shell.mjs` (T2) wires these into the real process,
@@ -11,7 +12,7 @@ import { CHILD_PACKAGE_INJECTION_ENV, encodeChildPackageInjection,
11
12
  // pi's own package-management subcommands (see pi's cli/args.ts printHelp
12
13
  // "Commands" list): each is dispatched by pi itself, before pi's own flag
13
14
  // parsing, purely on argv[0]. `uninstall` is pi's alias for `remove`.
14
- export const PI_SUBCOMMANDS = ["install", "remove", "uninstall", "update", "list", "config", "auth"] ;
15
+ export const PI_SUBCOMMANDS = ["install", "remove", "uninstall", "update", "list", "config", "auth", "mcp"] ;
15
16
 
16
17
 
17
18
 
@@ -42,7 +43,7 @@ function isPiSubcommand(token ) {
42
43
  // untouched as commandArgs — T2 owns interpreting `home link|isolated|<path>`.
43
44
  // `self-uninstall` is not `uninstall`, which stays pi's own alias for `remove`.
44
45
  export function parseLauncherArgs(argv ) {
45
- if (argv[0] === "home" || argv[0] === "upgrade" || argv[0] === "self-uninstall") {
46
+ if (argv[0] === "home" || argv[0] === "upgrade" || argv[0] === "self-uninstall" || argv[0] === "memory") {
46
47
  return {
47
48
  link: false,
48
49
  isolated: false,
@@ -77,6 +78,9 @@ export function parseLauncherArgs(argv ) {
77
78
  if (passthrough.length === 0 && rest.length > 0 && isPiSubcommand(rest[0])) {
78
79
  piSubcommand = rest[0];
79
80
  }
81
+ // After a pi subcommand the separator belongs to it, e.g.
82
+ // `mcp add <server> -- <command>`; only a leading one is the launcher's.
83
+ if (piSubcommand !== undefined && passthrough.length > 0) passthrough.push(arg);
80
84
  passthrough.push(...rest);
81
85
  break;
82
86
  }
@@ -148,6 +152,14 @@ export function parseLauncherArgs(argv ) {
148
152
  commandArgs = argv.slice(i + 1);
149
153
  break;
150
154
  }
155
+ // `home import-pi` likewise takes the home selectors ahead of it, so it
156
+ // imports into the home they resolve to; any other `home` after a
157
+ // selector stays pi's.
158
+ if (arg === "home" && argv[i + 1] === "import-pi" && command === undefined && passthrough.length === 0) {
159
+ command = "home";
160
+ commandArgs = argv.slice(i + 1);
161
+ break;
162
+ }
151
163
  if (passthrough.length === 0 && isPiSubcommand(arg)) {
152
164
  piSubcommand = arg;
153
165
  }
@@ -212,6 +224,77 @@ export function isolatedDir(env , homedir
212
224
  return env.GENTLE_SHELL_HOME || join(homedir, ".gentle-shell", "agent");
213
225
  }
214
226
 
227
+ // #2201: the isolated home keeps Gentle Shell's config in a gentle-ai folder
228
+ // next to its agent dir (~/.gentle-shell/gentle-ai by default), given to Pi as
229
+ // GENTLE_SHELL_CONFIG_HOME_ENV. `--link` and a custom `--home` keep the shared
230
+ // ~/.pi/gentle-ai: undefined for them.
231
+ export function standaloneConfigHome(home ) {
232
+ if (home.mode !== "isolated") return undefined;
233
+ const dir = resolvePath(home.dir);
234
+ const parent = dirname(dir);
235
+ // Only inside a .gentle-shell folder is the sibling Gentle Shell's own: next
236
+ // to a custom GENTLE_SHELL_HOME (~/myagent) it would adopt ~/gentle-ai, which
237
+ // may be anyone's, so such homes keep the shared config home.
238
+ return basename(dir) === "agent" && basename(parent) === ".gentle-shell" ? join(parent, "gentle-ai") : undefined;
239
+ }
240
+
241
+ // The filesystem behind migrateStandaloneConfig; bin/gentle-shell.mjs wires the real one.
242
+
243
+
244
+
245
+
246
+
247
+
248
+
249
+
250
+
251
+
252
+
253
+ // Install-level main-channel state stays in ~/.pi/gentle-ai: the installer and
254
+ // `gentle-shell upgrade` write it outside any session (gentleAiDevBinaryRegistrationPath).
255
+ const UNMIGRATED_CONFIG_FILES = new Set(["dev-binary.json", "channel.json"]);
256
+
257
+ // #2201: the first isolated launch after the move keeps the user's settings.
258
+ // Only when `target` does not exist yet: it is created (0700), and the regular
259
+ // files of `source` are copied into it, never overwriting and never changing
260
+ // `source`, which stays for Pi; symbolic links, subdirectories and the
261
+ // main-channel files are skipped. Once the folder exists this does nothing, so
262
+ // it is a one-time snapshot. A failure is reported in `lines`, never thrown:
263
+ // it never blocks the launch.
264
+ export function migrateStandaloneConfig(input ) {
265
+ const { source, target, fs } = input;
266
+ if (fs.kind(target) !== "missing") return { lines: [] };
267
+ const reason = (error ) => (error instanceof Error ? error.message : String(error));
268
+ try {
269
+ fs.mkdirPrivate(target);
270
+ } catch (error) {
271
+ return { lines: [`gentle-shell: could not create ${target} for your Gentle Shell settings (${reason(error)}); continuing`] };
272
+ }
273
+ if (fs.kind(source) === "missing") return { lines: [] };
274
+ let names ;
275
+ try {
276
+ names = fs.list(source).sort();
277
+ } catch (error) {
278
+ return { lines: [`gentle-shell: could not copy your settings from ${source} to ${target} (${reason(error)}); continuing`] };
279
+ }
280
+ const copied = [];
281
+ const failed = [];
282
+ for (const name of names) {
283
+ if (UNMIGRATED_CONFIG_FILES.has(name) || fs.kind(join(source, name)) !== "file") continue;
284
+ try {
285
+ fs.copyNew(join(source, name), join(target, name));
286
+ copied.push(name);
287
+ } catch (error) {
288
+ failed.push(`${name}: ${reason(error)}`);
289
+ }
290
+ }
291
+ if (failed.length > 0) {
292
+ return { lines: [`gentle-shell: could not copy ${failed.join("; ")} from ${source} to ${target}; continuing with ${copied.length} copied file(s)`] };
293
+ }
294
+ if (copied.length === 0) return { lines: [] };
295
+ return { lines: [`gentle-shell: copied ${copied.length} settings file(s) from ${source} to ${target}, Gentle Shell's own config folder from now on (one-time copy; ${source} stays for Pi)`] };
296
+ }
297
+
215
298
  export function resolveHome(input ) {
216
299
  const { args, env, homedir, config } = input;
217
300
 
@@ -242,6 +325,15 @@ export function homeSelectorFlags(home ) {
242
325
  return [];
243
326
  }
244
327
 
328
+ // The first-run line of a separate home. `home import-pi` is offered only
329
+ // when the user's pi home has sign-ins (auth.json) to copy.
330
+ export function separateHomeHint(home , input ) {
331
+ const base = `gentle-shell: using a separate home at ${home.dir}. Run 'gentle-shell --link' to reuse your pi sign-ins and chats`;
332
+ if (!input.piSignIns) return `${base}.`;
333
+ const command = ["gentle-shell", ...homeSelectorFlags(home).map(shellQuote), "home", "import-pi"].join(" ");
334
+ return `${base}, or '${command}' to copy your sign-ins and MCP servers into this home.`;
335
+ }
336
+
245
337
  export function launcherConfigPath(homedir ) {
246
338
  return join(homedir, ".gentle-shell", "config.json");
247
339
  }
@@ -393,7 +485,7 @@ export function missingPiMessage() {
393
485
 
394
486
  // --- pi version gate ---------------------------------------------------------
395
487
 
396
- export const MIN_PI_VERSION = "0.99.1";
488
+ export const MIN_PI_VERSION = "1.2.0";
397
489
 
398
490
 
399
491
 
@@ -576,6 +668,20 @@ const POST_INSTALL_REMOVAL_PACKAGES
576
668
  // bin/gentle-shell.mjs.
577
669
  export const POST_INSTALL_REMOVAL_SOURCES = POST_INSTALL_REMOVAL_PACKAGES.map((entry) => entry.source);
578
670
 
671
+ // #2143: a Gentle AI with package exclusion (gentle-ai#5503) skips these
672
+ // managed Pi packages instead of installing them only for the post-install
673
+ // removal above to delete them. An older Gentle AI ignores the variable (a flag
674
+ // would be rejected), so the removal stays as the fallback. Only sources Gentle
675
+ // AI manages belong here: it rejects any other value.
676
+ export const GENTLE_AI_PI_EXCLUDE_PACKAGES_ENV = "GENTLE_AI_PI_EXCLUDE_PACKAGES";
677
+ const LAUNCHER_EXCLUDED_PI_PACKAGES = ["npm:gentle-pi"];
678
+
679
+ export function withLauncherPackagesExcluded(env ) {
680
+ const own = (env[GENTLE_AI_PI_EXCLUDE_PACKAGES_ENV] ?? "").split(",").map((entry) => entry.trim()).filter((entry) => entry.length > 0);
681
+ const merged = [...own, ...LAUNCHER_EXCLUDED_PI_PACKAGES.filter((source) => !own.includes(source))];
682
+ return { ...env, [GENTLE_AI_PI_EXCLUDE_PACKAGES_ENV]: merged.join(",") };
683
+ }
684
+
579
685
  // Scans a settings.json `packages` list (same string/object-source parsing
580
686
  // as settingsDeclareGentlePi/findGentlePiDeclaration above) for any entry
581
687
  // whose npm package name matches POST_INSTALL_REMOVAL_PACKAGES, at any
@@ -891,13 +997,16 @@ export function discoverLooseExtensionEntries(dir , fs )
891
997
 
892
998
 
893
999
 
1000
+
1001
+
1002
+
894
1003
 
895
1004
 
896
1005
 
897
1006
 
898
1007
  // Four cases, checked in this order — `piSubcommand` first, then `takeOver`:
899
1008
  // - piSubcommand: pi dispatches install/remove/uninstall/update/list/
900
- // config/auth on argv[0] before it even parses flags, so any injected
1009
+ // config/auth/mcp on argv[0] before it even parses flags, so any injected
901
1010
  // -e flag ahead of it stops pi from
902
1011
  // recognising its subcommand at all — this is exactly the observed
903
1012
  // 2026-09-22 bug where `gentle-shell install npm:x` opened an
@@ -978,6 +1087,12 @@ export function buildPiInvocation(input ) {
978
1087
  GENTLE_PI_AGENT_HOME: input.home.dir,
979
1088
  [USER_PI_HOME_ENV]: userPiHome(input.baseEnv, input.homedir),
980
1089
  };
1090
+ // #2201: only the standalone isolated home gets its own config folder; any
1091
+ // other launch removes an inherited marker, so a nested `--link` launch from
1092
+ // an isolated session reads ~/.pi/gentle-ai again.
1093
+ const configHome = input.bundled === true ? undefined : standaloneConfigHome(input.home);
1094
+ if (configHome === undefined) delete env[GENTLE_SHELL_CONFIG_HOME_ENV];
1095
+ else env[GENTLE_SHELL_CONFIG_HOME_ENV] = configHome;
981
1096
  if (childInjection === undefined) delete env[CHILD_PACKAGE_INJECTION_ENV];
982
1097
  else env[CHILD_PACKAGE_INJECTION_ENV] = encodeChildPackageInjection(childInjection);
983
1098
 
@@ -1053,7 +1168,7 @@ export function planSpawn(input ) {
1053
1168
  // formatting as practical instead of imposing its own. `indent` is
1054
1169
  // `undefined` for compact (no-whitespace) JSON, matching what
1055
1170
  // `JSON.stringify(value)` (no third argument) produces.
1056
- function detectJsonFormatting(text ) {
1171
+ export function detectJsonFormatting(text ) {
1057
1172
  const match = text.match(/\{\r?\n([ \t]+)/);
1058
1173
  return { indent: match ? match[1] : undefined, trailingNewline: text.endsWith("\n") };
1059
1174
  }
@@ -1175,9 +1290,11 @@ export function helpText() {
1175
1290
  return [
1176
1291
  "Usage: gentle-shell [options] [-- pi-args...]",
1177
1292
  " gentle-shell home [link|isolated|<path>]",
1293
+ " gentle-shell [home selectors] home import-pi [--dry-run]",
1178
1294
  " gentle-shell [home selectors] setup [--dry-run]",
1179
1295
  " gentle-shell upgrade [--channel release|main]",
1180
1296
  " gentle-shell upgrade --rollback",
1297
+ " gentle-shell memory migrate --confirm-quiescent",
1181
1298
  " gentle-shell self-uninstall [--dry-run] [--yes] [--include-shared]",
1182
1299
  "",
1183
1300
  "Opens pi with the Gentle Shell package loaded, without touching your",
@@ -1185,7 +1302,8 @@ export function helpText() {
1185
1302
  "",
1186
1303
  "Options:",
1187
1304
  " --link Use your existing pi agent home (never edits its settings.json).",
1188
- " --isolated Use the dedicated ~/.gentle-shell/agent home (default).",
1305
+ " --isolated Use the dedicated ~/.gentle-shell/agent home (default), with its own",
1306
+ " settings in ~/.gentle-shell/gentle-ai (copied once from ~/.pi/gentle-ai).",
1189
1307
  " --home <path> Use a custom agent home directory.",
1190
1308
  " --package-root <dir> Force this directory as the gentle-pi package to load, taking over",
1191
1309
  " from any conflicting package the target settings.json already declares.",
@@ -1194,6 +1312,11 @@ export function helpText() {
1194
1312
  "",
1195
1313
  "Commands:",
1196
1314
  " home Print or persist the effective home mode (link, isolated, or a path).",
1315
+ " home import-pi Copy your pi sign-ins (auth.json) and MCP servers (mcp.json) into the",
1316
+ " resolved separate home, plus your default provider, model and thinking",
1317
+ " level when it has none. Never overwrites a file or setting, never copies",
1318
+ " packages, extensions or caches, and never changes your pi home.",
1319
+ " --dry-run only shows the plan. Refuses --link (nothing to import).",
1197
1320
  " setup Provision the resolved home with the gentle-ai companion packages",
1198
1321
  " (runs the package-local gentle-ai 'install --agent pi --scope global').",
1199
1322
  " Accepts --dry-run, forwarded to gentle-ai. Accepts a home selector",
@@ -1205,9 +1328,15 @@ export function helpText() {
1205
1328
  " installer's own Node, pnpm and Pi) follows the release channel only:",
1206
1329
  " it installs the new version beside the current one, verifies it, then",
1207
1330
  " switches; --rollback switches back to the previous kept version.",
1331
+ " memory migrate Explicit bundled-store recovery using the verified core's migrate-copy.",
1332
+ " Requires --confirm-quiescent: stop ALL Engram clients first. Keeps the",
1333
+ " original directory as a backup; never runs automatically on upgrade.",
1334
+ " Requires a bundled core release supporting migrate-copy; older cores",
1335
+ " fail closed without changing the source or its provenance.",
1208
1336
  " self-uninstall Remove Gentle Shell: its own data, the isolated home and the gentle-pi",
1209
- " package. Shows the plan first and asks before removing (--yes skips",
1210
- " the question). The shared ~/.pi/gentle-ai configuration is kept unless",
1337
+ " package, with its settings in ~/.gentle-shell/gentle-ai. Shows the plan",
1338
+ " first and asks before removing (--yes skips the question). The shared",
1339
+ " ~/.pi/gentle-ai configuration is kept unless",
1211
1340
  " you accept or pass --include-shared; --dry-run only shows the plan.",
1212
1341
  " Never touches your pi home or custom --home homes.",
1213
1342
  "",
@@ -1220,6 +1349,8 @@ export function helpText() {
1220
1349
  " runs 'gentle-shell upgrade' instead of updating Pi.",
1221
1350
  " gentle-shell config Run pi's own 'config' against the resolved home.",
1222
1351
  " gentle-shell auth <command> Run pi's own 'auth' against the resolved home.",
1352
+ " gentle-shell mcp <command> Run pi's own 'mcp' (add, list, login, logout) against the",
1353
+ " resolved home, e.g. gentle-shell mcp add <name> -- <command>.",
1223
1354
  " 'gentle-shell uninstall <source>' is pi's own alias for 'remove'; to remove Gentle",
1224
1355
  " Shell itself, use 'gentle-shell self-uninstall'.",
1225
1356
  " These run pi's own commands, forwarded verbatim, against the --isolated home",
@@ -1234,7 +1365,10 @@ export function helpText() {
1234
1365
  "",
1235
1366
  "Environment variables:",
1236
1367
  " GENTLE_SHELL_PI Path to the pi executable to run.",
1237
- " GENTLE_SHELL_HOME Directory for the isolated home (default: ~/.gentle-shell/agent).",
1368
+ " GENTLE_SHELL_HOME Directory for the isolated home (default: ~/.gentle-shell/agent);",
1369
+ " inside a .gentle-shell folder, its settings live in the gentle-ai",
1370
+ " folder next to it; elsewhere they stay in ~/.pi/gentle-ai.",
1371
+ " GENTLE_PI_CONFIG_HOME Gentle Shell settings folder for every home, overriding the above.",
1238
1372
  " PI_CODING_AGENT_DIR Directory for the --link home, shared with pi itself.",
1239
1373
  "",
1240
1374
  "Every other argument is forwarded to pi unchanged.",
@@ -264,6 +264,14 @@ async function planSelfUninstall(input , configHome ,
264
264
  { path: gentleAiState, label: "Gentle AI's state", inside: true },
265
265
  ];
266
266
  const defaultConfigHome = canonical(join(homedir, ".pi", "gentle-ai"));
267
+ // #2201: the standalone launcher keeps the isolated home's config in a
268
+ // gentle-ai folder next to it (standaloneConfigHome). Next to the default
269
+ // home it lies inside ~/.gentle-shell and is Gentle Shell's by location;
270
+ // next to a GENTLE_SHELL_HOME it may be anyone's, so it is only listed.
271
+ // When GENTLE_PI_CONFIG_HOME names it, the config home's rules apply instead.
272
+ const defaultHome = resolve(isolated) === resolve(join(homedir, ".gentle-shell", "agent"));
273
+ const ownConfig = join(dirname(isolated), "gentle-ai");
274
+ const ownConfigSeparate = comparable(canonical(ownConfig), platform) !== comparable(canonical(configHome), platform);
267
275
  const candidates = [
268
276
  {
269
277
  who: env.GENTLE_SHELL_HOME ? `GENTLE_SHELL_HOME points at ${isolated}` : `The isolated home ${isolated}`,
@@ -279,6 +287,12 @@ async function planSelfUninstall(input , configHome ,
279
287
  allowedInsidePi: defaultConfigHome,
280
288
  },
281
289
  { who: `The launcher folder ${shellDirectory}`, path: shellDirectory, guards, allowedInsidePi: undefined },
290
+ ...(defaultHome && ownConfigSeparate ? [{
291
+ who: `Gentle Shell's config folder ${ownConfig}`,
292
+ path: ownConfig,
293
+ guards: [...guards, { path: configHome, label: "the Gentle AI config home", inside: true }],
294
+ allowedInsidePi: undefined,
295
+ }] : []),
282
296
  ];
283
297
  for (const candidate of candidates) {
284
298
  const real = canonical(candidate.path);
@@ -313,11 +327,14 @@ async function planSelfUninstall(input , configHome ,
313
327
 
314
328
  // The default isolated home is Gentle Shell's by location; a GENTLE_SHELL_HOME
315
329
  // directory only with the launcher's ownership marker or setup record.
316
- const defaultHome = resolve(isolated) === resolve(join(homedir, ".gentle-shell", "agent"));
317
330
  const owned = defaultHome || inspect(join(isolated, HOME_OWNERSHIP_MARKER), "file") === "ok"
318
331
  || provisionedEntry(launcherConfig, isolatedReal) !== undefined;
319
332
  if (owned || inspect(isolated, "dir") !== "ok") consider({ path: isolated, label: "isolated home: its sign-ins, chats and settings", kind: "dir" });
320
333
  else plan.kept.push(`${isolated}: not created by Gentle Shell (no ${HOME_OWNERSHIP_MARKER} marker or setup record)`);
334
+ if (defaultHome && ownConfigSeparate) consider({ path: ownConfig, label: "Gentle Shell's own configuration: profiles, banner and other preferences", kind: "dir" });
335
+ else if (ownConfigSeparate && inspect(ownConfig, "dir") !== "missing") {
336
+ plan.kept.push(`${ownConfig}: next to GENTLE_SHELL_HOME, so it may not be Gentle Shell's; remove it yourself if it holds only Gentle Shell settings`);
337
+ }
321
338
  consider({ path: configPath, label: "launcher settings", kind: "file" });
322
339
 
323
340
  for (const name of SHARED_CONFIG_FILES) {
@@ -124,6 +124,7 @@ export const NATIVE_REVIEW_ERROR_CODE = {
124
124
 
125
125
 
126
126
 
127
+
127
128
  export const NATIVE_REVIEW_MODE_OPERATION = {
128
129
  STATUS: "status",
129
130
  ENABLE: "enable",
@@ -1083,6 +1084,13 @@ export const NATIVE_CLI_CONTRACTS = Object.freeze({
1083
1084
  // b04b6b75d1a446c942a816fbf92932d16f8c3d3001f93159dee2a92bbf2ebe44.
1084
1085
  // No new negotiated capability identity is asserted.
1085
1086
  "4.1.1": Object.freeze({ start: true, finalize: true, validate: true, bindSdd: true, status: true, inventory: true, reclaim: true, recover: true, abandon: true, quarantineLegacy: true, reconcileAuthority: true, repairLegacyAlias: true, mode: true, riskEvidence: false, hint: false, delivery: true }),
1087
+ // v4.2.0 repeats 4.1.1: the published binary still advertises
1088
+ // capabilities/v2.6 under review-integration/v2. The provider contract moved
1089
+ // from 1.3.0 to 1.4.0 (routing/pi.md, gentle-ai#5536), with published
1090
+ // tarball SHA-256
1091
+ // 9d2927a84ba9a596f69029e3f854b16f86ca4c8b32cc5d63683764ccf2fb394b.
1092
+ // No new negotiated capability identity is asserted.
1093
+ "4.2.0": Object.freeze({ start: true, finalize: true, validate: true, bindSdd: true, status: true, inventory: true, reclaim: true, recover: true, abandon: true, quarantineLegacy: true, reconcileAuthority: true, repairLegacyAlias: true, mode: true, riskEvidence: false, hint: false, delivery: true }),
1086
1094
  });
1087
1095
 
1088
1096
 
@@ -268,8 +268,9 @@ export const VERIFICATION_TIER = {
268
268
  // ---------------------------------------------------------------------------
269
269
  // Agent-raised risk (gentle-shell#1494). The agent that made the change may
270
270
  // raise its risk to high by citing one item of the high-risk list in the
271
- // always-on Task Size section; it can never lower a tier. Lowering stays with
272
- // the deterministic native assessment.
271
+ // always-on Task Size section; it can never lower a tier. That escalation is
272
+ // the only way a plan gets an independent verifier: a native high or a failed
273
+ // assessment informs but never adds one by itself.
273
274
  // ---------------------------------------------------------------------------
274
275
 
275
276
  export const HIGH_RISK_ITEMS = Object.freeze({
@@ -306,10 +307,17 @@ export function decodeAgentRiskEscalation(value ) {
306
307
  return Object.freeze({ item: item , reason });
307
308
  }
308
309
 
309
- /** Raises passive or medium to high when the agent escalated; never lowers. */
310
- export function escalatedRisk(risk , escalation ) {
311
- if (escalation === undefined) return risk;
312
- return risk === VERIFICATION_TIER.PASSIVE || risk === VERIFICATION_TIER.MEDIUM ? VERIFICATION_TIER.HIGH : risk;
310
+ /**
311
+ * The risk tier the verification plan follows. The independent verifier is
312
+ * for concrete occasions only: the plan is high only when the agent escalated
313
+ * a named Task Size high-risk item. Without an escalation a native passive
314
+ * stays passive, and every other native tier -- medium, high, or unassessable
315
+ * (a failed or unavailable assessment) -- is medium: it informs, but adds no
316
+ * verifier by itself. The native tier stays visible to callers as `nativeRisk`.
317
+ */
318
+ export function verificationRisk(nativeRisk , escalation ) {
319
+ if (escalation !== undefined) return VERIFICATION_TIER.HIGH;
320
+ return nativeRisk === VERIFICATION_TIER.PASSIVE ? VERIFICATION_TIER.PASSIVE : VERIFICATION_TIER.MEDIUM;
313
321
  }
314
322
 
315
323
  export const RDD_LINE = {
@@ -357,6 +365,8 @@ export const NATIVE_REVIEW_OUTCOME = {
357
365
 
358
366
 
359
367
 
368
+
369
+
360
370
 
361
371
 
362
372
 
@@ -367,7 +377,7 @@ export const NATIVE_REVIEW_OUTCOME = {
367
377
  * naming which branch fired, up to and including the word "and"; the
368
378
  * tier-specific clause is appended after it.
369
379
  */
370
- function riskGatedPlan(gatePrefix , risk , writerProfile ) {
380
+ function riskGatedPlan(gatePrefix , risk ) {
371
381
  if (risk === VERIFICATION_TIER.PASSIVE) {
372
382
  return Object.freeze({
373
383
  writerSelfVerification: false,
@@ -377,26 +387,22 @@ function riskGatedPlan(gatePrefix , risk , writerProfile
377
387
  });
378
388
  }
379
389
 
380
- if (risk === VERIFICATION_TIER.MEDIUM) {
381
- const smallModelBias = writerProfile === WRITER_PROFILE.SMALL;
390
+ if (risk === VERIFICATION_TIER.HIGH) {
382
391
  return Object.freeze({
383
392
  writerSelfVerification: true,
384
393
  structuralReadbackOnly: false,
385
- independentVerifier: smallModelBias,
386
- reason: smallModelBias
387
- ? `${gatePrefix} the native assessment reports medium risk, but the small-model bias raises it one tier to high for verification purposes: the writer self-verifies and a separate independent verifier also runs.`
388
- : `${gatePrefix} the native assessment reports medium risk with a large writer profile: the writer's self-verification stands and no separate verifier is required.`,
394
+ independentVerifier: true,
395
+ reason: `${gatePrefix} an agent escalation names a Task Size high-risk item: the writer self-verifies and a separate independent verifier runs.`,
389
396
  });
390
397
  }
391
398
 
392
- // high or unassessable.
399
+ // medium, or an unassessable tier that did not go through verificationRisk:
400
+ // both inform only.
393
401
  return Object.freeze({
394
402
  writerSelfVerification: true,
395
403
  structuralReadbackOnly: false,
396
- independentVerifier: true,
397
- reason: risk === VERIFICATION_TIER.UNASSESSABLE
398
- ? `${gatePrefix} the native risk assessment could not be produced, so the candidate is treated as high risk: the writer self-verifies and a separate independent verifier always runs.`
399
- : `${gatePrefix} the native assessment reports high risk: the writer self-verifies and a separate independent verifier always runs.`,
404
+ independentVerifier: false,
405
+ reason: `${gatePrefix} no Task Size high-risk item was escalated: the writer's self-verification stands and no separate verifier runs, whatever the native tier or the model that wrote the change.`,
400
406
  });
401
407
  }
402
408
 
@@ -417,24 +423,23 @@ function nonClosedOutcomeClause(outcome ) {
417
423
 
418
424
  /**
419
425
  * Computes who verifies a delegated writer's change. Verification follows the
420
- * native risk tier whatever the RDD line and native review outcome
426
+ * plan risk tier whatever the RDD line and native review outcome
421
427
  * (verify-always-rdd-high S1, superseding the gentle-pi#662/#668 on-path): the
422
428
  * native review is an additional outside view and never replaces or skips the
423
429
  * tier's verification. `nativeReviewOutcome` only shapes the reason text.
424
430
  *
431
+ * `risk` is the plan risk from `verificationRisk`; `writerProfile` is never
432
+ * consulted, so the model or effort that wrote the change never adds a
433
+ * verifier.
434
+ *
425
435
  * - `passive`: structural readback by the parent only; no verifier, no tests.
426
- * - `medium`: the writer self-verifies; a separate independent verifier runs
427
- * only when `writerProfile` is `"small"` -- the small-model bias raises the
428
- * tier by one for verification purposes (medium -> high). An unknown or
429
- * omitted writer profile resolves to `"small"` before it reaches this
430
- * function (see `resolveWriterProfile`), so an unrecognized profile never
431
- * lowers a tier below what a known small model would get.
432
- * - `high` or `unassessable` (a failed or unrecognized native assessment is
433
- * always treated as high): the writer self-verifies and an independent
434
- * verifier always runs.
436
+ * - `medium` (also an `unassessable` tier passed directly): the writer
437
+ * self-verifies; no separate verifier.
438
+ * - `high` (only through an agent escalation naming a Task Size high-risk
439
+ * item): the writer self-verifies and an independent verifier runs.
435
440
  */
436
441
  export function verificationPlan(input ) {
437
- const { rddLine, risk, writerProfile } = input;
442
+ const { rddLine, risk } = input;
438
443
 
439
444
  if (rddLine === RDD_LINE.ON) {
440
445
  const outcome = input.nativeReviewOutcome ?? NATIVE_REVIEW_OUTCOME.UNKNOWN;
@@ -444,14 +449,13 @@ export function verificationPlan(input )
444
449
  return riskGatedPlan(
445
450
  `receipt-driven development is on and ${clause}; the native review is an additional outside view that never replaces verification, so the risk-gated path applies exactly as receipt-driven development off, and`,
446
451
  risk,
447
- writerProfile,
448
452
  );
449
453
  }
450
454
 
451
455
  // rddLine is "off" or "unknown" here -- both gate on the native risk
452
456
  // assessment identically, so an unknown RDD line never lowers a tier, and
453
457
  // neither line ever consults nativeReviewOutcome.
454
- return riskGatedPlan(`receipt-driven development is ${rddLine} and`, risk, writerProfile);
458
+ return riskGatedPlan(`receipt-driven development is ${rddLine} and`, risk);
455
459
  }
456
460
 
457
461
  // ---------------------------------------------------------------------------
@@ -476,15 +480,16 @@ export function verificationPlan(input )
476
480
  const SMALL_MODEL_ID_TOKEN = /(?:^|[-_./:\s])mini(?:$|[-_./:\s])/i;
477
481
 
478
482
  /**
479
- * A writer profile counts as a "small model" for the medium-risk bias when:
483
+ * A writer profile counts as a "small model" (reported by ASSESS as
484
+ * `writerProfile`; it never changes the verification plan) when:
480
485
  * - its resolved effort is `low`, or
481
486
  * - its resolved model id carries `mini` as a whole token (see
482
487
  * `SMALL_MODEL_ID_TOKEN`), or
483
488
  * - it carries NO signal at all -- no profile object, or a profile with
484
489
  * neither a model id nor a resolved effort. An unknown or omitted writer
485
- * profile fails closed to small rather than defaulting to large, so a
486
- * caller that cannot resolve the writer's profile never gets a weaker
487
- * verification plan than a known small model would (gentle-pi#662).
490
+ * profile fails closed to small rather than defaulting to large. The
491
+ * result is reported in the assessment only: the verification plan never
492
+ * reads the writer profile, so it cannot add or remove a verifier.
488
493
  *
489
494
  * A profile that carries a model id or an effort, just not a matching one
490
495
  * (for example `{model: {id: "claude-sonnet-5"}, thinking: "high"}`), is
@@ -502,9 +507,9 @@ export function isSmallWriterProfile(profile
502
507
  }
503
508
 
504
509
  /**
505
- * Maps a resolved writer profile to the `writerProfile` input `verificationPlan`
506
- * expects. An unknown or omitted profile never lowers a tier: it resolves to
507
- * `"small"`, exactly like `isSmallWriterProfile` (gentle-pi#662).
510
+ * Maps a resolved writer profile to the reported `writerProfile`. An unknown
511
+ * or omitted profile resolves to `"small"`, exactly like
512
+ * `isSmallWriterProfile` (gentle-pi#662).
508
513
  */
509
514
  export function resolveWriterProfile(profile ) {
510
515
  return isSmallWriterProfile(profile) ? WRITER_PROFILE.SMALL : WRITER_PROFILE.LARGE;
@@ -22,6 +22,7 @@ const sources = [
22
22
  "gentle-shell-startup-flow",
23
23
  "gentle-shell-resume-hint",
24
24
  "gentle-shell-uninstall",
25
+ "gentle-shell-import-pi",
25
26
  ];
26
27
  const header = "// Generated by scripts/build-runtime-modules.mjs. Do not edit.\n";
27
28