@gavin-hu/my-pi-agent 0.17.0 → 0.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (274) hide show
  1. package/README.md +61 -45
  2. package/README.zh-CN.md +54 -42
  3. package/docs/extensions/README.md +34 -0
  4. package/docs/extensions/board.md +344 -0
  5. package/{extensions/bytefly/README.md → docs/extensions/bytefly.md} +465 -416
  6. package/{extensions/check/README.md → docs/extensions/check.md} +83 -68
  7. package/{extensions/context/README.md → docs/extensions/context.md} +40 -23
  8. package/docs/extensions/file-browse.md +554 -0
  9. package/{extensions/file-open/README.md → docs/extensions/file-open.md} +31 -23
  10. package/{extensions/file-read/README.md → docs/extensions/file-read.md} +47 -55
  11. package/{extensions/goal/README.md → docs/extensions/goal.md} +115 -131
  12. package/{extensions/job/README.md → docs/extensions/job.md} +66 -53
  13. package/{extensions/memory/README.md → docs/extensions/memory.md} +74 -63
  14. package/docs/extensions/plan.md +976 -0
  15. package/{extensions/question/README.md → docs/extensions/question.md} +54 -28
  16. package/{extensions/rewind/README.md → docs/extensions/rewind.md} +115 -122
  17. package/docs/extensions/session-bus.md +285 -0
  18. package/{extensions/subagent/README.md → docs/extensions/subagent.md} +166 -119
  19. package/docs/extensions/team.md +226 -0
  20. package/{extensions/todo/README.md → docs/extensions/todo.md} +85 -88
  21. package/{extensions/watch/README.md → docs/extensions/watch.md} +60 -38
  22. package/{extensions/web-access/README.md → docs/extensions/web-access.md} +93 -50
  23. package/{extensions/wechat/README.md → docs/extensions/wechat.md} +275 -192
  24. package/{extensions/worktree/README.md → docs/extensions/worktree.md} +115 -72
  25. package/extensions/board/commands.ts +87 -0
  26. package/extensions/board/config.ts +36 -0
  27. package/extensions/board/format.ts +72 -0
  28. package/extensions/board/index.ts +40 -0
  29. package/extensions/board/input.ts +54 -0
  30. package/extensions/board/join.ts +42 -0
  31. package/extensions/board/page.ts +312 -0
  32. package/extensions/board/result.ts +99 -0
  33. package/extensions/board/rows.ts +48 -0
  34. package/extensions/board/schema.ts +75 -0
  35. package/extensions/board/seat.ts +29 -0
  36. package/extensions/board/snapshot.ts +41 -0
  37. package/extensions/board/tools.ts +279 -0
  38. package/extensions/board/transport/router.ts +172 -0
  39. package/extensions/board/transport/server.ts +149 -0
  40. package/extensions/board/types.ts +54 -0
  41. package/extensions/board/view/actions.ts +306 -0
  42. package/extensions/board/view/client.ts +41 -0
  43. package/extensions/board/view/keys.ts +121 -0
  44. package/extensions/board/view/live.ts +397 -0
  45. package/extensions/board/view/page.ts +158 -0
  46. package/extensions/board/view/render.ts +496 -0
  47. package/extensions/board/view/styles.ts +211 -0
  48. package/extensions/board/view/team.ts +305 -0
  49. package/extensions/board/writes.ts +99 -0
  50. package/extensions/bytefly/notify/types.ts +1 -1
  51. package/extensions/bytefly/panel/commands.ts +40 -7
  52. package/extensions/bytefly/panel/settings-runtime.ts +0 -6
  53. package/extensions/bytefly/panel/settings.ts +11 -21
  54. package/extensions/bytefly/panel/tui/settings-view.ts +1 -1
  55. package/extensions/bytefly/picker/discovery.ts +0 -2
  56. package/extensions/bytefly/picker/types.ts +0 -2
  57. package/extensions/bytefly/update/check.ts +39 -0
  58. package/extensions/bytefly/update/format.ts +15 -0
  59. package/extensions/bytefly/update/register.ts +73 -34
  60. package/extensions/bytefly/update/state.ts +6 -3
  61. package/extensions/context/tui.ts +1 -1
  62. package/extensions/file-browse/{config.ts → config/config.ts} +13 -4
  63. package/extensions/file-browse/{files.ts → files/files.ts} +1 -14
  64. package/extensions/file-browse/{paths.ts → files/paths.ts} +1 -1
  65. package/extensions/file-browse/{git.ts → git/git.ts} +10 -3
  66. package/extensions/file-browse/index.ts +4 -4
  67. package/extensions/file-browse/{live.ts → live/live.ts} +54 -82
  68. package/extensions/file-browse/live/rev.ts +42 -0
  69. package/extensions/file-browse/{router.ts → transport/router.ts} +44 -17
  70. package/extensions/file-browse/transport/server.ts +110 -0
  71. package/extensions/file-browse/view/chrome.ts +83 -0
  72. package/extensions/file-browse/{client.ts → view/client.ts} +63 -1
  73. package/extensions/file-browse/view/diff-html.ts +94 -0
  74. package/extensions/file-browse/{html.ts → view/html.ts} +32 -158
  75. package/extensions/file-browse/{icons.ts → view/icons.ts} +1 -1
  76. package/extensions/file-browse/{live-client.ts → view/live-client.ts} +47 -1
  77. package/extensions/file-browse/{markdown.ts → view/markdown.ts} +7 -7
  78. package/extensions/file-browse/{raw-html.ts → view/raw-html.ts} +1 -1
  79. package/extensions/file-browse/{styles.ts → view/styles.ts} +31 -5
  80. package/extensions/file-browse/{tree.ts → view/tree.ts} +1 -1
  81. package/extensions/file-browse/{urls.ts → view/urls.ts} +1 -1
  82. package/extensions/file-read/schema.ts +2 -1
  83. package/extensions/goal/plan-route.ts +8 -2
  84. package/extensions/job/index.ts +15 -7
  85. package/extensions/memory/store.ts +12 -5
  86. package/extensions/plan/blocks.ts +23 -2
  87. package/extensions/plan/commands.ts +77 -21
  88. package/extensions/plan/feedback.ts +409 -63
  89. package/extensions/plan/index.ts +7 -5
  90. package/extensions/plan/plan-index.ts +44 -10
  91. package/extensions/plan/plan-text.ts +51 -24
  92. package/extensions/plan/plans.ts +162 -57
  93. package/extensions/plan/policy.ts +20 -12
  94. package/extensions/plan/review-prompt.ts +93 -0
  95. package/extensions/plan/review.ts +51 -95
  96. package/extensions/plan/runtime.ts +22 -10
  97. package/extensions/plan/sections.ts +112 -0
  98. package/extensions/plan/steps.ts +63 -95
  99. package/extensions/plan/tools/enter.ts +8 -3
  100. package/extensions/plan/tools/exit.ts +13 -19
  101. package/extensions/plan/tools/write.ts +8 -3
  102. package/extensions/plan/tools.ts +1 -1
  103. package/extensions/plan/tui.ts +29 -15
  104. package/extensions/plan/types.ts +29 -3
  105. package/extensions/plan/web-chrome.ts +2 -1
  106. package/extensions/plan/web-client.ts +122 -178
  107. package/extensions/plan/web-collab.ts +207 -0
  108. package/extensions/plan/web-comments.ts +269 -0
  109. package/extensions/plan/web-page.ts +96 -17
  110. package/extensions/plan/web-router.ts +109 -47
  111. package/extensions/plan/web-share-session.ts +191 -0
  112. package/extensions/plan/web-share.ts +169 -0
  113. package/extensions/plan/web-streams.ts +124 -0
  114. package/extensions/plan/web-tokens.ts +63 -0
  115. package/extensions/plan/web.ts +245 -151
  116. package/extensions/question/dialogs.ts +91 -1
  117. package/extensions/question/tools.ts +2 -1
  118. package/extensions/rewind/{commands.ts → commands/commands.ts} +5 -5
  119. package/extensions/rewind/{review.ts → commands/review.ts} +13 -13
  120. package/extensions/rewind/{rewind.ts → commands/rewind.ts} +6 -6
  121. package/extensions/rewind/{config.ts → config/config.ts} +1 -1
  122. package/extensions/rewind/index.ts +3 -3
  123. package/extensions/rewind/{policy.ts → state/policy.ts} +4 -4
  124. package/extensions/rewind/{runtime.ts → state/runtime.ts} +11 -11
  125. package/extensions/rewind/{snapshot-run.ts → state/snapshot-run.ts} +1 -1
  126. package/extensions/rewind/{timeline.ts → state/timeline.ts} +2 -2
  127. package/extensions/rewind/{format.ts → text/format.ts} +3 -3
  128. package/extensions/rewind/{git.ts → transport/git.ts} +2 -2
  129. package/extensions/rewind/{restore.ts → transport/restore.ts} +2 -2
  130. package/extensions/rewind/{snapshot.ts → transport/snapshot.ts} +1 -1
  131. package/extensions/rewind/{store.ts → transport/store.ts} +1 -1
  132. package/extensions/rewind/{checklist.ts → view/checklist.ts} +6 -6
  133. package/extensions/rewind/{hunk-picker.ts → view/hunk-picker.ts} +8 -8
  134. package/extensions/rewind/{path-picker.ts → view/path-picker.ts} +7 -7
  135. package/extensions/rewind/{review-tui.ts → view/review-tui.ts} +11 -11
  136. package/extensions/rewind/{rewind-tui.ts → view/rewind-tui.ts} +17 -11
  137. package/extensions/rewind/{status.ts → view/status.ts} +4 -4
  138. package/extensions/session-bus/commands.ts +113 -0
  139. package/extensions/session-bus/format.ts +101 -0
  140. package/extensions/session-bus/index.ts +75 -0
  141. package/extensions/session-bus/join-request.ts +40 -0
  142. package/extensions/session-bus/mail-watch.ts +134 -0
  143. package/extensions/session-bus/notice.ts +86 -0
  144. package/extensions/session-bus/overlap.ts +36 -0
  145. package/extensions/session-bus/protocol.ts +104 -0
  146. package/extensions/session-bus/resolve.ts +67 -0
  147. package/extensions/session-bus/result.ts +208 -0
  148. package/extensions/session-bus/rows.ts +171 -0
  149. package/extensions/session-bus/runtime.ts +466 -0
  150. package/extensions/session-bus/store.ts +365 -0
  151. package/extensions/session-bus/tools.ts +192 -0
  152. package/extensions/session-bus/tui.ts +394 -0
  153. package/extensions/session-bus/types.ts +98 -0
  154. package/extensions/subagent/agents.ts +9 -8
  155. package/extensions/subagent/invocation.ts +4 -2
  156. package/extensions/team/commands.ts +112 -0
  157. package/extensions/team/dispatch.ts +133 -0
  158. package/extensions/team/format.ts +105 -0
  159. package/extensions/team/index.ts +33 -0
  160. package/extensions/team/schema.ts +29 -0
  161. package/extensions/team/tools.ts +246 -0
  162. package/extensions/team/types.ts +48 -0
  163. package/extensions/watch/index.ts +15 -9
  164. package/extensions/web-access/fetch/page.ts +4 -1
  165. package/extensions/web-access/fetch/structured.ts +447 -0
  166. package/extensions/web-access/fetch/tool.ts +2 -1
  167. package/extensions/web-access/search/tool.ts +2 -1
  168. package/extensions/wechat/bridge.ts +76 -92
  169. package/extensions/wechat/{commands.ts → commands/commands.ts} +26 -18
  170. package/extensions/wechat/{doctor.ts → commands/doctor.ts} +5 -5
  171. package/extensions/wechat/{history.ts → commands/history.ts} +1 -1
  172. package/extensions/wechat/{login.ts → commands/login.ts} +3 -3
  173. package/extensions/wechat/{slash.ts → commands/slash.ts} +38 -2
  174. package/extensions/wechat/dialog/channels.ts +136 -0
  175. package/extensions/wechat/{interaction.ts → dialog/interaction.ts} +66 -51
  176. package/extensions/wechat/{prompt.ts → dialog/prompt.ts} +40 -25
  177. package/extensions/wechat/{remote-ui.ts → dialog/remote-ui.ts} +1 -1
  178. package/extensions/wechat/index.ts +10 -10
  179. package/extensions/wechat/{admission.ts → peer/admission.ts} +2 -2
  180. package/extensions/wechat/{peer-session.ts → peer/peer-session.ts} +2 -2
  181. package/extensions/wechat/{peer-worker.ts → peer/peer-worker.ts} +119 -56
  182. package/extensions/wechat/{presence.ts → peer/presence.ts} +11 -11
  183. package/extensions/wechat/{reply-pipeline.ts → peer/reply-pipeline.ts} +13 -5
  184. package/extensions/wechat/{credentials.ts → state/credentials.ts} +2 -2
  185. package/extensions/wechat/{state.ts → state/state.ts} +14 -2
  186. package/extensions/wechat/{format.ts → text/format.ts} +3 -3
  187. package/extensions/wechat/{notices.ts → text/notices.ts} +15 -7
  188. package/extensions/wechat/tools.ts +29 -12
  189. package/extensions/wechat/{client.ts → transport/client.ts} +26 -2
  190. package/extensions/wechat/{deliver.ts → transport/deliver.ts} +104 -40
  191. package/extensions/wechat/{inbound.ts → transport/inbound.ts} +5 -5
  192. package/extensions/wechat/{media.ts → transport/media.ts} +11 -5
  193. package/extensions/wechat/transport/outbound.ts +142 -0
  194. package/extensions/wechat/{poll.ts → transport/poll.ts} +3 -3
  195. package/extensions/wechat/types.ts +10 -1
  196. package/extensions/wechat/{login-screen.ts → view/login-screen.ts} +4 -4
  197. package/extensions/wechat/{status-screen.ts → view/status-screen.ts} +31 -26
  198. package/extensions/worktree/git.ts +5 -0
  199. package/extensions/worktree/guard.ts +3 -5
  200. package/extensions/worktree/registry.ts +11 -5
  201. package/extensions/worktree/status.ts +1 -3
  202. package/lib/README.md +12 -6
  203. package/lib/board/card.ts +290 -0
  204. package/lib/board/links.ts +117 -0
  205. package/lib/board/page-pointer.ts +256 -0
  206. package/lib/board/round-text.ts +72 -0
  207. package/lib/board/round.ts +89 -0
  208. package/lib/board/rules.ts +304 -0
  209. package/lib/board/session.ts +105 -0
  210. package/lib/board/store.ts +310 -0
  211. package/lib/board/view.ts +150 -0
  212. package/lib/errors.ts +12 -4
  213. package/lib/format.ts +13 -0
  214. package/lib/http/guard.ts +112 -0
  215. package/lib/http/index.ts +16 -5
  216. package/lib/http/router.ts +40 -13
  217. package/lib/http/serve.ts +234 -0
  218. package/lib/http/server.ts +29 -13
  219. package/lib/http/sink.ts +110 -0
  220. package/lib/http/token.ts +38 -0
  221. package/lib/interaction.ts +10 -0
  222. package/lib/notice.ts +29 -2
  223. package/lib/plan-entry.ts +7 -2
  224. package/lib/policy.ts +12 -2
  225. package/lib/qr.ts +64 -0
  226. package/lib/repo-key.ts +74 -0
  227. package/lib/report.ts +52 -33
  228. package/lib/requirements.ts +7 -9
  229. package/lib/session-label.ts +64 -0
  230. package/lib/session-roster.ts +130 -0
  231. package/lib/session-tool.ts +184 -0
  232. package/lib/tool-names.ts +25 -2
  233. package/lib/tui/README.md +16 -2
  234. package/lib/tui/dock-screen.ts +85 -17
  235. package/lib/tui/glyphs.ts +2 -0
  236. package/lib/tui/line-pane.ts +15 -4
  237. package/lib/tui/tool.ts +23 -4
  238. package/lib/web/README.md +5 -2
  239. package/lib/web/components.ts +6 -1
  240. package/lib/web/runtime.ts +7 -1
  241. package/lib/web/tokens.ts +25 -2
  242. package/package.json +27 -14
  243. package/skills/init/SKILL.md +80 -45
  244. package/skills/init/references/agents-md-quality.md +26 -2
  245. package/skills/init/references/interview-questions.md +36 -14
  246. package/skills/next/SKILL.md +77 -51
  247. package/skills/project-docs/SKILL.md +133 -0
  248. package/skills/project-docs/references/audit.md +131 -0
  249. package/skills/project-docs/references/changelog.md +105 -0
  250. package/skills/project-docs/references/discovery.md +127 -0
  251. package/skills/project-docs/references/readme.md +80 -0
  252. package/skills/project-docs/references/release.md +84 -0
  253. package/skills/project-docs/references/roadmap.md +93 -0
  254. package/skills/project-docs/scripts/state.ts +316 -0
  255. package/skills/refactor/SKILL.md +100 -125
  256. package/skills/refactor/references/handoff.md +35 -0
  257. package/skills/refactor/references/signals.md +54 -0
  258. package/skills/refactor/scripts/inventory.ts +587 -0
  259. package/extensions/file-browse/README.md +0 -467
  260. package/extensions/file-browse/server.ts +0 -134
  261. package/extensions/plan/README.md +0 -709
  262. package/extensions/plan/config.ts +0 -27
  263. package/extensions/wechat/outbound.ts +0 -100
  264. package/extensions/wechat/qrcode.ts +0 -46
  265. package/skills/changelog/SKILL.md +0 -148
  266. /package/extensions/file-browse/{diff.ts → text/diff.ts} +0 -0
  267. /package/extensions/file-browse/{fuzzy.ts → text/fuzzy.ts} +0 -0
  268. /package/extensions/file-browse/{palette.ts → view/palette.ts} +0 -0
  269. /package/extensions/rewind/{patch.ts → text/patch.ts} +0 -0
  270. /package/extensions/rewind/{paths.ts → text/paths.ts} +0 -0
  271. /package/extensions/rewind/{queue.ts → transport/queue.ts} +0 -0
  272. /package/extensions/rewind/{temp-index.ts → transport/temp-index.ts} +0 -0
  273. /package/extensions/wechat/{lock.ts → state/lock.ts} +0 -0
  274. /package/extensions/wechat/{channel.ts → text/channel.ts} +0 -0
