@astralyn/pi 0.84.3 → 0.84.5

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 (269) hide show
  1. package/CHANGELOG.md +54 -0
  2. package/dist/cli/args.d.ts +1 -0
  3. package/dist/cli/args.d.ts.map +1 -1
  4. package/dist/cli/args.js +11 -0
  5. package/dist/cli/args.js.map +1 -1
  6. package/dist/cli/auth-command.d.ts.map +1 -1
  7. package/dist/cli/auth-command.js +5 -4
  8. package/dist/cli/auth-command.js.map +1 -1
  9. package/dist/cli/project-trust.d.ts.map +1 -1
  10. package/dist/cli/project-trust.js +1 -4
  11. package/dist/cli/project-trust.js.map +1 -1
  12. package/dist/core/agent-session.d.ts +6 -1
  13. package/dist/core/agent-session.d.ts.map +1 -1
  14. package/dist/core/agent-session.js +7 -6
  15. package/dist/core/agent-session.js.map +1 -1
  16. package/dist/core/experimental.d.ts +4 -0
  17. package/dist/core/experimental.d.ts.map +1 -1
  18. package/dist/core/experimental.js +4 -0
  19. package/dist/core/experimental.js.map +1 -1
  20. package/dist/core/extensions/index.d.ts +1 -1
  21. package/dist/core/extensions/index.d.ts.map +1 -1
  22. package/dist/core/extensions/index.js.map +1 -1
  23. package/dist/core/extensions/runner.d.ts.map +1 -1
  24. package/dist/core/extensions/runner.js +4 -0
  25. package/dist/core/extensions/runner.js.map +1 -1
  26. package/dist/core/extensions/types.d.ts +10 -14
  27. package/dist/core/extensions/types.d.ts.map +1 -1
  28. package/dist/core/extensions/types.js.map +1 -1
  29. package/dist/core/keybindings.d.ts +29 -0
  30. package/dist/core/keybindings.d.ts.map +1 -1
  31. package/dist/core/keybindings.js +4 -0
  32. package/dist/core/keybindings.js.map +1 -1
  33. package/dist/core/model-config.d.ts +5 -0
  34. package/dist/core/model-config.d.ts.map +1 -1
  35. package/dist/core/model-config.js +1 -0
  36. package/dist/core/model-config.js.map +1 -1
  37. package/dist/core/model-registry.d.ts +2 -0
  38. package/dist/core/model-registry.d.ts.map +1 -1
  39. package/dist/core/model-registry.js +4 -0
  40. package/dist/core/model-registry.js.map +1 -1
  41. package/dist/core/project-trust.js +2 -2
  42. package/dist/core/project-trust.js.map +1 -1
  43. package/dist/core/sdk.d.ts +5 -3
  44. package/dist/core/sdk.d.ts.map +1 -1
  45. package/dist/core/sdk.js +2 -1
  46. package/dist/core/sdk.js.map +1 -1
  47. package/dist/core/session-manager.js +2 -2
  48. package/dist/core/session-manager.js.map +1 -1
  49. package/dist/core/settings-manager.d.ts +6 -0
  50. package/dist/core/settings-manager.d.ts.map +1 -1
  51. package/dist/core/settings-manager.js +12 -0
  52. package/dist/core/settings-manager.js.map +1 -1
  53. package/dist/core/system-prompt.js +1 -1
  54. package/dist/core/system-prompt.js.map +1 -1
  55. package/dist/core/tools/bash.d.ts +2 -1
  56. package/dist/core/tools/bash.d.ts.map +1 -1
  57. package/dist/core/tools/bash.js +3 -1
  58. package/dist/core/tools/bash.js.map +1 -1
  59. package/dist/core/tools/edit.d.ts.map +1 -1
  60. package/dist/core/tools/edit.js +2 -0
  61. package/dist/core/tools/edit.js.map +1 -1
  62. package/dist/core/tools/find.js +1 -1
  63. package/dist/core/tools/find.js.map +1 -1
  64. package/dist/core/tools/grep.js +1 -1
  65. package/dist/core/tools/grep.js.map +1 -1
  66. package/dist/core/tools/read.d.ts.map +1 -1
  67. package/dist/core/tools/read.js +2 -0
  68. package/dist/core/tools/read.js.map +1 -1
  69. package/dist/core/tools/write.d.ts.map +1 -1
  70. package/dist/core/tools/write.js +2 -0
  71. package/dist/core/tools/write.js.map +1 -1
  72. package/dist/extensions/background/index.d.ts +74 -0
  73. package/dist/extensions/background/index.d.ts.map +1 -0
  74. package/dist/extensions/background/index.js +332 -0
  75. package/dist/extensions/background/index.js.map +1 -0
  76. package/dist/extensions/background/manager.d.ts +81 -0
  77. package/dist/extensions/background/manager.d.ts.map +1 -0
  78. package/dist/extensions/background/manager.js +320 -0
  79. package/dist/extensions/background/manager.js.map +1 -0
  80. package/dist/extensions/background/registry.d.ts +138 -0
  81. package/dist/extensions/background/registry.d.ts.map +1 -0
  82. package/dist/extensions/background/registry.js +358 -0
  83. package/dist/extensions/background/registry.js.map +1 -0
  84. package/dist/extensions/background/render.d.ts +26 -0
  85. package/dist/extensions/background/render.d.ts.map +1 -0
  86. package/dist/extensions/background/render.js +118 -0
  87. package/dist/extensions/background/render.js.map +1 -0
  88. package/dist/extensions/index.d.ts.map +1 -1
  89. package/dist/extensions/index.js +2 -0
  90. package/dist/extensions/index.js.map +1 -1
  91. package/dist/extensions/subagent/activity.d.ts +0 -1
  92. package/dist/extensions/subagent/activity.d.ts.map +1 -1
  93. package/dist/extensions/subagent/activity.js +2 -5
  94. package/dist/extensions/subagent/activity.js.map +1 -1
  95. package/dist/extensions/subagent/agents-command.d.ts +4 -0
  96. package/dist/extensions/subagent/agents-command.d.ts.map +1 -0
  97. package/dist/extensions/subagent/agents-command.js +385 -0
  98. package/dist/extensions/subagent/agents-command.js.map +1 -0
  99. package/dist/extensions/subagent/agents.d.ts +3 -6
  100. package/dist/extensions/subagent/agents.d.ts.map +1 -1
  101. package/dist/extensions/subagent/agents.js +22 -190
  102. package/dist/extensions/subagent/agents.js.map +1 -1
  103. package/dist/extensions/subagent/constants.d.ts +4 -5
  104. package/dist/extensions/subagent/constants.d.ts.map +1 -1
  105. package/dist/extensions/subagent/constants.js +11 -7
  106. package/dist/extensions/subagent/constants.js.map +1 -1
  107. package/dist/extensions/subagent/index.d.ts +0 -3
  108. package/dist/extensions/subagent/index.d.ts.map +1 -1
  109. package/dist/extensions/subagent/index.js +58 -315
  110. package/dist/extensions/subagent/index.js.map +1 -1
  111. package/dist/extensions/subagent/render.d.ts +1 -1
  112. package/dist/extensions/subagent/render.d.ts.map +1 -1
  113. package/dist/extensions/subagent/render.js +208 -585
  114. package/dist/extensions/subagent/render.js.map +1 -1
  115. package/dist/extensions/subagent/resolve.d.ts +2 -2
  116. package/dist/extensions/subagent/resolve.d.ts.map +1 -1
  117. package/dist/extensions/subagent/resolve.js +23 -15
  118. package/dist/extensions/subagent/resolve.js.map +1 -1
  119. package/dist/extensions/subagent/runner.d.ts +1 -2
  120. package/dist/extensions/subagent/runner.d.ts.map +1 -1
  121. package/dist/extensions/subagent/runner.js +109 -131
  122. package/dist/extensions/subagent/runner.js.map +1 -1
  123. package/dist/extensions/subagent/schema.d.ts +4 -10
  124. package/dist/extensions/subagent/schema.d.ts.map +1 -1
  125. package/dist/extensions/subagent/schema.js +8 -13
  126. package/dist/extensions/subagent/schema.js.map +1 -1
  127. package/dist/extensions/subagent/sdk-runner.d.ts.map +1 -1
  128. package/dist/extensions/subagent/sdk-runner.js +9 -20
  129. package/dist/extensions/subagent/sdk-runner.js.map +1 -1
  130. package/dist/extensions/subagent/settings.d.ts +2 -3
  131. package/dist/extensions/subagent/settings.d.ts.map +1 -1
  132. package/dist/extensions/subagent/settings.js +30 -21
  133. package/dist/extensions/subagent/settings.js.map +1 -1
  134. package/dist/extensions/subagent/text.d.ts +3 -0
  135. package/dist/extensions/subagent/text.d.ts.map +1 -0
  136. package/dist/extensions/subagent/text.js +16 -0
  137. package/dist/extensions/subagent/text.js.map +1 -0
  138. package/dist/extensions/subagent/types.d.ts +13 -33
  139. package/dist/extensions/subagent/types.d.ts.map +1 -1
  140. package/dist/extensions/subagent/types.js.map +1 -1
  141. package/dist/extensions/subagent/ui/model-list.d.ts +68 -0
  142. package/dist/extensions/subagent/ui/model-list.d.ts.map +1 -0
  143. package/dist/extensions/subagent/ui/model-list.js +248 -0
  144. package/dist/extensions/subagent/ui/model-list.js.map +1 -0
  145. package/dist/extensions/todo/constants.d.ts +6 -17
  146. package/dist/extensions/todo/constants.d.ts.map +1 -1
  147. package/dist/extensions/todo/constants.js +20 -31
  148. package/dist/extensions/todo/constants.js.map +1 -1
  149. package/dist/extensions/todo/index.d.ts.map +1 -1
  150. package/dist/extensions/todo/index.js +36 -57
  151. package/dist/extensions/todo/index.js.map +1 -1
  152. package/dist/extensions/todo/schema.d.ts +20 -59
  153. package/dist/extensions/todo/schema.d.ts.map +1 -1
  154. package/dist/extensions/todo/schema.js +23 -69
  155. package/dist/extensions/todo/schema.js.map +1 -1
  156. package/dist/extensions/todo/state.d.ts +23 -65
  157. package/dist/extensions/todo/state.d.ts.map +1 -1
  158. package/dist/extensions/todo/state.js +238 -1262
  159. package/dist/extensions/todo/state.js.map +1 -1
  160. package/dist/extensions/todo/view.d.ts +19 -10
  161. package/dist/extensions/todo/view.d.ts.map +1 -1
  162. package/dist/extensions/todo/view.js +411 -463
  163. package/dist/extensions/todo/view.js.map +1 -1
  164. package/dist/extensions/todo/widget.d.ts +15 -0
  165. package/dist/extensions/todo/widget.d.ts.map +1 -0
  166. package/dist/extensions/todo/widget.js +50 -0
  167. package/dist/extensions/todo/widget.js.map +1 -0
  168. package/dist/index.d.ts +1 -1
  169. package/dist/index.d.ts.map +1 -1
  170. package/dist/index.js.map +1 -1
  171. package/dist/main.d.ts.map +1 -1
  172. package/dist/main.js +5 -1
  173. package/dist/main.js.map +1 -1
  174. package/dist/modes/interactive/components/extension-selector.d.ts +1 -2
  175. package/dist/modes/interactive/components/extension-selector.d.ts.map +1 -1
  176. package/dist/modes/interactive/components/extension-selector.js +5 -11
  177. package/dist/modes/interactive/components/extension-selector.js.map +1 -1
  178. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  179. package/dist/modes/interactive/components/model-selector.js +2 -1
  180. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  181. package/dist/modes/interactive/components/settings-selector.d.ts +3 -1
  182. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  183. package/dist/modes/interactive/components/settings-selector.js +10 -0
  184. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  185. package/dist/modes/interactive/interactive-mode.d.ts +8 -2
  186. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  187. package/dist/modes/interactive/interactive-mode.js +77 -25
  188. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  189. package/dist/modes/interactive/model-catalog-refresh.d.ts +7 -0
  190. package/dist/modes/interactive/model-catalog-refresh.d.ts.map +1 -0
  191. package/dist/modes/interactive/model-catalog-refresh.js +36 -0
  192. package/dist/modes/interactive/model-catalog-refresh.js.map +1 -0
  193. package/dist/modes/interactive/theme/dark.json +2 -0
  194. package/dist/modes/interactive/theme/light.json +2 -0
  195. package/dist/modes/interactive/theme/theme-controller.d.ts +10 -2
  196. package/dist/modes/interactive/theme/theme-controller.d.ts.map +1 -1
  197. package/dist/modes/interactive/theme/theme-controller.js +23 -10
  198. package/dist/modes/interactive/theme/theme-controller.js.map +1 -1
  199. package/dist/modes/interactive/theme/theme-schema.json +9 -1
  200. package/dist/modes/interactive/theme/theme.d.ts +5 -3
  201. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  202. package/dist/modes/interactive/theme/theme.js +12 -2
  203. package/dist/modes/interactive/theme/theme.js.map +1 -1
  204. package/dist/modes/json-event.d.ts +4 -1
  205. package/dist/modes/json-event.d.ts.map +1 -1
  206. package/dist/modes/json-event.js +5 -2
  207. package/dist/modes/json-event.js.map +1 -1
  208. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  209. package/dist/modes/rpc/rpc-mode.js +1 -8
  210. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  211. package/dist/package-manager-cli.js +1 -1
  212. package/dist/package-manager-cli.js.map +1 -1
  213. package/dist/server/create-harness.d.ts.map +1 -1
  214. package/dist/server/create-harness.js +2 -0
  215. package/dist/server/create-harness.js.map +1 -1
  216. package/dist/utils/tools-manager.d.ts +10 -1
  217. package/dist/utils/tools-manager.d.ts.map +1 -1
  218. package/dist/utils/tools-manager.js +14 -19
  219. package/dist/utils/tools-manager.js.map +1 -1
  220. package/docs/bundled/README.md +2 -1
  221. package/docs/bundled/extensions/background.md +64 -0
  222. package/docs/bundled/extensions/subagent.md +84 -57
  223. package/docs/bundled/extensions/todo.md +84 -24
  224. package/docs/bundled/tool-presentation.md +1 -1
  225. package/docs/compaction.md +6 -6
  226. package/docs/custom-provider.md +1 -1
  227. package/docs/docs.json +4 -0
  228. package/docs/environment-variables.md +8 -2
  229. package/docs/extensions.md +6 -2
  230. package/docs/json.md +6 -4
  231. package/docs/keybindings.md +9 -2
  232. package/docs/rpc.md +15 -4
  233. package/docs/sdk.md +9 -0
  234. package/docs/settings.md +31 -0
  235. package/docs/terminal-setup.md +23 -2
  236. package/docs/themes.md +24 -3
  237. package/docs/tui.md +2 -2
  238. package/docs/usage.md +4 -3
  239. package/examples/README.md +1 -1
  240. package/examples/extensions/README.md +0 -1
  241. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  242. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  243. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  244. package/examples/extensions/gondolin/package-lock.json +2 -2
  245. package/examples/extensions/gondolin/package.json +1 -1
  246. package/examples/extensions/sandbox/package-lock.json +2 -2
  247. package/examples/extensions/sandbox/package.json +1 -1
  248. package/examples/extensions/with-deps/package-lock.json +2 -2
  249. package/examples/extensions/with-deps/package.json +1 -1
  250. package/npm-shrinkwrap.json +170 -221
  251. package/package.json +6 -6
  252. package/dist/extensions/subagent/picker.d.ts +0 -31
  253. package/dist/extensions/subagent/picker.d.ts.map +0 -1
  254. package/dist/extensions/subagent/picker.js +0 -109
  255. package/dist/extensions/subagent/picker.js.map +0 -1
  256. package/dist/extensions/todo/overlay.d.ts +0 -24
  257. package/dist/extensions/todo/overlay.d.ts.map +0 -1
  258. package/dist/extensions/todo/overlay.js +0 -135
  259. package/dist/extensions/todo/overlay.js.map +0 -1
  260. package/examples/extensions/subagent/README.md +0 -175
  261. package/examples/extensions/subagent/agents/planner.md +0 -37
  262. package/examples/extensions/subagent/agents/reviewer.md +0 -35
  263. package/examples/extensions/subagent/agents/scout.md +0 -50
  264. package/examples/extensions/subagent/agents/worker.md +0 -24
  265. package/examples/extensions/subagent/agents.ts +0 -126
  266. package/examples/extensions/subagent/index.ts +0 -1009
  267. package/examples/extensions/subagent/prompts/implement-and-review.md +0 -10
  268. package/examples/extensions/subagent/prompts/implement.md +0 -10
  269. package/examples/extensions/subagent/prompts/scout-and-plan.md +0 -9
