@chengchenccc/oh-my-agent 0.2.0-rc.2 → 0.2.0-rc.4

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 (209) hide show
  1. package/README.md +11 -6
  2. package/dist/cli/args.d.ts +1 -1
  3. package/dist/cli/args.d.ts.map +1 -1
  4. package/dist/cli/args.js +9 -2
  5. package/dist/cli/gateway-commands.d.ts.map +1 -1
  6. package/dist/cli/gateway-commands.js +35 -5
  7. package/dist/cli/initial-input.d.ts +3 -2
  8. package/dist/cli/initial-input.d.ts.map +1 -1
  9. package/dist/core/coordination/registry.d.ts +11 -0
  10. package/dist/core/coordination/registry.d.ts.map +1 -1
  11. package/dist/core/coordination/registry.js +23 -0
  12. package/dist/core/gateway/artifact.d.ts +0 -1
  13. package/dist/core/gateway/artifact.d.ts.map +1 -1
  14. package/dist/core/gateway/artifact.js +1 -1
  15. package/dist/core/goals/index.d.ts +8 -0
  16. package/dist/core/goals/index.d.ts.map +1 -0
  17. package/dist/core/goals/index.js +7 -0
  18. package/dist/core/goals/runtime.d.ts +112 -0
  19. package/dist/core/goals/runtime.d.ts.map +1 -0
  20. package/dist/core/goals/runtime.js +241 -0
  21. package/dist/core/goals/state.d.ts +82 -0
  22. package/dist/core/goals/state.d.ts.map +1 -0
  23. package/dist/core/goals/state.js +225 -0
  24. package/dist/core/goals/tool.d.ts +10 -0
  25. package/dist/core/goals/tool.d.ts.map +1 -0
  26. package/dist/core/goals/tool.js +87 -0
  27. package/dist/core/index.d.ts.map +1 -1
  28. package/dist/core/index.js +4 -3
  29. package/dist/core/loops/condition.d.ts +57 -0
  30. package/dist/core/loops/condition.d.ts.map +1 -0
  31. package/dist/core/loops/condition.js +153 -0
  32. package/dist/core/loops/index.d.ts +9 -0
  33. package/dist/core/loops/index.d.ts.map +1 -0
  34. package/dist/core/loops/index.js +8 -0
  35. package/dist/core/loops/limits.d.ts +43 -0
  36. package/dist/core/loops/limits.d.ts.map +1 -0
  37. package/dist/core/loops/limits.js +219 -0
  38. package/dist/core/loops/ralph.d.ts +37 -0
  39. package/dist/core/loops/ralph.d.ts.map +1 -0
  40. package/dist/core/loops/ralph.js +72 -0
  41. package/dist/core/loops/runtime.d.ts +95 -0
  42. package/dist/core/loops/runtime.d.ts.map +1 -0
  43. package/dist/core/loops/runtime.js +222 -0
  44. package/dist/core/memory/managed-skills.d.ts +0 -11
  45. package/dist/core/memory/managed-skills.d.ts.map +1 -1
  46. package/dist/core/memory/managed-skills.js +2 -2
  47. package/dist/core/memory/vector-store.d.ts +0 -1
  48. package/dist/core/memory/vector-store.d.ts.map +1 -1
  49. package/dist/core/memory/vector-store.js +0 -3
  50. package/dist/core/plans/index.d.ts +7 -0
  51. package/dist/core/plans/index.d.ts.map +1 -0
  52. package/dist/core/plans/index.js +6 -0
  53. package/dist/core/plans/prompts.d.ts +20 -0
  54. package/dist/core/plans/prompts.d.ts.map +1 -0
  55. package/dist/core/plans/prompts.js +72 -0
  56. package/dist/core/plans/runtime.d.ts +89 -0
  57. package/dist/core/plans/runtime.d.ts.map +1 -0
  58. package/dist/core/plans/runtime.js +170 -0
  59. package/dist/core/plans/state.d.ts +55 -0
  60. package/dist/core/plans/state.d.ts.map +1 -0
  61. package/dist/core/plans/state.js +88 -0
  62. package/dist/core/runtime/agent-loop-messages.d.ts +6 -0
  63. package/dist/core/runtime/agent-loop-messages.d.ts.map +1 -1
  64. package/dist/core/runtime/agent-loop-messages.js +40 -15
  65. package/dist/core/runtime/agent-loop-run.d.ts.map +1 -1
  66. package/dist/core/runtime/agent-loop-run.js +18 -27
  67. package/dist/core/runtime/agent-loop-runner.d.ts +1 -23
  68. package/dist/core/runtime/agent-loop-runner.d.ts.map +1 -1
  69. package/dist/core/runtime/agent-loop-runner.js +84 -30
  70. package/dist/core/runtime/agent-loop-types.d.ts +4 -0
  71. package/dist/core/runtime/agent-loop-types.d.ts.map +1 -1
  72. package/dist/core/runtime/compaction.d.ts +9 -0
  73. package/dist/core/runtime/compaction.d.ts.map +1 -1
  74. package/dist/core/runtime/compaction.js +28 -0
  75. package/dist/core/runtime/context-estimate.d.ts +37 -4
  76. package/dist/core/runtime/context-estimate.d.ts.map +1 -1
  77. package/dist/core/runtime/context-estimate.js +70 -0
  78. package/dist/core/runtime/create-runtime.d.ts +27 -5
  79. package/dist/core/runtime/create-runtime.d.ts.map +1 -1
  80. package/dist/core/runtime/create-runtime.js +22 -2
  81. package/dist/core/runtime/permission-classifier.d.ts.map +1 -1
  82. package/dist/core/runtime/permission-classifier.js +83 -12
  83. package/dist/core/runtime/plugin.d.ts +7 -0
  84. package/dist/core/runtime/plugin.d.ts.map +1 -1
  85. package/dist/core/runtime/plugin.js +13 -0
  86. package/dist/core/runtime/process-tree.d.ts +0 -9
  87. package/dist/core/runtime/process-tree.d.ts.map +1 -1
  88. package/dist/core/runtime/process-tree.js +1 -1
  89. package/dist/core/runtime/run-runtime.d.ts.map +1 -1
  90. package/dist/core/runtime/run-runtime.js +88 -49
  91. package/dist/core/runtime/runtime-catalog.d.ts +0 -4
  92. package/dist/core/runtime/runtime-catalog.d.ts.map +1 -1
  93. package/dist/core/runtime/runtime-catalog.js +1 -1
  94. package/dist/core/runtime/stream-rules.d.ts +9 -2
  95. package/dist/core/runtime/stream-rules.d.ts.map +1 -1
  96. package/dist/core/runtime/stream-rules.js +19 -5
  97. package/dist/core/runtime/title.d.ts +13 -1
  98. package/dist/core/runtime/title.d.ts.map +1 -1
  99. package/dist/core/runtime/title.js +51 -17
  100. package/dist/core/runtime/tool-pruning.d.ts.map +1 -1
  101. package/dist/core/runtime/tool-pruning.js +8 -16
  102. package/dist/core/session/session-file.d.ts +91 -5
  103. package/dist/core/session/session-file.d.ts.map +1 -1
  104. package/dist/core/session/session-file.js +206 -24
  105. package/dist/core/session/session-loop.d.ts +3 -1
  106. package/dist/core/session/session-loop.d.ts.map +1 -1
  107. package/dist/core/session/session-loop.js +8 -4
  108. package/dist/core/settings/project-settings.d.ts +63 -9
  109. package/dist/core/settings/project-settings.d.ts.map +1 -1
  110. package/dist/core/settings/project-settings.js +43 -2
  111. package/dist/core/settings/workspace-context.js +4 -4
  112. package/dist/core/store/in-memory-session-store.d.ts.map +1 -1
  113. package/dist/core/store/in-memory-session-store.js +3 -2
  114. package/dist/core/store/session-store.contract.test-helper.d.ts +7 -5
  115. package/dist/core/store/session-store.contract.test-helper.d.ts.map +1 -1
  116. package/dist/core/store/session-store.contract.test-helper.js +7 -5
  117. package/dist/core/store/session-store.d.ts +4 -2
  118. package/dist/core/store/session-store.d.ts.map +1 -1
  119. package/dist/core/store/session-store.js +4 -2
  120. package/dist/core/tools/ask-question.d.ts.map +1 -1
  121. package/dist/core/tools/ask-question.js +51 -5
  122. package/dist/core/tools/bash-pty.d.ts +13 -4
  123. package/dist/core/tools/bash-pty.d.ts.map +1 -1
  124. package/dist/core/tools/bash-pty.js +15 -8
  125. package/dist/core/tools/bash-sandbox.d.ts +1 -1
  126. package/dist/core/tools/bash.d.ts +1 -1
  127. package/dist/core/tools/bash.d.ts.map +1 -1
  128. package/dist/core/tools/bash.js +18 -8
  129. package/dist/core/tools/browser.d.ts +54 -0
  130. package/dist/core/tools/browser.d.ts.map +1 -1
  131. package/dist/core/tools/browser.js +138 -1
  132. package/dist/core/tools/file-fingerprint.d.ts +24 -0
  133. package/dist/core/tools/file-fingerprint.d.ts.map +1 -0
  134. package/dist/core/tools/file-fingerprint.js +61 -0
  135. package/dist/core/tools/file-tools.d.ts +26 -0
  136. package/dist/core/tools/file-tools.d.ts.map +1 -1
  137. package/dist/core/tools/file-tools.js +113 -17
  138. package/dist/core/tools/index.d.ts +2 -0
  139. package/dist/core/tools/index.d.ts.map +1 -1
  140. package/dist/core/tools/index.js +1 -0
  141. package/dist/core/tools/mcp-mount.d.ts +1 -1
  142. package/dist/core/tools/mcp-mount.d.ts.map +1 -1
  143. package/dist/core/tools/mcp-mount.js +72 -26
  144. package/dist/core/tools/url-guard.d.ts +15 -0
  145. package/dist/core/tools/url-guard.d.ts.map +1 -1
  146. package/dist/core/tools/url-guard.js +54 -14
  147. package/dist/core/tools/web-ports-std.d.ts.map +1 -1
  148. package/dist/core/tools/web-ports-std.js +5 -2
  149. package/dist/modes/print-mode.d.ts +3 -2
  150. package/dist/modes/print-mode.d.ts.map +1 -1
  151. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  152. package/dist/modes/rpc/rpc-mode.js +2 -2
  153. package/dist/modes/shared.d.ts +12 -0
  154. package/dist/modes/shared.d.ts.map +1 -1
  155. package/dist/modes/shared.js +23 -6
  156. package/dist/modes/tui/agent-status.d.ts +20 -0
  157. package/dist/modes/tui/agent-status.d.ts.map +1 -0
  158. package/dist/modes/tui/agent-status.js +35 -0
  159. package/dist/modes/tui/ask-panel.d.ts +166 -0
  160. package/dist/modes/tui/ask-panel.d.ts.map +1 -0
  161. package/dist/modes/tui/ask-panel.js +888 -0
  162. package/dist/modes/tui/pty-console.d.ts +3 -0
  163. package/dist/modes/tui/pty-console.d.ts.map +1 -1
  164. package/dist/modes/tui/pty-console.js +19 -0
  165. package/dist/modes/tui/settings-overlay.d.ts +19 -0
  166. package/dist/modes/tui/settings-overlay.d.ts.map +1 -1
  167. package/dist/modes/tui/settings-overlay.js +46 -10
  168. package/dist/modes/tui/tui-commands-session.d.ts.map +1 -1
  169. package/dist/modes/tui/tui-commands-session.js +20 -6
  170. package/dist/modes/tui/tui-commands.d.ts +44 -3
  171. package/dist/modes/tui/tui-commands.d.ts.map +1 -1
  172. package/dist/modes/tui/tui-commands.js +380 -6
  173. package/dist/modes/tui/tui-components.d.ts +10 -0
  174. package/dist/modes/tui/tui-components.d.ts.map +1 -1
  175. package/dist/modes/tui/tui-components.js +26 -0
  176. package/dist/modes/tui/tui-format.d.ts +53 -4
  177. package/dist/modes/tui/tui-format.d.ts.map +1 -1
  178. package/dist/modes/tui/tui-format.js +137 -42
  179. package/dist/modes/tui/tui-frame-provider.d.ts +11 -3
  180. package/dist/modes/tui/tui-frame-provider.d.ts.map +1 -1
  181. package/dist/modes/tui/tui-frame-provider.js +14 -5
  182. package/dist/modes/tui/tui-interactive.d.ts.map +1 -1
  183. package/dist/modes/tui/tui-interactive.js +14 -0
  184. package/dist/modes/tui/tui-io.d.ts.map +1 -1
  185. package/dist/modes/tui/tui-io.js +150 -55
  186. package/dist/modes/tui/tui-mode.d.ts.map +1 -1
  187. package/dist/modes/tui/tui-mode.js +428 -23
  188. package/dist/modes/tui/tui-overlays.d.ts +6 -10
  189. package/dist/modes/tui/tui-overlays.d.ts.map +1 -1
  190. package/dist/modes/tui/tui-overlays.js +0 -43
  191. package/dist/modes/tui/tui-render.d.ts +10 -0
  192. package/dist/modes/tui/tui-render.d.ts.map +1 -1
  193. package/dist/modes/tui/tui-render.js +73 -38
  194. package/dist/modes/tui/tui-seam.d.ts +28 -6
  195. package/dist/modes/tui/tui-seam.d.ts.map +1 -1
  196. package/dist/modes/tui/tui-slash.d.ts.map +1 -1
  197. package/dist/modes/tui/tui-slash.js +3 -1
  198. package/dist/modes/tui/tui-tool-render.d.ts +14 -1
  199. package/dist/modes/tui/tui-tool-render.d.ts.map +1 -1
  200. package/dist/modes/tui/tui-tool-render.js +158 -50
  201. package/dist/modes/tui/tui-transcript-reconciler.d.ts +4 -0
  202. package/dist/modes/tui/tui-transcript-reconciler.d.ts.map +1 -1
  203. package/dist/modes/tui/tui-transcript-reconciler.js +12 -2
  204. package/dist/modes/tui/view-state.d.ts.map +1 -1
  205. package/dist/modes/tui/view-state.js +4 -1
  206. package/dist/protocol/transport.d.ts +10 -0
  207. package/dist/protocol/transport.d.ts.map +1 -1
  208. package/dist/protocol/transport.js +1 -0
  209. package/package.json +11 -11
