@oh-my-pi/pi-coding-agent 15.12.4 → 15.13.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 (291) hide show
  1. package/CHANGELOG.md +304 -6
  2. package/dist/cli.js +1015 -881
  3. package/dist/types/async/job-manager.d.ts +15 -0
  4. package/dist/types/autolearn/controller.d.ts +25 -0
  5. package/dist/types/autolearn/managed-skills.d.ts +45 -0
  6. package/dist/types/autoresearch/state.d.ts +1 -1
  7. package/dist/types/autoresearch/types.d.ts +1 -1
  8. package/dist/types/cli/args.d.ts +19 -1
  9. package/dist/types/cli/session-picker.d.ts +1 -1
  10. package/dist/types/cli/setup-cli.d.ts +1 -1
  11. package/dist/types/cli/setup-model-picker.d.ts +14 -0
  12. package/dist/types/collab/protocol.d.ts +1 -1
  13. package/dist/types/commands/say.d.ts +24 -0
  14. package/dist/types/config/keybindings.d.ts +3 -3
  15. package/dist/types/config/model-registry.d.ts +10 -0
  16. package/dist/types/config/models-config-schema.d.ts +12 -0
  17. package/dist/types/config/models-config.d.ts +8 -2
  18. package/dist/types/config/settings-schema.d.ts +261 -58
  19. package/dist/types/export/html/index.d.ts +2 -1
  20. package/dist/types/extensibility/extensions/model-api.d.ts +17 -0
  21. package/dist/types/extensibility/extensions/runner.d.ts +3 -1
  22. package/dist/types/extensibility/extensions/types.d.ts +47 -1
  23. package/dist/types/extensibility/hooks/index.d.ts +2 -1
  24. package/dist/types/extensibility/plugins/legacy-pi-compat.d.ts +9 -0
  25. package/dist/types/extensibility/plugins/loader.d.ts +11 -0
  26. package/dist/types/extensibility/shared-events.d.ts +1 -1
  27. package/dist/types/extensibility/skills.d.ts +10 -0
  28. package/dist/types/goals/guided-setup.d.ts +18 -0
  29. package/dist/types/goals/state.d.ts +1 -1
  30. package/dist/types/hindsight/transcript.d.ts +1 -1
  31. package/dist/types/index.d.ts +5 -0
  32. package/dist/types/internal-urls/local-protocol.d.ts +4 -2
  33. package/dist/types/main.d.ts +4 -3
  34. package/dist/types/mcp/startup-events.d.ts +11 -0
  35. package/dist/types/memories/index.d.ts +7 -0
  36. package/dist/types/memory-backend/local-backend.d.ts +4 -3
  37. package/dist/types/mnemopi/config.d.ts +4 -4
  38. package/dist/types/modes/components/agent-hub.d.ts +6 -0
  39. package/dist/types/modes/components/assistant-message.d.ts +1 -2
  40. package/dist/types/modes/components/compaction-summary-message.d.ts +15 -1
  41. package/dist/types/modes/components/custom-editor.d.ts +39 -1
  42. package/dist/types/modes/components/custom-editor.test.d.ts +1 -0
  43. package/dist/types/modes/components/session-selector.d.ts +1 -1
  44. package/dist/types/modes/components/tool-execution.d.ts +26 -16
  45. package/dist/types/modes/components/transcript-container.d.ts +23 -2
  46. package/dist/types/modes/components/tree-selector.d.ts +1 -1
  47. package/dist/types/modes/components/usage-row.d.ts +3 -0
  48. package/dist/types/modes/controllers/command-controller.d.ts +2 -2
  49. package/dist/types/modes/controllers/input-controller.d.ts +14 -0
  50. package/dist/types/modes/controllers/selector-controller.d.ts +3 -1
  51. package/dist/types/modes/gradient-highlight.d.ts +9 -4
  52. package/dist/types/modes/image-references.d.ts +6 -0
  53. package/dist/types/modes/interactive-mode.d.ts +27 -3
  54. package/dist/types/modes/magic-keywords.d.ts +13 -1
  55. package/dist/types/modes/rpc/rpc-mode.d.ts +35 -1
  56. package/dist/types/modes/rpc/rpc-types.d.ts +9 -1
  57. package/dist/types/modes/runtime-init.d.ts +4 -0
  58. package/dist/types/modes/theme/theme.d.ts +13 -2
  59. package/dist/types/modes/types.d.ts +8 -2
  60. package/dist/types/modes/utils/ui-helpers.d.ts +1 -1
  61. package/dist/types/registry/agent-registry.d.ts +17 -0
  62. package/dist/types/secrets/obfuscator.d.ts +1 -1
  63. package/dist/types/session/agent-session.d.ts +14 -2
  64. package/dist/types/session/indexed-session-storage.d.ts +3 -4
  65. package/dist/types/session/session-context.d.ts +39 -0
  66. package/dist/types/session/session-entries.d.ts +159 -0
  67. package/dist/types/session/session-listing.d.ts +69 -0
  68. package/dist/types/session/session-loader.d.ts +16 -0
  69. package/dist/types/session/session-manager.d.ts +82 -474
  70. package/dist/types/session/session-migrations.d.ts +12 -0
  71. package/dist/types/session/session-paths.d.ts +25 -0
  72. package/dist/types/session/session-persistence.d.ts +8 -0
  73. package/dist/types/session/session-storage.d.ts +11 -12
  74. package/dist/types/session/snapcompact-inline.d.ts +12 -1
  75. package/dist/types/session/snapcompact-savings-journal.d.ts +46 -0
  76. package/dist/types/session/tool-choice-queue.d.ts +6 -6
  77. package/dist/types/stt/asr-client.d.ts +90 -0
  78. package/dist/types/stt/asr-protocol.d.ts +97 -0
  79. package/dist/types/stt/asr-worker.d.ts +2 -0
  80. package/dist/types/stt/downloader.d.ts +38 -0
  81. package/dist/types/stt/endpointer.d.ts +59 -0
  82. package/dist/types/stt/index.d.ts +5 -1
  83. package/dist/types/stt/models.d.ts +120 -0
  84. package/dist/types/stt/recorder.d.ts +17 -0
  85. package/dist/types/stt/stt-controller.d.ts +6 -0
  86. package/dist/types/stt/transcriber.d.ts +5 -7
  87. package/dist/types/stt/wav.d.ts +29 -0
  88. package/dist/types/system-prompt.d.ts +4 -0
  89. package/dist/types/task/executor.d.ts +2 -0
  90. package/dist/types/task/index.d.ts +9 -1
  91. package/dist/types/task/types.d.ts +36 -0
  92. package/dist/types/tools/bash.d.ts +2 -2
  93. package/dist/types/tools/eval-render.d.ts +1 -1
  94. package/dist/types/tools/index.d.ts +11 -1
  95. package/dist/types/tools/irc.d.ts +1 -0
  96. package/dist/types/tools/learn.d.ts +51 -0
  97. package/dist/types/tools/manage-skill.d.ts +40 -0
  98. package/dist/types/tools/plan-mode-guard.d.ts +10 -0
  99. package/dist/types/tools/renderers.d.ts +7 -11
  100. package/dist/types/tools/ssh.d.ts +1 -1
  101. package/dist/types/tools/todo.d.ts +1 -1
  102. package/dist/types/tools/tts.d.ts +25 -0
  103. package/dist/types/tools/write.d.ts +1 -1
  104. package/dist/types/tts/downloader.d.ts +20 -0
  105. package/dist/types/tts/index.d.ts +8 -0
  106. package/dist/types/tts/models.d.ts +82 -0
  107. package/dist/types/tts/player.d.ts +32 -0
  108. package/dist/types/tts/runtime.d.ts +6 -0
  109. package/dist/types/tts/streaming-player.d.ts +41 -0
  110. package/dist/types/tts/tts-client.d.ts +93 -0
  111. package/dist/types/tts/tts-protocol.d.ts +95 -0
  112. package/dist/types/tts/tts-worker.d.ts +2 -0
  113. package/dist/types/tts/vocalizer.d.ts +41 -0
  114. package/dist/types/tts/wav.d.ts +8 -0
  115. package/dist/types/utils/tool-choice.d.ts +8 -0
  116. package/dist/types/utils/tools-manager.d.ts +2 -1
  117. package/dist/types/utils/tools-manager.test.d.ts +1 -0
  118. package/dist/types/web/scrapers/github.d.ts +1 -1
  119. package/package.json +15 -14
  120. package/src/async/job-manager.ts +49 -0
  121. package/src/autolearn/controller.ts +139 -0
  122. package/src/autolearn/managed-skills.ts +257 -0
  123. package/src/autoresearch/state.ts +1 -1
  124. package/src/autoresearch/types.ts +1 -1
  125. package/src/cli/args.ts +56 -2
  126. package/src/cli/session-picker.ts +2 -1
  127. package/src/cli/setup-cli.ts +148 -47
  128. package/src/cli/setup-model-picker.ts +43 -0
  129. package/src/cli-commands.ts +1 -0
  130. package/src/cli.ts +45 -13
  131. package/src/collab/host.ts +1 -1
  132. package/src/collab/protocol.ts +1 -1
  133. package/src/commands/say.ts +102 -0
  134. package/src/commands/setup.ts +1 -1
  135. package/src/commit/agentic/tools/analyze-file.ts +3 -0
  136. package/src/config/keybindings.ts +2 -2
  137. package/src/config/model-discovery.ts +11 -5
  138. package/src/config/model-registry.ts +64 -9
  139. package/src/config/models-config-schema.ts +4 -1
  140. package/src/config/models-config.ts +2 -1
  141. package/src/config/settings-schema.ts +248 -32
  142. package/src/config/settings.ts +10 -0
  143. package/src/discovery/builtin.ts +23 -1
  144. package/src/discovery/claude-plugins.ts +44 -5
  145. package/src/discovery/helpers.ts +41 -1
  146. package/src/eval/__tests__/budget-bridge.test.ts +1 -1
  147. package/src/eval/js/shared/prelude.txt +69 -17
  148. package/src/export/html/index.ts +3 -6
  149. package/src/extensibility/extensions/model-api.ts +41 -0
  150. package/src/extensibility/extensions/runner.ts +4 -0
  151. package/src/extensibility/extensions/types.ts +52 -1
  152. package/src/extensibility/extensions/wrapper.ts +41 -5
  153. package/src/extensibility/hooks/index.ts +2 -1
  154. package/src/extensibility/plugins/legacy-pi-compat.ts +43 -13
  155. package/src/extensibility/plugins/loader.ts +30 -19
  156. package/src/extensibility/plugins/manager.ts +221 -90
  157. package/src/extensibility/shared-events.ts +1 -1
  158. package/src/extensibility/skills.ts +96 -15
  159. package/src/goals/guided-setup.ts +133 -0
  160. package/src/goals/state.ts +1 -1
  161. package/src/hindsight/transcript.ts +1 -1
  162. package/src/index.ts +5 -0
  163. package/src/internal-urls/docs-index.generated.ts +10 -10
  164. package/src/internal-urls/history-protocol.ts +1 -1
  165. package/src/internal-urls/local-protocol.ts +29 -7
  166. package/src/main.ts +27 -7
  167. package/src/mcp/startup-events.ts +21 -0
  168. package/src/mcp/transports/stdio.ts +2 -1
  169. package/src/memories/index.ts +146 -11
  170. package/src/memory-backend/local-backend.ts +11 -5
  171. package/src/mnemopi/backend.ts +1 -0
  172. package/src/mnemopi/config.ts +26 -10
  173. package/src/modes/acp/acp-agent.ts +3 -5
  174. package/src/modes/components/agent-hub.ts +49 -4
  175. package/src/modes/components/assistant-message.ts +4 -37
  176. package/src/modes/components/compaction-summary-message.ts +125 -26
  177. package/src/modes/components/custom-editor.test.ts +96 -0
  178. package/src/modes/components/custom-editor.ts +164 -8
  179. package/src/modes/components/session-selector.ts +1 -1
  180. package/src/modes/components/settings-defs.ts +7 -0
  181. package/src/modes/components/tool-execution.ts +82 -43
  182. package/src/modes/components/transcript-container.ts +70 -1
  183. package/src/modes/components/tree-selector.ts +1 -1
  184. package/src/modes/components/usage-row.ts +18 -0
  185. package/src/modes/components/user-message.ts +4 -2
  186. package/src/modes/controllers/command-controller.ts +14 -4
  187. package/src/modes/controllers/event-controller.ts +78 -11
  188. package/src/modes/controllers/extension-ui-controller.ts +6 -0
  189. package/src/modes/controllers/input-controller.ts +258 -27
  190. package/src/modes/controllers/selector-controller.ts +12 -2
  191. package/src/modes/gradient-highlight.ts +21 -9
  192. package/src/modes/image-references.ts +20 -0
  193. package/src/modes/interactive-mode.ts +286 -40
  194. package/src/modes/magic-keywords.ts +27 -5
  195. package/src/modes/rpc/rpc-mode.ts +146 -14
  196. package/src/modes/rpc/rpc-subagents.ts +2 -2
  197. package/src/modes/rpc/rpc-types.ts +8 -2
  198. package/src/modes/runtime-init.ts +28 -3
  199. package/src/modes/theme/theme.ts +98 -50
  200. package/src/modes/types.ts +6 -2
  201. package/src/modes/utils/hotkeys-markdown.ts +1 -1
  202. package/src/modes/utils/ui-helpers.ts +34 -6
  203. package/src/priority.json +5 -1
  204. package/src/prompts/agents/task.md +1 -0
  205. package/src/prompts/goals/guided-goal-interview.md +8 -0
  206. package/src/prompts/goals/guided-goal-system.md +12 -0
  207. package/src/prompts/memories/read-path.md +6 -0
  208. package/src/prompts/system/autolearn-guidance-learn.md +1 -0
  209. package/src/prompts/system/autolearn-guidance.md +7 -0
  210. package/src/prompts/system/autolearn-nudge.md +3 -0
  211. package/src/prompts/system/eager-task.md +7 -0
  212. package/src/prompts/system/eager-todo.md +11 -6
  213. package/src/prompts/system/subagent-system-prompt.md +4 -0
  214. package/src/prompts/system/system-prompt.md +10 -5
  215. package/src/prompts/system/title-marker-instruction.md +1 -0
  216. package/src/prompts/system/title-system-marker.md +16 -0
  217. package/src/prompts/tools/job.md +1 -0
  218. package/src/prompts/tools/learn.md +7 -0
  219. package/src/prompts/tools/manage-skill.md +9 -0
  220. package/src/prompts/tools/task.md +3 -0
  221. package/src/registry/agent-registry.ts +30 -0
  222. package/src/sdk.ts +88 -24
  223. package/src/secrets/obfuscator.ts +1 -1
  224. package/src/session/agent-session.ts +209 -87
  225. package/src/session/history-storage.ts +2 -2
  226. package/src/session/indexed-session-storage.ts +7 -17
  227. package/src/session/session-context.ts +352 -0
  228. package/src/session/session-entries.ts +194 -0
  229. package/src/session/session-listing.ts +588 -0
  230. package/src/session/session-loader.ts +106 -0
  231. package/src/session/session-manager.ts +933 -3145
  232. package/src/session/session-migrations.ts +78 -0
  233. package/src/session/session-paths.ts +193 -0
  234. package/src/session/session-persistence.ts +131 -0
  235. package/src/session/session-storage.ts +91 -50
  236. package/src/session/snapcompact-inline.ts +21 -1
  237. package/src/session/snapcompact-savings-journal.ts +113 -0
  238. package/src/session/tool-choice-queue.ts +23 -11
  239. package/src/slash-commands/builtin-registry.ts +25 -3
  240. package/src/stt/asr-client.ts +520 -0
  241. package/src/stt/asr-protocol.ts +65 -0
  242. package/src/stt/asr-worker.ts +790 -0
  243. package/src/stt/downloader.ts +107 -47
  244. package/src/stt/endpointer.ts +259 -0
  245. package/src/stt/index.ts +5 -1
  246. package/src/stt/models.ts +150 -0
  247. package/src/stt/recorder.ts +247 -60
  248. package/src/stt/stt-controller.ts +201 -22
  249. package/src/stt/transcriber.ts +37 -68
  250. package/src/stt/wav.ts +173 -0
  251. package/src/system-prompt.ts +8 -0
  252. package/src/task/agents.ts +1 -2
  253. package/src/task/executor.ts +49 -15
  254. package/src/task/index.ts +60 -6
  255. package/src/task/render.ts +83 -8
  256. package/src/task/types.ts +53 -0
  257. package/src/tools/ask.ts +8 -0
  258. package/src/tools/bash.ts +4 -3
  259. package/src/tools/eval-render.ts +4 -3
  260. package/src/tools/index.ts +40 -4
  261. package/src/tools/irc.ts +10 -2
  262. package/src/tools/job.ts +14 -2
  263. package/src/tools/learn.ts +144 -0
  264. package/src/tools/manage-skill.ts +104 -0
  265. package/src/tools/plan-mode-guard.ts +53 -19
  266. package/src/tools/renderers.ts +7 -11
  267. package/src/tools/ssh.ts +4 -3
  268. package/src/tools/todo.ts +1 -1
  269. package/src/tools/tts.ts +203 -92
  270. package/src/tools/write.ts +18 -2
  271. package/src/tts/downloader.ts +64 -0
  272. package/src/tts/index.ts +8 -0
  273. package/src/tts/models.ts +137 -0
  274. package/src/tts/player.ts +137 -0
  275. package/src/tts/runtime.ts +21 -0
  276. package/src/tts/streaming-player.ts +266 -0
  277. package/src/tts/tts-client.ts +647 -0
  278. package/src/tts/tts-protocol.ts +60 -0
  279. package/src/tts/tts-worker.ts +497 -0
  280. package/src/tts/vocalizer.ts +162 -0
  281. package/src/tts/wav.ts +58 -0
  282. package/src/utils/title-generator.ts +48 -5
  283. package/src/utils/tool-choice.ts +16 -0
  284. package/src/utils/tools-manager.test.ts +25 -0
  285. package/src/utils/tools-manager.ts +19 -1
  286. package/src/web/scrapers/github.ts +96 -0
  287. package/src/web/search/index.ts +13 -0
  288. package/src/web/search/providers/searxng.ts +13 -1
  289. package/dist/types/stt/setup.d.ts +0 -18
  290. package/src/stt/setup.ts +0 -52
  291. package/src/stt/transcribe.py +0 -70