@@ -1,32 +1,25 @@
1
1
  /**
2
2
  * todo — Pi-native task tracking for multi-step work.
3
3
  *
4
- * The state is intentionally conversation-backed: every tool result carries a
5
- * full snapshot in `details`, and lifecycle handlers replay the current branch.
6
- * This keeps /reload, compaction, and session-tree navigation aligned with the
7
- * conversation without adding a separate disk database. (Compaction-safe by
8
- * design: sessionManager.getBranch() returns the FULL branch history including
9
- * pre-compaction toolResult entries — only buildSessionContext summarizes.)
10
- *
11
- * State is keyed per session id (see state.ts): resume and /tree switches can
12
- * change the session within one process, and execute + lifecycle handlers
13
- * re-point the active bucket before touching state.
4
+ * State is conversation-backed: every tool result carries a full v2 snapshot
5
+ * in `details`, and lifecycle handlers replay the current branch into the
6
+ * closure store created by createTodoStore(). Resume, /reload, and /tree
7
+ * navigation stay aligned with the conversation without a disk database or
8
+ * any per-session global state.
14
9
  */
15
10
  import { Text } from "@earendil-works/pi-tui";
16
11
  import { isStaleExtensionContextError, } from "../../core/extensions/types.js";
17
12
  import { TODO_PROMPT_GUIDELINES, TODO_PROMPT_SNIPPET, TODO_TOOL_DESCRIPTION, TODO_TOOL_LABEL, TODO_TOOL_NAME, TODOS_COMMAND_NAME, } from "./constants.js";
18
- import { TodoOverlay } from "./overlay.js";
19
13
  import { TodoParamsSchema } from "./schema.js";
