@ashx-j/lunr-dev 0.2.13-dev.5.1 → 0.2.13-dev.7.1

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 (208) hide show
  1. package/dist/builtin-extensions/ashxj-tui.d.ts.map +1 -1
  2. package/dist/builtin-extensions/ashxj-tui.js +4 -4
  3. package/dist/builtin-extensions/ashxj-tui.js.map +1 -1
  4. package/dist/builtin-extensions/index.d.ts.map +1 -1
  5. package/dist/builtin-extensions/index.js +2 -0
  6. package/dist/builtin-extensions/index.js.map +1 -1
  7. package/dist/builtin-extensions/lunr-settings-tools.d.ts +4 -0
  8. package/dist/builtin-extensions/lunr-settings-tools.d.ts.map +1 -0
  9. package/dist/builtin-extensions/lunr-settings-tools.js +120 -0
  10. package/dist/builtin-extensions/lunr-settings-tools.js.map +1 -0
  11. package/dist/builtin-extensions/pi-prompt-template-model/subagent-runtime.d.ts +2 -2
  12. package/dist/builtin-extensions/pi-prompt-template-model/subagent-runtime.d.ts.map +1 -1
  13. package/dist/builtin-extensions/pi-prompt-template-model/subagent-runtime.js.map +1 -1
  14. package/dist/builtin-extensions/pi-prompt-template-model/subagent-step.d.ts.map +1 -1
  15. package/dist/builtin-extensions/pi-prompt-template-model/subagent-step.js +3 -3
  16. package/dist/builtin-extensions/pi-prompt-template-model/subagent-step.js.map +1 -1
  17. package/dist/builtin-extensions/pi-subagents/src/api/delegation.d.ts +2 -2
  18. package/dist/builtin-extensions/pi-subagents/src/api/delegation.d.ts.map +1 -1
  19. package/dist/builtin-extensions/pi-subagents/src/api/delegation.js +1 -1
  20. package/dist/builtin-extensions/pi-subagents/src/api/delegation.js.map +1 -1
  21. package/dist/builtin-extensions/pi-subagents/src/extension/index.d.ts.map +1 -1
  22. package/dist/builtin-extensions/pi-subagents/src/extension/index.js +2 -1
  23. package/dist/builtin-extensions/pi-subagents/src/extension/index.js.map +1 -1
  24. package/dist/builtin-extensions/pi-subagents/src/extension/schemas.d.ts +5 -11
  25. package/dist/builtin-extensions/pi-subagents/src/extension/schemas.d.ts.map +1 -1
  26. package/dist/builtin-extensions/pi-subagents/src/extension/schemas.js +12 -15
  27. package/dist/builtin-extensions/pi-subagents/src/extension/schemas.js.map +1 -1
  28. package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.d.ts +3 -3
  29. package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.d.ts.map +1 -1
  30. package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.js +14 -27
  31. package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.js.map +1 -1
  32. package/dist/builtin-extensions/pi-subagents/src/runs/background/async-execution.d.ts.map +1 -1
  33. package/dist/builtin-extensions/pi-subagents/src/runs/background/async-execution.js +6 -4
  34. package/dist/builtin-extensions/pi-subagents/src/runs/background/async-execution.js.map +1 -1
  35. package/dist/builtin-extensions/pi-subagents/src/runs/background/async-job-tracker.d.ts.map +1 -1
  36. package/dist/builtin-extensions/pi-subagents/src/runs/background/async-job-tracker.js +2 -1
  37. package/dist/builtin-extensions/pi-subagents/src/runs/background/async-job-tracker.js.map +1 -1
  38. package/dist/builtin-extensions/pi-subagents/src/runs/background/async-resume.d.ts.map +1 -1
  39. package/dist/builtin-extensions/pi-subagents/src/runs/background/async-resume.js +6 -4
  40. package/dist/builtin-extensions/pi-subagents/src/runs/background/async-resume.js.map +1 -1
  41. package/dist/builtin-extensions/pi-subagents/src/runs/background/async-status.d.ts.map +1 -1
  42. package/dist/builtin-extensions/pi-subagents/src/runs/background/async-status.js +4 -2
  43. package/dist/builtin-extensions/pi-subagents/src/runs/background/async-status.js.map +1 -1
  44. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-clarify.d.ts.map +1 -1
  45. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-clarify.js +3 -35
  46. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-clarify.js.map +1 -1
  47. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-execution.d.ts.map +1 -1
  48. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-execution.js +5 -12
  49. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-execution.js.map +1 -1
  50. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.d.ts.map +1 -1
  51. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.js +14 -31
  52. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.js.map +1 -1
  53. package/dist/builtin-extensions/pi-subagents/src/runs/shared/model-fallback.d.ts +2 -0
  54. package/dist/builtin-extensions/pi-subagents/src/runs/shared/model-fallback.d.ts.map +1 -1
  55. package/dist/builtin-extensions/pi-subagents/src/runs/shared/model-fallback.js +28 -22
  56. package/dist/builtin-extensions/pi-subagents/src/runs/shared/model-fallback.js.map +1 -1
  57. package/dist/builtin-extensions/pi-subagents/src/runs/shared/parallel-utils.d.ts +1 -0
  58. package/dist/builtin-extensions/pi-subagents/src/runs/shared/parallel-utils.d.ts.map +1 -1
  59. package/dist/builtin-extensions/pi-subagents/src/runs/shared/parallel-utils.js.map +1 -1
  60. package/dist/builtin-extensions/pi-subagents/src/shared/child-spec.d.ts.map +1 -1
  61. package/dist/builtin-extensions/pi-subagents/src/shared/child-spec.js +9 -4
  62. package/dist/builtin-extensions/pi-subagents/src/shared/child-spec.js.map +1 -1
  63. package/dist/builtin-extensions/pi-subagents/src/shared/formatters.d.ts +1 -1
  64. package/dist/builtin-extensions/pi-subagents/src/shared/formatters.d.ts.map +1 -1
  65. package/dist/builtin-extensions/pi-subagents/src/shared/formatters.js +2 -2
  66. package/dist/builtin-extensions/pi-subagents/src/shared/formatters.js.map +1 -1
  67. package/dist/builtin-extensions/pi-subagents/src/shared/types.d.ts +4 -7
  68. package/dist/builtin-extensions/pi-subagents/src/shared/types.d.ts.map +1 -1
  69. package/dist/builtin-extensions/pi-subagents/src/shared/types.js +1 -1
  70. package/dist/builtin-extensions/pi-subagents/src/shared/types.js.map +1 -1
  71. package/dist/builtin-extensions/pi-subagents/src/slash/delegation-adapters.d.ts +3 -3
  72. package/dist/builtin-extensions/pi-subagents/src/slash/delegation-adapters.d.ts.map +1 -1
  73. package/dist/builtin-extensions/pi-subagents/src/slash/delegation-adapters.js +7 -6
  74. package/dist/builtin-extensions/pi-subagents/src/slash/delegation-adapters.js.map +1 -1
  75. package/dist/builtin-extensions/pi-subagents/src/slash/delegation-request.d.ts.map +1 -1
  76. package/dist/builtin-extensions/pi-subagents/src/slash/delegation-request.js +3 -3
  77. package/dist/builtin-extensions/pi-subagents/src/slash/delegation-request.js.map +1 -1
  78. package/dist/builtin-extensions/pi-subagents/src/slash/prompt-workflows.d.ts +1 -1
  79. package/dist/builtin-extensions/pi-subagents/src/slash/prompt-workflows.d.ts.map +1 -1
  80. package/dist/builtin-extensions/pi-subagents/src/slash/prompt-workflows.js +6 -4
  81. package/dist/builtin-extensions/pi-subagents/src/slash/prompt-workflows.js.map +1 -1
  82. package/dist/builtin-extensions/pi-subagents/src/slash/slash-commands.d.ts +1 -1
  83. package/dist/builtin-extensions/pi-subagents/src/slash/slash-commands.d.ts.map +1 -1
  84. package/dist/builtin-extensions/pi-subagents/src/slash/slash-commands.js +15 -10
  85. package/dist/builtin-extensions/pi-subagents/src/slash/slash-commands.js.map +1 -1
  86. package/dist/builtin-extensions/pi-subagents/src/tui/fleet.d.ts.map +1 -1
  87. package/dist/builtin-extensions/pi-subagents/src/tui/fleet.js +3 -2
  88. package/dist/builtin-extensions/pi-subagents/src/tui/fleet.js.map +1 -1
  89. package/dist/builtin-extensions/pi-subagents/src/tui/render.d.ts +2 -2
  90. package/dist/builtin-extensions/pi-subagents/src/tui/render.d.ts.map +1 -1
  91. package/dist/builtin-extensions/pi-subagents/src/tui/render.js +75 -43
  92. package/dist/builtin-extensions/pi-subagents/src/tui/render.js.map +1 -1
  93. package/dist/catalog/models.json +1 -1
  94. package/dist/catalog/providers/amazon-bedrock.json +1 -1
  95. package/dist/catalog/providers/anthropic.json +1 -1
  96. package/dist/catalog/providers/cloudflare-ai-gateway.json +1 -1
  97. package/dist/catalog/providers/fireworks.json +1 -1
  98. package/dist/catalog/providers/github-copilot.json +1 -1
  99. package/dist/catalog/providers/google-vertex.json +1 -1
  100. package/dist/catalog/providers/google.json +1 -1
  101. package/dist/catalog/providers/huggingface.json +1 -1
  102. package/dist/catalog/providers/nvidia.json +1 -1
  103. package/dist/catalog/providers/opencode-go.json +1 -1
  104. package/dist/catalog/providers/opencode.json +1 -1
  105. package/dist/catalog/providers/openrouter.json +1 -1
  106. package/dist/catalog/providers/vercel-ai-gateway.json +1 -1
  107. package/dist/catalog/publication.json +3 -3
  108. package/dist/core/agent-session-runtime.d.ts +5 -1
  109. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  110. package/dist/core/agent-session-runtime.js +7 -2
  111. package/dist/core/agent-session-runtime.js.map +1 -1
  112. package/dist/core/agent-session.d.ts +2 -0
  113. package/dist/core/agent-session.d.ts.map +1 -1
  114. package/dist/core/agent-session.js +20 -5
  115. package/dist/core/agent-session.js.map +1 -1
  116. package/dist/core/context-breakdown.d.ts +2 -0
  117. package/dist/core/context-breakdown.d.ts.map +1 -1
  118. package/dist/core/context-breakdown.js +6 -2
  119. package/dist/core/context-breakdown.js.map +1 -1
  120. package/dist/core/injected-prompt.d.ts +3 -3
  121. package/dist/core/injected-prompt.d.ts.map +1 -1
  122. package/dist/core/injected-prompt.js +2 -7
  123. package/dist/core/injected-prompt.js.map +1 -1
  124. package/dist/core/large-subagent-launch.d.ts +13 -0
  125. package/dist/core/large-subagent-launch.d.ts.map +1 -0
  126. package/dist/core/large-subagent-launch.js +54 -0
  127. package/dist/core/large-subagent-launch.js.map +1 -0
  128. package/dist/core/model-instructions.d.ts +24 -0
  129. package/dist/core/model-instructions.d.ts.map +1 -0
  130. package/dist/core/model-instructions.js +123 -0
  131. package/dist/core/model-instructions.js.map +1 -0
  132. package/dist/core/permissions.d.ts +11 -10
  133. package/dist/core/permissions.d.ts.map +1 -1
  134. package/dist/core/permissions.js +61 -45
  135. package/dist/core/permissions.js.map +1 -1
  136. package/dist/core/plan-mode.d.ts.map +1 -1
  137. package/dist/core/plan-mode.js +10 -1
  138. package/dist/core/plan-mode.js.map +1 -1
  139. package/dist/core/resource-loader.d.ts +3 -0
  140. package/dist/core/resource-loader.d.ts.map +1 -1
  141. package/dist/core/resource-loader.js +13 -4
  142. package/dist/core/resource-loader.js.map +1 -1
  143. package/dist/core/runtime-bridges.d.ts +4 -0
  144. package/dist/core/runtime-bridges.d.ts.map +1 -0
  145. package/dist/core/runtime-bridges.js +16 -0
  146. package/dist/core/runtime-bridges.js.map +1 -0
  147. package/dist/core/sdk.d.ts.map +1 -1
  148. package/dist/core/sdk.js +1 -0
  149. package/dist/core/sdk.js.map +1 -1
  150. package/dist/core/session-manager.d.ts.map +1 -1
  151. package/dist/core/session-manager.js +17 -16
  152. package/dist/core/session-manager.js.map +1 -1
  153. package/dist/core/settings-manager.d.ts +13 -0
  154. package/dist/core/settings-manager.d.ts.map +1 -1
  155. package/dist/core/settings-manager.js +32 -0
  156. package/dist/core/settings-manager.js.map +1 -1
  157. package/dist/core/settings-tools-bridge.d.ts +35 -0
  158. package/dist/core/settings-tools-bridge.d.ts.map +1 -0
  159. package/dist/core/settings-tools-bridge.js +56 -0
  160. package/dist/core/settings-tools-bridge.js.map +1 -0
  161. package/dist/core/swarm.d.ts +0 -31
  162. package/dist/core/swarm.d.ts.map +1 -1
  163. package/dist/core/swarm.js +2 -76
  164. package/dist/core/swarm.js.map +1 -1
  165. package/dist/core/system-prompt.d.ts.map +1 -1
  166. package/dist/core/system-prompt.js +1 -1
  167. package/dist/core/system-prompt.js.map +1 -1
  168. package/dist/gateway/agent-bridge.d.ts.map +1 -1
  169. package/dist/gateway/agent-bridge.js +3 -2
  170. package/dist/gateway/agent-bridge.js.map +1 -1
  171. package/dist/gateway/approval.d.ts.map +1 -1
  172. package/dist/gateway/approval.js +4 -3
  173. package/dist/gateway/approval.js.map +1 -1
  174. package/dist/gateway/cron.d.ts.map +1 -1
  175. package/dist/gateway/cron.js +3 -2
  176. package/dist/gateway/cron.js.map +1 -1
  177. package/dist/gateway/router.d.ts +1 -1
  178. package/dist/gateway/router.d.ts.map +1 -1
  179. package/dist/gateway/router.js +1 -1
  180. package/dist/gateway/router.js.map +1 -1
  181. package/dist/main.d.ts.map +1 -1
  182. package/dist/main.js +3 -9
  183. package/dist/main.js.map +1 -1
  184. package/dist/migrations.d.ts.map +1 -1
  185. package/dist/migrations.js +4 -0
  186. package/dist/migrations.js.map +1 -1
  187. package/dist/modes/interactive/components/injected-prompt-message.d.ts +1 -1
  188. package/dist/modes/interactive/components/injected-prompt-message.d.ts.map +1 -1
  189. package/dist/modes/interactive/components/injected-prompt-message.js +1 -1
  190. package/dist/modes/interactive/components/injected-prompt-message.js.map +1 -1
  191. package/dist/modes/interactive/components/settings-selector.d.ts +8 -1
  192. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  193. package/dist/modes/interactive/components/settings-selector.js +61 -1
  194. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  195. package/dist/modes/interactive/interactive-mode.d.ts +1 -1
  196. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  197. package/dist/modes/interactive/interactive-mode.js +31 -23
  198. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  199. package/dist/startup/interactive-shell.d.ts.map +1 -1
  200. package/dist/startup/interactive-shell.js +2 -1
  201. package/dist/startup/interactive-shell.js.map +1 -1
  202. package/docs/features.md +7 -6
  203. package/docs/quickstart.md +3 -2
  204. package/docs/settings.md +3 -1
  205. package/docs/termux.md +1 -1
  206. package/docs/usage.md +2 -1
  207. package/examples/extensions/subagent/README.md +1 -1
  208. package/package.json +4 -4