@@ -3,7 +3,7 @@
3
3
  */
4
4
 
5
5
  import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
6
- import { askHuman } from "../../lib/interaction.ts";
6
+ import { askHuman, remoteLanguage } from "../../lib/interaction.ts";
7
7
  import { sanitizeLine } from "../../lib/format.ts";
8
8
  import { withRailsSuppressed } from "../../lib/rails.ts";
9
9
  import { reuseText, toolDetails } from "../../lib/tui/chrome.ts";
@@ -25,6 +25,7 @@ function dialogUI(ctx: ExtensionContext): QuestionUI {
25
25
  select: (title, options, opts) => ui.select(title, options, opts),
26
26
  input: (title, placeholder, opts) => ui.input(title, placeholder, opts),
27
27
  editor: (title, prefill) => ui.editor(title, prefill),
28
+ language: () => remoteLanguage(ctx) ?? "en",
28
29
  };
29
30
  }
30
31
 
@@ -8,13 +8,13 @@
8
8
  */
9
9
 
10
10
  import type { ExtensionAPI, ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
11
- import { withRailsSuppressed } from "../../lib/rails.ts";
12
- import { formatRewindListText, formatRewindRow } from "./format.ts";
11
+ import { withRailsSuppressed } from "../../../lib/rails.ts";
12
+ import { formatRewindListText, formatRewindRow } from "../text/format.ts";
13
13
  import { openReview } from "./review.ts";
14
14
  import { rewindTo } from "./rewind.ts";
15
- import type { RewindRuntime } from "./runtime.ts";
16
- import { RewindListComponent } from "./rewind-tui.ts";
17
- import { buildRewindPoints, type RewindPoint } from "./timeline.ts";
15
+ import type { RewindRuntime } from "../state/runtime.ts";
16
+ import { RewindListComponent } from "../view/rewind-tui.ts";
17
+ import { buildRewindPoints, type RewindPoint } from "../state/timeline.ts";
18
18
 
19
19
  /** Pick a point from the timeline, or undefined when the user cancels. */
20
20
  async function choosePoint(ctx: ExtensionCommandContext, points: RewindPoint[]): Promise<RewindPoint | undefined> {
@@ -10,10 +10,10 @@
10
10
  */
11
11
 
12
12
  import type { ExtensionAPI, ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
13
- import { messageOf } from "../../lib/errors.ts";
14
- import { sanitizeLine } from "../../lib/format.ts";
15
- import { isPlanModeEnabled } from "../../lib/plan-state.ts";
16
- import { withRailsSuppressed } from "../../lib/rails.ts";
13
+ import { messageOf } from "../../../lib/errors.ts";
14
+ import { sanitizeLine } from "../../../lib/format.ts";
15
+ import { isPlanModeEnabled } from "../../../lib/plan-state.ts";
16
+ import { withRailsSuppressed } from "../../../lib/rails.ts";
17
17
  import {
18
18
  boundDiff,
19
19
  formatHunkRevertBody,
@@ -23,20 +23,20 @@ import {
23
23
  formatRevertSelectedBody,
24
24
  formatReviewListText,
25
25
  formatReviewRevertText,
26
- } from "./format.ts";
27
- import { HunkPickerComponent } from "./hunk-picker.ts";
28
- import { buildHunkPatch, parseFilePatch } from "./patch.ts";
29
- import { entryPaths, toReviewEntries, type ReviewEntry } from "./paths.ts";
26
+ } from "../text/format.ts";
27
+ import { HunkPickerComponent } from "../view/hunk-picker.ts";
28
+ import { buildHunkPatch, parseFilePatch } from "../text/patch.ts";
29
+ import { entryPaths, toReviewEntries, type ReviewEntry } from "../text/paths.ts";
30
30
  import {
31
31
  ReviewDiffComponent,
32
32
  ReviewListComponent,
33
33
  type ReviewDiffAction,
34
34
  type ReviewListResult,
35
- } from "./review-tui.ts";
36
- import type { RestorePlan } from "./restore.ts";
37
- import type { RewindRuntime } from "./runtime.ts";
38
- import { buildRewindPoints, type RewindPoint } from "./timeline.ts";
39
- import type { Snapshot, RestoreSummary } from "./types.ts";
35
+ } from "../view/review-tui.ts";
36
+ import type { RestorePlan } from "../transport/restore.ts";
37
+ import type { RewindRuntime } from "../state/runtime.ts";
38
+ import { buildRewindPoints, type RewindPoint } from "../state/timeline.ts";
39
+ import type { Snapshot, RestoreSummary } from "../types.ts";
40
40
 
41
41
  /** One reviewable view of the working tree. */
42
42
  interface ReviewView {
@@ -9,13 +9,13 @@
9
9
  */
10
10
 
11
11
  import type { ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
12
- import { withRailsSuppressed } from "../../lib/rails.ts";
12
+ import { withRailsSuppressed } from "../../../lib/rails.ts";
13
13
  import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
14
- import { formatChangeSummary, formatRestoreText, previewDiffText } from "./format.ts";
15
- import { PathPickerComponent } from "./path-picker.ts";
16
- import type { ChangedPath } from "./paths.ts";
17
- import type { RewindRuntime } from "./runtime.ts";
18
- import { rewindScopes, type RewindPoint, type RewindScope } from "./timeline.ts";
14
+ import { formatChangeSummary, formatRestoreText, previewDiffText } from "../text/format.ts";
15
+ import { PathPickerComponent } from "../view/path-picker.ts";
16
+ import type { ChangedPath } from "../text/paths.ts";
17
+ import type { RewindRuntime } from "../state/runtime.ts";
18
+ import { rewindScopes, type RewindPoint, type RewindScope } from "../state/timeline.ts";
19
19
 
20
20
  /** Human labels for the scope picker, in menu order. */
21
21
  const SCOPE_LABELS: Record<RewindScope, string> = {
@@ -6,7 +6,7 @@
6
6
  * malformed documents are ignored, and every value is clamped to a safe range.
7
7
  */
8
8
 
9
- import { clampInteger, cleanString, loadConfigSection, stringList } from "../../lib/config.ts";
9
+ import { clampInteger, cleanString, loadConfigSection, stringList } from "../../../lib/config.ts";
10
10
 
11
11
  export interface RewindConfig {
12
12
  /** Take one automatic snapshot per user prompt. Default: true. */
@@ -16,9 +16,9 @@
16
16
 
17
17
  import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
18
18
  import { isExtensionEnabled } from "../../lib/env.ts";
19
- import { registerCommands } from "./commands.ts";
20
- import { createRuntime } from "./runtime.ts";
21
- import { createSnapshotRun } from "./snapshot-run.ts";
19
+ import { registerCommands } from "./commands/commands.ts";
20
+ import { createRuntime } from "./state/runtime.ts";
21
+ import { createSnapshotRun } from "./state/snapshot-run.ts";
22
22
 
23
23
  export function registerRewind(pi: ExtensionAPI): void {
24
24
  const runtime = createRuntime(pi);
@@ -9,12 +9,12 @@
9
9
  */
10
10
 
11
11
  import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
12
- import { createReadOnlyPolicy } from "../../lib/policy.ts";
13
- import { ASK_USER_QUESTION_TOOL, GOAL_TOOL, TODO_TOOL } from "../../lib/tool-names.ts";
14
- import type { RewindConfig } from "./config.ts";
12
+ import { createReadOnlyPolicy, WORKSPACE_READERS } from "../../../lib/policy.ts";
13
+ import { ASK_USER_QUESTION_TOOL, GOAL_TOOL, TODO_TOOL } from "../../../lib/tool-names.ts";
14
+ import type { RewindConfig } from "../config/config.ts";
15
15
 
16
16
  /** Tools that only read files or track session state, so they never snapshot. */
17
- const READER_TOOLS = ["read", "grep", "find", "ls", TODO_TOOL, GOAL_TOOL];
17
+ const READER_TOOLS = [...WORKSPACE_READERS, TODO_TOOL, GOAL_TOOL];
18
18
 
19
19
  /** The interactive tool: it prompts the user and never touches the working tree. */
20
20
  const SESSION_TOOLS = [ASK_USER_QUESTION_TOOL];
@@ -9,8 +9,8 @@
9
9
  */
10
10
 
11
11
  import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
12
- import { resolveEffectiveCwd } from "../../lib/env.ts";
13
- import { loadConfig, type RewindConfig } from "./config.ts";
12
+ import { resolveEffectiveCwd } from "../../../lib/env.ts";
13
+ import { loadConfig, type RewindConfig } from "../config/config.ts";
14
14
  import {
15
15
  applyPatchReverse,
16
16
  createRewindRunner,
@@ -19,16 +19,16 @@ import {
19
19
  repoRoot,
20
20
  revParse,
21
21
  type RunGit,
22
- } from "./git.ts";
23
- import { createOperationQueue } from "./queue.ts";
24
- import { applyRestore, planRestore, type PlanResult, type RestoreInput } from "./restore.ts";
25
- import type { PathStat } from "./paths.ts";
26
- import { createSnapshot } from "./snapshot.ts";
27
- import { createStatusChip } from "./status.ts";
28
- import { belongsToRoot, listSnapshots, pruneSnapshots } from "./store.ts";
29
- import { createTempIndexStore } from "./temp-index.ts";
22
+ } from "../transport/git.ts";
23
+ import { createOperationQueue } from "../transport/queue.ts";
24
+ import { applyRestore, planRestore, type PlanResult, type RestoreInput } from "../transport/restore.ts";
25
+ import type { PathStat } from "../text/paths.ts";
26
+ import { createSnapshot } from "../transport/snapshot.ts";
27
+ import { createStatusChip } from "../view/status.ts";
28
+ import { belongsToRoot, listSnapshots, pruneSnapshots } from "../transport/store.ts";
29
+ import { createTempIndexStore } from "../transport/temp-index.ts";
30
30
  import { lastUserEntryId } from "./timeline.ts";
31
- import type { Snapshot, SnapshotReason, RestoreSummary } from "./types.ts";
31
+ import type { Snapshot, SnapshotReason, RestoreSummary } from "../types.ts";
32
32
 
33
33
  export interface SnapshotOptions {
34
34
  reason: SnapshotReason;
@@ -10,7 +10,7 @@
10
10
  */
11
11
 
12
12
  import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
13
- import { summarizePrompt } from "./format.ts";
13
+ import { summarizePrompt } from "../text/format.ts";
14
14
  import { createSnapshotPolicy, type SnapshotPolicy } from "./policy.ts";
15
15
  import type { RewindRuntime } from "./runtime.ts";
16
16
 
@@ -9,8 +9,8 @@
9
9
  */
10
10
 
11
11
  import type { SessionEntry, SessionMessageEntry } from "@earendil-works/pi-coding-agent";
12
- import { summarizePrompt } from "./format.ts";
13
- import type { Snapshot } from "./types.ts";
12
+ import { summarizePrompt } from "../text/format.ts";
13
+ import type { Snapshot } from "../types.ts";
14
14
 
15
15
  /** What a rewind can restore for one point. */
16
16
  export type RewindScope = "both" | "conversation" | "code";
@@ -7,10 +7,10 @@
7
7
  */
8
8
 
9
9
  import { sliceByColumn, truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
10
- import { sanitizeLine, stripControlChars } from "../../lib/format.ts";
11
- import { GLYPHS, SEPARATORS } from "../../lib/tui/glyphs.ts";
10
+ import { sanitizeLine, stripControlChars } from "../../../lib/format.ts";
11
+ import { GLYPHS, SEPARATORS } from "../../../lib/tui/glyphs.ts";
12
12
  import { SELECTION_MARKS, type ReviewEntry } from "./paths.ts";
13
- import type { RestoreSummary } from "./types.ts";
13
+ import type { RestoreSummary } from "../types.ts";
14
14
 
15
15
  /** Longest prompt summary shown before truncation. */
16
16
  const LABEL_WIDTH = 48;
@@ -23,8 +23,8 @@ import {
23
23
  revParseMany,
24
24
  runGitOrThrow as run,
25
25
  type RunGit,
26
- } from "../../lib/git/index.ts";
27
- import { parseNameStatus, parseNumStat, type ChangedPath, type PathStat } from "./paths.ts";
26
+ } from "../../../lib/git/index.ts";
27
+ import { parseNameStatus, parseNumStat, type ChangedPath, type PathStat } from "../text/paths.ts";
28
28
 
29
29
  // Re-export exactly the shared helpers this extension consumes, so rewind code
30
30
  // has one git import surface instead of reaching into `lib/git` directly.
@@ -26,8 +26,8 @@ import {
26
26
  treeFromWorkingTree,
27
27
  type RunGit,
28
28
  } from "./git.ts";
29
- import { entryPaths, summarize, type ChangedPath } from "./paths.ts";
30
- import type { Snapshot, RestoreSummary } from "./types.ts";
29
+ import { entryPaths, summarize, type ChangedPath } from "../text/paths.ts";
30
+ import type { Snapshot, RestoreSummary } from "../types.ts";
31
31
 
32
32
  export interface RestoreDeps {
33
33
  runGit: RunGit;
@@ -18,7 +18,7 @@ import {
18
18
  type RunGit,
19
19
  } from "./git.ts";
20
20
  import { encodeMessage, refFor, META_VERSION, type SnapshotMeta } from "./store.ts";
21
- import type { Snapshot, SnapshotReason } from "./types.ts";
21
+ import type { Snapshot, SnapshotReason } from "../types.ts";
22
22
 
23
23
  export interface SnapshotDeps {
24
24
  runGit: RunGit;
@@ -7,7 +7,7 @@
7
7
  */
8
8
 
9
9
  import { commitMessages, deleteRef, listRefs, type RunGit } from "./git.ts";
10
- import type { Snapshot, SnapshotReason } from "./types.ts";
10
+ import type { Snapshot, SnapshotReason } from "../types.ts";
11
11
 
12
12
  /** Prefix of the metadata line in a snapshot commit body. */
13
13
  export const META_MARKER = "pi-rewind: ";
@@ -14,12 +14,12 @@
14
14
 
15
15
  import type { Theme } from "@earendil-works/pi-coding-agent";
16
16
  import { Key, matchesKey, type Component, type TuiMouseEvent, type TuiMouseEventResult } from "@earendil-works/pi-tui";
17
- import { detailBlockRows, dockListFrame, type ViewportRowsSource } from "../../lib/tui/chrome.ts";
18
- import { clip } from "../../lib/tui/columns.ts";
19
- import { fitRows, formatRange, isCloseKey, ListCursor, navigateList, scrollList } from "../../lib/tui/cursor.ts";
20
- import { emptyState } from "../../lib/tui/rows.ts";
21
- import { titleRule } from "../../lib/tui/rules.ts";
22
- import { paint } from "../../lib/tui/tokens.ts";
17
+ import { detailBlockRows, dockListFrame, type ViewportRowsSource } from "../../../lib/tui/chrome.ts";
18
+ import { clip } from "../../../lib/tui/columns.ts";
19
+ import { fitRows, formatRange, isCloseKey, ListCursor, navigateList, scrollList } from "../../../lib/tui/cursor.ts";
20
+ import { emptyState } from "../../../lib/tui/rows.ts";
21
+ import { titleRule } from "../../../lib/tui/rules.ts";
22
+ import { paint } from "../../../lib/tui/tokens.ts";
23
23
 
24
24
  /** Rows the checklist shows when the terminal height is unknown. */
25
25
  const SCREEN_DEFAULT_ITEMS = 12;
@@ -11,15 +11,15 @@
11
11
  */
12
12
 
13
13
  import type { Theme } from "@earendil-works/pi-coding-agent";
14
- import { sanitizeLine } from "../../lib/format.ts";
15
- import { screenHint, type ViewportRowsSource } from "../../lib/tui/chrome.ts";
16
- import { clip } from "../../lib/tui/columns.ts";
17
- import { SEPARATORS } from "../../lib/tui/glyphs.ts";
18
- import { checkbox, listRow } from "../../lib/tui/rows.ts";
19
- import { paint } from "../../lib/tui/tokens.ts";
14
+ import { sanitizeLine } from "../../../lib/format.ts";
15
+ import { screenHint, type ViewportRowsSource } from "../../../lib/tui/chrome.ts";
16
+ import { clip } from "../../../lib/tui/columns.ts";
17
+ import { SEPARATORS } from "../../../lib/tui/glyphs.ts";
18
+ import { checkbox, listRow } from "../../../lib/tui/rows.ts";
19
+ import { paint } from "../../../lib/tui/tokens.ts";
20
20
  import { ChecklistScreen } from "./checklist.ts";
21
- import { formatReviewEntryCounts } from "./format.ts";
22
- import type { Hunk } from "./patch.ts";
21
+ import { formatReviewEntryCounts } from "../text/format.ts";
22
+ import type { Hunk } from "../text/patch.ts";
23
23
 
24
24
  export interface HunkPickerOptions {
25
25
  /** The file the hunks belong to. */
@@ -13,14 +13,14 @@
13
13
  */
14
14
 
15
15
  import type { Theme } from "@earendil-works/pi-coding-agent";
16
- import { sanitizeLine } from "../../lib/format.ts";
17
- import { screenHint, type ViewportRowsSource } from "../../lib/tui/chrome.ts";
18
- import { clip } from "../../lib/tui/columns.ts";
19
- import { SEPARATORS } from "../../lib/tui/glyphs.ts";
20
- import { checkbox, listRow } from "../../lib/tui/rows.ts";
21
- import { paint } from "../../lib/tui/tokens.ts";
16
+ import { sanitizeLine } from "../../../lib/format.ts";
17
+ import { screenHint, type ViewportRowsSource } from "../../../lib/tui/chrome.ts";
18
+ import { clip } from "../../../lib/tui/columns.ts";
19
+ import { SEPARATORS } from "../../../lib/tui/glyphs.ts";
20
+ import { checkbox, listRow } from "../../../lib/tui/rows.ts";
21
+ import { paint } from "../../../lib/tui/tokens.ts";
22
22
  import { ChecklistScreen } from "./checklist.ts";
23
- import { baseName, expandGroup, groupPaths, SELECTION_MARKS, type ChangedPath, type PathGroup } from "./paths.ts";
23
+ import { baseName, expandGroup, groupPaths, SELECTION_MARKS, type ChangedPath, type PathGroup } from "../text/paths.ts";
24
24
 
25
25
  export interface PathPickerOptions {
26
26
  /** The changed paths the snapshot differs on. */
@@ -13,18 +13,18 @@
13
13
 
14
14
  import type { Theme } from "@earendil-works/pi-coding-agent";
15
15
  import type { Component, TuiMouseEvent, TuiMouseEventResult } from "@earendil-works/pi-tui";
16
- import { clip } from "../../lib/tui/columns.ts";
17
- import { detailBlockRows, dockListFrame, screenHint, type ViewportRowsSource } from "../../lib/tui/chrome.ts";
18
- import { sanitizeLine } from "../../lib/format.ts";
19
- import { fitRows, formatRange, isCloseKey, wheelDelta } from "../../lib/tui/cursor.ts";
20
- import { SEPARATORS } from "../../lib/tui/glyphs.ts";
21
- import { LinePane } from "../../lib/tui/line-pane.ts";
22
- import { checkbox, emptyState, listRow } from "../../lib/tui/rows.ts";
23
- import { titleRule } from "../../lib/tui/rules.ts";
24
- import { paint, type TuiRole } from "../../lib/tui/tokens.ts";
16
+ import { clip } from "../../../lib/tui/columns.ts";
17
+ import { detailBlockRows, dockListFrame, screenHint, type ViewportRowsSource } from "../../../lib/tui/chrome.ts";
18
+ import { sanitizeLine } from "../../../lib/format.ts";
19
+ import { fitRows, formatRange, isCloseKey, wheelDelta } from "../../../lib/tui/cursor.ts";
20
+ import { SEPARATORS } from "../../../lib/tui/glyphs.ts";
21
+ import { LinePane } from "../../../lib/tui/line-pane.ts";
22
+ import { checkbox, emptyState, listRow } from "../../../lib/tui/rows.ts";
23
+ import { titleRule } from "../../../lib/tui/rules.ts";
24
+ import { paint, type TuiRole } from "../../../lib/tui/tokens.ts";
25
25
  import { ChecklistScreen } from "./checklist.ts";
26
- import { formatReviewDetail, formatReviewEntryCounts, formatReviewSummary } from "./format.ts";
27
- import { SELECTION_MARKS, type PathChange, type ReviewEntry } from "./paths.ts";
26
+ import { formatReviewDetail, formatReviewEntryCounts, formatReviewSummary } from "../text/format.ts";
27
+ import { SELECTION_MARKS, type PathChange, type ReviewEntry } from "../text/paths.ts";
28
28
 
29
29
  /** Rows a diff screen shows when the terminal height is unknown. */
30
30
  const DIFF_DEFAULT_ITEMS = 20;
@@ -10,15 +10,15 @@
10
10
 
11
11
  import type { Theme } from "@earendil-works/pi-coding-agent";
12
12
  import { Key, matchesKey, type Component, type TuiMouseEvent, type TuiMouseEventResult } from "@earendil-works/pi-tui";
13
- import { fitRows, formatRange, isCloseKey, ListCursor, navigateList, scrollList } from "../../lib/tui/cursor.ts";
14
- import { detailBlockRows, dockListFrame, screenHint, type ViewportRowsSource } from "../../lib/tui/chrome.ts";
15
- import { clip } from "../../lib/tui/columns.ts";
16
- import { SEPARATORS } from "../../lib/tui/glyphs.ts";
17
- import { emptyState, listRow } from "../../lib/tui/rows.ts";
18
- import { titleRule } from "../../lib/tui/rules.ts";
19
- import { paint } from "../../lib/tui/tokens.ts";
20
- import { formatRewindDetail, formatRewindParts } from "./format.ts";
21
- import type { RewindPoint } from "./timeline.ts";
13
+ import { fitRows, formatRange, isCloseKey, ListCursor, navigateList, scrollList } from "../../../lib/tui/cursor.ts";
14
+ import { detailBlockRows, dockListFrame, screenHint, type ViewportRowsSource } from "../../../lib/tui/chrome.ts";
15
+ import { clip } from "../../../lib/tui/columns.ts";
16
+ import { SEPARATORS } from "../../../lib/tui/glyphs.ts";
17
+ import { emptyState, listRow } from "../../../lib/tui/rows.ts";
18
+ import { titleRule } from "../../../lib/tui/rules.ts";
19
+ import { paint } from "../../../lib/tui/tokens.ts";
20
+ import { formatRewindDetail, formatRewindParts } from "../text/format.ts";
21
+ import type { RewindPoint } from "../state/timeline.ts";
22
22
 
23
23
  export interface RewindListOptions {
24
24
  points: RewindPoint[];
@@ -57,7 +57,7 @@ export class RewindListComponent implements Component {
57
57
  }
58
58
  const count = this.points.length;
59
59
  if (navigateList(data, this.cursor, count)) return;
60
- if (matchesKey(data, Key.enter) || data === "r") {
60
+ if (matchesKey(data, Key.enter)) {
61
61
  const point = this.points[this.cursor.selected];
62
62
  if (point) this.options.onClose(point);
63
63
  }
@@ -139,6 +139,12 @@ export class RewindListComponent implements Component {
139
139
 
140
140
  /** The key-hint row, with the primary action in the accent role. */
141
141
  private hint(width: number): string {
142
- return screenHint(this.theme, width, ["Esc close", { text: "Enter choose", color: "accent" }, "↑/↓ or k/j select"]);
142
+ return screenHint(this.theme, width, [
143
+ "Esc close",
144
+ { text: "Enter choose", color: "accent" },
145
+ "↑/↓ or k/j select",
146
+ "PgUp/PgDn",
147
+ "g/G or Home/End",
148
+ ]);
143
149
  }
144
150
  }
@@ -8,10 +8,10 @@
8
8
  */
9
9
 
10
10
  import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
11
- import { GLYPHS, STATUS_KEYS } from "../../lib/tui/glyphs.ts";
12
- import { paint } from "../../lib/tui/tokens.ts";
13
- import type { RewindConfig } from "./config.ts";
14
- import { userMessagesFromBranch } from "./timeline.ts";
11
+ import { GLYPHS, STATUS_KEYS } from "../../../lib/tui/glyphs.ts";
12
+ import { paint } from "../../../lib/tui/tokens.ts";
13
+ import type { RewindConfig } from "../config/config.ts";
14
+ import { userMessagesFromBranch } from "../state/timeline.ts";
15
15
 
16
16
  const STATUS_KEY = STATUS_KEYS.rewind;
17
17
  const STATUS_GLYPH = GLYPHS.rewind;
@@ -0,0 +1,113 @@
1
+ /**
2
+ * The `/sessions` command: one act, no arguments.
3
+ *
4
+ * In the TUI it opens the live board: `Tab` cycles Sessions, Inbox, and Claims,
5
+ * and `w`/`x` act on this session's own watch and claims. Every other mode prints
6
+ * the compact listing, because there is no dock to mount the screen in. Reading is
7
+ * not joining, so the board is empty until this session joins — and a command
8
+ * context cannot name a session, so the join is `session({action:"join"})`,
9
+ * `/team join [<label>]`, or the board's `w`.
10
+ */
11
+
12
+ import type { ExtensionAPI, ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
13
+ import { messageOf } from "../../lib/errors.ts";
14
+ import { sanitizeLine } from "../../lib/format.ts";
15
+ import { withPolledScreen } from "../../lib/screen-session.ts";
16
+ import { formatJoin, formatStatus } from "./format.ts";
17
+ import { COMMAND_NAME } from "./protocol.ts";
18
+ import type { SessionBus } from "./runtime.ts";
19
+ import { SessionListComponent } from "./tui.ts";
20
+
21
+ /** How often the open board re-reads the bus. */
22
+ const BOARD_POLL_MS = 1_000;
23
+
24
+ /**
25
+ * One board read at a time, shared by the open screen's poll and its watch verb.
26
+ *
27
+ * A read that is still running is skipped rather than queued, and a failed read
28
+ * leaves the last board on screen; the bus's own heartbeat keeps this session's
29
+ * record fresh, so a poll never has to write. Both reads are read-only: the
30
+ * snapshot neither prunes nor refreshes, and the peek neither consumes nor marks.
31
+ */
32
+ function createBoardReader(bus: SessionBus): (screen: SessionListComponent) => Promise<void> {
33
+ let busy = false;
34
+ return async (screen) => {
35
+ if (busy) return;
36
+ busy = true;
37
+ try {
38
+ const [status, messages] = await Promise.all([bus.snapshot(), bus.peek()]);
39
+ screen.setBoard({ status, messages });
40
+ } catch {
41
+ // Best-effort: the next tick tries again, and the board keeps its last read.
42
+ } finally {
43
+ busy = false;
44
+ }
45
+ };
46
+ }
47
+
48
+ /** Open the TUI board, and resolve when it closes. */
49
+ async function openSessionsScreen(pi: ExtensionAPI, ctx: ExtensionCommandContext, bus: SessionBus): Promise<void> {
50
+ await bus.start(ctx);
51
+ const [status, messages] = await Promise.all([bus.snapshot(), bus.peek()]);
52
+ const first = { status, messages };
53
+ let read: ((screen: SessionListComponent) => Promise<void>) | undefined;
54
+ await withPolledScreen(
55
+ pi,
56
+ ctx,
57
+ (screen) => {
58
+ const reader = createBoardReader(bus);
59
+ read = reader;
60
+ // The verbs repaint the board they belong to; their callbacks only run after
61
+ // construction, so a holder keeps the wiring one-directional.
62
+ const holder: { screen?: SessionListComponent } = {};
63
+ const component = new SessionListComponent({
64
+ latest: () => first,
65
+ theme: screen.theme,
66
+ callbacks: {
67
+ toggleWatch: async (armed) => {
68
+ // The board's toggle is the same act as a join, so it says the same thing.
69
+ const joined = await bus.join({ listen: !armed });
70
+ if (holder.screen) await reader(holder.screen);
71
+ return formatJoin(joined.label, joined.watching);
72
+ },
73
+ releaseClaim: async (path) => {
74
+ const released = await bus.releaseStored(path);
75
+ if (holder.screen) await reader(holder.screen);
76
+ const name = sanitizeLine(path);
77
+ return released ? `Released ${name}.` : `${name} is no longer yours.`;
78
+ },
79
+ },
80
+ onClose: screen.close,
81
+ requestRender: screen.requestRender,
82
+ viewportRowsSource: screen.viewportRows,
83
+ });
84
+ holder.screen = component;
85
+ return component;
86
+ },
87
+ { pollMs: BOARD_POLL_MS, poll: (component) => void read?.(component) },
88
+ );
89
+ }
90
+
91
+ async function open(ctx: ExtensionCommandContext, pi: ExtensionAPI, bus: SessionBus): Promise<void> {
92
+ try {
93
+ if (ctx.mode === "tui") {
94
+ await openSessionsScreen(pi, ctx, bus);
95
+ return;
96
+ }
97
+ await bus.start(ctx);
98
+ ctx.ui.notify(formatStatus(await bus.status()), "info");
99
+ } catch (error) {
100
+ ctx.ui.notify(`Session bus: ${messageOf(error)}`, "warning");
101
+ }
102
+ }
103
+
104
+ export function registerCommands(pi: ExtensionAPI, bus: SessionBus): void {
105
+ pi.registerCommand(COMMAND_NAME, {
106
+ description: "Open the bus board: sessions, unread mail, and path claims",
107
+ // One command, one act: an argument is not a sub-command, so it is ignored
108
+ // rather than warned about — the board is what the user asked for.
109
+ handler: async (_args, ctx) => {
110
+ await open(ctx, pi, bus);
111
+ },
112
+ });
113
+ }