20
- import { applyTodoMutation, buildTodoDetails, commitTodoState, disposeTodoSession, formatTodoContent, getTodoState, replaceTodoState, replayTodosFromBranch, setActiveTodoSession, } from "./state.js";
21
- import { formatCommandList, formatTodoCall, formatTodoGroupCall } from "./view.js";
22
- function safeReplay(ctx) {
23
- // Every ctx.sessionManager access goes through a stale guard, so the whole
24
- // body stays inside the try: a lifecycle event can race session replacement
25
- // (resume, /tree, /reload), and a stale ctx just means another session took
26
- // over — nothing left to replay for it.
14
+ import { createTodoStore, replayTodosFromBranch } from "./state.js";
15
+ import { formatCommandList, formatTodoCall, formatTodoContent, formatTodoGroupCall } from "./view.js";
16
+ import { TodoWidget } from "./widget.js";
17
+ function safeReplay(ctx, store) {
18
+ // Every ctx.sessionManager access stays inside the guard: a lifecycle event
19
+ // can race session replacement (resume, /tree, /reload), and a stale ctx
20
+ // just means another session took over — nothing left to replay for it.
27
21
  try {
28
- setActiveTodoSession(ctx.sessionManager.getSessionId());
29
- replaceTodoState(replayTodosFromBranch(ctx));
22
+ store.replaceState(replayTodosFromBranch(ctx));
30
23
  }
31
24
  catch (error) {
32
25
  if (!isStaleExtensionContextError(error))
@@ -34,7 +27,8 @@ function safeReplay(ctx) {
34
27
  }
35
28
  }
36
29
  export default function todo(pi) {
37
- let overlay;
30
+ const store = createTodoStore();
31
+ let widget;
38
32
  pi.registerTool({
39
33
  name: TODO_TOOL_NAME,
40
34
  label: TODO_TOOL_LABEL,
@@ -44,23 +38,15 @@ export default function todo(pi) {
44
38
  parameters: TodoParamsSchema,
45
39
  executionMode: "sequential",
46
40
  // Consecutive todo calls collapse into one run like read/find's `explore`
47
- // group; the overlay already carries the live list, so the transcript only
41
+ // group; the widget already carries the live list, so the transcript only
48
42
  // needs the sequence of operations.
49
43
  toolGroup: TODO_TOOL_NAME,
50
- async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
51
- // Re-point the active bucket: resume//tree can switch sessions between
52
- // lifecycle events and this call.
53
- setActiveTodoSession(ctx.sessionManager.getSessionId());
54
- const result = applyTodoMutation(getTodoState(), params);
55
- if (result.operation.kind === "error") {
56
- throw new Error(result.operation.message);
57
- }
58
- commitTodoState(result.state);
59
- const text = formatTodoContent(result.operation, result.state);
60
- return {
61
- content: [{ type: "text", text }],
62
- details: buildTodoDetails(params, result.state),
63
- };
44
+ async execute(_toolCallId, params, _signal, _onUpdate) {
45
+ // Validation errors throw before any state mutation, so the store is
46
+ // untouched on failure.
47
+ const details = store.execute(params);
48
+ const text = formatTodoContent(details.change, details.state);
49
+ return { content: [{ type: "text", text }], details };
64
50
  },
65
51
  renderCall(args, theme, context) {
66
52
  const text = context.lastComponent ?? new Text("", 0, 0);
@@ -71,44 +57,37 @@ export default function todo(pi) {
71
57
  },
72
58
  });
73
59
  pi.registerCommand(TODOS_COMMAND_NAME, {
74
- description: "Show todos for the current conversation branch",
60
+ description: "Show the complete todo list for the current conversation branch",
75
61
  handler: async (_args, ctx) => {
76
62
  if (!ctx.hasUI) {
77
63
  ctx.ui.notify("/todos requires an interactive UI.", "warning");
78
64
  return;
79
65
  }
80
- setActiveTodoSession(ctx.sessionManager.getSessionId());
81
- ctx.ui.notify(formatCommandList(getTodoState()), "info");
66
+ ctx.ui.notify(formatCommandList(store.getState()), "info");
82
67
  },
83
68
  });
84
69
  pi.on("session_start", async (_event, ctx) => {
85
- safeReplay(ctx);
70
+ safeReplay(ctx, store);
86
71
  if (ctx.hasUI) {
87
- overlay ??= new TodoOverlay();
88
- overlay.setUI(ctx.ui);
89
- overlay.resetVisibility();
90
- overlay.update();
72
+ widget ??= new TodoWidget(() => store.getState());
73
+ widget.setUI(ctx.ui);
74
+ widget.update();
91
75
  }
92
76
  });
93
- pi.on("session_compact", async (_event, ctx) => {
94
- safeReplay(ctx);
95
- overlay?.resetVisibility();
96
- overlay?.update();
97
- });
98
77
  pi.on("session_tree", async (_event, ctx) => {
99
- safeReplay(ctx);
100
- overlay?.resetVisibility();
101
- overlay?.update();
78
+ safeReplay(ctx, store);
79
+ widget?.update();
102
80
  });
103
- pi.on("session_shutdown", async (_event, ctx) => {
104
- disposeTodoSession(ctx.sessionManager.getSessionId());
105
- overlay?.dispose();
106
- overlay = undefined;
81
+ pi.on("session_shutdown", async (_event, _ctx) => {
82
+ // The store belongs to this extension runtime and is collected with it;
83
+ // the next runtime restores its own store during session_start.
84
+ widget?.dispose();
85
+ widget = undefined;
107
86
  });
108
87
  pi.on("tool_execution_end", async (event) => {
109
88
  if (event.toolName !== TODO_TOOL_NAME || event.isError)
110
89
  return;
111
- overlay?.update();
90
+ widget?.update();
112
91
  });
113
92
  }
114
93
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/extensions/todo/index.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * todo — Pi-native task tracking for multi-step work.\n *\n * The state is intentionally conversation-backed: every tool result carries a\n * full snapshot in `details`, and lifecycle handlers replay the current branch.\n * This keeps /reload, compaction, and session-tree navigation aligned with the\n * conversation without adding a separate disk database. (Compaction-safe by\n * design: sessionManager.getBranch() returns the FULL branch history including\n * pre-compaction toolResult entries — only buildSessionContext summarizes.)\n *\n * State is keyed per session id (see state.ts): resume and /tree switches can\n * change the session within one process, and execute + lifecycle handlers\n * re-point the active bucket before touching state.\n */\nimport { Text } from \"@earendil-works/pi-tui\";\nimport {\n\ttype AgentToolResult,\n\ttype ExtensionAPI,\n\tisStaleExtensionContextError,\n\ttype ToolExecutionMode,\n} from \"../../core/extensions/types.ts\";\nimport {\n\tTODO_PROMPT_GUIDELINES,\n\tTODO_PROMPT_SNIPPET,\n\tTODO_TOOL_DESCRIPTION,\n\tTODO_TOOL_LABEL,\n\tTODO_TOOL_NAME,\n\tTODOS_COMMAND_NAME,\n} from \"./constants.ts\";\nimport { TodoOverlay } from \"./overlay.ts\";\nimport { type TodoDetails, TodoParamsSchema } from \"./schema.ts\";\nimport {\n\tapplyTodoMutation,\n\tbuildTodoDetails,\n\tcommitTodoState,\n\tdisposeTodoSession,\n\tformatTodoContent,\n\tgetTodoState,\n\treplaceTodoState,\n\treplayTodosFromBranch,\n\tsetActiveTodoSession,\n} from \"./state.ts\";\nimport { formatCommandList, formatTodoCall, formatTodoGroupCall } from \"./view.ts\";\n\ninterface TodoSessionCtx {\n\tsessionManager: { getBranch(): Iterable<unknown>; getSessionId(): string };\n}\n\nfunction safeReplay(ctx: TodoSessionCtx): void {\n\t// Every ctx.sessionManager access goes through a stale guard, so the whole\n\t// body stays inside the try: a lifecycle event can race session replacement\n\t// (resume, /tree, /reload), and a stale ctx just means another session took\n\t// over — nothing left to replay for it.\n\ttry {\n\t\tsetActiveTodoSession(ctx.sessionManager.getSessionId());\n\t\treplaceTodoState(replayTodosFromBranch(ctx));\n\t} catch (error) {\n\t\tif (!isStaleExtensionContextError(error)) throw error;\n\t}\n}\n\nexport default function todo(pi: ExtensionAPI): void {\n\tlet overlay: TodoOverlay | undefined;\n\n\tpi.registerTool({\n\t\tname: TODO_TOOL_NAME,\n\t\tlabel: TODO_TOOL_LABEL,\n\t\tdescription: TODO_TOOL_DESCRIPTION,\n\t\tpromptSnippet: TODO_PROMPT_SNIPPET,\n\t\tpromptGuidelines: TODO_PROMPT_GUIDELINES,\n\t\tparameters: TodoParamsSchema,\n\t\texecutionMode: \"sequential\" as ToolExecutionMode,\n\t\t// Consecutive todo calls collapse into one run like read/find's `explore`\n\t\t// group; the overlay already carries the live list, so the transcript only\n\t\t// needs the sequence of operations.\n\t\ttoolGroup: TODO_TOOL_NAME,\n\n\t\tasync execute(_toolCallId, params, _signal, _onUpdate, ctx): Promise<AgentToolResult<TodoDetails>> {\n\t\t\t// Re-point the active bucket: resume//tree can switch sessions between\n\t\t\t// lifecycle events and this call.\n\t\t\tsetActiveTodoSession(ctx.sessionManager.getSessionId());\n\t\t\tconst result = applyTodoMutation(getTodoState(), params);\n\t\t\tif (result.operation.kind === \"error\") {\n\t\t\t\tthrow new Error(result.operation.message);\n\t\t\t}\n\t\t\tcommitTodoState(result.state);\n\t\t\tconst text = formatTodoContent(result.operation, result.state);\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: \"text\", text }],\n\t\t\t\tdetails: buildTodoDetails(params, result.state),\n\t\t\t};\n\t\t},\n\n\t\trenderCall(args, theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(\n\t\t\t\tcontext.toolGroupSummary\n\t\t\t\t\t? formatTodoGroupCall(args, theme, context)\n\t\t\t\t\t: formatTodoCall(args, theme, context.expanded, context.result),\n\t\t\t);\n\t\t\treturn text;\n\t\t},\n\t});\n\n\tpi.registerCommand(TODOS_COMMAND_NAME, {\n\t\tdescription: \"Show todos for the current conversation branch\",\n\t\thandler: async (_args, ctx) => {\n\t\t\tif (!ctx.hasUI) {\n\t\t\t\tctx.ui.notify(\"/todos requires an interactive UI.\", \"warning\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tsetActiveTodoSession(ctx.sessionManager.getSessionId());\n\t\t\tctx.ui.notify(formatCommandList(getTodoState()), \"info\");\n\t\t},\n\t});\n\n\tpi.on(\"session_start\", async (_event, ctx) => {\n\t\tsafeReplay(ctx);\n\t\tif (ctx.hasUI) {\n\t\t\toverlay ??= new TodoOverlay();\n\t\t\toverlay.setUI(ctx.ui);\n\t\t\toverlay.resetVisibility();\n\t\t\toverlay.update();\n\t\t}\n\t});\n\n\tpi.on(\"session_compact\", async (_event, ctx) => {\n\t\tsafeReplay(ctx);\n\t\toverlay?.resetVisibility();\n\t\toverlay?.update();\n\t});\n\n\tpi.on(\"session_tree\", async (_event, ctx) => {\n\t\tsafeReplay(ctx);\n\t\toverlay?.resetVisibility();\n\t\toverlay?.update();\n\t});\n\n\tpi.on(\"session_shutdown\", async (_event, ctx) => {\n\t\tdisposeTodoSession(ctx.sessionManager.getSessionId());\n\t\toverlay?.dispose();\n\t\toverlay = undefined;\n\t});\n\n\tpi.on(\"tool_execution_end\", async (event) => {\n\t\tif (event.toolName !== TODO_TOOL_NAME || event.isError) return;\n\t\toverlay?.update();\n\t});\n}\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/extensions/todo/index.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * todo — Pi-native task tracking for multi-step work.\n *\n * State is conversation-backed: every tool result carries a full v2 snapshot\n * in `details`, and lifecycle handlers replay the current branch into the\n * closure store created by createTodoStore(). Resume, /reload, and /tree\n * navigation stay aligned with the conversation without a disk database or\n * any per-session global state.\n */\nimport { Text } from \"@earendil-works/pi-tui\";\nimport {\n\ttype AgentToolResult,\n\ttype ExtensionAPI,\n\tisStaleExtensionContextError,\n\ttype ToolExecutionMode,\n} from \"../../core/extensions/types.ts\";\nimport {\n\tTODO_PROMPT_GUIDELINES,\n\tTODO_PROMPT_SNIPPET,\n\tTODO_TOOL_DESCRIPTION,\n\tTODO_TOOL_LABEL,\n\tTODO_TOOL_NAME,\n\tTODOS_COMMAND_NAME,\n} from \"./constants.ts\";\nimport { type TodoDetails, TodoParamsSchema } from \"./schema.ts\";\nimport { createTodoStore, replayTodosFromBranch, type TodoStore } from \"./state.ts\";\nimport { formatCommandList, formatTodoCall, formatTodoContent, formatTodoGroupCall } from \"./view.ts\";\nimport { TodoWidget } from \"./widget.ts\";\n\ninterface TodoSessionCtx {\n\tsessionManager: { getBranch(): Iterable<unknown> };\n}\n\nfunction safeReplay(ctx: TodoSessionCtx, store: TodoStore): void {\n\t// Every ctx.sessionManager access stays inside the guard: a lifecycle event\n\t// can race session replacement (resume, /tree, /reload), and a stale ctx\n\t// just means another session took over — nothing left to replay for it.\n\ttry {\n\t\tstore.replaceState(replayTodosFromBranch(ctx));\n\t} catch (error) {\n\t\tif (!isStaleExtensionContextError(error)) throw error;\n\t}\n}\n\nexport default function todo(pi: ExtensionAPI): void {\n\tconst store = createTodoStore();\n\tlet widget: TodoWidget | undefined;\n\n\tpi.registerTool({\n\t\tname: TODO_TOOL_NAME,\n\t\tlabel: TODO_TOOL_LABEL,\n\t\tdescription: TODO_TOOL_DESCRIPTION,\n\t\tpromptSnippet: TODO_PROMPT_SNIPPET,\n\t\tpromptGuidelines: TODO_PROMPT_GUIDELINES,\n\t\tparameters: TodoParamsSchema,\n\t\texecutionMode: \"sequential\" as ToolExecutionMode,\n\t\t// Consecutive todo calls collapse into one run like read/find's `explore`\n\t\t// group; the widget already carries the live list, so the transcript only\n\t\t// needs the sequence of operations.\n\t\ttoolGroup: TODO_TOOL_NAME,\n\n\t\tasync execute(_toolCallId, params, _signal, _onUpdate): Promise<AgentToolResult<TodoDetails>> {\n\t\t\t// Validation errors throw before any state mutation, so the store is\n\t\t\t// untouched on failure.\n\t\t\tconst details = store.execute(params);\n\t\t\tconst text = formatTodoContent(details.change, details.state);\n\t\t\treturn { content: [{ type: \"text\", text }], details };\n\t\t},\n\n\t\trenderCall(args, theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(\n\t\t\t\tcontext.toolGroupSummary\n\t\t\t\t\t? formatTodoGroupCall(args, theme, context)\n\t\t\t\t\t: formatTodoCall(args, theme, context.expanded, context.result),\n\t\t\t);\n\t\t\treturn text;\n\t\t},\n\t});\n\n\tpi.registerCommand(TODOS_COMMAND_NAME, {\n\t\tdescription: \"Show the complete todo list for the current conversation branch\",\n\t\thandler: async (_args, ctx) => {\n\t\t\tif (!ctx.hasUI) {\n\t\t\t\tctx.ui.notify(\"/todos requires an interactive UI.\", \"warning\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tctx.ui.notify(formatCommandList(store.getState()), \"info\");\n\t\t},\n\t});\n\n\tpi.on(\"session_start\", async (_event, ctx) => {\n\t\tsafeReplay(ctx, store);\n\t\tif (ctx.hasUI) {\n\t\t\twidget ??= new TodoWidget(() => store.getState());\n\t\t\twidget.setUI(ctx.ui);\n\t\t\twidget.update();\n\t\t}\n\t});\n\n\tpi.on(\"session_tree\", async (_event, ctx) => {\n\t\tsafeReplay(ctx, store);\n\t\twidget?.update();\n\t});\n\n\tpi.on(\"session_shutdown\", async (_event, _ctx) => {\n\t\t// The store belongs to this extension runtime and is collected with it;\n\t\t// the next runtime restores its own store during session_start.\n\t\twidget?.dispose();\n\t\twidget = undefined;\n\t});\n\n\tpi.on(\"tool_execution_end\", async (event) => {\n\t\tif (event.toolName !== TODO_TOOL_NAME || event.isError) return;\n\t\twidget?.update();\n\t});\n}\n"]}
@@ -1,92 +1,53 @@
1
1
  import { type Static, Type } from "typebox";
2
- export type TodoStatus = "pending" | "in_progress" | "completed" | "deleted";
3
- export type TodoAction = "create" | "create_many" | "update" | "list" | "get" | "delete" | "clear";
2
+ export type TodoStatus = "pending" | "in_progress" | "completed";
3
+ export type TodoAction = "create" | "update" | "list" | "delete";
4
4
  export interface TodoItem {
5
5
  id: number;
6
6
  subject: string;
7
- description?: string;
8
- activeForm?: string;
7
+ description: string;
9
8
  status: TodoStatus;
10
- blockedBy?: number[];
11
- owner?: string;
12
- metadata?: Record<string, unknown>;
13
9
  }
14
10
  export interface TodoState {
15
11
  items: TodoItem[];
16
12
  nextId: number;
17
13
  }
18
14
  /** Current shape of snapshots written to todo tool results. */
19
- export declare const TODO_DETAILS_SCHEMA_VERSION = 1;
20
- export type TodoOperationSummary = {
15
+ export declare const TODO_DETAILS_SCHEMA_VERSION = 2;
16
+ /** Single operation model: what one todo call did, independent of params. */
17
+ export type TodoChange = {
21
18
  kind: "create";
22
19
  ids: number[];
23
- } | {
24
- kind: "create_many";
25
- ids: number[];
26
20
  } | {
27
21
  kind: "update";
28
22
  id: number;
29
- status: TodoStatus;
23
+ from: TodoStatus;
24
+ to: TodoStatus;
25
+ demotedId?: number;
30
26
  } | {
31
27
  kind: "list";
32
- status?: TodoStatus;
33
- includeDeleted: boolean;
34
- limit?: number;
35
- afterId?: number;
36
- query?: string;
37
- unblockedOnly: boolean;
38
- /** Exact status counts for the returned page, not the full snapshot. */
39
- statusCounts?: Partial<Record<TodoStatus, number>>;
40
- resultCount?: number;
41
- } | {
42
- kind: "get";
43
- id: number;
44
28
  } | {
45
29
  kind: "delete";
46
- id: number;
47
- } | {
48
- kind: "clear";
49
- count: number;
30
+ removed: Array<{
31
+ id: number;
32
+ subject: string;
33
+ }>;
50
34
  };
51
35
  export interface TodoDetails {
52
36
  schemaVersion: typeof TODO_DETAILS_SCHEMA_VERSION;
53
- action: TodoAction;
54
- params: Record<string, unknown>;
55
- operation: TodoOperationSummary;
56
- items: TodoItem[];
57
- nextId: number;
37
+ change: TodoChange;
38
+ state: TodoState;
58
39
  }
59
40
  export declare const TodoParamsSchema: Type.TObject<{
60
- action: Type.TUnsafe<"update" | "list" | "delete" | "clear" | "create" | "create_many" | "get">;
61
- subject: Type.TOptional<Type.TString>;
62
- description: Type.TOptional<Type.TString>;
63
- activeForm: Type.TOptional<Type.TString>;
64
- status: Type.TOptional<Type.TUnsafe<"pending" | "completed" | "in_progress" | "deleted">>;
65
- blockedBy: Type.TOptional<Type.TArray<Type.TInteger>>;
41
+ action: Type.TUnsafe<"update" | "list" | "delete" | "create">;
66
42
  items: Type.TOptional<Type.TArray<Type.TObject<{
67
- key: Type.TOptional<Type.TString>;
68
43
  subject: Type.TString;
69
44
  description: Type.TString;
70
- activeForm: Type.TOptional<Type.TString>;
71
- blockedBy: Type.TOptional<Type.TArray<Type.TInteger>>;
72
- blockedByKeys: Type.TOptional<Type.TArray<Type.TString>>;
73
- owner: Type.TOptional<Type.TString>;
74
- metadata: Type.TOptional<Type.TRecord<"^.*$", Type.TUnknown>>;
75
45
  }>>>;
76
- addBlockedBy: Type.TOptional<Type.TArray<Type.TInteger>>;
77
- removeBlockedBy: Type.TOptional<Type.TArray<Type.TInteger>>;
78
- addBlocks: Type.TOptional<Type.TArray<Type.TInteger>>;
79
- removeBlocks: Type.TOptional<Type.TArray<Type.TInteger>>;
80
- owner: Type.TOptional<Type.TString>;
81
- metadata: Type.TOptional<Type.TRecord<"^.*$", Type.TUnknown>>;
82
46
  id: Type.TOptional<Type.TInteger>;
83
- includeDeleted: Type.TOptional<Type.TBoolean>;
84
- limit: Type.TOptional<Type.TInteger>;
85
- afterId: Type.TOptional<Type.TInteger>;
86
- query: Type.TOptional<Type.TString>;
87
- unblockedOnly: Type.TOptional<Type.TBoolean>;
88
- confirm: Type.TOptional<Type.TBoolean>;
89
- expectedCount: Type.TOptional<Type.TInteger>;
47
+ subject: Type.TOptional<Type.TString>;
48
+ description: Type.TOptional<Type.TString>;
49
+ status: Type.TOptional<Type.TUnsafe<"pending" | "completed" | "in_progress">>;
50
+ ids: Type.TOptional<Type.TArray<Type.TInteger>>;
90
51
  }>;
91
52
  export type TodoParams = Static<typeof TodoParamsSchema>;
92
53
  export declare const EMPTY_TODO_STATE: TodoState;
@@ -1 +1 @@
1
- {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../src/extensions/todo/schema.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAe5C,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,aAAa,GAAG,WAAW,GAAG,SAAS,CAAC;AAC7E,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,aAAa,GAAG,QAAQ,GAAG,MAAM,GAAG,KAAK,GAAG,QAAQ,GAAG,OAAO,CAAC;AAEnG,MAAM,WAAW,QAAQ;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,UAAU,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED,MAAM,WAAW,SAAS;IACzB,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;CACf;AAED,+DAA+D;AAC/D,eAAO,MAAM,2BAA2B,IAAI,CAAC;AAE7C,MAAM,MAAM,oBAAoB,GAC7B;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,GAAG,EAAE,MAAM,EAAE,CAAA;CAAE,GACjC;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,GAAG,EAAE,MAAM,EAAE,CAAA;CAAE,GACtC;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,UAAU,CAAA;CAAE,GAClD;IACA,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,cAAc,EAAE,OAAO,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,OAAO,CAAC;IACvB,wEAAwE;IACxE,YAAY,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC;IACnD,WAAW,CAAC,EAAE,MAAM,CAAC;CACpB,GACD;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAC3B;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAC9B;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAEpC,MAAM,WAAW,WAAW;IAC3B,aAAa,EAAE,OAAO,2BAA2B,CAAC;IAClD,MAAM,EAAE,UAAU,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,SAAS,EAAE,oBAAoB,CAAC;IAChC,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;CACf;AAgDD,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAyF3B,CAAC;AAEH,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAEzD,eAAO,MAAM,gBAAgB,EAAE,SAAoC,CAAC"}
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../src/extensions/todo/schema.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAG5C,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,aAAa,GAAG,WAAW,CAAC;AACjE,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,QAAQ,GAAG,MAAM,GAAG,QAAQ,CAAC;AAEjE,MAAM,WAAW,QAAQ;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,UAAU,CAAC;CACnB;AAED,MAAM,WAAW,SAAS;IACzB,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;CACf;AAED,+DAA+D;AAC/D,eAAO,MAAM,2BAA2B,IAAI,CAAC;AAE7C,6EAA6E;AAC7E,MAAM,MAAM,UAAU,GACnB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,GAAG,EAAE,MAAM,EAAE,CAAA;CAAE,GACjC;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,UAAU,CAAC;IAAC,EAAE,EAAE,UAAU,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GACpF;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,CAAC;AAEvE,MAAM,WAAW,WAAW;IAC3B,aAAa,EAAE,OAAO,2BAA2B,CAAC;IAClD,MAAM,EAAE,UAAU,CAAC;IACnB,KAAK,EAAE,SAAS,CAAC;CACjB;AAyBD,eAAO,MAAM,gBAAgB;;;;;;;;;;;EA8B3B,CAAC;AAEH,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAEzD,eAAO,MAAM,gBAAgB,EAAE,SAAoC,CAAC"}
@@ -1,96 +1,50 @@
1
+ /**
2
+ * todo/schema.ts — v2 tool parameters, state shape, and operation model.
3
+ */
1
4
  import { StringEnum } from "@earendil-works/pi-ai";
2
5
  import { Type } from "typebox";
3
- import { TODO_MAX_ACTIVE_FORM_LENGTH, TODO_MAX_BATCH_ITEMS, TODO_MAX_BATCH_KEY_LENGTH, TODO_MAX_BLOCKED_BY, TODO_MAX_DESCRIPTION_LENGTH, TODO_MAX_LIST_LIMIT, TODO_MAX_LIST_QUERY_LENGTH, TODO_MAX_METADATA_ENTRIES, TODO_MAX_METADATA_KEY_LENGTH, TODO_MAX_OWNER_LENGTH, TODO_MAX_SUBJECT_LENGTH, } from "./constants.js";
6
+ import { TODO_MAX_BATCH_ITEMS, TODO_MAX_DESCRIPTION_LENGTH, TODO_MAX_SUBJECT_LENGTH } from "./constants.js";
4
7
  /** Current shape of snapshots written to todo tool results. */
5
- export const TODO_DETAILS_SCHEMA_VERSION = 1;
6
- const StatusSchema = StringEnum(["pending", "in_progress", "completed", "deleted"], {
7
- description: "Task status: pending for future work, in_progress for the single active task, completed for verified done work, and deleted for an immutable obsolete-task tombstone. Set deleted through update or use the delete action. With action list, status also acts as a filter: only tasks with this status are listed.",
8
+ export const TODO_DETAILS_SCHEMA_VERSION = 2;
9
+ const StatusSchema = StringEnum(["pending", "in_progress", "completed"], {
10
+ description: "Task status: pending for future work, in_progress for the single active task, completed for verified done work. Exactly one task may be in_progress; setting one demotes any other active task to pending.",
8
11
  });
9
- const ActionSchema = StringEnum(["create", "create_many", "update", "list", "get", "delete", "clear"], {
10
- description: "Todo operation: create one pending task, create_many pending tasks atomically, update status/details/dependencies, list current tasks, get one task, delete an obsolete task, or clear the list with confirmation. Parameters that do not apply to the chosen action are rejected.",
12
+ const ActionSchema = StringEnum(["create", "update", "list", "delete"], {
13
+ description: "Todo operation: create one or many pending tasks from the ordered items array, update one task by id, list all remaining tasks, or delete obsolete tasks by ids. Parameters that do not apply to the chosen action are rejected.",
11
14
  });
12
- const TaskId = (description) => Type.Integer({ minimum: 1, description });
13
- const MetadataSchema = Type.Record(Type.String({ maxLength: TODO_MAX_METADATA_KEY_LENGTH }), Type.Unknown(), {
14
- maxProperties: TODO_MAX_METADATA_ENTRIES,
15
- description: "Structured JSON-like metadata. Values and total payload are validated by the tool.",
16
- });
17
- const CreateManyItemSchema = Type.Object({
18
- key: Type.Optional(Type.String({
19
- maxLength: TODO_MAX_BATCH_KEY_LENGTH,
20
- description: "Optional unique batch key used by blockedByKeys references.",
21
- })),
15
+ const TaskIdSchema = Type.Integer({ minimum: 1, description: "Positive task id." });
16
+ const CreateItemSchema = Type.Object({
22
17
  subject: Type.String({
23
18
  maxLength: TODO_MAX_SUBJECT_LENGTH,
24
- description: "Short imperative task subject.",
19
+ description: "Short imperative task subject; a reviewable unit of work.",
25
20
  }),
26
21
  description: Type.String({
27
22
  maxLength: TODO_MAX_DESCRIPTION_LENGTH,
28
- description: "What done means for this task.",
23
+ description: "What done means for this task: acceptance criteria or verification detail.",
29
24
  }),
30
- activeForm: Type.Optional(Type.String({ maxLength: TODO_MAX_ACTIVE_FORM_LENGTH })),
31
- blockedBy: Type.Optional(Type.Array(TaskId("Existing task id this task depends on."), { maxItems: TODO_MAX_BLOCKED_BY })),
32
- blockedByKeys: Type.Optional(Type.Array(Type.String({ maxLength: TODO_MAX_BATCH_KEY_LENGTH }), {
33
- maxItems: TODO_MAX_BLOCKED_BY,
34
- description: "Keys of tasks in this create_many batch that must complete first.",
35
- })),
36
- owner: Type.Optional(Type.String({ maxLength: TODO_MAX_OWNER_LENGTH })),
37
- metadata: Type.Optional(MetadataSchema),
38
25
  });
39
26
  export const TodoParamsSchema = Type.Object({
40
27
  action: ActionSchema,
28
+ items: Type.Optional(Type.Array(CreateItemSchema, {
29
+ minItems: 1,
30
+ maxItems: TODO_MAX_BATCH_ITEMS,
31
+ description: "create only: 1 to 20 pending tasks, created atomically in input order.",
32
+ })),
33
+ id: Type.Optional(TaskIdSchema),
41
34
  subject: Type.Optional(Type.String({
42
35
  maxLength: TODO_MAX_SUBJECT_LENGTH,
43
- description: "Short imperative task subject, required for create; use a reviewable unit of work, not a micro-step.",
36
+ description: "update only: replacement subject.",
44
37
  })),
45
38
  description: Type.Optional(Type.String({
46
39
  maxLength: TODO_MAX_DESCRIPTION_LENGTH,
47
- description: "What done means for this task: notes, acceptance criteria, or verification detail. Required for create; on update an empty string removes it.",
48
- })),
49
- activeForm: Type.Optional(Type.String({
50
- maxLength: TODO_MAX_ACTIVE_FORM_LENGTH,
51
- description: "Present-continuous label shown while in_progress, such as 'reading code' or 'updating prompts'; on update an empty string removes it.",
40
+ description: "update only: replacement description (what done means).",
52
41
  })),
53
42
  status: Type.Optional(StatusSchema),
54
- blockedBy: Type.Optional(Type.Array(TaskId("Existing task id this task depends on."), {
55
- maxItems: TODO_MAX_BLOCKED_BY,
56
- description: "Initial dependency ids, create only (update rejects it; use addBlockedBy/removeBlockedBy there); use only for real ordering constraints.",
57
- })),
58
- items: Type.Optional(Type.Array(CreateManyItemSchema, {
43
+ ids: Type.Optional(Type.Array(TaskIdSchema, {
59
44
  minItems: 1,
60
45
  maxItems: TODO_MAX_BATCH_ITEMS,
61
- description: "create_many only: up to 20 pending tasks, created atomically in input order. Use key and blockedByKeys for dependencies within this batch.",
62
- })),
63
- addBlockedBy: Type.Optional(Type.Array(TaskId("Existing task id that must complete first."), {
64
- maxItems: TODO_MAX_BLOCKED_BY,
65
- description: "Dependency ids to add on update; dependencies must exist and cannot create cycles.",
66
- })),
67
- removeBlockedBy: Type.Optional(Type.Array(TaskId("Dependency id to detach."), { maxItems: TODO_MAX_BLOCKED_BY })),
68
- addBlocks: Type.Optional(Type.Array(TaskId("Existing task id that must wait for this one."), {
69
- maxItems: TODO_MAX_BLOCKED_BY,
70
- description: "Update only: ids of tasks that cannot start until this task completes (the reverse of addBlockedBy); targets must exist and cannot create cycles.",
71
- })),
72
- removeBlocks: Type.Optional(Type.Array(TaskId("Dependent task id to release."), { maxItems: TODO_MAX_BLOCKED_BY })),
73
- owner: Type.Optional(Type.String({
74
- maxLength: TODO_MAX_OWNER_LENGTH,
75
- description: "Optional owner or agent label for multi-agent coordination; on update an empty string removes it.",
76
- })),
77
- metadata: Type.Optional(Type.Record(Type.String({ maxLength: TODO_MAX_METADATA_KEY_LENGTH }), Type.Unknown(), {
78
- maxProperties: TODO_MAX_METADATA_ENTRIES,
79
- description: "Optional bounded JSON-like structured metadata; null values delete keys on update.",
80
- })),
81
- id: Type.Optional(TaskId("Task id, required for update, get, and delete.")),
82
- includeDeleted: Type.Optional(Type.Boolean({
83
- description: "Include deleted tombstones in unfiltered list output; an explicit status=deleted query includes them automatically.",
84
- })),
85
- limit: Type.Optional(Type.Integer({ minimum: 1, maximum: TODO_MAX_LIST_LIMIT, description: "List page size (1 through 50)." })),
86
- afterId: Type.Optional(TaskId("List only tasks with ids greater than this id.")),
87
- query: Type.Optional(Type.String({
88
- maxLength: TODO_MAX_LIST_QUERY_LENGTH,
89
- description: "Case-insensitive subject and description search for list.",
46
+ description: "delete only: 1 to 20 ids to remove from the current list; duplicates are ignored.",
90
47
  })),
91
- unblockedOnly: Type.Optional(Type.Boolean({ description: "List only tasks with no unresolved dependencies." })),
92
- confirm: Type.Optional(Type.Boolean({ description: "clear only: must be true." })),
93
- expectedCount: Type.Optional(Type.Integer({ minimum: 0, description: "clear only: exact current task count required as a safety check." })),
94
48
  });
95
49
  export const EMPTY_TODO_STATE = { items: [], nextId: 1 };
96
50
  //# sourceMappingURL=schema.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../../src/extensions/todo/schema.ts"],"names":[],"mappings":"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","sourcesContent":["import { StringEnum } from \"@earendil-works/pi-ai\";\nimport { type Static, Type } from \"typebox\";\nimport {\n\tTODO_MAX_ACTIVE_FORM_LENGTH,\n\tTODO_MAX_BATCH_ITEMS,\n\tTODO_MAX_BATCH_KEY_LENGTH,\n\tTODO_MAX_BLOCKED_BY,\n\tTODO_MAX_DESCRIPTION_LENGTH,\n\tTODO_MAX_LIST_LIMIT,\n\tTODO_MAX_LIST_QUERY_LENGTH,\n\tTODO_MAX_METADATA_ENTRIES,\n\tTODO_MAX_METADATA_KEY_LENGTH,\n\tTODO_MAX_OWNER_LENGTH,\n\tTODO_MAX_SUBJECT_LENGTH,\n} from \"./constants.ts\";\n\nexport type TodoStatus = \"pending\" | \"in_progress\" | \"completed\" | \"deleted\";\nexport type TodoAction = \"create\" | \"create_many\" | \"update\" | \"list\" | \"get\" | \"delete\" | \"clear\";\n\nexport interface TodoItem {\n\tid: number;\n\tsubject: string;\n\tdescription?: string;\n\tactiveForm?: string;\n\tstatus: TodoStatus;\n\tblockedBy?: number[];\n\towner?: string;\n\tmetadata?: Record<string, unknown>;\n}\n\nexport interface TodoState {\n\titems: TodoItem[];\n\tnextId: number;\n}\n\n/** Current shape of snapshots written to todo tool results. */\nexport const TODO_DETAILS_SCHEMA_VERSION = 1;\n\nexport type TodoOperationSummary =\n\t| { kind: \"create\"; ids: number[] }\n\t| { kind: \"create_many\"; ids: number[] }\n\t| { kind: \"update\"; id: number; status: TodoStatus }\n\t| {\n\t\t\tkind: \"list\";\n\t\t\tstatus?: TodoStatus;\n\t\t\tincludeDeleted: boolean;\n\t\t\tlimit?: number;\n\t\t\tafterId?: number;\n\t\t\tquery?: string;\n\t\t\tunblockedOnly: boolean;\n\t\t\t/** Exact status counts for the returned page, not the full snapshot. */\n\t\t\tstatusCounts?: Partial<Record<TodoStatus, number>>;\n\t\t\tresultCount?: number;\n\t }\n\t| { kind: \"get\"; id: number }\n\t| { kind: \"delete\"; id: number }\n\t| { kind: \"clear\"; count: number };\n\nexport interface TodoDetails {\n\tschemaVersion: typeof TODO_DETAILS_SCHEMA_VERSION;\n\taction: TodoAction;\n\tparams: Record<string, unknown>;\n\toperation: TodoOperationSummary;\n\titems: TodoItem[];\n\tnextId: number;\n}\n\nconst StatusSchema = StringEnum([\"pending\", \"in_progress\", \"completed\", \"deleted\"] as const, {\n\tdescription:\n\t\t\"Task status: pending for future work, in_progress for the single active task, completed for verified done work, and deleted for an immutable obsolete-task tombstone. Set deleted through update or use the delete action. With action list, status also acts as a filter: only tasks with this status are listed.\",\n});\n\nconst ActionSchema = StringEnum([\"create\", \"create_many\", \"update\", \"list\", \"get\", \"delete\", \"clear\"] as const, {\n\tdescription:\n\t\t\"Todo operation: create one pending task, create_many pending tasks atomically, update status/details/dependencies, list current tasks, get one task, delete an obsolete task, or clear the list with confirmation. Parameters that do not apply to the chosen action are rejected.\",\n});\n\nconst TaskId = (description: string) => Type.Integer({ minimum: 1, description });\n\nconst MetadataSchema = Type.Record(Type.String({ maxLength: TODO_MAX_METADATA_KEY_LENGTH }), Type.Unknown(), {\n\tmaxProperties: TODO_MAX_METADATA_ENTRIES,\n\tdescription: \"Structured JSON-like metadata. Values and total payload are validated by the tool.\",\n});\n\nconst CreateManyItemSchema = Type.Object({\n\tkey: Type.Optional(\n\t\tType.String({\n\t\t\tmaxLength: TODO_MAX_BATCH_KEY_LENGTH,\n\t\t\tdescription: \"Optional unique batch key used by blockedByKeys references.\",\n\t\t}),\n\t),\n\tsubject: Type.String({\n\t\tmaxLength: TODO_MAX_SUBJECT_LENGTH,\n\t\tdescription: \"Short imperative task subject.\",\n\t}),\n\tdescription: Type.String({\n\t\tmaxLength: TODO_MAX_DESCRIPTION_LENGTH,\n\t\tdescription: \"What done means for this task.\",\n\t}),\n\tactiveForm: Type.Optional(Type.String({ maxLength: TODO_MAX_ACTIVE_FORM_LENGTH })),\n\tblockedBy: Type.Optional(\n\t\tType.Array(TaskId(\"Existing task id this task depends on.\"), { maxItems: TODO_MAX_BLOCKED_BY }),\n\t),\n\tblockedByKeys: Type.Optional(\n\t\tType.Array(Type.String({ maxLength: TODO_MAX_BATCH_KEY_LENGTH }), {\n\t\t\tmaxItems: TODO_MAX_BLOCKED_BY,\n\t\t\tdescription: \"Keys of tasks in this create_many batch that must complete first.\",\n\t\t}),\n\t),\n\towner: Type.Optional(Type.String({ maxLength: TODO_MAX_OWNER_LENGTH })),\n\tmetadata: Type.Optional(MetadataSchema),\n});\n\nexport const TodoParamsSchema = Type.Object({\n\taction: ActionSchema,\n\tsubject: Type.Optional(\n\t\tType.String({\n\t\t\tmaxLength: TODO_MAX_SUBJECT_LENGTH,\n\t\t\tdescription:\n\t\t\t\t\"Short imperative task subject, required for create; use a reviewable unit of work, not a micro-step.\",\n\t\t}),\n\t),\n\tdescription: Type.Optional(\n\t\tType.String({\n\t\t\tmaxLength: TODO_MAX_DESCRIPTION_LENGTH,\n\t\t\tdescription:\n\t\t\t\t\"What done means for this task: notes, acceptance criteria, or verification detail. Required for create; on update an empty string removes it.\",\n\t\t}),\n\t),\n\tactiveForm: Type.Optional(\n\t\tType.String({\n\t\t\tmaxLength: TODO_MAX_ACTIVE_FORM_LENGTH,\n\t\t\tdescription:\n\t\t\t\t\"Present-continuous label shown while in_progress, such as 'reading code' or 'updating prompts'; on update an empty string removes it.\",\n\t\t}),\n\t),\n\tstatus: Type.Optional(StatusSchema),\n\tblockedBy: Type.Optional(\n\t\tType.Array(TaskId(\"Existing task id this task depends on.\"), {\n\t\t\tmaxItems: TODO_MAX_BLOCKED_BY,\n\t\t\tdescription:\n\t\t\t\t\"Initial dependency ids, create only (update rejects it; use addBlockedBy/removeBlockedBy there); use only for real ordering constraints.\",\n\t\t}),\n\t),\n\titems: Type.Optional(\n\t\tType.Array(CreateManyItemSchema, {\n\t\t\tminItems: 1,\n\t\t\tmaxItems: TODO_MAX_BATCH_ITEMS,\n\t\t\tdescription:\n\t\t\t\t\"create_many only: up to 20 pending tasks, created atomically in input order. Use key and blockedByKeys for dependencies within this batch.\",\n\t\t}),\n\t),\n\taddBlockedBy: Type.Optional(\n\t\tType.Array(TaskId(\"Existing task id that must complete first.\"), {\n\t\t\tmaxItems: TODO_MAX_BLOCKED_BY,\n\t\t\tdescription: \"Dependency ids to add on update; dependencies must exist and cannot create cycles.\",\n\t\t}),\n\t),\n\tremoveBlockedBy: Type.Optional(Type.Array(TaskId(\"Dependency id to detach.\"), { maxItems: TODO_MAX_BLOCKED_BY })),\n\taddBlocks: Type.Optional(\n\t\tType.Array(TaskId(\"Existing task id that must wait for this one.\"), {\n\t\t\tmaxItems: TODO_MAX_BLOCKED_BY,\n\t\t\tdescription:\n\t\t\t\t\"Update only: ids of tasks that cannot start until this task completes (the reverse of addBlockedBy); targets must exist and cannot create cycles.\",\n\t\t}),\n\t),\n\tremoveBlocks: Type.Optional(Type.Array(TaskId(\"Dependent task id to release.\"), { maxItems: TODO_MAX_BLOCKED_BY })),\n\towner: Type.Optional(\n\t\tType.String({\n\t\t\tmaxLength: TODO_MAX_OWNER_LENGTH,\n\t\t\tdescription:\n\t\t\t\t\"Optional owner or agent label for multi-agent coordination; on update an empty string removes it.\",\n\t\t}),\n\t),\n\tmetadata: Type.Optional(\n\t\tType.Record(Type.String({ maxLength: TODO_MAX_METADATA_KEY_LENGTH }), Type.Unknown(), {\n\t\t\tmaxProperties: TODO_MAX_METADATA_ENTRIES,\n\t\t\tdescription: \"Optional bounded JSON-like structured metadata; null values delete keys on update.\",\n\t\t}),\n\t),\n\tid: Type.Optional(TaskId(\"Task id, required for update, get, and delete.\")),\n\tincludeDeleted: Type.Optional(\n\t\tType.Boolean({\n\t\t\tdescription:\n\t\t\t\t\"Include deleted tombstones in unfiltered list output; an explicit status=deleted query includes them automatically.\",\n\t\t}),\n\t),\n\tlimit: Type.Optional(\n\t\tType.Integer({ minimum: 1, maximum: TODO_MAX_LIST_LIMIT, description: \"List page size (1 through 50).\" }),\n\t),\n\tafterId: Type.Optional(TaskId(\"List only tasks with ids greater than this id.\")),\n\tquery: Type.Optional(\n\t\tType.String({\n\t\t\tmaxLength: TODO_MAX_LIST_QUERY_LENGTH,\n\t\t\tdescription: \"Case-insensitive subject and description search for list.\",\n\t\t}),\n\t),\n\tunblockedOnly: Type.Optional(Type.Boolean({ description: \"List only tasks with no unresolved dependencies.\" })),\n\tconfirm: Type.Optional(Type.Boolean({ description: \"clear only: must be true.\" })),\n\texpectedCount: Type.Optional(\n\t\tType.Integer({ minimum: 0, description: \"clear only: exact current task count required as a safety check.\" }),\n\t),\n});\n\nexport type TodoParams = Static<typeof TodoParamsSchema>;\n\nexport const EMPTY_TODO_STATE: TodoState = { items: [], nextId: 1 };\n"]}
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../../src/extensions/todo/schema.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,EAAe,IAAI,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,EAAE,oBAAoB,EAAE,2BAA2B,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAC;AAiB5G,+DAA+D;AAC/D,MAAM,CAAC,MAAM,2BAA2B,GAAG,CAAC,CAAC;AAe7C,MAAM,YAAY,GAAG,UAAU,CAAC,CAAC,SAAS,EAAE,aAAa,EAAE,WAAW,CAAU,EAAE;IACjF,WAAW,EACV,4MAA4M;CAC7M,CAAC,CAAC;AAEH,MAAM,YAAY,GAAG,UAAU,CAAC,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAU,EAAE;IAChF,WAAW,EACV,kOAAkO;CACnO,CAAC,CAAC;AAEH,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,WAAW,EAAE,mBAAmB,EAAE,CAAC,CAAC;AAEpF,MAAM,gBAAgB,GAAG,IAAI,CAAC,MAAM,CAAC;IACpC,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC;QACpB,SAAS,EAAE,uBAAuB;QAClC,WAAW,EAAE,2DAA2D;KACxE,CAAC;IACF,WAAW,EAAE,IAAI,CAAC,MAAM,CAAC;QACxB,SAAS,EAAE,2BAA2B;QACtC,WAAW,EAAE,4EAA4E;KACzF,CAAC;CACF,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,gBAAgB,GAAG,IAAI,CAAC,MAAM,CAAC;IAC3C,MAAM,EAAE,YAAY;IACpB,KAAK,EAAE,IAAI,CAAC,QAAQ,CACnB,IAAI,CAAC,KAAK,CAAC,gBAAgB,EAAE;QAC5B,QAAQ,EAAE,CAAC;QACX,QAAQ,EAAE,oBAAoB;QAC9B,WAAW,EAAE,wEAAwE;KACrF,CAAC,CACF;IACD,EAAE,EAAE,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC;IAC/B,OAAO,EAAE,IAAI,CAAC,QAAQ,CACrB,IAAI,CAAC,MAAM,CAAC;QACX,SAAS,EAAE,uBAAuB;QAClC,WAAW,EAAE,mCAAmC;KAChD,CAAC,CACF;IACD,WAAW,EAAE,IAAI,CAAC,QAAQ,CACzB,IAAI,CAAC,MAAM,CAAC;QACX,SAAS,EAAE,2BAA2B;QACtC,WAAW,EAAE,yDAAyD;KACtE,CAAC,CACF;IACD,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC;IACnC,GAAG,EAAE,IAAI,CAAC,QAAQ,CACjB,IAAI,CAAC,KAAK,CAAC,YAAY,EAAE;QACxB,QAAQ,EAAE,CAAC;QACX,QAAQ,EAAE,oBAAoB;QAC9B,WAAW,EAAE,mFAAmF;KAChG,CAAC,CACF;CACD,CAAC,CAAC;AAIH,MAAM,CAAC,MAAM,gBAAgB,GAAc,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC","sourcesContent":["/**\n * todo/schema.ts — v2 tool parameters, state shape, and operation model.\n */\nimport { StringEnum } from \"@earendil-works/pi-ai\";\nimport { type Static, Type } from \"typebox\";\nimport { TODO_MAX_BATCH_ITEMS, TODO_MAX_DESCRIPTION_LENGTH, TODO_MAX_SUBJECT_LENGTH } from \"./constants.ts\";\n\nexport type TodoStatus = \"pending\" | \"in_progress\" | \"completed\";\nexport type TodoAction = \"create\" | \"update\" | \"list\" | \"delete\";\n\nexport interface TodoItem {\n\tid: number;\n\tsubject: string;\n\tdescription: string;\n\tstatus: TodoStatus;\n}\n\nexport interface TodoState {\n\titems: TodoItem[];\n\tnextId: number;\n}\n\n/** Current shape of snapshots written to todo tool results. */\nexport const TODO_DETAILS_SCHEMA_VERSION = 2;\n\n/** Single operation model: what one todo call did, independent of params. */\nexport type TodoChange =\n\t| { kind: \"create\"; ids: number[] }\n\t| { kind: \"update\"; id: number; from: TodoStatus; to: TodoStatus; demotedId?: number }\n\t| { kind: \"list\" }\n\t| { kind: \"delete\"; removed: Array<{ id: number; subject: string }> };\n\nexport interface TodoDetails {\n\tschemaVersion: typeof TODO_DETAILS_SCHEMA_VERSION;\n\tchange: TodoChange;\n\tstate: TodoState;\n}\n\nconst StatusSchema = StringEnum([\"pending\", \"in_progress\", \"completed\"] as const, {\n\tdescription:\n\t\t\"Task status: pending for future work, in_progress for the single active task, completed for verified done work. Exactly one task may be in_progress; setting one demotes any other active task to pending.\",\n});\n\nconst ActionSchema = StringEnum([\"create\", \"update\", \"list\", \"delete\"] as const, {\n\tdescription:\n\t\t\"Todo operation: create one or many pending tasks from the ordered items array, update one task by id, list all remaining tasks, or delete obsolete tasks by ids. Parameters that do not apply to the chosen action are rejected.\",\n});\n\nconst TaskIdSchema = Type.Integer({ minimum: 1, description: \"Positive task id.\" });\n\nconst CreateItemSchema = Type.Object({\n\tsubject: Type.String({\n\t\tmaxLength: TODO_MAX_SUBJECT_LENGTH,\n\t\tdescription: \"Short imperative task subject; a reviewable unit of work.\",\n\t}),\n\tdescription: Type.String({\n\t\tmaxLength: TODO_MAX_DESCRIPTION_LENGTH,\n\t\tdescription: \"What done means for this task: acceptance criteria or verification detail.\",\n\t}),\n});\n\nexport const TodoParamsSchema = Type.Object({\n\taction: ActionSchema,\n\titems: Type.Optional(\n\t\tType.Array(CreateItemSchema, {\n\t\t\tminItems: 1,\n\t\t\tmaxItems: TODO_MAX_BATCH_ITEMS,\n\t\t\tdescription: \"create only: 1 to 20 pending tasks, created atomically in input order.\",\n\t\t}),\n\t),\n\tid: Type.Optional(TaskIdSchema),\n\tsubject: Type.Optional(\n\t\tType.String({\n\t\t\tmaxLength: TODO_MAX_SUBJECT_LENGTH,\n\t\t\tdescription: \"update only: replacement subject.\",\n\t\t}),\n\t),\n\tdescription: Type.Optional(\n\t\tType.String({\n\t\t\tmaxLength: TODO_MAX_DESCRIPTION_LENGTH,\n\t\t\tdescription: \"update only: replacement description (what done means).\",\n\t\t}),\n\t),\n\tstatus: Type.Optional(StatusSchema),\n\tids: Type.Optional(\n\t\tType.Array(TaskIdSchema, {\n\t\t\tminItems: 1,\n\t\t\tmaxItems: TODO_MAX_BATCH_ITEMS,\n\t\t\tdescription: \"delete only: 1 to 20 ids to remove from the current list; duplicates are ignored.\",\n\t\t}),\n\t),\n});\n\nexport type TodoParams = Static<typeof TodoParamsSchema>;\n\nexport const EMPTY_TODO_STATE: TodoState = { items: [], nextId: 1 };\n"]}
@@ -1,72 +1,30 @@
1
- import { type TodoDetails, type TodoItem, type TodoParams, type TodoState, type TodoStatus } from "./schema.ts";
2
- type Operation = {
3
- kind: "create";
4
- id: number;
5
- } | {
6
- kind: "create_many";
7
- ids: number[];
8
- } | {
9
- kind: "update";
10
- id: number;
11
- from: TodoStatus;
12
- to: TodoStatus;
13
- /** Other tasks auto-demoted from in_progress → pending to keep exactly one active. */
14
- demotedIds?: number[];
15
- /** Active tasks demoted because a new dependency is still incomplete. */
16
- blockedIds?: number[];
17
- /** Pending dependents left fully unblocked by an update to status deleted. */
18
- releasedIds?: number[];
19
- /** Soft note when the list is fully closed without a verification-style task. */
20
- verificationNudge?: boolean;
21
- } | {
22
- kind: "list";
23
- status?: TodoStatus;
24
- includeDeleted: boolean;
25
- limit: number;
26
- afterId?: number;
27
- query?: string;
28
- unblockedOnly: boolean;
29
- /** Keep the historical no-options list text stable. */
30
- legacyOutput: boolean;
31
- } | {
32
- kind: "get";
33
- item: TodoItem;
34
- } | {
35
- kind: "delete";
36
- id: number;
37
- subject: string;
38
- releasedIds?: number[];
39
- } | {
40
- kind: "clear";
41
- count: number;
42
- } | {
43
- kind: "error";
44
- message: string;
45
- };
46
- export interface MutationResult {
47
- state: TodoState;
48
- operation: Operation;
1
+ import { type TodoChange, type TodoDetails, type TodoParams, type TodoState } from "./schema.ts";
2
+ /** Snapshot clone: items are plain string/number records, so a shallow copy is safe. */
3
+ export declare function cloneTodoState(state: TodoState): TodoState;
4
+ /**
5
+ * Pure action application: validates every runtime input and inapplicable
6
+ * parameter (tool args can be tampered after schema validation), throws on
7
+ * any invalid call, and never mutates the input state.
8
+ */
9
+ export declare function applyTodoAction(state: TodoState, params: TodoParams): TodoState;
10
+ /** Derive the operation model for one call from the before/after states. */
11
+ export declare function buildTodoChange(params: TodoParams, before: TodoState, after: TodoState): TodoChange;
12
+ export declare function buildTodoDetails(change: TodoChange, state: TodoState): TodoDetails;
13
+ export interface TodoStore {
14
+ getState(): TodoState;
15
+ replaceState(state: TodoState): void;
16
+ execute(params: TodoParams): TodoDetails;
49
17
  }
50
- /** Point the module at a session's state bucket. Call wherever ctx is in hand. */
51
- export declare function setActiveTodoSession(sid: string): void;
52
- /** Snapshot of the active session's state; mutate via applyTodoMutation + commitTodoState. */
53
- export declare function getTodoState(): TodoState;
54
- export declare function replaceTodoState(next: TodoState): void;
55
- export declare function commitTodoState(next: TodoState): void;
56
- /** Drop in-memory state for a session (call from session_shutdown). */
57
- export declare function disposeTodoSession(sid: string): void;
58
- export declare function cloneState(source: TodoState): TodoState;
59
- /** IDs of dependencies that still prevent a task from starting or completing. */
60
- export declare function unresolvedDependencyIds(state: TodoState, item: TodoItem): number[];
61
- /** True when every blockedBy dependency is completed (for transition and overlay checks). */
62
- export declare function dependenciesSatisfied(state: TodoState, item: TodoItem): boolean;
63
- export declare function applyTodoMutation(input: TodoState, params: TodoParams): MutationResult;
18
+ /** Closure-scoped store: one list per store, no module-global session state. */
19
+ export declare function createTodoStore(initial?: TodoState): TodoStore;
20
+ /**
21
+ * Replay the newest valid v2 todo snapshot from a branch, scanning tail to
22
+ * head so a malformed latest snapshot falls back to an earlier valid one.
23
+ * v1 details are ignored, and the `change` field is not validated.
24
+ */
64
25
  export declare function replayTodosFromBranch(ctx: {
65
26
  sessionManager: {
66
27
  getBranch(): Iterable<unknown>;
67
28
  };
68
29
  }): TodoState;
69
- export declare function buildTodoDetails(params: TodoParams, next: TodoState): TodoDetails;
70
- export declare function formatTodoContent(operation: Operation, state: TodoState): string;
71
- export {};
72
30
  //# sourceMappingURL=state.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../../src/extensions/todo/state.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../../src/extensions/todo/state.ts"],"names":[],"mappings":"AAYA,OAAO,EAIN,KAAK,UAAU,EACf,KAAK,WAAW,EAEhB,KAAK,UAAU,EACf,KAAK,SAAS,EAEd,MAAM,aAAa,CAAC;AAgErB,wFAAwF;AACxF,wBAAgB,cAAc,CAAC,KAAK,EAAE,SAAS,GAAG,SAAS,CAE1D;AAiGD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,GAAG,SAAS,CAe/E;AAED,4EAA4E;AAC5E,wBAAgB,eAAe,CAAC,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,GAAG,UAAU,CA+BnG;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,SAAS,GAAG,WAAW,CAElF;AAED,MAAM,WAAW,SAAS;IACzB,QAAQ,IAAI,SAAS,CAAC;IACtB,YAAY,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI,CAAC;IACrC,OAAO,CAAC,MAAM,EAAE,UAAU,GAAG,WAAW,CAAC;CACzC;AAQD,gFAAgF;AAChF,wBAAgB,eAAe,CAAC,OAAO,CAAC,EAAE,SAAS,GAAG,SAAS,CAiB9D;AAgCD;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE;IAAE,cAAc,EAAE;QAAE,SAAS,IAAI,QAAQ,CAAC,OAAO,CAAC,CAAA;KAAE,CAAA;CAAE,GAAG,SAAS,CAiB5G"}