@@ -35,7 +35,41 @@ export type RpcSessionChangeResult = {
35
35
  };
36
36
  export type RpcSessionChangeSession = Pick<AgentSession, "newSession" | "switchSession" | "branch">;
37
37
  export type RpcSkillCommandSession = Pick<AgentSession, "promptCustomMessage" | "skills" | "skillsSettings">;
38
- export declare function tryRunRpcSkillCommand(session: RpcSkillCommandSession, text: string): Promise<boolean>;
38
+ export type RpcSkillCommandResult = {
39
+ agentInvoked: true;
40
+ };
41
+ export declare function tryRunRpcSkillCommand(session: RpcSkillCommandSession, text: string): Promise<RpcSkillCommandResult | false>;
42
+ export declare function reportLocalOnlyPromptResult(input: {
43
+ id: string | undefined;
44
+ prompt: Promise<boolean>;
45
+ output: (obj: object) => void;
46
+ onError: (error: Error) => void;
47
+ hasExtensionAgentMessageTask?: () => boolean;
48
+ waitForExtensionAgentMessageTasks?: () => Promise<void>;
49
+ }): void;
50
+ /**
51
+ * Tracks extension-originated messages while an RPC prompt is executing.
52
+ * A slash command can resolve the outer prompt as local-only while also
53
+ * scheduling agent work through pi.sendUserMessage() or pi.sendMessage()
54
+ * with triggerTurn; that prompt must not report agentInvoked:false to the host.
55
+ */
56
+ export declare class RpcExtensionUserMessageTracker {
57
+ #private;
58
+ markAgentMessageTask(): void;
59
+ trackAgentMessageTask(task: Promise<unknown>): void;
60
+ watchPrompt<T>(startPrompt: () => Promise<T>): {
61
+ prompt: Promise<T>;
62
+ hasAgentMessageTask: () => boolean;
63
+ waitForAgentMessageTasks: () => Promise<void>;
64
+ };
65
+ }
66
+ export declare function watchAndReportLocalOnlyPromptResult(input: {
67
+ id: string | undefined;
68
+ startPrompt: () => Promise<boolean>;
69
+ output: (obj: object) => void;
70
+ onError: (error: Error) => void;
71
+ extensionUserMessageTracker: RpcExtensionUserMessageTracker;
72
+ }): void;
39
73
  export type RpcSubagentResetRegistry = Pick<RpcSubagentRegistry, "clear">;