@@ -1 +1 @@
1
- {"version":3,"file":"interactive-shell.d.ts","sourceRoot":"","sources":["../../src/startup/interactive-shell.ts"],"names":[],"mappings":"AAIA,OAAO,EAEN,KAAK,qBAAqB,EAM1B,GAAG,EACH,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,KAAK,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACnF,OAAO,EAAE,YAAY,EAAE,MAAM,kDAAkD,CAAC;AAGhF,MAAM,WAAW,sBAAsB;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,qBAAqB,EAAE,CAAC;CACrC;AAED,MAAM,WAAW,uBAAuB;IACvC,EAAE,EAAE,GAAG,CAAC;IACR,MAAM,EAAE,YAAY,CAAC;IACrB,WAAW,EAAE,kBAAkB,CAAC;IAChC,kBAAkB,EAAE,sBAAsB,EAAE,CAAC;CAC7C;AAED,KAAK,cAAc,GAAG,CAAC,UAAU,CAAC,EAAE,mBAAmB,KAAK,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;AAuCnF,qBAAa,uBAAuB;IACnC,QAAQ,CAAC,EAAE,EAAE,GAAG,CAAC;IACjB,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B,QAAQ,CAAC,WAAW,EAAE,kBAAkB,CAAC;IACzC,QAAQ,CAAC,kBAAkB,EAAE,sBAAsB,EAAE,CAAM;IAC3D,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAyB;IAClD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAsD;IAC7E,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAmB;IACnD,OAAO,CAAC,iBAAiB,CAAgB;IACzC,OAAO,CAAC,iBAAiB,CAAc;IACvC,OAAO,CAAC,WAAW,CAAgB;IACnC,OAAO,CAAC,WAAW,CAAc;IACjC,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,WAAW,CAAK;IAExB,cAeC;IAED,IAAI,eAAe,IAAI,OAAO,CAE7B;IAED,KAAK,IAAI,IAAI,CAMZ;IAED,KAAK,IAAI,IAAI,CAIZ;IAED,MAAM,IAAI,IAAI,CAKb;IAED,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CAEjC;IAED,OAAO,IAAI,uBAAuB,CAQjC;IAED,SAAS,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAO9B;IAEK,IAAI,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAOxC;IAED,IAAI,IAAI,IAAI,CAQX;IAEK,MAAM,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,CAAC,CAAA;KAAE,CAAC,GAAG,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC,CAmBlG;IAEK,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAO9D;IAEK,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAgB5E;IAEK,aAAa,CAClB,qBAAqB,EAAE,cAAc,EACrC,iBAAiB,EAAE,cAAc,GAC/B,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAqBxB;IAED,OAAO,CAAC,SAAS;IAQjB,OAAO,CAAC,kBAAkB;IAW1B,OAAO,CAAC,oBAAoB;YA6Bd,cAAc;CA4B5B","sourcesContent":["import * as crypto from \"node:crypto\";\nimport * as fs from \"node:fs\";\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\nimport {\n\tContainer,\n\ttype EditorImageAttachment,\n\ttype EditorTheme,\n\tProcessTerminal,\n\tSpacer,\n\tsetKeybindings,\n\tText,\n\tTUI,\n} from \"@ashx-j/lunr-tui\";\nimport { KeybindingsManager } from \"../core/keybindings.ts\";\nimport type { SessionInfo, SessionListProgress } from \"../core/session-manager.ts\";\nimport { CustomEditor } from \"../modes/interactive/components/custom-editor.ts\";\nimport { markStartupMilestone } from \"./startup-milestones.ts\";\n\nexport interface StartupShellSubmission {\n\ttext: string;\n\tattachments: EditorImageAttachment[];\n}\n\nexport interface InteractiveShellBinding {\n\tui: TUI;\n\teditor: CustomEditor;\n\tkeybindings: KeybindingsManager;\n\tpendingSubmissions: StartupShellSubmission[];\n}\n\ntype SessionsLoader = (onProgress?: SessionListProgress) => Promise<SessionInfo[]>;\n\nconst identity = (text: string) => text;\nconst shellEditorTheme: EditorTheme = {\n\tborderColor: (text) => `\\x1b[38;5;60m${text}\\x1b[0m`,\n\tselectList: {\n\t\tselectedPrefix: identity,\n\t\tselectedText: identity,\n\t\tdescription: identity,\n\t\tscrollInfo: identity,\n\t\tnoMatch: identity,\n\t},\n};\n\nclass StartupProcessTerminal extends ProcessTerminal {\n\tprivate watchForFirstFrame = false;\n\tprivate firstFrameCallback: (() => void) | undefined;\n\n\tsetFirstFrameCallback(callback: () => void): void {\n\t\tthis.firstFrameCallback = callback;\n\t\tthis.watchForFirstFrame = true;\n\t}\n\n\toverride start(onInput: (data: string) => void, onResize: () => void): void {\n\t\tmarkStartupMilestone(\"input_handler_armed\");\n\t\tsuper.start(onInput, onResize);\n\t\tmarkStartupMilestone(\"raw_mode_active\");\n\t}\n\n\toverride write(data: string): void {\n\t\tsuper.write(data);\n\t\tif (this.watchForFirstFrame && data.includes(\"Starting lunR\")) {\n\t\t\tthis.watchForFirstFrame = false;\n\t\t\tmarkStartupMilestone(\"first_frame_committed\");\n\t\t\tthis.firstFrameCallback?.();\n\t\t}\n\t}\n}\n\nexport class InteractiveStartupShell {\n\treadonly ui: TUI;\n\treadonly editor: CustomEditor;\n\treadonly keybindings: KeybindingsManager;\n\treadonly pendingSubmissions: StartupShellSubmission[] = [];\n\tprivate readonly terminal: StartupProcessTerminal;\n\tprivate readonly status = new Text(\"Starting lunR. You can type now.\", 1, 0);\n\tprivate readonly editorContainer = new Container();\n\tprivate firstFramePromise: Promise<void>;\n\tprivate resolveFirstFrame!: () => void;\n\tprivate exitPromise: Promise<void>;\n\tprivate resolveExit!: () => void;\n\tprivate started = false;\n\tprivate handedOff = false;\n\tprivate exitRequested = false;\n\tprivate lastClearAt = 0;\n\n\tconstructor() {\n\t\tthis.terminal = new StartupProcessTerminal();\n\t\tthis.ui = new TUI(this.terminal);\n\t\tthis.keybindings = KeybindingsManager.create();\n\t\tsetKeybindings(this.keybindings);\n\t\tthis.editor = new CustomEditor(this.ui, shellEditorTheme, this.keybindings, { paddingX: 1 });\n\t\tthis.editorContainer.addChild(this.editor);\n\t\tthis.firstFramePromise = new Promise((resolve) => {\n\t\t\tthis.resolveFirstFrame = resolve;\n\t\t});\n\t\tthis.exitPromise = new Promise((resolve) => {\n\t\t\tthis.resolveExit = resolve;\n\t\t});\n\t\tthis.terminal.setFirstFrameCallback(this.resolveFirstFrame);\n\t\tthis.installInputHandlers();\n\t}\n\n\tget isExitRequested(): boolean {\n\t\treturn this.exitRequested;\n\t}\n\n\tstart(): void {\n\t\tif (this.started) return;\n\t\tthis.restoreShellLayout();\n\t\tthis.ui.setAlternateScreen(true);\n\t\tthis.ui.start();\n\t\tthis.started = true;\n\t}\n\n\tpause(): void {\n\t\tif (!this.started || this.handedOff) return;\n\t\tthis.ui.stop();\n\t\tthis.started = false;\n\t}\n\n\tresume(): void {\n\t\tif (this.started || this.handedOff || this.exitRequested) return;\n\t\tthis.restoreShellLayout();\n\t\tthis.ui.start();\n\t\tthis.started = true;\n\t}\n\n\twaitForFirstFrame(): Promise<void> {\n\t\treturn this.firstFramePromise;\n\t}\n\n\tbinding(): InteractiveShellBinding {\n\t\tthis.handedOff = true;\n\t\treturn {\n\t\t\tui: this.ui,\n\t\t\teditor: this.editor,\n\t\t\tkeybindings: this.keybindings,\n\t\t\tpendingSubmissions: this.pendingSubmissions,\n\t\t};\n\t}\n\n\tshowError(error: unknown): void {\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\tthis.status.setText(\n\t\t\t`Startup failed: ${message}\\nYour draft is intact. Press Ctrl+C twice or Ctrl+D on an empty draft to exit.`,\n\t\t);\n\t\tthis.editor.disableSubmit = true;\n\t\tthis.ui.requestRender();\n\t}\n\n\tasync fail(error: unknown): Promise<void> {\n\t\tthis.showError(error);\n\t\tif (process.env.PI_STARTUP_BENCHMARK === \"1\") {\n\t\t\tthis.stop();\n\t\t\treturn;\n\t\t}\n\t\tawait this.exitPromise;\n\t}\n\n\tstop(): void {\n\t\tif (this.exitRequested) return;\n\t\tthis.exitRequested = true;\n\t\tif (this.started) {\n\t\t\tthis.ui.stop();\n\t\t\tthis.started = false;\n\t\t}\n\t\tthis.resolveExit();\n\t}\n\n\tasync select<T>(title: string, options: Array<{ label: string; value: T }>): Promise<T | undefined> {\n\t\tconst { ExtensionSelectorComponent } = await import(\"../modes/interactive/components/extension-selector.ts\");\n\t\treturn new Promise((resolve) => {\n\t\t\tlet settled = false;\n\t\t\tconst finish = (value: T | undefined) => {\n\t\t\t\tif (settled) return;\n\t\t\t\tsettled = true;\n\t\t\t\tthis.restoreShellLayout();\n\t\t\t\tresolve(value);\n\t\t\t};\n\t\t\tconst selector = new ExtensionSelectorComponent(\n\t\t\t\ttitle,\n\t\t\t\toptions.map((option) => option.label),\n\t\t\t\t(label) => finish(options.find((option) => option.label === label)?.value),\n\t\t\t\t() => finish(undefined),\n\t\t\t\t{ tui: this.ui },\n\t\t\t);\n\t\t\tthis.showModal(selector, selector);\n\t\t});\n\t}\n\n\tasync confirm(title: string, message: string): Promise<boolean> {\n\t\treturn (\n\t\t\t(await this.select(`${title}\\n${message}`, [\n\t\t\t\t{ label: \"Yes\", value: true },\n\t\t\t\t{ label: \"No\", value: false },\n\t\t\t])) ?? false\n\t\t);\n\t}\n\n\tasync input(title: string, placeholder?: string): Promise<string | undefined> {\n\t\tconst { ExtensionInputComponent } = await import(\"../modes/interactive/components/extension-input.ts\");\n\t\treturn new Promise((resolve) => {\n\t\t\tlet settled = false;\n\t\t\tconst finish = (value: string | undefined) => {\n\t\t\t\tif (settled) return;\n\t\t\t\tsettled = true;\n\t\t\t\tinput.dispose();\n\t\t\t\tthis.restoreShellLayout();\n\t\t\t\tresolve(value);\n\t\t\t};\n\t\t\tconst input = new ExtensionInputComponent(title, placeholder, finish, () => finish(undefined), {\n\t\t\t\ttui: this.ui,\n\t\t\t});\n\t\t\tthis.showModal(input, input);\n\t\t});\n\t}\n\n\tasync selectSession(\n\t\tcurrentSessionsLoader: SessionsLoader,\n\t\tallSessionsLoader: SessionsLoader,\n\t): Promise<string | null> {\n\t\tconst { SessionSelectorComponent } = await import(\"../modes/interactive/components/session-selector.ts\");\n\t\treturn new Promise((resolve) => {\n\t\t\tlet settled = false;\n\t\t\tconst finish = (path: string | null) => {\n\t\t\t\tif (settled) return;\n\t\t\t\tsettled = true;\n\t\t\t\tthis.restoreShellLayout();\n\t\t\t\tresolve(path);\n\t\t\t};\n\t\t\tconst selector = new SessionSelectorComponent(\n\t\t\t\tcurrentSessionsLoader,\n\t\t\t\tallSessionsLoader,\n\t\t\t\t(path) => finish(path),\n\t\t\t\t() => finish(null),\n\t\t\t\t() => this.stop(),\n\t\t\t\t() => this.ui.requestRender(),\n\t\t\t\t{ showRenameHint: false, keybindings: this.keybindings },\n\t\t\t);\n\t\t\tthis.showModal(selector, selector.getSessionList());\n\t\t});\n\t}\n\n\tprivate showModal(component: Parameters<TUI[\"addChild\"]>[0], focus: Parameters<TUI[\"setFocus\"]>[0]): void {\n\t\tthis.ui.pinFrom(null);\n\t\tthis.ui.clear();\n\t\tthis.ui.addChild(component);\n\t\tthis.ui.setFocus(focus);\n\t\tthis.ui.requestRender(true);\n\t}\n\n\tprivate restoreShellLayout(): void {\n\t\tthis.ui.pinFrom(null);\n\t\tthis.ui.clear();\n\t\tthis.ui.addChild(new Spacer(1));\n\t\tthis.ui.addChild(this.status);\n\t\tthis.ui.addChild(this.editorContainer);\n\t\tthis.ui.pinFrom(this.editorContainer);\n\t\tthis.ui.setFocus(this.editor);\n\t\tthis.ui.requestRender(true);\n\t}\n\n\tprivate installInputHandlers(): void {\n\t\tthis.editor.onAction(\"app.clear\", () => {\n\t\t\tconst now = Date.now();\n\t\t\tif (this.editor.getText().length === 0 && now - this.lastClearAt < 500) {\n\t\t\t\tthis.stop();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.editor.setText(\"\");\n\t\t\tthis.lastClearAt = now;\n\t\t});\n\t\tthis.editor.onCtrlD = () => this.stop();\n\t\tthis.editor.onPasteImage = () => void this.pasteClipboard();\n\t\tthis.editor.onSubmit = (text) => {\n\t\t\tconst attachments = this.editor.takePendingImages();\n\t\t\tif (!text.trim()) return;\n\t\t\tif (this.pendingSubmissions.length > 0) {\n\t\t\t\tthis.editor.setText(text);\n\t\t\t\tthis.editor.restoreImageMarkers(attachments);\n\t\t\t\tthis.status.setText(\"One prompt is already queued. Your current draft will stay in the editor.\");\n\t\t\t\tthis.ui.requestRender();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.pendingSubmissions.push({ text, attachments });\n\t\t\tthis.editor.addToHistory(text);\n\t\t\tthis.status.setText(\"Prompt queued. Finishing startup before it can run.\");\n\t\t\tthis.ui.requestRender();\n\t\t};\n\t}\n\n\tprivate async pasteClipboard(): Promise<void> {\n\t\ttry {\n\t\t\tconst [{ readClipboardText }, { extensionForImageMimeType, readClipboardImage }] = await Promise.all([\n\t\t\t\timport(\"../utils/clipboard.ts\"),\n\t\t\t\timport(\"../utils/clipboard-image.ts\"),\n\t\t\t]);\n\t\t\tconst image = await readClipboardImage();\n\t\t\tif (image) {\n\t\t\t\tconst extension = extensionForImageMimeType(image.mimeType) ?? \"png\";\n\t\t\t\tconst filePath = path.join(os.tmpdir(), `lunr-clipboard-${crypto.randomUUID()}.${extension}`);\n\t\t\t\tfs.writeFileSync(filePath, Buffer.from(image.bytes));\n\t\t\t\tconst id = this.editor.insertImageMarker({ path: filePath, mimeType: image.mimeType });\n\t\t\t\tthis.status.setText(`Pasted [image_${id}] while startup continues.`);\n\t\t\t\tthis.ui.requestRender();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst text = await readClipboardText();\n\t\t\tif (text) {\n\t\t\t\tthis.editor.insertTextAtCursor(text);\n\t\t\t\tthis.ui.requestRender();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.status.setText(\"Clipboard contains no image or text.\");\n\t\t} catch (error) {\n\t\t\tthis.status.setText(`Clipboard paste failed: ${error instanceof Error ? error.message : String(error)}`);\n\t\t}\n\t\tthis.ui.requestRender();\n\t}\n}\n"]}
1
+ {"version":3,"file":"interactive-shell.d.ts","sourceRoot":"","sources":["../../src/startup/interactive-shell.ts"],"names":[],"mappings":"AAIA,OAAO,EAEN,KAAK,qBAAqB,EAM1B,GAAG,EACH,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,KAAK,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACnF,OAAO,EAAE,YAAY,EAAE,MAAM,kDAAkD,CAAC;AAGhF,MAAM,WAAW,sBAAsB;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,qBAAqB,EAAE,CAAC;CACrC;AAED,MAAM,WAAW,uBAAuB;IACvC,EAAE,EAAE,GAAG,CAAC;IACR,MAAM,EAAE,YAAY,CAAC;IACrB,WAAW,EAAE,kBAAkB,CAAC;IAChC,kBAAkB,EAAE,sBAAsB,EAAE,CAAC;CAC7C;AAED,KAAK,cAAc,GAAG,CAAC,UAAU,CAAC,EAAE,mBAAmB,KAAK,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;AAwCnF,qBAAa,uBAAuB;IACnC,QAAQ,CAAC,EAAE,EAAE,GAAG,CAAC;IACjB,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B,QAAQ,CAAC,WAAW,EAAE,kBAAkB,CAAC;IACzC,QAAQ,CAAC,kBAAkB,EAAE,sBAAsB,EAAE,CAAM;IAC3D,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAyB;IAClD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAsD;IAC7E,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAmB;IACnD,OAAO,CAAC,iBAAiB,CAAgB;IACzC,OAAO,CAAC,iBAAiB,CAAc;IACvC,OAAO,CAAC,WAAW,CAAgB;IACnC,OAAO,CAAC,WAAW,CAAc;IACjC,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,WAAW,CAAK;IAExB,cAeC;IAED,IAAI,eAAe,IAAI,OAAO,CAE7B;IAED,KAAK,IAAI,IAAI,CAMZ;IAED,KAAK,IAAI,IAAI,CAIZ;IAED,MAAM,IAAI,IAAI,CAKb;IAED,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CAEjC;IAED,OAAO,IAAI,uBAAuB,CAQjC;IAED,SAAS,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAO9B;IAEK,IAAI,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAOxC;IAED,IAAI,IAAI,IAAI,CAQX;IAEK,MAAM,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,CAAC,CAAA;KAAE,CAAC,GAAG,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC,CAmBlG;IAEK,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAO9D;IAEK,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAgB5E;IAEK,aAAa,CAClB,qBAAqB,EAAE,cAAc,EACrC,iBAAiB,EAAE,cAAc,GAC/B,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAqBxB;IAED,OAAO,CAAC,SAAS;IAQjB,OAAO,CAAC,kBAAkB;IAW1B,OAAO,CAAC,oBAAoB;YA6Bd,cAAc;CA4B5B","sourcesContent":["import * as crypto from \"node:crypto\";\nimport * as fs from \"node:fs\";\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\nimport {\n\tContainer,\n\ttype EditorImageAttachment,\n\ttype EditorTheme,\n\tProcessTerminal,\n\tSpacer,\n\tsetKeybindings,\n\tText,\n\tTUI,\n} from \"@ashx-j/lunr-tui\";\nimport { KeybindingsManager } from \"../core/keybindings.ts\";\nimport type { SessionInfo, SessionListProgress } from \"../core/session-manager.ts\";\nimport { CustomEditor } from \"../modes/interactive/components/custom-editor.ts\";\nimport { markStartupMilestone } from \"./startup-milestones.ts\";\n\nexport interface StartupShellSubmission {\n\ttext: string;\n\tattachments: EditorImageAttachment[];\n}\n\nexport interface InteractiveShellBinding {\n\tui: TUI;\n\teditor: CustomEditor;\n\tkeybindings: KeybindingsManager;\n\tpendingSubmissions: StartupShellSubmission[];\n}\n\ntype SessionsLoader = (onProgress?: SessionListProgress) => Promise<SessionInfo[]>;\n\nconst identity = (text: string) => text;\nconst shellEditorTheme: EditorTheme = {\n\tborderColor: (text) => `\\x1b[38;5;60m${text}\\x1b[0m`,\n\tselectList: {\n\t\tselectedPrefix: identity,\n\t\tselectedText: identity,\n\t\tdescription: identity,\n\t\tscrollInfo: identity,\n\t\tnoMatch: identity,\n\t},\n};\n\nclass StartupProcessTerminal extends ProcessTerminal {\n\tprivate watchForFirstFrame = false;\n\tprivate firstFrameCallback: (() => void) | undefined;\n\n\tsetFirstFrameCallback(callback: () => void): void {\n\t\tthis.firstFrameCallback = callback;\n\t\tthis.watchForFirstFrame = true;\n\t}\n\n\toverride start(onInput: (data: string) => void, onResize: () => void): void {\n\t\tmarkStartupMilestone(\"input_handler_armed\");\n\t\tsuper.start(onInput, onResize);\n\t\tmarkStartupMilestone(\"raw_mode_active\");\n\t}\n\n\toverride write(data: string): void {\n\t\tsuper.write(data);\n\t\t// Narrow terminals wrap the status line, so do not key off a substring.\n\t\tif (this.watchForFirstFrame && data.length > 0) {\n\t\t\tthis.watchForFirstFrame = false;\n\t\t\tmarkStartupMilestone(\"first_frame_committed\");\n\t\t\tthis.firstFrameCallback?.();\n\t\t}\n\t}\n}\n\nexport class InteractiveStartupShell {\n\treadonly ui: TUI;\n\treadonly editor: CustomEditor;\n\treadonly keybindings: KeybindingsManager;\n\treadonly pendingSubmissions: StartupShellSubmission[] = [];\n\tprivate readonly terminal: StartupProcessTerminal;\n\tprivate readonly status = new Text(\"Starting lunR. You can type now.\", 1, 0);\n\tprivate readonly editorContainer = new Container();\n\tprivate firstFramePromise: Promise<void>;\n\tprivate resolveFirstFrame!: () => void;\n\tprivate exitPromise: Promise<void>;\n\tprivate resolveExit!: () => void;\n\tprivate started = false;\n\tprivate handedOff = false;\n\tprivate exitRequested = false;\n\tprivate lastClearAt = 0;\n\n\tconstructor() {\n\t\tthis.terminal = new StartupProcessTerminal();\n\t\tthis.ui = new TUI(this.terminal);\n\t\tthis.keybindings = KeybindingsManager.create();\n\t\tsetKeybindings(this.keybindings);\n\t\tthis.editor = new CustomEditor(this.ui, shellEditorTheme, this.keybindings, { paddingX: 1 });\n\t\tthis.editorContainer.addChild(this.editor);\n\t\tthis.firstFramePromise = new Promise((resolve) => {\n\t\t\tthis.resolveFirstFrame = resolve;\n\t\t});\n\t\tthis.exitPromise = new Promise((resolve) => {\n\t\t\tthis.resolveExit = resolve;\n\t\t});\n\t\tthis.terminal.setFirstFrameCallback(this.resolveFirstFrame);\n\t\tthis.installInputHandlers();\n\t}\n\n\tget isExitRequested(): boolean {\n\t\treturn this.exitRequested;\n\t}\n\n\tstart(): void {\n\t\tif (this.started) return;\n\t\tthis.restoreShellLayout();\n\t\tthis.ui.setAlternateScreen(true);\n\t\tthis.ui.start();\n\t\tthis.started = true;\n\t}\n\n\tpause(): void {\n\t\tif (!this.started || this.handedOff) return;\n\t\tthis.ui.stop();\n\t\tthis.started = false;\n\t}\n\n\tresume(): void {\n\t\tif (this.started || this.handedOff || this.exitRequested) return;\n\t\tthis.restoreShellLayout();\n\t\tthis.ui.start();\n\t\tthis.started = true;\n\t}\n\n\twaitForFirstFrame(): Promise<void> {\n\t\treturn this.firstFramePromise;\n\t}\n\n\tbinding(): InteractiveShellBinding {\n\t\tthis.handedOff = true;\n\t\treturn {\n\t\t\tui: this.ui,\n\t\t\teditor: this.editor,\n\t\t\tkeybindings: this.keybindings,\n\t\t\tpendingSubmissions: this.pendingSubmissions,\n\t\t};\n\t}\n\n\tshowError(error: unknown): void {\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\tthis.status.setText(\n\t\t\t`Startup failed: ${message}\\nYour draft is intact. Press Ctrl+C twice or Ctrl+D on an empty draft to exit.`,\n\t\t);\n\t\tthis.editor.disableSubmit = true;\n\t\tthis.ui.requestRender();\n\t}\n\n\tasync fail(error: unknown): Promise<void> {\n\t\tthis.showError(error);\n\t\tif (process.env.PI_STARTUP_BENCHMARK === \"1\") {\n\t\t\tthis.stop();\n\t\t\treturn;\n\t\t}\n\t\tawait this.exitPromise;\n\t}\n\n\tstop(): void {\n\t\tif (this.exitRequested) return;\n\t\tthis.exitRequested = true;\n\t\tif (this.started) {\n\t\t\tthis.ui.stop();\n\t\t\tthis.started = false;\n\t\t}\n\t\tthis.resolveExit();\n\t}\n\n\tasync select<T>(title: string, options: Array<{ label: string; value: T }>): Promise<T | undefined> {\n\t\tconst { ExtensionSelectorComponent } = await import(\"../modes/interactive/components/extension-selector.ts\");\n\t\treturn new Promise((resolve) => {\n\t\t\tlet settled = false;\n\t\t\tconst finish = (value: T | undefined) => {\n\t\t\t\tif (settled) return;\n\t\t\t\tsettled = true;\n\t\t\t\tthis.restoreShellLayout();\n\t\t\t\tresolve(value);\n\t\t\t};\n\t\t\tconst selector = new ExtensionSelectorComponent(\n\t\t\t\ttitle,\n\t\t\t\toptions.map((option) => option.label),\n\t\t\t\t(label) => finish(options.find((option) => option.label === label)?.value),\n\t\t\t\t() => finish(undefined),\n\t\t\t\t{ tui: this.ui },\n\t\t\t);\n\t\t\tthis.showModal(selector, selector);\n\t\t});\n\t}\n\n\tasync confirm(title: string, message: string): Promise<boolean> {\n\t\treturn (\n\t\t\t(await this.select(`${title}\\n${message}`, [\n\t\t\t\t{ label: \"Yes\", value: true },\n\t\t\t\t{ label: \"No\", value: false },\n\t\t\t])) ?? false\n\t\t);\n\t}\n\n\tasync input(title: string, placeholder?: string): Promise<string | undefined> {\n\t\tconst { ExtensionInputComponent } = await import(\"../modes/interactive/components/extension-input.ts\");\n\t\treturn new Promise((resolve) => {\n\t\t\tlet settled = false;\n\t\t\tconst finish = (value: string | undefined) => {\n\t\t\t\tif (settled) return;\n\t\t\t\tsettled = true;\n\t\t\t\tinput.dispose();\n\t\t\t\tthis.restoreShellLayout();\n\t\t\t\tresolve(value);\n\t\t\t};\n\t\t\tconst input = new ExtensionInputComponent(title, placeholder, finish, () => finish(undefined), {\n\t\t\t\ttui: this.ui,\n\t\t\t});\n\t\t\tthis.showModal(input, input);\n\t\t});\n\t}\n\n\tasync selectSession(\n\t\tcurrentSessionsLoader: SessionsLoader,\n\t\tallSessionsLoader: SessionsLoader,\n\t): Promise<string | null> {\n\t\tconst { SessionSelectorComponent } = await import(\"../modes/interactive/components/session-selector.ts\");\n\t\treturn new Promise((resolve) => {\n\t\t\tlet settled = false;\n\t\t\tconst finish = (path: string | null) => {\n\t\t\t\tif (settled) return;\n\t\t\t\tsettled = true;\n\t\t\t\tthis.restoreShellLayout();\n\t\t\t\tresolve(path);\n\t\t\t};\n\t\t\tconst selector = new SessionSelectorComponent(\n\t\t\t\tcurrentSessionsLoader,\n\t\t\t\tallSessionsLoader,\n\t\t\t\t(path) => finish(path),\n\t\t\t\t() => finish(null),\n\t\t\t\t() => this.stop(),\n\t\t\t\t() => this.ui.requestRender(),\n\t\t\t\t{ showRenameHint: false, keybindings: this.keybindings },\n\t\t\t);\n\t\t\tthis.showModal(selector, selector.getSessionList());\n\t\t});\n\t}\n\n\tprivate showModal(component: Parameters<TUI[\"addChild\"]>[0], focus: Parameters<TUI[\"setFocus\"]>[0]): void {\n\t\tthis.ui.pinFrom(null);\n\t\tthis.ui.clear();\n\t\tthis.ui.addChild(component);\n\t\tthis.ui.setFocus(focus);\n\t\tthis.ui.requestRender(true);\n\t}\n\n\tprivate restoreShellLayout(): void {\n\t\tthis.ui.pinFrom(null);\n\t\tthis.ui.clear();\n\t\tthis.ui.addChild(new Spacer(1));\n\t\tthis.ui.addChild(this.status);\n\t\tthis.ui.addChild(this.editorContainer);\n\t\tthis.ui.pinFrom(this.editorContainer);\n\t\tthis.ui.setFocus(this.editor);\n\t\tthis.ui.requestRender(true);\n\t}\n\n\tprivate installInputHandlers(): void {\n\t\tthis.editor.onAction(\"app.clear\", () => {\n\t\t\tconst now = Date.now();\n\t\t\tif (this.editor.getText().length === 0 && now - this.lastClearAt < 500) {\n\t\t\t\tthis.stop();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.editor.setText(\"\");\n\t\t\tthis.lastClearAt = now;\n\t\t});\n\t\tthis.editor.onCtrlD = () => this.stop();\n\t\tthis.editor.onPasteImage = () => void this.pasteClipboard();\n\t\tthis.editor.onSubmit = (text) => {\n\t\t\tconst attachments = this.editor.takePendingImages();\n\t\t\tif (!text.trim()) return;\n\t\t\tif (this.pendingSubmissions.length > 0) {\n\t\t\t\tthis.editor.setText(text);\n\t\t\t\tthis.editor.restoreImageMarkers(attachments);\n\t\t\t\tthis.status.setText(\"One prompt is already queued. Your current draft will stay in the editor.\");\n\t\t\t\tthis.ui.requestRender();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.pendingSubmissions.push({ text, attachments });\n\t\t\tthis.editor.addToHistory(text);\n\t\t\tthis.status.setText(\"Prompt queued. Finishing startup before it can run.\");\n\t\t\tthis.ui.requestRender();\n\t\t};\n\t}\n\n\tprivate async pasteClipboard(): Promise<void> {\n\t\ttry {\n\t\t\tconst [{ readClipboardText }, { extensionForImageMimeType, readClipboardImage }] = await Promise.all([\n\t\t\t\timport(\"../utils/clipboard.ts\"),\n\t\t\t\timport(\"../utils/clipboard-image.ts\"),\n\t\t\t]);\n\t\t\tconst image = await readClipboardImage();\n\t\t\tif (image) {\n\t\t\t\tconst extension = extensionForImageMimeType(image.mimeType) ?? \"png\";\n\t\t\t\tconst filePath = path.join(os.tmpdir(), `lunr-clipboard-${crypto.randomUUID()}.${extension}`);\n\t\t\t\tfs.writeFileSync(filePath, Buffer.from(image.bytes));\n\t\t\t\tconst id = this.editor.insertImageMarker({ path: filePath, mimeType: image.mimeType });\n\t\t\t\tthis.status.setText(`Pasted [image_${id}] while startup continues.`);\n\t\t\t\tthis.ui.requestRender();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst text = await readClipboardText();\n\t\t\tif (text) {\n\t\t\t\tthis.editor.insertTextAtCursor(text);\n\t\t\t\tthis.ui.requestRender();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.status.setText(\"Clipboard contains no image or text.\");\n\t\t} catch (error) {\n\t\t\tthis.status.setText(`Clipboard paste failed: ${error instanceof Error ? error.message : String(error)}`);\n\t\t}\n\t\tthis.ui.requestRender();\n\t}\n}\n"]}
@@ -31,7 +31,8 @@ class StartupProcessTerminal extends ProcessTerminal {
31
31
  }