@@ -44,36 +44,50 @@ export function isLowSignalTitleInput(message) {
44
44
  return tokens.every((t) => FILLER_TOKENS.has(t) || /^\d+$/.test(t));
45
45
  }
46
46
  // ── Prompt (XML tag format + few-shot) ───────────────────────
47
- const TITLE_SYSTEM_PROMPT = `Write a 3-7 word title for the task.
47
+ const TITLE_SYSTEM_PROMPT = `Write a 3-7 word title and a one-sentence summary for the task.
48
48
 
49
- Answer with only the title inside <title> and </title> tags, nothing before or after.
50
- If there is no concrete task (greeting, small talk, acknowledgment), output exactly: <title>none</title>
49
+ Answer with only these two tags, nothing before or after:
50
+ <title>the title</title>
51
+ <summary>one sentence on what the user wants and where it stands</summary>
52
+ If there is no concrete task (greeting, small talk, acknowledgment), output exactly:
53
+ <title>none</title>
54
+ <summary>none</summary>
51
55
  Capitalize only the first word and proper names.
52
56
 
53
57
  Examples:
54
58
  User: the login button is broken on mobile, can you fix?
55
59
  <title>Fix login button on mobile</title>
60
+ <summary>The mobile login button is unresponsive; the fix has not started yet.</summary>
56
61
 