40
74
  export declare function handleRpcSessionChange(session: RpcSessionChangeSession, command: RpcSessionChangeCommand, subagentRegistry?: RpcSubagentResetRegistry): Promise<RpcSessionChangeResult>;
41
75
  export declare function requestRpcEditor(pendingRequests: Map<string, PendingExtensionRequest>, output: RpcOutput, title: string, prefill?: string, dialogOptions?: ExtensionUIDialogOptions, editorOptions?: {
@@ -10,7 +10,7 @@ import type { Effort, ImageContent, Model } from "@oh-my-pi/pi-ai";
10
10
  import type { BashResult } from "../../exec/bash-executor";
11
11
  import type { ContextUsage } from "../../extensibility/extensions/types";
12
12
  import type { AgentSessionEvent, SessionStats } from "../../session/agent-session";
13
- import type { FileEntry } from "../../session/session-manager";
13
+ import type { FileEntry } from "../../session/session-entries";
14
14
  import type { AvailableSlashCommandSource } from "../../slash-commands/available-commands";
15
15
  import type { AgentProgress, SubagentEventPayload, SubagentLifecyclePayload, SubagentProgressPayload } from "../../task";
16
16
  import type { TodoPhase } from "../../tools/todo";
@@ -208,6 +208,11 @@ export interface RpcAvailableCommandsUpdateFrame {
208
208
  type: "available_commands_update";
209
209
  commands: RpcAvailableSlashCommand[];
210
210
  }
211
+ export interface RpcPromptResultFrame {
212
+ type: "prompt_result";
213
+ id?: string;
214
+ agentInvoked: boolean;
215
+ }
211
216
  export interface RpcHandoffResult {
212
217
  savedPath?: string;
213
218
  }
@@ -239,6 +244,9 @@ export type RpcResponse = {
239
244
  type: "response";
240
245
  command: "prompt";
241
246
  success: true;
247
+ data?: {
248
+ agentInvoked: boolean;
249
+ };
242
250
  } | {
243
251
  id?: string;
244
252
  type: "response";
@@ -11,6 +11,10 @@ export interface InitializeExtensionsOptions {
11
11
  onShutdown?: () => void;
12
12
  /** Optional UI context (rpc supplies one; print runs headless). */
13
13
  uiContext?: ExtensionUIContext;
14
+ /** Optional lifecycle hook for extension-originated messages that can start an agent turn. */
15
+ markAgentInvokingMessage?: () => void;
16
+ /** Optional lifecycle hook for extension-originated sends whose success/failure determines turn ownership. */
17
+ trackAgentInvokingMessage?: (task: Promise<unknown>) => void;
14
18
  }
15
19
  /**
16
20
  * Initialize the session's extension runner with the standard action set
@@ -246,6 +246,8 @@ export declare function getThemeByName(name: string): Promise<Theme | undefined>
246
246
  export declare var theme: Theme;
247
247
  /** Get the name of the currently active theme. */
248
248
  export declare function getCurrentThemeName(): string | undefined;
249
+ /** Returns unstyled `text` before `initTheme()` assigns the global theme; use only for early-render paths. */
250
+ export declare function fgOrPlain(color: ThemeColor, text: string, styledText?: string): string;
249
251
  export declare function initTheme(enableWatcher?: boolean, symbolPreset?: SymbolPreset, colorBlindMode?: boolean, darkTheme?: string, lightTheme?: string): Promise<void>;
250
252
  export declare function setTheme(name: string, enableWatcher?: boolean): Promise<{
251
253
  success: boolean;
@@ -289,6 +291,14 @@ export declare function setColorBlindMode(enabled: boolean): Promise<void>;
289
291
  */
290
292
  export declare function getColorBlindMode(): boolean;
291
293
  export declare function onThemeChange(callback: () => void): void;
294
+ /**
295
+ * Monotonic counter bumped on any theme-affecting change that should invalidate
296
+ * cached renders: theme swaps and reloads (including the invalid-theme dark
297
+ * fallback), theme previews, symbol-preset changes, and color-blind-mode
298
+ * changes — everything that routes through {@link notifyThemeChange}. Consumers
299
+ * key cached renders on it so the next render re-shapes their output.
300
+ */
301
+ export declare function getThemeEpoch(): number;
292
302
  /**
293
303
  * Get available symbol presets.
294
304
  */
@@ -304,8 +314,9 @@ export declare function stopThemeWatcher(): void;
304
314
  */
305
315
  export declare function getResolvedThemeColors(themeName?: string): Promise<Record<string, string>>;
306
316
  /**
307
- * Check if a theme is a "light" theme by analyzing its background color luminance.
308
- * Loads theme JSON synchronously (built-in or custom file) and resolves userMessageBg.
317
+ * Check if a theme is a "light" theme by analyzing its status-line background
318
+ * luminance. Loads theme JSON synchronously (built-in or custom file on disk)
319
+ * for callers in synchronous flows (settings migration, setup wizard).
309
320
  */
310
321
  export declare function isLightTheme(themeName?: string): boolean;
311
322
  /**
@@ -12,7 +12,8 @@ import type { MCPManager } from "../mcp";
12
12
  import type { PlanApprovalDetails } from "../plan-mode/approved-plan";
13
13
  import type { AgentSession } from "../session/agent-session";
14
14
  import type { HistoryStorage } from "../session/history-storage";
15
- import type { SessionContext, SessionManager } from "../session/session-manager";
15
+ import type { SessionContext } from "../session/session-context";
16
+ import type { SessionManager } from "../session/session-manager";
16
17
  import type { ShakeMode } from "../session/shake-types";
17
18
  import type { LspStartupServerInfo } from "../tools";
18
19
  import type { EventBus } from "../utils/event-bus";
@@ -74,6 +75,7 @@ export interface InteractiveModeContext {
74
75
  btwContainer: Container;
75
76
  omfgContainer: Container;
76
77
  errorBannerContainer: Container;
78
+ modelCycleContainer: Container;
77
79
  editor: CustomEditor;
78
80
  editorContainer: Container;
79
81
  hookWidgetContainerAbove: Container;
@@ -171,6 +173,7 @@ export interface InteractiveModeContext {
171
173
  showStatus(message: string, options?: {
172
174
  dim?: boolean;
173
175
  }): void;
176
+ showModelCycleTrack(track: string): void;
174
177
  showError(message: string): void;
175
178
  showPinnedError(message: string): void;
176
179
  clearPinnedError(): void;
@@ -284,7 +287,9 @@ export interface InteractiveModeContext {
284
287
  showProviderSetup(): Promise<void>;
285
288
  showHookConfirm(title: string, message: string): Promise<boolean>;
286
289
  showDebugSelector(): Promise<void>;
287
- showAgentHub(): void;
290
+ showAgentHub(options?: {
291
+ requireContent?: boolean;
292
+ }): void;
288
293
  resetObserverRegistry(): void;
289
294
  handleCtrlC(): void;
290
295
  handleCtrlD(): void;
@@ -307,6 +312,7 @@ export interface InteractiveModeContext {
307
312
  registerExtensionShortcuts(): void;
308
313
  handlePlanModeCommand(initialPrompt?: string): Promise<void>;
309
314
  handleGoalModeCommand(rest?: string): Promise<void>;
315
+ handleGuidedGoalCommand(rest?: string): Promise<void>;
310
316
  handleLoopCommand(args?: string): Promise<void>;
311
317
  disableLoopMode(): void;
312
318
  pauseLoop(): void;
@@ -2,7 +2,7 @@ import type { AgentMessage } from "@oh-my-pi/pi-agent-core";
2
2
  import type { AssistantMessage, ImageContent, Message } from "@oh-my-pi/pi-ai";
3
3
  import { type Component } from "@oh-my-pi/pi-tui";
4
4
  import type { InteractiveModeContext } from "../../modes/types";
5
- import type { SessionContext } from "../../session/session-manager";
5
+ import type { SessionContext } from "../../session/session-context";
6
6
  interface RenderInitialMessagesOptions {
7
7
  preserveExistingChat?: boolean;
8
8
  clearTerminalHistory?: boolean;
@@ -30,6 +30,8 @@ export interface AgentRef {
30
30
  sessionFile: string | null;
31
31
  createdAt: number;
32
32
  lastActivity: number;
33
+ /** Short gist of what the agent is currently doing (latest intent or tool), for the work-aware roster. Display-only. */
34
+ activity?: string;
33
35
  }
34
36
  export type RegistryEvent = {
35
37
  type: "registered";
@@ -58,6 +60,21 @@ export declare class AgentRegistry {
58
60
  static resetGlobalForTests(): void;
59
61
  register(input: RegisterInput): AgentRef;
60
62
  setStatus(id: string, status: AgentStatus): void;
63
+ /**
64
+ * Record a short activity gist for the work-aware roster. Display-only and
65
+ * read on demand (`irc list`, peer roster), so it emits no event — keeping
66
+ * the per-tool-call update rate off the registry listener path (same as
67
+ * `attachSession`, which also bumps `lastActivity` without emitting). Only a
68
+ * `running` agent has current work: a heartbeat for any other status is
69
+ * dropped, so a late progress flush can't resurrect activity on a ref that
70
+ * `setStatus` just cleared. Every running heartbeat refreshes `lastActivity`
71
+ * — even when the gist text is unchanged — so the roster's "active … ago" and
72
+ * recency sort track real work, not just the last status change.
73
+ * The gist is normalized to one bounded line (`oneLineLabel`) so model-derived
74
+ * intent text can neither break the roster nor smuggle terminal escapes —
75
+ * every caller is safe without sanitizing at its own call site.
76
+ */
77
+ setActivity(id: string, activity: string): void;
61
78
  attachSession(id: string, session: AgentSession, sessionFile?: string | null): void;
62
79
  detachSession(id: string): void;
63
80
  unregister(id: string): void;
@@ -1,5 +1,5 @@
1
1
  import type { Context, Message, Tool } from "@oh-my-pi/pi-ai";
2
- import type { SessionContext } from "../session/session-manager";
2
+ import type { SessionContext } from "../session/session-context";
3
3
  export interface SecretEntry {
4
4
  type: "plain" | "regex";
5
5
  content: string;
@@ -46,7 +46,9 @@ import type { CheckpointState } from "../tools/checkpoint";
46
46
  import { type TodoItem, type TodoPhase } from "../tools/todo";
47
47
  import type { ClientBridge } from "./client-bridge";
48
48
  import { type CustomMessage } from "./messages";
49
- import type { BranchSummaryEntry, NewSessionOptions, SessionContext, SessionManager } from "./session-manager";
49
+ import type { SessionContext } from "./session-context";
50
+ import type { BranchSummaryEntry, NewSessionOptions } from "./session-entries";
51
+ import type { SessionManager } from "./session-manager";
50
52
  import type { ShakeMode, ShakeResult } from "./shake-types";
51
53
  import { ToolChoiceQueue } from "./tool-choice-queue";
52
54
  import { YieldQueue } from "./yield-queue";
@@ -215,6 +217,10 @@ export interface AgentSessionConfig {
215
217
  asyncJobManager?: AsyncJobManager;
216
218
  /** Agent identity (registry id like "Main" or "Alice") used for IRC routing. */
217
219
  agentId?: string;
220
+ /** Whether this session is the top-level agent or a subagent. Drives eager-task
221
+ * prelude gating so a top-level session created with a custom `agentId` still
222
+ * receives the always-mode reminder. Defaults to "main". */
223
+ agentKind?: "main" | "sub";
218
224
  /**
219
225
  * Override the provider-facing session ID for all API requests from this session.
220
226
  * When absent, `sessionManager.getSessionId()` is used. Needed when benchmark or
@@ -605,12 +611,18 @@ export declare class AgentSession {
605
611
  * - Streaming: queue as steer/follow-up or store for next turn
606
612
  * - Not streaming + triggerTurn: appends to state/session, starts new turn unless the client cannot own it
607
613
  * - Not streaming + no trigger: appends to state/session, no turn
614
+ *
615
+ * @returns true iff this call synchronously started a new turn (awaited
616
+ * `agent.prompt`); false when the message was queued/appended without a turn
617
+ * — including when `triggerTurn` is downgraded because the client defers
618
+ * agent-initiated turns. Callers that must mirror the resulting `agent_end`
619
+ * use this to avoid acting on a turn that never ran.
608
620
  */
609
621
  sendCustomMessage<T = unknown>(message: Pick<CustomMessage<T>, "customType" | "content" | "display" | "details" | "attribution">, options?: {
610
622
  triggerTurn?: boolean;
611
623
  deliverAs?: "steer" | "followUp" | "nextTurn";
612
624
  queueChipText?: string;
613
- }): Promise<void>;
625
+ }): Promise<boolean>;
614
626
  /**
615
627
  * Send a user message to the agent.
616
628
  * When deliverAs is set, queue the message instead of starting a new turn.
@@ -30,6 +30,7 @@ export declare class IndexedSessionStorage implements SessionStorage {
30
30
  readText(path: string): Promise<string>;
31
31
  readTextSlices(path: string, prefixBytes: number, suffixBytes: number): Promise<[string, string]>;
32
32
  writeText(path: string, content: string): Promise<void>;
33
+ writeTextAtomic(path: string, content: string): Promise<void>;
33
34
  rename(src: string, dst: string): Promise<void>;
34
35
  unlink(path: string): Promise<void>;
35
36
  deleteSessionWithArtifacts(sessionPath: string): Promise<void>;
@@ -49,11 +50,9 @@ declare class IndexedSessionStorageWriter implements SessionStorageWriter {
49
50
  flags?: "a" | "w";
50
51
  onError?: (err: Error) => void;
51
52
  });
52
- writeLineSync(line: string): void;
53
- writeLine(line: string): Promise<void>;
53
+ append(line: string): Promise<void>;
54
54
  flush(): Promise<void>;
55
- fsync(): Promise<void>;
56
- fsyncSync(): void;
55
+ isOpen(): boolean;
57
56
  close(): Promise<void>;
58
57
  getError(): Error | undefined;
59
58
  }
@@ -0,0 +1,39 @@
1
+ import type { AgentMessage } from "@oh-my-pi/pi-agent-core";
2
+ import type { ServiceTier } from "@oh-my-pi/pi-ai";
3
+ import { type CompactionEntry, type SessionEntry } from "./session-entries";
4
+ export interface SessionContext {
5
+ messages: AgentMessage[];
6
+ thinkingLevel?: string;
7
+ serviceTier?: ServiceTier;
8
+ /** Model roles: { default: "provider/modelId", small: "provider/modelId", ... } */
9
+ models: Record<string, string>;
10
+ /** Names of TTSR rules that have been injected this session */
11
+ injectedTtsrRules: string[];
12
+ /** MCP tool names selected through discovery for this session branch. */
13
+ selectedMCPToolNames: string[];
14
+ /** Whether this branch contains an explicit persisted MCP selection entry. */
15
+ hasPersistedMCPToolSelection: boolean;
16
+ /** Active mode (e.g. "plan") or "none" if no special mode is active */
17
+ mode: string;
18
+ /** Mode-specific data from the last mode_change entry */
19
+ modeData?: Record<string, unknown>;
20
+ }
21
+ /** Lists session model strings to try when restoring, in fallback order. */
22
+ export declare function getRestorableSessionModels(models: Readonly<Record<string, string>>, lastModelChangeRole: string | undefined): string[];
23
+ export declare function getLatestCompactionEntry(entries: SessionEntry[]): CompactionEntry | null;
24
+ export interface BuildSessionContextOptions {
25
+ /**
26
+ * Build the full-history display transcript instead of the LLM context:
27
+ * every path entry in chronological order, with each compaction emitted
28
+ * inline as a `compactionSummary` message at the position it fired rather
29
+ * than replacing the history before it. Display-only — never send the
30
+ * result to a provider.
31
+ */
32
+ transcript?: boolean;
33
+ }
34
+ /**
35
+ * Build the session context from entries using tree traversal.
36
+ * If leafId is provided, walks from that entry to root.
37
+ * Handles compaction and branch summaries along the path.
38
+ */
39
+ export declare function buildSessionContext(entries: SessionEntry[], leafId?: string | null, byId?: Map<string, SessionEntry>, options?: BuildSessionContextOptions): SessionContext;
@@ -0,0 +1,159 @@
1
+ import type { AgentMessage } from "@oh-my-pi/pi-agent-core";
2
+ import type { ImageContent, MessageAttribution, ServiceTier, TextContent } from "@oh-my-pi/pi-ai";
3
+ export declare const CURRENT_SESSION_VERSION = 3;
4
+ export declare const EPHEMERAL_MODEL_CHANGE_ROLE = "fallback";
5
+ export interface SessionHeader {
6
+ type: "session";
7
+ version?: number;
8
+ id: string;
9
+ title?: string;
10
+ titleSource?: "auto" | "user";
11
+ timestamp: string;
12
+ cwd: string;
13
+ parentSession?: string;
14
+ }
15
+ export interface NewSessionOptions {
16
+ parentSession?: string;
17
+ /** Skip flushing the current session and delete it instead of saving. */
18
+ drop?: boolean;
19
+ }
20
+ export interface SessionEntryBase {
21
+ type: string;
22
+ id: string;
23
+ parentId: string | null;
24
+ timestamp: string;
25
+ }
26
+ export interface SessionMessageEntry extends SessionEntryBase {
27
+ type: "message";
28
+ message: AgentMessage;
29
+ }
30
+ export interface ThinkingLevelChangeEntry extends SessionEntryBase {
31
+ type: "thinking_level_change";
32
+ thinkingLevel?: string | null;
33
+ }
34
+ export interface ModelChangeEntry extends SessionEntryBase {
35
+ type: "model_change";
36
+ /** Model in "provider/modelId" format */
37
+ model: string;
38
+ /** Role: "default", "smol", "slow", etc. Undefined treated as "default" */
39
+ role?: string;
40
+ }
41
+ export interface ServiceTierChangeEntry extends SessionEntryBase {
42
+ type: "service_tier_change";
43
+ serviceTier: ServiceTier | null;
44
+ }
45
+ export interface CompactionEntry<T = unknown> extends SessionEntryBase {
46
+ type: "compaction";
47
+ summary: string;
48
+ shortSummary?: string;
49
+ firstKeptEntryId: string;
50
+ tokensBefore: number;
51
+ /** Extension-specific data (e.g., ArtifactIndex, version markers for structured compaction) */
52
+ details?: T;
53
+ /** Hook-provided data to persist across compaction */
54
+ preserveData?: Record<string, unknown>;
55
+ /** True if generated by an extension, undefined/false if pi-generated (backward compatible) */
56
+ fromExtension?: boolean;
57
+ }
58
+ export interface BranchSummaryEntry<T = unknown> extends SessionEntryBase {
59
+ type: "branch_summary";
60
+ fromId: string;
61
+ summary: string;
62
+ /** Extension-specific data (not sent to LLM) */
63
+ details?: T;
64
+ /** True if generated by an extension, false if pi-generated */
65
+ fromExtension?: boolean;
66
+ }
67
+ /**
68
+ * Custom entry for extensions to store extension-specific data in the session.
69
+ * Use customType to identify your extension's entries.
70
+ *
71
+ * Purpose: Persist extension state across session reloads. On reload, extensions can
72
+ * scan entries for their customType and reconstruct internal state.
73
+ *
74
+ * Does NOT participate in LLM context (ignored by buildSessionContext).
75
+ * For injecting content into context, see CustomMessageEntry.
76
+ */
77
+ export interface CustomEntry<T = unknown> extends SessionEntryBase {
78
+ type: "custom";
79
+ customType: string;
80
+ data?: T;
81
+ }
82
+ /** Label entry for user-defined bookmarks/markers on entries. */
83
+ export interface LabelEntry extends SessionEntryBase {
84
+ type: "label";
85
+ targetId: string;
86
+ label: string | undefined;
87
+ }
88
+ /** TTSR injection entry - tracks which time-traveling rules have been injected this session. */
89
+ export interface TtsrInjectionEntry extends SessionEntryBase {
90
+ type: "ttsr_injection";
91
+ /** Names of rules that were injected */
92
+ injectedRules: string[];
93
+ }
94
+ /** Persisted MCP discovery selection state for a session branch. */
95
+ export interface MCPToolSelectionEntry extends SessionEntryBase {
96
+ type: "mcp_tool_selection";
97
+ /** MCP tool names selected for visibility in discovery mode. */
98
+ selectedToolNames: string[];
99
+ }
100
+ /** Session init entry - captures initial context for subagent sessions (debugging/replay). */
101
+ export interface SessionInitEntry extends SessionEntryBase {
102
+ type: "session_init";
103
+ /** Full system prompt sent to the model */
104
+ systemPrompt: string;
105
+ /** Initial task/user message */
106
+ task: string;
107
+ /** Tools available to the agent */
108
+ tools: string[];
109
+ /** Output schema if structured output was requested */
110
+ outputSchema?: unknown;
111
+ }
112
+ /** Mode change entry - tracks agent mode transitions (e.g. plan mode). */
113
+ export interface ModeChangeEntry extends SessionEntryBase {
114
+ type: "mode_change";
115
+ /** Current mode name, or "none" when exiting a mode */
116
+ mode: string;
117
+ /** Optional mode-specific data (e.g. plan file path) */
118
+ data?: Record<string, unknown>;
119
+ }
120
+ /**
121
+ * Custom message entry for extensions to inject messages into LLM context.
122
+ * Use customType to identify your extension's entries.
123
+ *
124
+ * Unlike CustomEntry, this DOES participate in LLM context.
125
+ * The content participates in LLM context through convertToLlm().
126
+ * Use details for extension-specific metadata (not sent to LLM).
127
+ *
128
+ * display controls TUI rendering:
129
+ * - false: hidden entirely
130
+ * - true: rendered with distinct styling (different from user messages)
131
+ */
132
+ export interface CustomMessageEntry<T = unknown> extends SessionEntryBase {
133
+ type: "custom_message";
134
+ customType: string;
135
+ content: string | (TextContent | ImageContent)[];
136
+ details?: T;
137
+ display: boolean;
138
+ /** Who initiated this message for billing/attribution semantics. */
139
+ attribution?: MessageAttribution;
140
+ }
141
+ /** Session entry - has id/parentId for tree structure (returned by "read" methods in SessionManager) */
142
+ export type SessionEntry = SessionMessageEntry | ThinkingLevelChangeEntry | ModelChangeEntry | ServiceTierChangeEntry | CompactionEntry | BranchSummaryEntry | CustomEntry | CustomMessageEntry | LabelEntry | TtsrInjectionEntry | MCPToolSelectionEntry | SessionInitEntry | ModeChangeEntry;
143
+ /** Raw file entry (includes header) */
144
+ export type FileEntry = SessionHeader | SessionEntry;
145
+ /** Tree node for getTree() - defensive copy of session structure */
146
+ export interface SessionTreeNode {
147
+ entry: SessionEntry;
148
+ children: SessionTreeNode[];
149
+ /** Resolved label for this entry, if any */
150
+ label?: string;
151
+ }
152
+ export interface UsageStatistics {
153
+ input: number;
154
+ output: number;
155
+ cacheRead: number;
156
+ cacheWrite: number;
157
+ premiumRequests: number;
158
+ cost: number;
159
+ }
@@ -0,0 +1,69 @@
1
+ import { type SessionStorage } from "./session-storage";
2
+ /**
3
+ * Coarse lifecycle status of a session, derived from its last persisted message.
4
+ *
5
+ * - `complete` — the last assistant turn ended with no unanswered tool calls, i.e.
6
+ * the agent yielded control back to the user.
7
+ * - `interrupted` — work was cut off mid-flight: a trailing assistant turn with
8
+ * pending tool calls, a trailing tool result the agent never continued from, or
9
+ * a length-truncated turn.
10
+ * - `aborted` — the last assistant turn was cancelled by the user.
11
+ * - `error` — the last assistant turn ended in an error.
12
+ * - `pending` — a trailing user message with no assistant reply persisted after it.
13
+ * - `unknown` — status could not be determined (empty/header-only session, or the
14
+ * final message was larger than the tail window that was read).
15
+ */
16
+ export type SessionStatus = "complete" | "interrupted" | "aborted" | "error" | "pending" | "unknown";
17
+ export interface SessionInfo {
18
+ path: string;
19
+ id: string;
20
+ /** Working directory where the session was started. Empty string for old sessions. */
21
+ cwd: string;
22
+ title?: string;
23
+ /** Path to the parent session (if this session was forked). */
24
+ parentSessionPath?: string;
25
+ created: Date;
26
+ modified: Date;
27
+ messageCount: number;
28
+ /** File size in bytes on disk; used for compact list rendering. */
29
+ size: number;
30
+ firstMessage: string;
31
+ allMessagesText: string;
32
+ /**
33
+ * Coarse lifecycle status from the session's last persisted message. Optional:
34
+ * synthesized {@link SessionInfo}s (cross-project stubs, tests) leave it unset.
35
+ */
36
+ status?: SessionStatus;
37
+ }
38
+ export interface ResolvedSessionMatch {
39
+ session: SessionInfo;
40
+ scope: "local" | "global";
41
+ }
42
+ /** Lightweight metadata for a recent session, used in welcome/picker UI. */
43
+ export interface RecentSessionInfo {
44
+ path: string;
45
+ name: string;
46
+ timeAgo: string;
47
+ }
48
+ /**
49
+ * Promote orphaned `<basename>.jsonl.<snowflake>.bak` backups created by the
50
+ * EPERM-rewrite path back to their primary path when the primary is missing.
51
+ * This runs once per session-dir scan, before the main `*.jsonl` glob, so a
52
+ * crash between the two renames in the EPERM-rewrite path does not leave the
53
+ * user's last good state stranded outside the loader's view.
54
+ *
55
+ * Exported for testing.
56
+ */
57
+ export declare function recoverOrphanedBackups(sessionDir: string, storage: SessionStorage): Promise<void>;
58
+ /**
59
+ * List sessions in a resolved session directory (newest first), reading each
60
+ * file's lifecycle {@link SessionStatus}.
61
+ */
62
+ export declare function listSessions(sessionDir: string, storage: SessionStorage): Promise<SessionInfo[]>;
63
+ /** List all sessions across all project directories (newest first). */
64
+ export declare function listAllSessions(storage?: SessionStorage): Promise<SessionInfo[]>;
65
+ /** Exported for testing */
66
+ export declare function findMostRecentSession(sessionDir: string, storage?: SessionStorage): Promise<string | null>;
67
+ /** Get recent sessions for display in the welcome screen. */
68
+ export declare function getRecentSessions(sessionDir: string, limit?: number, storage?: SessionStorage): Promise<RecentSessionInfo[]>;
69
+ export declare function resolveResumableSession(sessionArg: string, cwd: string, sessionDir?: string, storage?: SessionStorage): Promise<ResolvedSessionMatch | undefined>;
@@ -0,0 +1,16 @@
1
+ import type { AgentMessage } from "@oh-my-pi/pi-agent-core";
2
+ import { BlobStore } from "./blob-store";
3
+ import type { FileEntry } from "./session-entries";
4
+ import { type SessionStorage } from "./session-storage";
5
+ /** Exported for compaction.test.ts */
6
+ export declare function parseSessionEntries(content: string): FileEntry[];
7
+ /** Exported for testing */
8
+ export declare function loadEntriesFromFile(filePath: string, storage?: SessionStorage): Promise<FileEntry[]>;
9
+ export declare function resolveBlobRefsInEntries(entries: FileEntry[], blobStore: BlobStore): Promise<void>;
10
+ /**
11
+ * Read-only message view of a session file: load entries, migrate to the
12
+ * current version, resolve blob refs, and build the context along the
13
+ * persisted leaf path (last entry). Does NOT create a writer or take the
14
+ * session lock — safe to call against a file another session is writing.
15
+ */
16
+ export declare function loadSessionMessagesReadOnly(filePath: string): Promise<AgentMessage[]>;