32
32
  write(data) {
33
33
  super.write(data);
34
- if (this.watchForFirstFrame && data.includes("Starting lunR")) {
34
+ // Narrow terminals wrap the status line, so do not key off a substring.
35
+ if (this.watchForFirstFrame && data.length > 0) {
35
36
  this.watchForFirstFrame = false;
36
37
  markStartupMilestone("first_frame_committed");
37
38
  this.firstFrameCallback?.();
@@ -1 +1 @@
1
- {"version":3,"file":"interactive-shell.js","sourceRoot":"","sources":["../../src/startup/interactive-shell.ts"],"names":[],"mappings":"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","sourcesContent":["import * as crypto from \"node:crypto\";\nimport * as fs from \"node:fs\";\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\nimport {\n\tContainer,\n\ttype EditorImageAttachment,\n\ttype EditorTheme,\n\tProcessTerminal,\n\tSpacer,\n\tsetKeybindings,\n\tText,\n\tTUI,\n} from \"@ashx-j/lunr-tui\";\nimport { KeybindingsManager } from \"../core/keybindings.ts\";\nimport type { SessionInfo, SessionListProgress } from \"../core/session-manager.ts\";\nimport { CustomEditor } from \"../modes/interactive/components/custom-editor.ts\";\nimport { markStartupMilestone } from \"./startup-milestones.ts\";\n\nexport interface StartupShellSubmission {\n\ttext: string;\n\tattachments: EditorImageAttachment[];\n}\n\nexport interface InteractiveShellBinding {\n\tui: TUI;\n\teditor: CustomEditor;\n\tkeybindings: KeybindingsManager;\n\tpendingSubmissions: StartupShellSubmission[];\n}\n\ntype SessionsLoader = (onProgress?: SessionListProgress) => Promise<SessionInfo[]>;\n\nconst identity = (text: string) => text;\nconst shellEditorTheme: EditorTheme = {\n\tborderColor: (text) => `\\x1b[38;5;60m${text}\\x1b[0m`,\n\tselectList: {\n\t\tselectedPrefix: identity,\n\t\tselectedText: identity,\n\t\tdescription: identity,\n\t\tscrollInfo: identity,\n\t\tnoMatch: identity,\n\t},\n};\n\nclass StartupProcessTerminal extends ProcessTerminal {\n\tprivate watchForFirstFrame = false;\n\tprivate firstFrameCallback: (() => void) | undefined;\n\n\tsetFirstFrameCallback(callback: () => void): void {\n\t\tthis.firstFrameCallback = callback;\n\t\tthis.watchForFirstFrame = true;\n\t}\n\n\toverride start(onInput: (data: string) => void, onResize: () => void): void {\n\t\tmarkStartupMilestone(\"input_handler_armed\");\n\t\tsuper.start(onInput, onResize);\n\t\tmarkStartupMilestone(\"raw_mode_active\");\n\t}\n\n\toverride write(data: string): void {\n\t\tsuper.write(data);\n\t\tif (this.watchForFirstFrame && data.includes(\"Starting lunR\")) {\n\t\t\tthis.watchForFirstFrame = false;\n\t\t\tmarkStartupMilestone(\"first_frame_committed\");\n\t\t\tthis.firstFrameCallback?.();\n\t\t}\n\t}\n}\n\nexport class InteractiveStartupShell {\n\treadonly ui: TUI;\n\treadonly editor: CustomEditor;\n\treadonly keybindings: KeybindingsManager;\n\treadonly pendingSubmissions: StartupShellSubmission[] = [];\n\tprivate readonly terminal: StartupProcessTerminal;\n\tprivate readonly status = new Text(\"Starting lunR. You can type now.\", 1, 0);\n\tprivate readonly editorContainer = new Container();\n\tprivate firstFramePromise: Promise<void>;\n\tprivate resolveFirstFrame!: () => void;\n\tprivate exitPromise: Promise<void>;\n\tprivate resolveExit!: () => void;\n\tprivate started = false;\n\tprivate handedOff = false;\n\tprivate exitRequested = false;\n\tprivate lastClearAt = 0;\n\n\tconstructor() {\n\t\tthis.terminal = new StartupProcessTerminal();\n\t\tthis.ui = new TUI(this.terminal);\n\t\tthis.keybindings = KeybindingsManager.create();\n\t\tsetKeybindings(this.keybindings);\n\t\tthis.editor = new CustomEditor(this.ui, shellEditorTheme, this.keybindings, { paddingX: 1 });\n\t\tthis.editorContainer.addChild(this.editor);\n\t\tthis.firstFramePromise = new Promise((resolve) => {\n\t\t\tthis.resolveFirstFrame = resolve;\n\t\t});\n\t\tthis.exitPromise = new Promise((resolve) => {\n\t\t\tthis.resolveExit = resolve;\n\t\t});\n\t\tthis.terminal.setFirstFrameCallback(this.resolveFirstFrame);\n\t\tthis.installInputHandlers();\n\t}\n\n\tget isExitRequested(): boolean {\n\t\treturn this.exitRequested;\n\t}\n\n\tstart(): void {\n\t\tif (this.started) return;\n\t\tthis.restoreShellLayout();\n\t\tthis.ui.setAlternateScreen(true);\n\t\tthis.ui.start();\n\t\tthis.started = true;\n\t}\n\n\tpause(): void {\n\t\tif (!this.started || this.handedOff) return;\n\t\tthis.ui.stop();\n\t\tthis.started = false;\n\t}\n\n\tresume(): void {\n\t\tif (this.started || this.handedOff || this.exitRequested) return;\n\t\tthis.restoreShellLayout();\n\t\tthis.ui.start();\n\t\tthis.started = true;\n\t}\n\n\twaitForFirstFrame(): Promise<void> {\n\t\treturn this.firstFramePromise;\n\t}\n\n\tbinding(): InteractiveShellBinding {\n\t\tthis.handedOff = true;\n\t\treturn {\n\t\t\tui: this.ui,\n\t\t\teditor: this.editor,\n\t\t\tkeybindings: this.keybindings,\n\t\t\tpendingSubmissions: this.pendingSubmissions,\n\t\t};\n\t}\n\n\tshowError(error: unknown): void {\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\tthis.status.setText(\n\t\t\t`Startup failed: ${message}\\nYour draft is intact. Press Ctrl+C twice or Ctrl+D on an empty draft to exit.`,\n\t\t);\n\t\tthis.editor.disableSubmit = true;\n\t\tthis.ui.requestRender();\n\t}\n\n\tasync fail(error: unknown): Promise<void> {\n\t\tthis.showError(error);\n\t\tif (process.env.PI_STARTUP_BENCHMARK === \"1\") {\n\t\t\tthis.stop();\n\t\t\treturn;\n\t\t}\n\t\tawait this.exitPromise;\n\t}\n\n\tstop(): void {\n\t\tif (this.exitRequested) return;\n\t\tthis.exitRequested = true;\n\t\tif (this.started) {\n\t\t\tthis.ui.stop();\n\t\t\tthis.started = false;\n\t\t}\n\t\tthis.resolveExit();\n\t}\n\n\tasync select<T>(title: string, options: Array<{ label: string; value: T }>): Promise<T | undefined> {\n\t\tconst { ExtensionSelectorComponent } = await import(\"../modes/interactive/components/extension-selector.ts\");\n\t\treturn new Promise((resolve) => {\n\t\t\tlet settled = false;\n\t\t\tconst finish = (value: T | undefined) => {\n\t\t\t\tif (settled) return;\n\t\t\t\tsettled = true;\n\t\t\t\tthis.restoreShellLayout();\n\t\t\t\tresolve(value);\n\t\t\t};\n\t\t\tconst selector = new ExtensionSelectorComponent(\n\t\t\t\ttitle,\n\t\t\t\toptions.map((option) => option.label),\n\t\t\t\t(label) => finish(options.find((option) => option.label === label)?.value),\n\t\t\t\t() => finish(undefined),\n\t\t\t\t{ tui: this.ui },\n\t\t\t);\n\t\t\tthis.showModal(selector, selector);\n\t\t});\n\t}\n\n\tasync confirm(title: string, message: string): Promise<boolean> {\n\t\treturn (\n\t\t\t(await this.select(`${title}\\n${message}`, [\n\t\t\t\t{ label: \"Yes\", value: true },\n\t\t\t\t{ label: \"No\", value: false },\n\t\t\t])) ?? false\n\t\t);\n\t}\n\n\tasync input(title: string, placeholder?: string): Promise<string | undefined> {\n\t\tconst { ExtensionInputComponent } = await import(\"../modes/interactive/components/extension-input.ts\");\n\t\treturn new Promise((resolve) => {\n\t\t\tlet settled = false;\n\t\t\tconst finish = (value: string | undefined) => {\n\t\t\t\tif (settled) return;\n\t\t\t\tsettled = true;\n\t\t\t\tinput.dispose();\n\t\t\t\tthis.restoreShellLayout();\n\t\t\t\tresolve(value);\n\t\t\t};\n\t\t\tconst input = new ExtensionInputComponent(title, placeholder, finish, () => finish(undefined), {\n\t\t\t\ttui: this.ui,\n\t\t\t});\n\t\t\tthis.showModal(input, input);\n\t\t});\n\t}\n\n\tasync selectSession(\n\t\tcurrentSessionsLoader: SessionsLoader,\n\t\tallSessionsLoader: SessionsLoader,\n\t): Promise<string | null> {\n\t\tconst { SessionSelectorComponent } = await import(\"../modes/interactive/components/session-selector.ts\");\n\t\treturn new Promise((resolve) => {\n\t\t\tlet settled = false;\n\t\t\tconst finish = (path: string | null) => {\n\t\t\t\tif (settled) return;\n\t\t\t\tsettled = true;\n\t\t\t\tthis.restoreShellLayout();\n\t\t\t\tresolve(path);\n\t\t\t};\n\t\t\tconst selector = new SessionSelectorComponent(\n\t\t\t\tcurrentSessionsLoader,\n\t\t\t\tallSessionsLoader,\n\t\t\t\t(path) => finish(path),\n\t\t\t\t() => finish(null),\n\t\t\t\t() => this.stop(),\n\t\t\t\t() => this.ui.requestRender(),\n\t\t\t\t{ showRenameHint: false, keybindings: this.keybindings },\n\t\t\t);\n\t\t\tthis.showModal(selector, selector.getSessionList());\n\t\t});\n\t}\n\n\tprivate showModal(component: Parameters<TUI[\"addChild\"]>[0], focus: Parameters<TUI[\"setFocus\"]>[0]): void {\n\t\tthis.ui.pinFrom(null);\n\t\tthis.ui.clear();\n\t\tthis.ui.addChild(component);\n\t\tthis.ui.setFocus(focus);\n\t\tthis.ui.requestRender(true);\n\t}\n\n\tprivate restoreShellLayout(): void {\n\t\tthis.ui.pinFrom(null);\n\t\tthis.ui.clear();\n\t\tthis.ui.addChild(new Spacer(1));\n\t\tthis.ui.addChild(this.status);\n\t\tthis.ui.addChild(this.editorContainer);\n\t\tthis.ui.pinFrom(this.editorContainer);\n\t\tthis.ui.setFocus(this.editor);\n\t\tthis.ui.requestRender(true);\n\t}\n\n\tprivate installInputHandlers(): void {\n\t\tthis.editor.onAction(\"app.clear\", () => {\n\t\t\tconst now = Date.now();\n\t\t\tif (this.editor.getText().length === 0 && now - this.lastClearAt < 500) {\n\t\t\t\tthis.stop();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.editor.setText(\"\");\n\t\t\tthis.lastClearAt = now;\n\t\t});\n\t\tthis.editor.onCtrlD = () => this.stop();\n\t\tthis.editor.onPasteImage = () => void this.pasteClipboard();\n\t\tthis.editor.onSubmit = (text) => {\n\t\t\tconst attachments = this.editor.takePendingImages();\n\t\t\tif (!text.trim()) return;\n\t\t\tif (this.pendingSubmissions.length > 0) {\n\t\t\t\tthis.editor.setText(text);\n\t\t\t\tthis.editor.restoreImageMarkers(attachments);\n\t\t\t\tthis.status.setText(\"One prompt is already queued. Your current draft will stay in the editor.\");\n\t\t\t\tthis.ui.requestRender();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.pendingSubmissions.push({ text, attachments });\n\t\t\tthis.editor.addToHistory(text);\n\t\t\tthis.status.setText(\"Prompt queued. Finishing startup before it can run.\");\n\t\t\tthis.ui.requestRender();\n\t\t};\n\t}\n\n\tprivate async pasteClipboard(): Promise<void> {\n\t\ttry {\n\t\t\tconst [{ readClipboardText }, { extensionForImageMimeType, readClipboardImage }] = await Promise.all([\n\t\t\t\timport(\"../utils/clipboard.ts\"),\n\t\t\t\timport(\"../utils/clipboard-image.ts\"),\n\t\t\t]);\n\t\t\tconst image = await readClipboardImage();\n\t\t\tif (image) {\n\t\t\t\tconst extension = extensionForImageMimeType(image.mimeType) ?? \"png\";\n\t\t\t\tconst filePath = path.join(os.tmpdir(), `lunr-clipboard-${crypto.randomUUID()}.${extension}`);\n\t\t\t\tfs.writeFileSync(filePath, Buffer.from(image.bytes));\n\t\t\t\tconst id = this.editor.insertImageMarker({ path: filePath, mimeType: image.mimeType });\n\t\t\t\tthis.status.setText(`Pasted [image_${id}] while startup continues.`);\n\t\t\t\tthis.ui.requestRender();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst text = await readClipboardText();\n\t\t\tif (text) {\n\t\t\t\tthis.editor.insertTextAtCursor(text);\n\t\t\t\tthis.ui.requestRender();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.status.setText(\"Clipboard contains no image or text.\");\n\t\t} catch (error) {\n\t\t\tthis.status.setText(`Clipboard paste failed: ${error instanceof Error ? error.message : String(error)}`);\n\t\t}\n\t\tthis.ui.requestRender();\n\t}\n}\n"]}
1
+ {"version":3,"file":"interactive-shell.js","sourceRoot":"","sources":["../../src/startup/interactive-shell.ts"],"names":[],"mappings":"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","sourcesContent":["import * as crypto from \"node:crypto\";\nimport * as fs from \"node:fs\";\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\nimport {\n\tContainer,\n\ttype EditorImageAttachment,\n\ttype EditorTheme,\n\tProcessTerminal,\n\tSpacer,\n\tsetKeybindings,\n\tText,\n\tTUI,\n} from \"@ashx-j/lunr-tui\";\nimport { KeybindingsManager } from \"../core/keybindings.ts\";\nimport type { SessionInfo, SessionListProgress } from \"../core/session-manager.ts\";\nimport { CustomEditor } from \"../modes/interactive/components/custom-editor.ts\";\nimport { markStartupMilestone } from \"./startup-milestones.ts\";\n\nexport interface StartupShellSubmission {\n\ttext: string;\n\tattachments: EditorImageAttachment[];\n}\n\nexport interface InteractiveShellBinding {\n\tui: TUI;\n\teditor: CustomEditor;\n\tkeybindings: KeybindingsManager;\n\tpendingSubmissions: StartupShellSubmission[];\n}\n\ntype SessionsLoader = (onProgress?: SessionListProgress) => Promise<SessionInfo[]>;\n\nconst identity = (text: string) => text;\nconst shellEditorTheme: EditorTheme = {\n\tborderColor: (text) => `\\x1b[38;5;60m${text}\\x1b[0m`,\n\tselectList: {\n\t\tselectedPrefix: identity,\n\t\tselectedText: identity,\n\t\tdescription: identity,\n\t\tscrollInfo: identity,\n\t\tnoMatch: identity,\n\t},\n};\n\nclass StartupProcessTerminal extends ProcessTerminal {\n\tprivate watchForFirstFrame = false;\n\tprivate firstFrameCallback: (() => void) | undefined;\n\n\tsetFirstFrameCallback(callback: () => void): void {\n\t\tthis.firstFrameCallback = callback;\n\t\tthis.watchForFirstFrame = true;\n\t}\n\n\toverride start(onInput: (data: string) => void, onResize: () => void): void {\n\t\tmarkStartupMilestone(\"input_handler_armed\");\n\t\tsuper.start(onInput, onResize);\n\t\tmarkStartupMilestone(\"raw_mode_active\");\n\t}\n\n\toverride write(data: string): void {\n\t\tsuper.write(data);\n\t\t// Narrow terminals wrap the status line, so do not key off a substring.\n\t\tif (this.watchForFirstFrame && data.length > 0) {\n\t\t\tthis.watchForFirstFrame = false;\n\t\t\tmarkStartupMilestone(\"first_frame_committed\");\n\t\t\tthis.firstFrameCallback?.();\n\t\t}\n\t}\n}\n\nexport class InteractiveStartupShell {\n\treadonly ui: TUI;\n\treadonly editor: CustomEditor;\n\treadonly keybindings: KeybindingsManager;\n\treadonly pendingSubmissions: StartupShellSubmission[] = [];\n\tprivate readonly terminal: StartupProcessTerminal;\n\tprivate readonly status = new Text(\"Starting lunR. You can type now.\", 1, 0);\n\tprivate readonly editorContainer = new Container();\n\tprivate firstFramePromise: Promise<void>;\n\tprivate resolveFirstFrame!: () => void;\n\tprivate exitPromise: Promise<void>;\n\tprivate resolveExit!: () => void;\n\tprivate started = false;\n\tprivate handedOff = false;\n\tprivate exitRequested = false;\n\tprivate lastClearAt = 0;\n\n\tconstructor() {\n\t\tthis.terminal = new StartupProcessTerminal();\n\t\tthis.ui = new TUI(this.terminal);\n\t\tthis.keybindings = KeybindingsManager.create();\n\t\tsetKeybindings(this.keybindings);\n\t\tthis.editor = new CustomEditor(this.ui, shellEditorTheme, this.keybindings, { paddingX: 1 });\n\t\tthis.editorContainer.addChild(this.editor);\n\t\tthis.firstFramePromise = new Promise((resolve) => {\n\t\t\tthis.resolveFirstFrame = resolve;\n\t\t});\n\t\tthis.exitPromise = new Promise((resolve) => {\n\t\t\tthis.resolveExit = resolve;\n\t\t});\n\t\tthis.terminal.setFirstFrameCallback(this.resolveFirstFrame);\n\t\tthis.installInputHandlers();\n\t}\n\n\tget isExitRequested(): boolean {\n\t\treturn this.exitRequested;\n\t}\n\n\tstart(): void {\n\t\tif (this.started) return;\n\t\tthis.restoreShellLayout();\n\t\tthis.ui.setAlternateScreen(true);\n\t\tthis.ui.start();\n\t\tthis.started = true;\n\t}\n\n\tpause(): void {\n\t\tif (!this.started || this.handedOff) return;\n\t\tthis.ui.stop();\n\t\tthis.started = false;\n\t}\n\n\tresume(): void {\n\t\tif (this.started || this.handedOff || this.exitRequested) return;\n\t\tthis.restoreShellLayout();\n\t\tthis.ui.start();\n\t\tthis.started = true;\n\t}\n\n\twaitForFirstFrame(): Promise<void> {\n\t\treturn this.firstFramePromise;\n\t}\n\n\tbinding(): InteractiveShellBinding {\n\t\tthis.handedOff = true;\n\t\treturn {\n\t\t\tui: this.ui,\n\t\t\teditor: this.editor,\n\t\t\tkeybindings: this.keybindings,\n\t\t\tpendingSubmissions: this.pendingSubmissions,\n\t\t};\n\t}\n\n\tshowError(error: unknown): void {\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\tthis.status.setText(\n\t\t\t`Startup failed: ${message}\\nYour draft is intact. Press Ctrl+C twice or Ctrl+D on an empty draft to exit.`,\n\t\t);\n\t\tthis.editor.disableSubmit = true;\n\t\tthis.ui.requestRender();\n\t}\n\n\tasync fail(error: unknown): Promise<void> {\n\t\tthis.showError(error);\n\t\tif (process.env.PI_STARTUP_BENCHMARK === \"1\") {\n\t\t\tthis.stop();\n\t\t\treturn;\n\t\t}\n\t\tawait this.exitPromise;\n\t}\n\n\tstop(): void {\n\t\tif (this.exitRequested) return;\n\t\tthis.exitRequested = true;\n\t\tif (this.started) {\n\t\t\tthis.ui.stop();\n\t\t\tthis.started = false;\n\t\t}\n\t\tthis.resolveExit();\n\t}\n\n\tasync select<T>(title: string, options: Array<{ label: string; value: T }>): Promise<T | undefined> {\n\t\tconst { ExtensionSelectorComponent } = await import(\"../modes/interactive/components/extension-selector.ts\");\n\t\treturn new Promise((resolve) => {\n\t\t\tlet settled = false;\n\t\t\tconst finish = (value: T | undefined) => {\n\t\t\t\tif (settled) return;\n\t\t\t\tsettled = true;\n\t\t\t\tthis.restoreShellLayout();\n\t\t\t\tresolve(value);\n\t\t\t};\n\t\t\tconst selector = new ExtensionSelectorComponent(\n\t\t\t\ttitle,\n\t\t\t\toptions.map((option) => option.label),\n\t\t\t\t(label) => finish(options.find((option) => option.label === label)?.value),\n\t\t\t\t() => finish(undefined),\n\t\t\t\t{ tui: this.ui },\n\t\t\t);\n\t\t\tthis.showModal(selector, selector);\n\t\t});\n\t}\n\n\tasync confirm(title: string, message: string): Promise<boolean> {\n\t\treturn (\n\t\t\t(await this.select(`${title}\\n${message}`, [\n\t\t\t\t{ label: \"Yes\", value: true },\n\t\t\t\t{ label: \"No\", value: false },\n\t\t\t])) ?? false\n\t\t);\n\t}\n\n\tasync input(title: string, placeholder?: string): Promise<string | undefined> {\n\t\tconst { ExtensionInputComponent } = await import(\"../modes/interactive/components/extension-input.ts\");\n\t\treturn new Promise((resolve) => {\n\t\t\tlet settled = false;\n\t\t\tconst finish = (value: string | undefined) => {\n\t\t\t\tif (settled) return;\n\t\t\t\tsettled = true;\n\t\t\t\tinput.dispose();\n\t\t\t\tthis.restoreShellLayout();\n\t\t\t\tresolve(value);\n\t\t\t};\n\t\t\tconst input = new ExtensionInputComponent(title, placeholder, finish, () => finish(undefined), {\n\t\t\t\ttui: this.ui,\n\t\t\t});\n\t\t\tthis.showModal(input, input);\n\t\t});\n\t}\n\n\tasync selectSession(\n\t\tcurrentSessionsLoader: SessionsLoader,\n\t\tallSessionsLoader: SessionsLoader,\n\t): Promise<string | null> {\n\t\tconst { SessionSelectorComponent } = await import(\"../modes/interactive/components/session-selector.ts\");\n\t\treturn new Promise((resolve) => {\n\t\t\tlet settled = false;\n\t\t\tconst finish = (path: string | null) => {\n\t\t\t\tif (settled) return;\n\t\t\t\tsettled = true;\n\t\t\t\tthis.restoreShellLayout();\n\t\t\t\tresolve(path);\n\t\t\t};\n\t\t\tconst selector = new SessionSelectorComponent(\n\t\t\t\tcurrentSessionsLoader,\n\t\t\t\tallSessionsLoader,\n\t\t\t\t(path) => finish(path),\n\t\t\t\t() => finish(null),\n\t\t\t\t() => this.stop(),\n\t\t\t\t() => this.ui.requestRender(),\n\t\t\t\t{ showRenameHint: false, keybindings: this.keybindings },\n\t\t\t);\n\t\t\tthis.showModal(selector, selector.getSessionList());\n\t\t});\n\t}\n\n\tprivate showModal(component: Parameters<TUI[\"addChild\"]>[0], focus: Parameters<TUI[\"setFocus\"]>[0]): void {\n\t\tthis.ui.pinFrom(null);\n\t\tthis.ui.clear();\n\t\tthis.ui.addChild(component);\n\t\tthis.ui.setFocus(focus);\n\t\tthis.ui.requestRender(true);\n\t}\n\n\tprivate restoreShellLayout(): void {\n\t\tthis.ui.pinFrom(null);\n\t\tthis.ui.clear();\n\t\tthis.ui.addChild(new Spacer(1));\n\t\tthis.ui.addChild(this.status);\n\t\tthis.ui.addChild(this.editorContainer);\n\t\tthis.ui.pinFrom(this.editorContainer);\n\t\tthis.ui.setFocus(this.editor);\n\t\tthis.ui.requestRender(true);\n\t}\n\n\tprivate installInputHandlers(): void {\n\t\tthis.editor.onAction(\"app.clear\", () => {\n\t\t\tconst now = Date.now();\n\t\t\tif (this.editor.getText().length === 0 && now - this.lastClearAt < 500) {\n\t\t\t\tthis.stop();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.editor.setText(\"\");\n\t\t\tthis.lastClearAt = now;\n\t\t});\n\t\tthis.editor.onCtrlD = () => this.stop();\n\t\tthis.editor.onPasteImage = () => void this.pasteClipboard();\n\t\tthis.editor.onSubmit = (text) => {\n\t\t\tconst attachments = this.editor.takePendingImages();\n\t\t\tif (!text.trim()) return;\n\t\t\tif (this.pendingSubmissions.length > 0) {\n\t\t\t\tthis.editor.setText(text);\n\t\t\t\tthis.editor.restoreImageMarkers(attachments);\n\t\t\t\tthis.status.setText(\"One prompt is already queued. Your current draft will stay in the editor.\");\n\t\t\t\tthis.ui.requestRender();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.pendingSubmissions.push({ text, attachments });\n\t\t\tthis.editor.addToHistory(text);\n\t\t\tthis.status.setText(\"Prompt queued. Finishing startup before it can run.\");\n\t\t\tthis.ui.requestRender();\n\t\t};\n\t}\n\n\tprivate async pasteClipboard(): Promise<void> {\n\t\ttry {\n\t\t\tconst [{ readClipboardText }, { extensionForImageMimeType, readClipboardImage }] = await Promise.all([\n\t\t\t\timport(\"../utils/clipboard.ts\"),\n\t\t\t\timport(\"../utils/clipboard-image.ts\"),\n\t\t\t]);\n\t\t\tconst image = await readClipboardImage();\n\t\t\tif (image) {\n\t\t\t\tconst extension = extensionForImageMimeType(image.mimeType) ?? \"png\";\n\t\t\t\tconst filePath = path.join(os.tmpdir(), `lunr-clipboard-${crypto.randomUUID()}.${extension}`);\n\t\t\t\tfs.writeFileSync(filePath, Buffer.from(image.bytes));\n\t\t\t\tconst id = this.editor.insertImageMarker({ path: filePath, mimeType: image.mimeType });\n\t\t\t\tthis.status.setText(`Pasted [image_${id}] while startup continues.`);\n\t\t\t\tthis.ui.requestRender();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst text = await readClipboardText();\n\t\t\tif (text) {\n\t\t\t\tthis.editor.insertTextAtCursor(text);\n\t\t\t\tthis.ui.requestRender();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.status.setText(\"Clipboard contains no image or text.\");\n\t\t} catch (error) {\n\t\t\tthis.status.setText(`Clipboard paste failed: ${error instanceof Error ? error.message : String(error)}`);\n\t\t}\n\t\tthis.ui.requestRender();\n\t}\n}\n"]}
package/docs/features.md CHANGED
@@ -9,7 +9,7 @@ Sample code under `examples/extensions/plan-mode`, `examples/extensions/todo.ts`
9
9
  Permission modes: `manual | yolo | plan | auto`. Shift+Tab (`app.mode.cycle`) cycles that order. Thinking cycle is unbound; use `/thinking`, `/effort`, or `/reasoning`.
10
10
 
11
11
  - **manual** — approve every tool
12
- - **yolo** — auto-approve tools; **does not** bypass the swarm gate
12
+ - **yolo** — auto-approve ordinary tools; large subagent launches still request confirmation
13
13
  - **plan** — read-oriented planning; the model calls `present_plan` with a summary; you approve or decline in a dock
14
14
  - **auto** — fully autonomous
15
15
 
@@ -17,13 +17,12 @@ Permission modes: `manual | yolo | plan | auto`. Shift+Tab (`app.mode.cycle`) cy
17
17
 
18
18
  `present_plan` is only available in plan mode. After approval, interactive lunR leaves plan mode before the tool result resolves.
19
19
 
20
- ## Subagents and swarm
20
+ ## Subagents
21
21
 
22
22
  Advertised subagents always start **fresh** (no forked parent context). Default parallel concurrency / max tasks / global run cap are unlimited; an explicit `concurrency` is still honored.
23
23
 
24
- A **swarm** is 3+ parallel subagents in one `tasks`/`chain.parallel` call, or 3+ same-turn SINGLE `subagent` calls. Swarms are gated in **manual and yolo**. Sequential work stays `chain`.
24
+ A launch of 3+ parallel children in one `tasks`/`chain.parallel` call, or 3+ same-turn SINGLE `subagent` calls, receives one aggregate confirmation in **manual and yolo**. Sequential work stays `chain`. Auto bypasses this confirmation, and it can be disabled independently in `/settings`.
25
25
 
26
- - `/swarm <task>` — orchestrate parallel subagents
27
26
 
28
27
  `/goal` sets a session goal and **forces session auto** permission mode.
29
28
 
@@ -31,7 +30,8 @@ A **swarm** is 3+ parallel subagents in one `tasks`/`chain.parallel` call, or 3+
31
30
 
32
31
  - **Todos** — lunr-todos is a full-replace list. Completed todos prune on the next user turn (no leftover `✓ N done` footer).
33
32
  - **Agent memory** — durable established facts and stable preferences in `~/.lunr/simple-memory/memory.md`. `/settings` → Agent memory controls injection and the `memory_add`, `memory_remove`, and `memory_load` tools without deleting stored facts. `memoryCharCap` defaults to 5000. Behavior instructions, transient task state, transcripts, guesses, and secrets do not belong in memory.
34
- - **Global instructions** — create `~/.lunr/agent/AGENTS.md` yourself when you want global behavior or instructions. lunR injects it through the normal context loader; `/reload` picks up changes. The model cannot modify this user-managed file. The retired `behavior.md` file and behavior presets are no longer loaded.
33
+ - **Global instructions** — create `~/.lunr/agent/agents/AGENTS.md` yourself when you want global behavior or instructions. lunR injects it through the normal context loader; `/reload` picks up changes. The model cannot modify this user-managed file. The retired `behavior.md` file and behavior presets are no longer loaded.
34
+ - **Model instructions** — `/settings` can enable `~/.lunr/agent/agents/<model-name>/AGENTS.md` and choose **Both** (global then model-specific) or **Model only**. The folder name is provider-independent and filesystem-safe. Project `AGENTS.md`/`CLAUDE.md` files are unaffected, and `--no-context-files` disables all instruction files.
35
35
 
36
36
  ## Cron
37
37
 
@@ -86,7 +86,8 @@ Without runnable adapters (enabled platform + resolvable token), `lunr gateway`
86
86
  - Click a ✻ Thought or tool card to expand/collapse that item. `app.tools.expand` is unbound. `/tree` still uses `ctrl+o` for filters.
87
87
  - Smooth streaming (`smoothStreaming`, default off) is **interactive TUI only** (grapheme reveal at ~30 FPS). Print, RPC, and gateway stay unsmoothed.
88
88
  - Image paste inserts `[image_n]` chips. Windows uses **Alt+V**; VS Code must forward it because it owns Ctrl+V and Alt+V. `/paste-image` bypasses terminal shortcuts.
89
- - Model tiers: `/settings` Enable model tiers. Per-tier thinking; unset = parent session.
89
+ - Model tiers: every child launch selects `light`, `standard`, or `heavy`. Configure authenticated models for those routes in `/settings`; a missing, disabled, unauthenticated, or unavailable route fails closed. Per-tier thinking is optional; unset inherits the parent session.
90
+ - Settings tools: `settings_load` is always available to the model. It injects four narrowly scoped tools for model tiers, model instruction subscriptions, rollback behavior, and session retention only after the model requests them.
90
91
 
91
92
  ## Updates, catalogs, local models
92
93
 
@@ -121,7 +121,8 @@ lunR loads context files at startup. Add an `AGENTS.md` file to tell it how to w
121
121
 
122
122
  lunR loads:
123
123
 
124
- - `~/.lunr/agent/AGENTS.md` for global instructions
124
+ - `~/.lunr/agent/agents/AGENTS.md` for global instructions
125
+ - `~/.lunr/agent/agents/<model-name>/AGENTS.md` for optional model-specific instructions enabled in `/settings`
125
126
  - `AGENTS.md` or `CLAUDE.md` from parent directories and the current directory
126
127
 
127
128
  Restart lunR, or run `/reload`, after changing context files.
@@ -137,7 +138,7 @@ lunr @README.md "Summarize this"
137
138
  lunr @src/app.ts @src/app.test.ts "Review these together"
138
139
  ```
139
140
 
140
- Paste images with Ctrl+V or Alt+V on Windows. VS Code must forward Alt+V; `/paste-image` works when the terminal owns the key. The editor inserts `[image_1]`, `[image_2]`, … chips instead of a temp path. Dragging images into supported terminals also works.
141
+ Paste images with Ctrl+V or Alt+V on Windows. VS Code owns those keys, so `/paste-image` pastes without a terminal shortcut. The editor inserts `[image_1]`, `[image_2]`, … chips instead of a temp path. Dragging images into supported terminals also works.
141
142
 
142
143
  ### Run shell commands
143
144
 
package/docs/settings.md CHANGED
@@ -64,6 +64,8 @@ Use `/trust` in interactive mode to save a project trust decision for future ses
64
64
  | `memoryCharCap` | number | `5000` | Durable-facts memory character cap (1–30000) |
65
65
  | `sessionRetentionDays` | number | `30` | Delete session files older than N days at launch; `0` keeps forever |
66
66
  | `modelTiers` | object | - | Enable model tiers and per-tier thinking |
67
+ | `modelInstructions` | object | `{ enabled: false, mode: "both" }` | Model-specific instructions and whether they append to or replace global instructions |
68
+ | `confirmLargeSubagentLaunches` | boolean | `true` | Ask once before aggregate launches of three or more children outside Auto mode |
67
69
  | `enableAnalytics` | boolean | `false` | Opt-in analytics data sharing. Currently only asked for during the experimental first-time setup (`PI_EXPERIMENTAL=1`) |
68
70
  | `trackingId` | string | - | Analytics tracking identifier, generated when `enableAnalytics` is turned on |
69
71
  | `doubleEscapeAction` | string | `"tree"` | Action for double-escape: `"tree"`, `"fork"`, or `"none"` |
@@ -230,7 +232,7 @@ When multiple sources specify a session directory, precedence is `--session-dir`
230
232
  | `footerTokens` | boolean | `true` | Show ↑in ↓out token totals |
231
233
  | `footerCacheHitRate` | boolean | `true` | Show the latest prompt cache-hit rate when reported |
232
234
  | `footerTps` | boolean | `true` | Show tokens/second. Independent of feature statuses |
233
- | `footerStatuses` | boolean | `true` | Show plan/goal/swarm status segments |
235
+ | `footerStatuses` | boolean | `true` | Show plan and goal status segments |
234
236
  | `footerGit` | boolean | `true` | Show git branch + added/removed |
235
237
  | `footerPlan` | boolean | `true` | Show the subscription usage segment |
236
238
  | `footerPlanBar` | boolean | `true` | Show the █░ fill; off keeps the percent only |
package/docs/termux.md CHANGED
@@ -34,7 +34,7 @@ Image clipboard is not supported on Termux (the `ctrl+v` image paste feature wil
34
34
 
35
35
  ## Example AGENTS.md for Termux
36
36
 
37
- Create `~/.lunr/agent/AGENTS.md` to help the agent understand the Termux environment:
37
+ Create `~/.lunr/agent/agents/AGENTS.md` to help the agent understand the Termux environment:
38
38
 
39
39
  ````markdown
40
40
  # Agent Environment: Termux on Android
package/docs/usage.md CHANGED
@@ -121,7 +121,8 @@ See [Sessions](sessions.md) and [Compaction](compaction.md) for details.
121
121
 
122
122
  lunR loads `AGENTS.md` or `CLAUDE.md` at startup from:
123
123
 
124
- - `~/.lunr/agent/AGENTS.md` for global instructions
124
+ - `~/.lunr/agent/agents/AGENTS.md` for global instructions
125
+ - `~/.lunr/agent/agents/<model-name>/AGENTS.md` for optional model-specific instructions enabled in `/settings`
125
126
  - parent directories, walking up from the current working directory
126
127
  - the current directory
127
128
 
@@ -1,6 +1,6 @@
1
1
  # Subagent Example (sample)
2
2
 
3
- This is an **Extension API sample**, not lunR's product subagent implementation. lunR ships baked-in subagents (always fresh; swarm gate for 3+ parallel). See [docs/features.md](../../../docs/features.md).
3
+ This is an **Extension API sample**, not lunR's product subagent implementation. lunR ships baked-in subagents (always fresh; aggregate confirmation for 3+ parallel). See [docs/features.md](../../../docs/features.md).
4
4
 
5
5
  Delegate tasks to specialized subagents with isolated context windows.
6
6
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ashx-j/lunr-dev",
3
- "version": "0.2.13-dev.5.1",
3
+ "version": "0.2.13-dev.7.1",
4
4
  "description": "lunR — terminal coding agent CLI with read, bash, edit, write tools and session management",
5
5
  "type": "module",
6
6
  "piConfig": {
@@ -37,9 +37,9 @@
37
37
  "shrinkwrap": "node ../../scripts/generate-coding-agent-shrinkwrap.mjs"
38
38
  },
39
39
  "dependencies": {
40
- "@ashx-j/lunr-agent": "0.2.13-dev.5.1",
41
- "@ashx-j/lunr-ai": "0.2.13-dev.5.1",
42
- "@ashx-j/lunr-tui": "0.2.13-dev.5.1",
40
+ "@ashx-j/lunr-agent": "0.2.13-dev.7.1",
41
+ "@ashx-j/lunr-ai": "0.2.13-dev.7.1",
42
+ "@ashx-j/lunr-tui": "0.2.13-dev.7.1",
43
43
  "@modelcontextprotocol/ext-apps": "^1.7.4",
44
44
  "@modelcontextprotocol/sdk": "1.30.0",
45
45
  "@mozilla/readability": "^0.6.0",