57
62
  User: refactor error handling in the API client
58
63
  <title>Refactor API error handling</title>
64
+ <summary>Reworking the API client's error handling onto typed errors.</summary>
59
65
 
60
66
  User: hey
61
- <title>none</title>`;
67
+ <title>none</title>
68
+ <summary>none</summary>`;
62
69
  // ── Normalization (robust extraction) ────────────────────────
63
70
  const MAX_TITLE_CHARS = 80;
64
71
  const MAX_TITLE_WORDS = 12;
72
+ const MAX_SUMMARY_CHARS = 240;
65
73
  const NO_TITLE_SENTINELS = new Set(["none", "(无)", "无"]);
66
- export function normalizeGeneratedTitle(raw) {
67
- const firstLine = raw.trim().split(/\r?\n/, 1)[0]?.trim();
68
- if (!firstLine)
69
- return null;
70
- // Strip XML tags if present
71
- const title = firstLine
74
+ const TITLE_TAG = /<title>([\s\S]*?)<\/title>/i;
75
+ const SUMMARY_TAG = /<summary>([\s\S]*?)<\/summary>/i;
76
+ function stripTitleDecoration(raw) {
77
+ return raw
72
78
  .replace(/^<title>/i, "")
73
79
  .replace(/<\/title>$/i, "")
74
80
  .replace(/^["'「『]|["'」』]$/g, "")
75
81
  .replace(/[.!?。!?]$/, "")
76
82
  .trim();
83
+ }
84
+ export function normalizeGeneratedTitle(raw) {
85
+ // A tagged reply is authoritative (the combined title+summary answer puts
86
+ // the two tags on their own lines, so the old first-line-only read would
87
+ // have swallowed the summary into the title).
88
+ const tagged = TITLE_TAG.exec(raw)?.[1];
89
+ const candidate = tagged ?? raw.trim().split(/\r?\n/, 1)[0] ?? "";
90
+ const title = stripTitleDecoration(candidate.trim());
77
91
  if (!title || NO_TITLE_SENTINELS.has(title.toLowerCase()))
78
92
  return null;
79
93
  // Reject overlong output (model answered instead of titling)
@@ -83,6 +97,24 @@ export function normalizeGeneratedTitle(raw) {
83
97
  return null;
84
98
  return title;
85
99
  }
100
+ /** The one-sentence session summary that rides the title call. Null when the
101
+ * model answered with a bare title (older prompts, weak models) — the resume
102
+ * list then falls back to the title/preview it showed before. */
103
+ export function normalizeGeneratedSummary(raw) {
104
+ const tagged = SUMMARY_TAG.exec(raw)?.[1];
105
+ if (tagged === undefined)
106
+ return null;
107
+ const summary = tagged.replace(/\s+/g, " ").trim();
108
+ if (!summary || NO_TITLE_SENTINELS.has(summary.toLowerCase()))
109
+ return null;
110
+ if (summary.length <= MAX_SUMMARY_CHARS)
111
+ return summary;
112
+ // Long answers are model overshoot: keep the first sentence-ish slice at a
113
+ // word boundary rather than a hard cut mid-word.
114
+ const clipped = summary.slice(0, MAX_SUMMARY_CHARS);
115
+ const lastSpace = clipped.lastIndexOf(" ");
116
+ return `${(lastSpace > MAX_SUMMARY_CHARS / 2 ? clipped.slice(0, lastSpace) : clipped).trimEnd()}…`;
117
+ }
86
118
  // ── Context builder ───────────────────────────────────────────────────────
87
119
  export function buildTitleContext(msgs, maxTurns = 4) {
88
120
  return msgs
@@ -92,23 +124,25 @@ export function buildTitleContext(msgs, maxTurns = 4) {
92
124
  .filter((line) => line.length > 3)
93
125
  .join("\n");
94
126
  }
95
- // ── Title generation (uses runEphemeralTurn) ──────────────────────────────
96
- export async function generateTitle(rt, context) {
127
+ export async function generateTitleAndSummary(rt, context) {
97
128
  if (!context || context.length < 4)
98
- return null;
129
+ return { title: null, summary: null };
99
130
  if (isLowSignalTitleInput(context))
100
- return null;
131
+ return { title: null, summary: null };
101
132
  try {
102
133
  const ephemeral = rt.runEphemeralTurn;
103
134
  if (!ephemeral)
104
- return null;
135
+ return { title: null, summary: null };
105
136
  const raw = await ephemeral(`${TITLE_SYSTEM_PROMPT}\n\n<conversation>\n${context}\n</conversation>`, { signal: rt.signal });
106
- return normalizeGeneratedTitle(raw);
137
+ return {
138
+ title: normalizeGeneratedTitle(raw),
139
+ summary: normalizeGeneratedSummary(raw),
140
+ };
107
141
  }
108
142
  catch (err) {
109
143
  // Silent-null used to hide provider failures entirely — surface them so
110
144
  // "auto title stopped working" is diagnosable from the child's stderr.
111
145
  console.warn(`[oma] auto-title generation failed: ${err instanceof Error ? err.message : String(err)}`);
112
- return null;
146
+ return { title: null, summary: null };
113
147
  }
114
148
  }
@@ -1 +1 @@
1
- {"version":3,"file":"tool-pruning.d.ts","sourceRoot":"","sources":["../../../src/core/runtime/tool-pruning.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAErD,iDAAiD;AACjD,MAAM,WAAW,WAAW;IAC1B;0EACsE;IACtE,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B;8CAC0C;IAC1C,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC;;4BAEwB;IACxB,QAAQ,CAAC,cAAc,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;CAC9C;AAoCD;;;;;;;;;mFASmF;AACnF,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,SAAS,OAAO,EAAE,EAC5B,MAAM,GAAE,OAAO,CAAC,WAAW,CAAM,GAChC;IAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAiE9C"}
1
+ {"version":3,"file":"tool-pruning.d.ts","sourceRoot":"","sources":["../../../src/core/runtime/tool-pruning.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAGrD,iDAAiD;AACjD,MAAM,WAAW,WAAW;IAC1B;0EACsE;IACtE,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B;8CAC0C;IAC1C,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC;;4BAEwB;IACxB,QAAQ,CAAC,cAAc,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;CAC9C;AA6BD;;;;;;;;;mFASmF;AACnF,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,SAAS,OAAO,EAAE,EAC5B,MAAM,GAAE,OAAO,CAAC,WAAW,CAAM,GAChC;IAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAiE9C"}
@@ -1,3 +1,4 @@
1
+ import { estimateMessageTokens } from "./context-estimate.js";
1
2
  const DEFAULT_CONFIG = {
2
3
  protectTokens: 8_000,
3
4
  minimumSavings: 500,
@@ -12,22 +13,13 @@ function isAlreadyPruned(message) {
12
13
  typeof b.content === "string" &&
13
14
  b.content.startsWith(PRUNED_PREFIX));
14
15
  }
15
- /** Estimate token count of a message (same proxy as contextBudget: char/4). */
16
- function estimateTokens(message) {
17
- // Blocks are canonical content; text is a display fallback. When blocks
18
- // exist, count their content only — avoids double-counting text+blocks.
19
- if (message.blocks && message.blocks.length > 0) {
20
- let chars = 0;
21
- for (const b of message.blocks) {
22
- if (b.type === "tool_result" && typeof b.content === "string")
23
- chars += b.content.length;
24
- else if (b.type === "text")
25
- chars += b.text.length;
26
- }
27
- return Math.ceil(chars / 4);
28
- }
29
- return Math.ceil((message.text?.length ?? 0) / 4);
30
- }
16
+ /** Same estimator the compaction budget uses (context-estimate.ts), so the
17
+ * pruning window and "savedTokens" are on the budget's scale. A local copy
18
+ * that counted different block types made those numbers incomparable.
19
+ *
20
+ * Note: the loop still decides compaction on the STORED entries, so a pruned
21
+ * result does not by itself lower the threshold estimate. */
22
+ const estimateTokens = estimateMessageTokens;
31
23
  /** Prune old tool-result content from a message list.
32
24
  *
33
25
  * Walks backward from the newest message, accumulating tool-result tokens.
@@ -19,19 +19,49 @@ export declare function sessionDirFor(workspaceRoot: string): string;
19
19
  * workspaces never see each other's sessions. OMA_SESSION_DIR overrides
20
20
  * the WHOLE store as a flat directory (pi's PI_CODING_AGENT_SESSION_DIR). */
21
21
  export declare function sessionDir(): string;
22
+ /** Session ids reach the FILESYSTEM, and callers supply them (RPC resume,
23
+ * TUI rename/delete): validate at this boundary. A path-shaped id
24
+ * ("../x", "/abs", "a\\b", "..", trailing dots) would otherwise escape the
25
+ * session directory and read/append/rename/delete outside it. Legit ids
26
+ * are newSessionId() UUIDs (hex + dashes). */
27
+ export declare function assertSafeSessionId(id: string): string;
22
28
  export declare function sessionPath(id: string): string;
23
29
  export declare function newSessionId(): string;
24
30
  /** Load the transcript messages of a session file (wire-loose shape).
25
- * Missing/corrupt files yield [] (the caller falls back to a fresh
26
- * session). A compaction event REPLACES everything recorded before it:
27
- * the summary becomes one context message, later turns stay live — so a
28
- * resumed session does not re-inflate the context it already compacted. */
31
+ * Missing/corrupt files yield [] (the caller falls back to a fresh session).
32
+ *
33
+ * A compaction event carries `replacesEarlierMessages`: whether its summary
34
+ * describes everything written before it. Only then is folding lossless —
35
+ * the summary becomes one context message and later turns stay live.
36
+ *
37
+ * Why a flag and not a count: the count would have to be expressed in THIS
38
+ * file's message-event space, but the run that produces the summary counts
39
+ * coverage over its own session branch, and the two spaces do not align —
40
+ * the branch also holds entries that never reach the file (re-seeded
41
+ * `product_history`, the `meta` entry) and folds a prior summary into a
42
+ * single entry. A count in the wrong space lands past the real boundary and
43
+ * DELETES messages the summary never described. The flag cannot be
44
+ * mis-indexed: when the summary does not describe the whole file, the
45
+ * transcript is simply left intact (a resume may re-summarize, never lose).
46
+ *
47
+ * Events without the field (files written before it existed) keep the
48
+ * historical behavior: the summary replaces everything before it.
49
+ *
50
+ * The LAST event that says "replaces" decides the fold, and a later event
51
+ * saying otherwise does NOT cancel it. That distinction is what makes manual
52
+ * /compact stick: /compact folds the transcript to one summary, a later
53
+ * automatic compaction covers only part of what follows, and "latest event
54
+ * wins" would resurrect every message the user deliberately compacted away.
55
+ * Ignoring a partial summary is always safe — its content is either already
56
+ * summarized or still present as messages. */
29
57
  export declare function loadSessionMessages(id: string, dir?: string): Record<string, unknown>[];
30
58
  export interface SessionSummary {
31
59
  readonly id: string;
32
60
  readonly modifiedAt: number;
33
61
  /** Auto title from the last completed run's title event, when present. */
34
62
  readonly title?: string;
63
+ /** One-sentence content summary (the `summary` event), when present. */
64
+ readonly summary?: string;
35
65
  /** First user message text (truncated), fallback when no title exists. */
36
66
  readonly preview: string;
37
67
  /** Workspace root the session was created in (from the file header's
@@ -56,15 +86,71 @@ export declare function readSessionTitle(id: string, dir?: string): string | und
56
86
  * loop after each completed run. Last one wins in listings. Also the
57
87
  * primitive for /rename: appending a new title overrides the display. */
58
88
  export declare function appendSessionTitle(id: string, title: string, dir?: string): void;
89
+ /** Append a summary event: a one-sentence description of what the session is
90
+ * about, produced by the same ephemeral call as the title. Last one wins in
91
+ * listings (the resume list shows it next to the title). */
92
+ export declare function appendSessionSummary(id: string, summary: string, dir?: string): void;
59
93
  /** Delete a session file. Returns false when it did not exist. */
60
94
  export declare function deleteSession(id: string, dir?: string): boolean;
61
95
  /** Rename a session's display title (last-wins title event). Returns false
62
96
  * when the session file does not exist. */
63
97
  export declare function renameSession(id: string, title: string, dir?: string): boolean;
98
+ /** Append a goal-mode event (omp mode-change analogue): the latest goal
99
+ * state transition for the session. Replay reconstructs the current goal
100
+ * (active/paused/complete/dropped); a goal:null event means dropped. */
101
+ export declare function appendSessionGoalEvent(id: string, state: {
102
+ enabled: boolean;
103
+ mode: "active" | "exiting";
104
+ reason?: "completed";
105
+ goal: unknown;
106
+ } | null, dir?: string): void;
107
+ /** Append a goal COMPLETION record: the objective and the tracked usage at the
108
+ * moment the model declared the goal done. Separate from the mode-change
109
+ * events so a completed goal reads as a durable achievement rather than a
110
+ * status flip (and so resumed sessions can report what was finished). */
111
+ export declare function appendSessionGoalCompletion(id: string, record: {
112
+ objective: string;
113
+ tokensUsed: number;
114
+ tokenBudget?: number;
115
+ timeUsedSeconds: number;
116
+ }, dir?: string): void;
117
+ /** Append a plan-mode event (same mode-change shape as the goal one): the
118
+ * mode plus whether it is paused. The draft itself is a FILE, so the journal
119
+ * only needs the mode; resume restores "planning, paused" and never
120
+ * re-enters a read-only planning turn on its own. */
121
+ export declare function appendSessionPlanEvent(id: string, state: {
122
+ planPath: string;
123
+ } | null, paused: boolean, dir?: string): void;
124
+ /** Replay plan-mode events: the latest one wins (null = plan mode off). */
125
+ export declare function loadSessionPlanState(id: string, dir?: string): {
126
+ planPath: string;
127
+ paused: boolean;
128
+ } | null;
129
+ /** Reconstruct the current goal-mode state by replaying goal events (last
130
+ * one wins; malformed entries are skipped like every other scan here). */
131
+ export declare function loadSessionGoalState(id: string, dir?: string): {
132
+ enabled: boolean;
133
+ mode: "active" | "exiting";
134
+ reason?: "completed";
135
+ goal: {
136
+ id: string;
137
+ objective: string;
138
+ status: "active" | "paused" | "budget-limited" | "complete" | "dropped";
139
+ tokenBudget?: number;
140
+ tokensUsed: number;
141
+ timeUsedSeconds: number;
142
+ createdAt: number;
143
+ updatedAt: number;
144
+ };
145
+ } | null;
64
146
  /** Append a compaction event: records that the run compacted everything
65
147
  * recorded so far in this file into `summary`. Must be called AFTER the
66
148
  * turn's messages are appended. */
67
- export declare function appendSessionCompaction(id: string, summary: string, dir?: string): void;
149
+ export declare function appendSessionCompaction(id: string, summary: string, dir?: string,
150
+ /** Whether this summary describes EVERYTHING already in the file, which is
151
+ * what makes folding on load lossless. Omit when unknown: the load path
152
+ * then keeps the transcript intact instead of folding it. */
153
+ replacesEarlierMessages?: boolean): void;
68
154
  export interface SessionBranchNode {
69
155
  readonly id: string;
70
156
  readonly parentId: string | null;
@@ -1 +1 @@
1
- {"version":3,"file":"session-file.d.ts","sourceRoot":"","sources":["../../../src/core/session/session-file.ts"],"names":[],"mappings":"AAaA;;;;;;;4EAO4E;AAE5E;;6CAE6C;AAC7C,wBAAgB,QAAQ,IAAI,MAAM,CAEjC;AAED,0CAA0C;AAC1C,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED,0EAA0E;AAC1E,wBAAgB,aAAa,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,CAG3D;AAED;;;8EAG8E;AAC9E,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AAED,wBAAgB,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAE9C;AAED,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED;;;;4EAI4E;AAC5E,wBAAgB,mBAAmB,CACjC,EAAE,EAAE,MAAM,EACV,GAAG,GAAE,MAAqB,GACzB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CA2B3B;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,0EAA0E;IAC1E,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,0EAA0E;IAC1E,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB;4DACwD;IACxD,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B;mDAC+C;IAC/C,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAiED,4DAA4D;AAC5D,wBAAgB,YAAY,IAAI,cAAc,EAAE,CAK/C;AAED;;;2CAG2C;AAC3C,wBAAgB,eAAe,IAAI,cAAc,EAAE,CAWlD;AAED;;4BAE4B;AAC5B,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,GAAE,MAAqB,GAAG,MAAM,GAAG,SAAS,CAoB3F;AAED;;0EAE0E;AAC1E,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,GAAE,MAAqB,GAAG,IAAI,CAW9F;AAED,kEAAkE;AAClE,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,GAAE,MAAqB,GAAG,OAAO,CAK7E;AAED;4CAC4C;AAC5C,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,GAAE,MAAqB,GAAG,OAAO,CAK5F;AACD;;oCAEoC;AACpC,wBAAgB,uBAAuB,CACrC,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,MAAM,EACf,GAAG,GAAE,MAAqB,GACzB,IAAI,CAWN;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,mFAAmF;IACnF,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED;;8CAE8C;AAC9C,wBAAgB,sBAAsB,CACpC,EAAE,EAAE,MAAM,EACV,GAAG,GAAE,MAAqB,GACzB,iBAAiB,EAAE,CA8DrB;AAiCD;iBACiB;AACjB,wBAAgB,WAAW,CACzB,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,MAAM,EACf,GAAG,GAAE,MAAqB,GACzB,MAAM,GAAG,IAAI,CAyBf;AAED;kEACkE;AAClE,wBAAgB,kBAAkB,CAChC,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,MAAM,EACf,GAAG,GAAE,MAAqB,GACzB,MAAM,GAAG,IAAI,CAqBf;AAyBD,wBAAgB,qBAAqB,CACnC,EAAE,EAAE,MAAM,EACV,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,SAAS,OAAO,EAAE,EAC5B,GAAG,GAAE,MAAqB,GACzB,IAAI,CAsCN"}
1
+ {"version":3,"file":"session-file.d.ts","sourceRoot":"","sources":["../../../src/core/session/session-file.ts"],"names":[],"mappings":"AAaA;;;;;;;4EAO4E;AAE5E;;6CAE6C;AAC7C,wBAAgB,QAAQ,IAAI,MAAM,CAEjC;AAED,0CAA0C;AAC1C,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED,0EAA0E;AAC1E,wBAAgB,aAAa,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,CAG3D;AAED;;;8EAG8E;AAC9E,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AAED;;;;+CAI+C;AAC/C,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAKtD;AAOD,wBAAgB,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAE9C;AAED,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;+CA0B+C;AAC/C,wBAAgB,mBAAmB,CACjC,EAAE,EAAE,MAAM,EACV,GAAG,GAAE,MAAqB,GACzB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAyC3B;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,0EAA0E;IAC1E,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,wEAAwE;IACxE,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,0EAA0E;IAC1E,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB;4DACwD;IACxD,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B;mDAC+C;IAC/C,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAyED,4DAA4D;AAC5D,wBAAgB,YAAY,IAAI,cAAc,EAAE,CAK/C;AAED;;;2CAG2C;AAC3C,wBAAgB,eAAe,IAAI,cAAc,EAAE,CAWlD;AAED;;4BAE4B;AAC5B,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,GAAE,MAAqB,GAAG,MAAM,GAAG,SAAS,CAoB3F;AAED;;0EAE0E;AAC1E,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,GAAE,MAAqB,GAAG,IAAI,CAW9F;AAED;;6DAE6D;AAC7D,wBAAgB,oBAAoB,CAClC,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,MAAM,EACf,GAAG,GAAE,MAAqB,GACzB,IAAI,CAWN;AAED,kEAAkE;AAClE,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,GAAE,MAAqB,GAAG,OAAO,CAK7E;AAED;4CAC4C;AAC5C,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,GAAE,MAAqB,GAAG,OAAO,CAK5F;AAED;;yEAEyE;AACzE,wBAAgB,sBAAsB,CACpC,EAAE,EAAE,MAAM,EACV,KAAK,EAAE;IACL,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,QAAQ,GAAG,SAAS,CAAC;IAC3B,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,IAAI,EAAE,OAAO,CAAC;CACf,GAAG,IAAI,EACR,GAAG,GAAE,MAAqB,GACzB,IAAI,CAWN;AAED;;;0EAG0E;AAC1E,wBAAgB,2BAA2B,CACzC,EAAE,EAAE,MAAM,EACV,MAAM,EAAE;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,eAAe,EAAE,MAAM,CAAA;CAAE,EAChG,GAAG,GAAE,MAAqB,GACzB,IAAI,CAYN;AAED;;;sDAGsD;AACtD,wBAAgB,sBAAsB,CACpC,EAAE,EAAE,MAAM,EACV,KAAK,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,EAClC,MAAM,EAAE,OAAO,EACf,GAAG,GAAE,MAAqB,GACzB,IAAI,CAWN;AAED,2EAA2E;AAC3E,wBAAgB,oBAAoB,CAClC,EAAE,EAAE,MAAM,EACV,GAAG,GAAE,MAAqB,GACzB;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,OAAO,CAAA;CAAE,GAAG,IAAI,CAuB9C;AAED;2EAC2E;AAC3E,wBAAgB,oBAAoB,CAClC,EAAE,EAAE,MAAM,EACV,GAAG,GAAE,MAAqB,GACzB;IACD,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,QAAQ,GAAG,SAAS,CAAC;IAC3B,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,IAAI,EAAE;QACJ,EAAE,EAAE,MAAM,CAAC;QACX,SAAS,EAAE,MAAM,CAAC;QAClB,MAAM,EAAE,QAAQ,GAAG,QAAQ,GAAG,gBAAgB,GAAG,UAAU,GAAG,SAAS,CAAC;QACxE,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,UAAU,EAAE,MAAM,CAAC;QACnB,eAAe,EAAE,MAAM,CAAC;QACxB,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;CACH,GAAG,IAAI,CAyCP;AACD;;oCAEoC;AACpC,wBAAgB,uBAAuB,CACrC,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,MAAM,EACf,GAAG,GAAE,MAAqB;AAC1B;;8DAE8D;AAC9D,uBAAuB,CAAC,EAAE,OAAO,GAChC,IAAI,CAYN;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,mFAAmF;IACnF,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED;;8CAE8C;AAC9C,wBAAgB,sBAAsB,CACpC,EAAE,EAAE,MAAM,EACV,GAAG,GAAE,MAAqB,GACzB,iBAAiB,EAAE,CA8DrB;AAiCD;iBACiB;AACjB,wBAAgB,WAAW,CACzB,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,MAAM,EACf,GAAG,GAAE,MAAqB,GACzB,MAAM,GAAG,IAAI,CAyBf;AAED;kEACkE;AAClE,wBAAgB,kBAAkB,CAChC,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,MAAM,EACf,GAAG,GAAE,MAAqB,GACzB,MAAM,GAAG,IAAI,CAqBf;AAyBD,wBAAgB,qBAAqB,CACnC,EAAE,EAAE,MAAM,EACV,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,SAAS,OAAO,EAAE,EAC5B,GAAG,GAAE,MAAqB,GACzB,IAAI,CAsCN"}