gsd-pi 2.44.0 → 2.45.0-dev.e0ee972

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 (505) hide show
  1. package/README.md +30 -12
  2. package/dist/help-text.js +1 -1
  3. package/dist/loader.js +34 -0
  4. package/dist/resources/extensions/gsd/activity-log.js +7 -0
  5. package/dist/resources/extensions/gsd/auto/infra-errors.js +3 -0
  6. package/dist/resources/extensions/gsd/auto/phases.js +52 -45
  7. package/dist/resources/extensions/gsd/auto/run-unit.js +6 -3
  8. package/dist/resources/extensions/gsd/auto-prompts.js +24 -1
  9. package/dist/resources/extensions/gsd/auto-start.js +31 -2
  10. package/dist/resources/extensions/gsd/auto-timers.js +57 -3
  11. package/dist/resources/extensions/gsd/auto-worktree-sync.js +4 -0
  12. package/dist/resources/extensions/gsd/auto-worktree.js +14 -10
  13. package/dist/resources/extensions/gsd/auto.js +34 -8
  14. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +168 -11
  15. package/dist/resources/extensions/gsd/bootstrap/system-context.js +46 -12
  16. package/dist/resources/extensions/gsd/commands/catalog.js +7 -1
  17. package/dist/resources/extensions/gsd/commands/handlers/core.js +2 -0
  18. package/dist/resources/extensions/gsd/commands/handlers/ops.js +10 -0
  19. package/dist/resources/extensions/gsd/commands/handlers/workflow.js +5 -0
  20. package/dist/resources/extensions/gsd/commands-mcp-status.js +187 -0
  21. package/dist/resources/extensions/gsd/db-writer.js +40 -22
  22. package/dist/resources/extensions/gsd/doctor-checks.js +1 -1
  23. package/dist/resources/extensions/gsd/doctor.js +10 -2
  24. package/dist/resources/extensions/gsd/git-service.js +8 -3
  25. package/dist/resources/extensions/gsd/gsd-db.js +17 -2
  26. package/dist/resources/extensions/gsd/markdown-renderer.js +1 -1
  27. package/dist/resources/extensions/gsd/preferences-types.js +2 -2
  28. package/dist/resources/extensions/gsd/preferences.js +17 -5
  29. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +2 -4
  30. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  31. package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +6 -6
  32. package/dist/resources/extensions/gsd/prompts/replan-slice.md +3 -14
  33. package/dist/resources/extensions/gsd/prompts/rethink.md +78 -0
  34. package/dist/resources/extensions/gsd/prompts/validate-milestone.md +7 -37
  35. package/dist/resources/extensions/gsd/provider-error-pause.js +7 -0
  36. package/dist/resources/extensions/gsd/repo-identity.js +45 -7
  37. package/dist/resources/extensions/gsd/rethink.js +115 -0
  38. package/dist/resources/extensions/gsd/state.js +41 -3
  39. package/dist/resources/extensions/gsd/tools/plan-slice.js +1 -0
  40. package/dist/resources/extensions/gsd/tools/plan-task.js +1 -0
  41. package/dist/resources/extensions/gsd/tools/replan-slice.js +2 -0
  42. package/dist/resources/extensions/gsd/tools/validate-milestone.js +88 -0
  43. package/dist/resources/extensions/gsd/workflow-logger.js +138 -0
  44. package/dist/resources/extensions/gsd/worktree-manager.js +34 -3
  45. package/dist/resources/extensions/gsd/worktree-resolver.js +43 -0
  46. package/dist/resources/extensions/mcp-client/index.js +14 -0
  47. package/dist/resources/extensions/voice/index.js +11 -16
  48. package/dist/resources/extensions/voice/linux-ready.js +67 -0
  49. package/dist/web/standalone/.next/BUILD_ID +1 -1
  50. package/dist/web/standalone/.next/app-path-routes-manifest.json +15 -15
  51. package/dist/web/standalone/.next/build-manifest.json +4 -4
  52. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  53. package/dist/web/standalone/.next/react-loadable-manifest.json +2 -2
  54. package/dist/web/standalone/.next/required-server-files.json +3 -3
  55. package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
  56. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  57. package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
  58. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  59. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  60. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  61. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  62. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  63. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  64. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  65. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  66. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  67. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  68. package/dist/web/standalone/.next/server/app/_not-found.rsc +5 -5
  69. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +5 -5
  70. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  71. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +4 -4
  72. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  73. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  74. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  75. package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
  76. package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
  77. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
  78. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
  79. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
  80. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
  81. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
  82. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
  83. package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
  84. package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
  85. package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
  86. package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
  87. package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
  88. package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
  89. package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
  90. package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
  91. package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
  92. package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
  93. package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
  94. package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
  95. package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
  96. package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  97. package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
  98. package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
  99. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  100. package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  101. package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
  102. package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
  103. package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
  104. package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
  105. package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
  106. package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
  107. package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
  108. package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
  109. package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
  110. package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
  111. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  112. package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
  113. package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
  114. package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
  115. package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
  116. package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  117. package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
  118. package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
  119. package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +5 -5
  120. package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
  121. package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
  122. package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
  123. package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
  124. package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
  125. package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
  126. package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
  127. package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
  128. package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
  129. package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
  130. package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
  131. package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
  132. package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
  133. package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
  134. package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
  135. package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
  136. package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
  137. package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
  138. package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
  139. package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +2 -2
  140. package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
  141. package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
  142. package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
  143. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +2 -2
  144. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
  145. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +4 -4
  146. package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
  147. package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
  148. package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
  149. package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
  150. package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
  151. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  152. package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  153. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  154. package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
  155. package/dist/web/standalone/.next/server/app/index.html +1 -1
  156. package/dist/web/standalone/.next/server/app/index.rsc +6 -6
  157. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  158. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +6 -6
  159. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  160. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +4 -4
  161. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  162. package/dist/web/standalone/.next/server/app/page.js +2 -2
  163. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  164. package/dist/web/standalone/.next/server/app-paths-manifest.json +15 -15
  165. package/dist/web/standalone/.next/server/chunks/229.js +1 -1
  166. package/dist/web/standalone/.next/server/chunks/471.js +3 -3
  167. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  168. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  169. package/dist/web/standalone/.next/server/middleware.js +2 -2
  170. package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
  171. package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
  172. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  173. package/dist/web/standalone/.next/server/pages/500.html +2 -2
  174. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  175. package/dist/web/standalone/.next/static/chunks/4024.11ca5c01938e5948.js +9 -0
  176. package/dist/web/standalone/.next/static/chunks/{3721.bf31263de6d5fa46.js → 485.243af25f0cdf50d6.js} +2 -2
  177. package/dist/web/standalone/.next/static/chunks/app/_not-found/{page-2f24283c162b6ab3.js → page-f2a7482d42a5614b.js} +1 -1
  178. package/dist/web/standalone/.next/static/chunks/app/{layout-9ecfd95f343793f0.js → layout-a16c7a7ecdf0c2cf.js} +1 -1
  179. package/dist/web/standalone/.next/static/chunks/app/page-6654a8cca61a3d1c.js +1 -0
  180. package/dist/web/standalone/.next/static/chunks/main-app-fdab67f7802d7832.js +1 -0
  181. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.js +1 -0
  182. package/dist/web/standalone/.next/static/chunks/webpack-0a4cd455ec4197d2.js +1 -0
  183. package/dist/web/standalone/.next/static/css/dd4ae3f58ac9b600.css +1 -0
  184. package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
  185. package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
  186. package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
  187. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
  188. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
  189. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
  190. package/dist/web/standalone/server.js +1 -1
  191. package/package.json +1 -1
  192. package/packages/native/dist/stream-process/index.js +2 -2
  193. package/packages/native/src/__tests__/stream-process.test.mjs +34 -0
  194. package/packages/native/src/stream-process/index.ts +2 -2
  195. package/packages/pi-coding-agent/dist/core/auth-storage.d.ts +3 -1
  196. package/packages/pi-coding-agent/dist/core/auth-storage.d.ts.map +1 -1
  197. package/packages/pi-coding-agent/dist/core/auth-storage.js +15 -1
  198. package/packages/pi-coding-agent/dist/core/auth-storage.js.map +1 -1
  199. package/packages/pi-coding-agent/dist/core/auth-storage.test.js +6 -8
  200. package/packages/pi-coding-agent/dist/core/auth-storage.test.js.map +1 -1
  201. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.d.ts.map +1 -1
  202. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.js +2 -0
  203. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.js.map +1 -1
  204. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js +24 -26
  205. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js.map +1 -1
  206. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +2 -1
  207. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
  208. package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
  209. package/packages/pi-coding-agent/dist/core/fs-utils.test.js +29 -48
  210. package/packages/pi-coding-agent/dist/core/fs-utils.test.js.map +1 -1
  211. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.d.ts +4 -0
  212. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.d.ts.map +1 -1
  213. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.js +10 -5
  214. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.js.map +1 -1
  215. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.test.d.ts +2 -0
  216. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.test.d.ts.map +1 -0
  217. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.test.js +185 -0
  218. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.test.js.map +1 -0
  219. package/packages/pi-coding-agent/dist/core/local-model-check.d.ts +15 -0
  220. package/packages/pi-coding-agent/dist/core/local-model-check.d.ts.map +1 -0
  221. package/packages/pi-coding-agent/dist/core/local-model-check.js +41 -0
  222. package/packages/pi-coding-agent/dist/core/local-model-check.js.map +1 -0
  223. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js +239 -10
  224. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js.map +1 -1
  225. package/packages/pi-coding-agent/dist/core/model-registry.d.ts +13 -1
  226. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  227. package/packages/pi-coding-agent/dist/core/model-registry.js +40 -3
  228. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  229. package/packages/pi-coding-agent/dist/core/package-commands.test.js +206 -195
  230. package/packages/pi-coding-agent/dist/core/package-commands.test.js.map +1 -1
  231. package/packages/pi-coding-agent/dist/core/resolve-config-value.test.js +34 -44
  232. package/packages/pi-coding-agent/dist/core/resolve-config-value.test.js.map +1 -1
  233. package/packages/pi-coding-agent/dist/core/session-manager.test.js +30 -34
  234. package/packages/pi-coding-agent/dist/core/session-manager.test.js.map +1 -1
  235. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +3 -0
  236. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  237. package/packages/pi-coding-agent/dist/core/settings-manager.js +6 -0
  238. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  239. package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.js +10 -12
  240. package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.js.map +1 -1
  241. package/packages/pi-coding-agent/dist/main.d.ts.map +1 -1
  242. package/packages/pi-coding-agent/dist/main.js +17 -0
  243. package/packages/pi-coding-agent/dist/main.js.map +1 -1
  244. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.d.ts +2 -0
  245. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.d.ts.map +1 -0
  246. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.js +32 -0
  247. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.js.map +1 -0
  248. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts +3 -1
  249. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  250. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js +8 -1
  251. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
  252. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts +2 -0
  253. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  254. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js +12 -0
  255. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js.map +1 -1
  256. package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.d.ts +15 -0
  257. package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.d.ts.map +1 -0
  258. package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.js +40 -0
  259. package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.js.map +1 -0
  260. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  261. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +4 -1
  262. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  263. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts +5 -2
  264. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  265. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js +13 -2
  266. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js.map +1 -1
  267. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  268. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +17 -8
  269. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  270. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  271. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +7 -3
  272. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  273. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.test.js +43 -47
  274. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.test.js.map +1 -1
  275. package/packages/pi-coding-agent/package.json +1 -1
  276. package/packages/pi-coding-agent/src/core/auth-storage.test.ts +7 -7
  277. package/packages/pi-coding-agent/src/core/auth-storage.ts +15 -1
  278. package/packages/pi-coding-agent/src/core/compaction-orchestrator.ts +2 -0
  279. package/packages/pi-coding-agent/src/core/extensions/runner.test.ts +26 -26
  280. package/packages/pi-coding-agent/src/core/extensions/types.ts +2 -1
  281. package/packages/pi-coding-agent/src/core/fs-utils.test.ts +31 -43
  282. package/packages/pi-coding-agent/src/core/lifecycle-hooks.test.ts +227 -0
  283. package/packages/pi-coding-agent/src/core/lifecycle-hooks.ts +11 -5
  284. package/packages/pi-coding-agent/src/core/local-model-check.ts +45 -0
  285. package/packages/pi-coding-agent/src/core/model-registry-auth-mode.test.ts +297 -11
  286. package/packages/pi-coding-agent/src/core/model-registry.ts +51 -4
  287. package/packages/pi-coding-agent/src/core/package-commands.test.ts +227 -205
  288. package/packages/pi-coding-agent/src/core/resolve-config-value.test.ts +40 -45
  289. package/packages/pi-coding-agent/src/core/session-manager.test.ts +33 -33
  290. package/packages/pi-coding-agent/src/core/settings-manager.ts +9 -0
  291. package/packages/pi-coding-agent/src/core/tools/edit-diff.test.ts +17 -17
  292. package/packages/pi-coding-agent/src/main.ts +19 -0
  293. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/timestamp.test.ts +38 -0
  294. package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +10 -0
  295. package/packages/pi-coding-agent/src/modes/interactive/components/settings-selector.ts +15 -0
  296. package/packages/pi-coding-agent/src/modes/interactive/components/timestamp.ts +48 -0
  297. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +3 -1
  298. package/packages/pi-coding-agent/src/modes/interactive/components/user-message.ts +18 -3
  299. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +16 -7
  300. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +8 -1
  301. package/packages/pi-coding-agent/src/resources/extensions/memory/storage.test.ts +74 -74
  302. package/pkg/package.json +1 -1
  303. package/src/resources/extensions/gsd/activity-log.ts +1 -0
  304. package/src/resources/extensions/gsd/auto/infra-errors.ts +3 -0
  305. package/src/resources/extensions/gsd/auto/phases.ts +61 -59
  306. package/src/resources/extensions/gsd/auto/run-unit.ts +6 -3
  307. package/src/resources/extensions/gsd/auto-prompts.ts +24 -1
  308. package/src/resources/extensions/gsd/auto-start.ts +39 -2
  309. package/src/resources/extensions/gsd/auto-timers.ts +64 -3
  310. package/src/resources/extensions/gsd/auto-worktree-sync.ts +5 -0
  311. package/src/resources/extensions/gsd/auto-worktree.ts +17 -11
  312. package/src/resources/extensions/gsd/auto.ts +40 -6
  313. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +160 -11
  314. package/src/resources/extensions/gsd/bootstrap/system-context.ts +48 -11
  315. package/src/resources/extensions/gsd/commands/catalog.ts +7 -1
  316. package/src/resources/extensions/gsd/commands/handlers/core.ts +2 -0
  317. package/src/resources/extensions/gsd/commands/handlers/ops.ts +10 -0
  318. package/src/resources/extensions/gsd/commands/handlers/workflow.ts +8 -0
  319. package/src/resources/extensions/gsd/commands-mcp-status.ts +247 -0
  320. package/src/resources/extensions/gsd/db-writer.ts +41 -27
  321. package/src/resources/extensions/gsd/doctor-checks.ts +1 -1
  322. package/src/resources/extensions/gsd/doctor.ts +9 -3
  323. package/src/resources/extensions/gsd/git-service.ts +6 -2
  324. package/src/resources/extensions/gsd/gsd-db.ts +21 -2
  325. package/src/resources/extensions/gsd/journal.ts +6 -1
  326. package/src/resources/extensions/gsd/markdown-renderer.ts +1 -1
  327. package/src/resources/extensions/gsd/preferences-types.ts +2 -2
  328. package/src/resources/extensions/gsd/preferences.ts +18 -4
  329. package/src/resources/extensions/gsd/prompts/complete-milestone.md +2 -4
  330. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  331. package/src/resources/extensions/gsd/prompts/reassess-roadmap.md +6 -6
  332. package/src/resources/extensions/gsd/prompts/replan-slice.md +3 -14
  333. package/src/resources/extensions/gsd/prompts/rethink.md +78 -0
  334. package/src/resources/extensions/gsd/prompts/validate-milestone.md +7 -37
  335. package/src/resources/extensions/gsd/provider-error-pause.ts +9 -0
  336. package/src/resources/extensions/gsd/repo-identity.ts +46 -7
  337. package/src/resources/extensions/gsd/rethink.ts +154 -0
  338. package/src/resources/extensions/gsd/state.ts +41 -1
  339. package/src/resources/extensions/gsd/tests/all-milestones-complete-merge.test.ts +99 -99
  340. package/src/resources/extensions/gsd/tests/auto-lock-creation.test.ts +14 -16
  341. package/src/resources/extensions/gsd/tests/auto-paused-session-validation.test.ts +43 -57
  342. package/src/resources/extensions/gsd/tests/auto-pr-bugs.test.ts +88 -0
  343. package/src/resources/extensions/gsd/tests/auto-preflight.test.ts +11 -13
  344. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +465 -523
  345. package/src/resources/extensions/gsd/tests/auto-secrets-gate.test.ts +73 -75
  346. package/src/resources/extensions/gsd/tests/auto-start-needs-discussion.test.ts +34 -56
  347. package/src/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +533 -656
  348. package/src/resources/extensions/gsd/tests/auto-worktree.test.ts +165 -143
  349. package/src/resources/extensions/gsd/tests/cache-staleness-regression.test.ts +29 -52
  350. package/src/resources/extensions/gsd/tests/captures.test.ts +148 -176
  351. package/src/resources/extensions/gsd/tests/claude-import-tui.test.ts +32 -33
  352. package/src/resources/extensions/gsd/tests/collect-from-manifest.test.ts +141 -143
  353. package/src/resources/extensions/gsd/tests/commands-inspect-open-db.test.ts +25 -25
  354. package/src/resources/extensions/gsd/tests/commands-logs.test.ts +81 -81
  355. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +38 -59
  356. package/src/resources/extensions/gsd/tests/complete-slice.test.ts +228 -263
  357. package/src/resources/extensions/gsd/tests/complete-task.test.ts +250 -302
  358. package/src/resources/extensions/gsd/tests/completed-units-metrics-sync.test.ts +114 -0
  359. package/src/resources/extensions/gsd/tests/context-store.test.ts +354 -367
  360. package/src/resources/extensions/gsd/tests/continue-here.test.ts +68 -72
  361. package/src/resources/extensions/gsd/tests/cost-projection.test.ts +92 -106
  362. package/src/resources/extensions/gsd/tests/crash-recovery.test.ts +27 -35
  363. package/src/resources/extensions/gsd/tests/dashboard-budget.test.ts +220 -237
  364. package/src/resources/extensions/gsd/tests/db-writer.test.ts +465 -416
  365. package/src/resources/extensions/gsd/tests/definition-loader.test.ts +76 -92
  366. package/src/resources/extensions/gsd/tests/derive-state-crossval.test.ts +68 -83
  367. package/src/resources/extensions/gsd/tests/derive-state-db-disk-reconcile.test.ts +121 -0
  368. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +210 -181
  369. package/src/resources/extensions/gsd/tests/derive-state-deps.test.ts +78 -101
  370. package/src/resources/extensions/gsd/tests/derive-state.test.ts +192 -227
  371. package/src/resources/extensions/gsd/tests/detection.test.ts +232 -278
  372. package/src/resources/extensions/gsd/tests/dev-engine-wrapper.test.ts +30 -34
  373. package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +164 -180
  374. package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +43 -49
  375. package/src/resources/extensions/gsd/tests/dispatch-uat-last-completed.test.ts +28 -32
  376. package/src/resources/extensions/gsd/tests/doctor-completion-deferral.test.ts +27 -29
  377. package/src/resources/extensions/gsd/tests/doctor-delimiter-fix.test.ts +34 -38
  378. package/src/resources/extensions/gsd/tests/doctor-enhancements.test.ts +54 -75
  379. package/src/resources/extensions/gsd/tests/doctor-environment-worktree.test.ts +21 -32
  380. package/src/resources/extensions/gsd/tests/doctor-environment.test.ts +72 -97
  381. package/src/resources/extensions/gsd/tests/doctor-fixlevel.test.ts +38 -44
  382. package/src/resources/extensions/gsd/tests/doctor-git.test.ts +104 -145
  383. package/src/resources/extensions/gsd/tests/doctor-proactive.test.ts +84 -106
  384. package/src/resources/extensions/gsd/tests/doctor-roadmap-summary-atomicity.test.ts +54 -60
  385. package/src/resources/extensions/gsd/tests/doctor-runtime.test.ts +72 -93
  386. package/src/resources/extensions/gsd/tests/doctor.test.ts +104 -134
  387. package/src/resources/extensions/gsd/tests/ensure-db-open.test.ts +123 -131
  388. package/src/resources/extensions/gsd/tests/est-annotation-timeout.test.ts +120 -0
  389. package/src/resources/extensions/gsd/tests/exit-command.test.ts +20 -24
  390. package/src/resources/extensions/gsd/tests/feature-branch-lifecycle-integration.test.ts +48 -57
  391. package/src/resources/extensions/gsd/tests/files-loadfile-eisdir.test.ts +5 -7
  392. package/src/resources/extensions/gsd/tests/flag-file-db.test.ts +30 -42
  393. package/src/resources/extensions/gsd/tests/freeform-decisions.test.ts +198 -206
  394. package/src/resources/extensions/gsd/tests/git-locale.test.ts +13 -27
  395. package/src/resources/extensions/gsd/tests/git-service.test.ts +285 -388
  396. package/src/resources/extensions/gsd/tests/gitignore-tracked-gsd.test.ts +31 -39
  397. package/src/resources/extensions/gsd/tests/graph-operations.test.ts +63 -69
  398. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +255 -264
  399. package/src/resources/extensions/gsd/tests/gsd-inspect.test.ts +108 -119
  400. package/src/resources/extensions/gsd/tests/gsd-recover.test.ts +81 -103
  401. package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +229 -262
  402. package/src/resources/extensions/gsd/tests/headless-answers.test.ts +13 -13
  403. package/src/resources/extensions/gsd/tests/health-widget.test.ts +29 -37
  404. package/src/resources/extensions/gsd/tests/idle-recovery.test.ts +81 -102
  405. package/src/resources/extensions/gsd/tests/infra-error.test.ts +20 -2
  406. package/src/resources/extensions/gsd/tests/inherited-repo-home-dir.test.ts +121 -0
  407. package/src/resources/extensions/gsd/tests/init-wizard.test.ts +16 -18
  408. package/src/resources/extensions/gsd/tests/integration-edge.test.ts +41 -46
  409. package/src/resources/extensions/gsd/tests/integration-lifecycle.test.ts +42 -53
  410. package/src/resources/extensions/gsd/tests/integration-mixed-milestones.test.ts +75 -91
  411. package/src/resources/extensions/gsd/tests/integration-proof.test.ts +18 -18
  412. package/src/resources/extensions/gsd/tests/knowledge.test.ts +89 -0
  413. package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +150 -194
  414. package/src/resources/extensions/gsd/tests/mcp-status.test.ts +103 -0
  415. package/src/resources/extensions/gsd/tests/md-importer.test.ts +101 -125
  416. package/src/resources/extensions/gsd/tests/memory-extractor.test.ts +45 -54
  417. package/src/resources/extensions/gsd/tests/memory-store.test.ts +80 -93
  418. package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +66 -0
  419. package/src/resources/extensions/gsd/tests/migrate-command.test.ts +57 -66
  420. package/src/resources/extensions/gsd/tests/migrate-hierarchy.test.ts +83 -93
  421. package/src/resources/extensions/gsd/tests/migrate-parser.test.ts +161 -170
  422. package/src/resources/extensions/gsd/tests/migrate-transformer.test.ts +125 -141
  423. package/src/resources/extensions/gsd/tests/migrate-validator-parsers.test.ts +107 -131
  424. package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +87 -96
  425. package/src/resources/extensions/gsd/tests/migrate-writer.test.ts +125 -164
  426. package/src/resources/extensions/gsd/tests/must-have-parser.test.ts +81 -94
  427. package/src/resources/extensions/gsd/tests/none-mode-gates.test.ts +75 -37
  428. package/src/resources/extensions/gsd/tests/overrides.test.ts +99 -106
  429. package/src/resources/extensions/gsd/tests/parallel-crash-recovery.test.ts +40 -47
  430. package/src/resources/extensions/gsd/tests/parallel-worker-monitoring.test.ts +25 -28
  431. package/src/resources/extensions/gsd/tests/parallel-workers-multi-milestone-e2e.test.ts +66 -83
  432. package/src/resources/extensions/gsd/tests/park-edge-cases.test.ts +54 -77
  433. package/src/resources/extensions/gsd/tests/park-milestone.test.ts +68 -115
  434. package/src/resources/extensions/gsd/tests/parsers.test.ts +546 -611
  435. package/src/resources/extensions/gsd/tests/paths.test.ts +72 -87
  436. package/src/resources/extensions/gsd/tests/post-unit-hooks.test.ts +77 -117
  437. package/src/resources/extensions/gsd/tests/preferences.test.ts +34 -9
  438. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +11 -7
  439. package/src/resources/extensions/gsd/tests/prompt-db.test.ts +56 -56
  440. package/src/resources/extensions/gsd/tests/queue-draft-detection.test.ts +93 -119
  441. package/src/resources/extensions/gsd/tests/queue-order.test.ts +70 -82
  442. package/src/resources/extensions/gsd/tests/queue-reorder-e2e.test.ts +42 -55
  443. package/src/resources/extensions/gsd/tests/quick-auto-guard.test.ts +100 -0
  444. package/src/resources/extensions/gsd/tests/quick-branch-lifecycle.test.ts +45 -73
  445. package/src/resources/extensions/gsd/tests/reassess-prompt.test.ts +28 -38
  446. package/src/resources/extensions/gsd/tests/recovery-attempts-reset.test.ts +176 -0
  447. package/src/resources/extensions/gsd/tests/replan-slice.test.ts +73 -80
  448. package/src/resources/extensions/gsd/tests/repo-identity-worktree.test.ts +71 -74
  449. package/src/resources/extensions/gsd/tests/requirements.test.ts +70 -75
  450. package/src/resources/extensions/gsd/tests/retry-state-reset.test.ts +44 -66
  451. package/src/resources/extensions/gsd/tests/roadmap-parse-regression.test.ts +114 -181
  452. package/src/resources/extensions/gsd/tests/rule-registry.test.ts +63 -65
  453. package/src/resources/extensions/gsd/tests/run-uat.test.ts +66 -128
  454. package/src/resources/extensions/gsd/tests/session-lock-multipath.test.ts +18 -25
  455. package/src/resources/extensions/gsd/tests/session-lock-regression.test.ts +37 -44
  456. package/src/resources/extensions/gsd/tests/shared-wal.test.ts +19 -26
  457. package/src/resources/extensions/gsd/tests/sqlite-unavailable-gate.test.ts +63 -0
  458. package/src/resources/extensions/gsd/tests/stalled-tool-recovery.test.ts +6 -8
  459. package/src/resources/extensions/gsd/tests/stop-auto-merge-back.test.ts +67 -0
  460. package/src/resources/extensions/gsd/tests/survivor-branch-complete.test.ts +108 -0
  461. package/src/resources/extensions/gsd/tests/symlink-numbered-variants.test.ts +22 -28
  462. package/src/resources/extensions/gsd/tests/terminated-transient.test.ts +49 -0
  463. package/src/resources/extensions/gsd/tests/token-savings.test.ts +54 -56
  464. package/src/resources/extensions/gsd/tests/tool-call-loop-guard.test.ts +23 -25
  465. package/src/resources/extensions/gsd/tests/tool-naming.test.ts +10 -11
  466. package/src/resources/extensions/gsd/tests/unique-milestone-ids.test.ts +66 -82
  467. package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +46 -47
  468. package/src/resources/extensions/gsd/tests/visualizer-critical-path.test.ts +20 -22
  469. package/src/resources/extensions/gsd/tests/visualizer-data.test.ts +84 -86
  470. package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +41 -43
  471. package/src/resources/extensions/gsd/tests/visualizer-views.test.ts +94 -96
  472. package/src/resources/extensions/gsd/tests/windows-path-normalization.test.ts +11 -13
  473. package/src/resources/extensions/gsd/tests/worker-registry.test.ts +27 -29
  474. package/src/resources/extensions/gsd/tests/workflow-logger.test.ts +275 -0
  475. package/src/resources/extensions/gsd/tests/workflow-templates.test.ts +50 -52
  476. package/src/resources/extensions/gsd/tests/worktree-bugfix.test.ts +10 -13
  477. package/src/resources/extensions/gsd/tests/worktree-db-integration.test.ts +14 -18
  478. package/src/resources/extensions/gsd/tests/worktree-db.test.ts +38 -39
  479. package/src/resources/extensions/gsd/tests/worktree-e2e.test.ts +17 -21
  480. package/src/resources/extensions/gsd/tests/worktree-health.test.ts +25 -30
  481. package/src/resources/extensions/gsd/tests/worktree-integration.test.ts +30 -37
  482. package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +220 -0
  483. package/src/resources/extensions/gsd/tests/worktree-submodule-safety.test.ts +65 -0
  484. package/src/resources/extensions/gsd/tests/worktree-symlink-removal.test.ts +15 -22
  485. package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +59 -66
  486. package/src/resources/extensions/gsd/tests/worktree.test.ts +44 -50
  487. package/src/resources/extensions/gsd/tools/plan-slice.ts +2 -0
  488. package/src/resources/extensions/gsd/tools/plan-task.ts +2 -0
  489. package/src/resources/extensions/gsd/tools/replan-slice.ts +3 -0
  490. package/src/resources/extensions/gsd/tools/validate-milestone.ts +127 -0
  491. package/src/resources/extensions/gsd/workflow-logger.ts +193 -0
  492. package/src/resources/extensions/gsd/worktree-manager.ts +41 -5
  493. package/src/resources/extensions/gsd/worktree-resolver.ts +44 -0
  494. package/src/resources/extensions/mcp-client/index.ts +20 -0
  495. package/src/resources/extensions/voice/index.ts +11 -21
  496. package/src/resources/extensions/voice/linux-ready.ts +87 -0
  497. package/src/resources/extensions/voice/tests/linux-ready.test.ts +124 -0
  498. package/dist/web/standalone/.next/static/chunks/4024.0de81b543b28b9fe.js +0 -9
  499. package/dist/web/standalone/.next/static/chunks/app/page-7e9530a7122506c5.js +0 -1
  500. package/dist/web/standalone/.next/static/chunks/main-app-d3d4c336195465f9.js +0 -1
  501. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ab5a8926e07ec673.js +0 -1
  502. package/dist/web/standalone/.next/static/chunks/webpack-9014b5adb127a98a.js +0 -1
  503. package/dist/web/standalone/.next/static/css/8a727f372cf53002.css +0 -1
  504. /package/dist/web/standalone/.next/static/{mgkxN0mGP6gSUmGPEzbk_ → dFMji9G1LZ-Tv36el9pRT}/_buildManifest.js +0 -0
  505. /package/dist/web/standalone/.next/static/{mgkxN0mGP6gSUmGPEzbk_ → dFMji9G1LZ-Tv36el9pRT}/_ssgManifest.js +0 -0
@@ -1,5 +1,5 @@
1
1
  import assert from "node:assert/strict";
2
- import { describe, it } from "node:test";
2
+ import { describe, it, afterEach } from "node:test";
3
3
  import { mkdtempSync, rmSync } from "node:fs";
4
4
  import { join } from "node:path";
5
5
  import { tmpdir } from "node:os";
@@ -22,44 +22,44 @@ function makeAssistantMessage(input: number, output: number, cacheRead = 0, cach
22
22
  }
23
23
 
24
24
  describe("SessionManager usage totals", () => {
25
- it("tracks assistant usage incrementally without rescanning entries", () => {
26
- const dir = mkdtempSync(join(tmpdir(), "gsd-session-manager-test-"));
27
- try {
28
- const manager = SessionManager.create(dir, dir);
29
-
30
- manager.appendMessage({ role: "user", content: [{ type: "text", text: "hello" }] } as any);
31
- manager.appendMessage(makeAssistantMessage(10, 5, 3, 2, 0.25));
32
- manager.appendMessage(makeAssistantMessage(7, 4, 1, 0, 0.1));
25
+ let dir: string;
33
26
 
34
- assert.deepEqual(manager.getUsageTotals(), {
35
- input: 17,
36
- output: 9,
37
- cacheRead: 4,
38
- cacheWrite: 2,
39
- cost: 0.35,
40
- });
41
- } finally {
27
+ afterEach(() => {
28
+ if (dir) {
42
29
  rmSync(dir, { recursive: true, force: true });
43
30
  }
44
31
  });
45
32
 
33
+ it("tracks assistant usage incrementally without rescanning entries", () => {
34
+ dir = mkdtempSync(join(tmpdir(), "gsd-session-manager-test-"));
35
+ const manager = SessionManager.create(dir, dir);
36
+
37
+ manager.appendMessage({ role: "user", content: [{ type: "text", text: "hello" }] } as any);
38
+ manager.appendMessage(makeAssistantMessage(10, 5, 3, 2, 0.25));
39
+ manager.appendMessage(makeAssistantMessage(7, 4, 1, 0, 0.1));
40
+
41
+ assert.deepEqual(manager.getUsageTotals(), {
42
+ input: 17,
43
+ output: 9,
44
+ cacheRead: 4,
45
+ cacheWrite: 2,
46
+ cost: 0.35,
47
+ });
48
+ });
49
+
46
50
  it("resets totals when starting a new session", () => {
47
- const dir = mkdtempSync(join(tmpdir(), "gsd-session-manager-test-"));
48
- try {
49
- const manager = SessionManager.create(dir, dir);
50
- manager.appendMessage(makeAssistantMessage(5, 5, 0, 0, 0.05));
51
- assert.equal(manager.getUsageTotals().input, 5);
51
+ dir = mkdtempSync(join(tmpdir(), "gsd-session-manager-test-"));
52
+ const manager = SessionManager.create(dir, dir);
53
+ manager.appendMessage(makeAssistantMessage(5, 5, 0, 0, 0.05));
54
+ assert.equal(manager.getUsageTotals().input, 5);
52
55
 
53
- manager.newSession();
54
- assert.deepEqual(manager.getUsageTotals(), {
55
- input: 0,
56
- output: 0,
57
- cacheRead: 0,
58
- cacheWrite: 0,
59
- cost: 0,
60
- });
61
- } finally {
62
- rmSync(dir, { recursive: true, force: true });
63
- }
56
+ manager.newSession();
57
+ assert.deepEqual(manager.getUsageTotals(), {
58
+ input: 0,
59
+ output: 0,
60
+ cacheRead: 0,
61
+ cacheWrite: 0,
62
+ cost: 0,
63
+ });
64
64
  });
65
65
  });
@@ -151,6 +151,7 @@ export interface Settings {
151
151
  fallback?: FallbackSettings;
152
152
  modelDiscovery?: ModelDiscoverySettings;
153
153
  editMode?: "standard" | "hashline"; // Edit tool mode: "standard" (text match) or "hashline" (LINE#ID anchors). Default: "standard"
154
+ timestampFormat?: "date-time-iso" | "date-time-us"; // Timestamp display format for messages. Default: "date-time-iso"
154
155
  }
155
156
 
156
157
  /** Deep merge settings: project/overrides take precedence, nested objects merge recursively */
@@ -1087,4 +1088,12 @@ export class SettingsManager {
1087
1088
  setEditMode(mode: "standard" | "hashline"): void {
1088
1089
  this.setGlobalSetting("editMode", mode);
1089
1090
  }
1091
+
1092
+ getTimestampFormat(): "date-time-iso" | "date-time-us" {
1093
+ return this.settings.timestampFormat ?? "date-time-iso";
1094
+ }
1095
+
1096
+ setTimestampFormat(format: "date-time-iso" | "date-time-us"): void {
1097
+ this.setGlobalSetting("timestampFormat", format);
1098
+ }
1090
1099
  }
@@ -60,26 +60,26 @@ describe("edit-diff", () => {
60
60
  assert.match(result.diff, /CHANGED/);
61
61
  });
62
62
 
63
- it("computes diffs for preview without native helpers", async () => {
63
+ it("computes diffs for preview without native helpers", async (t) => {
64
64
  const dir = mkdtempSync(join(tmpdir(), "edit-diff-test-"));
65
- try {
66
- const file = join(dir, "sample.ts");
67
- writeFileSync(file, "const title = “Hello”;\n", "utf-8");
65
+ t.after(() => {
66
+ rmSync(dir, { recursive: true, force: true });
67
+ });
68
68
 
69
- const result = await computeEditDiff(
70
- file,
71
- "const title = \"Hello\";\n",
72
- "const title = \"Hi\";\n",
73
- dir,
74
- );
69
+ const file = join(dir, "sample.ts");
70
+ writeFileSync(file, "const title = “Hello”;\n", "utf-8");
75
71
 
76
- assert.ok(!("error" in result), "expected a diff result");
77
- if (!("error" in result)) {
78
- assert.equal(result.firstChangedLine, 1);
79
- assert.match(result.diff, /\+1 const title = "Hi";/);
80
- }
81
- } finally {
82
- rmSync(dir, { recursive: true, force: true });
72
+ const result = await computeEditDiff(
73
+ file,
74
+ "const title = \"Hello\";\n",
75
+ "const title = \"Hi\";\n",
76
+ dir,
77
+ );
78
+
79
+ assert.ok(!("error" in result), "expected a diff result");
80
+ if (!("error" in result)) {
81
+ assert.equal(result.firstChangedLine, 1);
82
+ assert.match(result.diff, /\+1 const title = "Hi";/);
83
83
  }
84
84
  });
85
85
  });
@@ -391,6 +391,25 @@ export async function main(args: string[]) {
391
391
  const authStorage = AuthStorage.create();
392
392
  const modelRegistry = new ModelRegistry(authStorage, getModelsPath());
393
393
 
394
+ // Offline mode validation / auto-detection
395
+ if (offlineMode) {
396
+ // --offline flag: validate all models are local
397
+ if (!modelRegistry.isAllLocalChain()) {
398
+ const remoteModel = modelRegistry.getAll().find((m) => !ModelRegistry.isLocalModel(m));
399
+ if (remoteModel) {
400
+ console.error(
401
+ `Error: --offline requires all configured models to be local. Found remote model: ${remoteModel.name} (${remoteModel.baseUrl || "cloud API"})`,
402
+ );
403
+ process.exit(1);
404
+ }
405
+ }
406
+ } else if (modelRegistry.isAllLocalChain() && modelRegistry.getAll().length > 0) {
407
+ // Auto-detect: all models are local, enable offline mode
408
+ process.env.PI_OFFLINE = "1";
409
+ process.env.PI_SKIP_VERSION_CHECK = "1";
410
+ console.log("[gsd] All configured models are local \u2014 enabling offline mode automatically.");
411
+ }
412
+
394
413
  const resourceLoader = new DefaultResourceLoader({
395
414
  cwd,
396
415
  agentDir,
@@ -0,0 +1,38 @@
1
+ import { test, describe } from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import { formatTimestamp } from "../timestamp.js";
4
+
5
+ describe("formatTimestamp", () => {
6
+ // Use a fixed local timestamp to avoid timezone issues
7
+ const d = new Date(2026, 2, 24, 10, 34, 0); // Mar 24, 2026 10:34:00 local time
8
+ const ts = d.getTime();
9
+
10
+ test("date-time-iso format (default)", () => {
11
+ assert.equal(formatTimestamp(ts, "date-time-iso"), "2026-03-24 10:34");
12
+ assert.equal(formatTimestamp(ts), "2026-03-24 10:34"); // default
13
+ });
14
+
15
+ test("date-time-us format", () => {
16
+ assert.equal(formatTimestamp(ts, "date-time-us"), "03-24-2026 10:34 AM");
17
+ });
18
+
19
+ test("US format handles PM correctly", () => {
20
+ const pm = new Date(2026, 2, 24, 14, 5, 0).getTime();
21
+ assert.equal(formatTimestamp(pm, "date-time-us"), "03-24-2026 2:05 PM");
22
+ });
23
+
24
+ test("US format handles noon as 12 PM", () => {
25
+ const noon = new Date(2026, 2, 24, 12, 0, 0).getTime();
26
+ assert.equal(formatTimestamp(noon, "date-time-us"), "03-24-2026 12:00 PM");
27
+ });
28
+
29
+ test("US format handles midnight as 12 AM", () => {
30
+ const midnight = new Date(2026, 2, 24, 0, 0, 0).getTime();
31
+ assert.equal(formatTimestamp(midnight, "date-time-us"), "03-24-2026 12:00 AM");
32
+ });
33
+
34
+ test("ISO format pads single digit months and days", () => {
35
+ const jan1 = new Date(2026, 0, 1, 9, 5, 0).getTime();
36
+ assert.equal(formatTimestamp(jan1, "date-time-iso"), "2026-01-01 09:05");
37
+ });
38
+ });
@@ -1,6 +1,7 @@
1
1
  import type { AssistantMessage } from "@gsd/pi-ai";
2
2
  import { Container, Markdown, type MarkdownTheme, Spacer, Text } from "@gsd/pi-tui";
3
3
  import { getMarkdownTheme, theme } from "../theme/theme.js";
4
+ import { formatTimestamp, type TimestampFormat } from "./timestamp.js";
4
5
 
5
6
  /**
6
7
  * Component that renders a complete assistant message
@@ -10,16 +11,19 @@ export class AssistantMessageComponent extends Container {
10
11
  private hideThinkingBlock: boolean;
11
12
  private markdownTheme: MarkdownTheme;
12
13
  private lastMessage?: AssistantMessage;
14
+ private timestampFormat: TimestampFormat;
13
15
 
14
16
  constructor(
15
17
  message?: AssistantMessage,
16
18
  hideThinkingBlock = false,
17
19
  markdownTheme: MarkdownTheme = getMarkdownTheme(),
20
+ timestampFormat: TimestampFormat = "date-time-iso",
18
21
  ) {
19
22
  super();
20
23
 
21
24
  this.hideThinkingBlock = hideThinkingBlock;
22
25
  this.markdownTheme = markdownTheme;
26
+ this.timestampFormat = timestampFormat;
23
27
 
24
28
  // Container for text/thinking content
25
29
  this.contentContainer = new Container();
@@ -111,5 +115,11 @@ export class AssistantMessageComponent extends Container {
111
115
  this.contentContainer.addChild(new Text(theme.fg("error", `Error: ${errorMsg}`), 1, 0));
112
116
  }
113
117
  }
118
+
119
+ // Show timestamp when the message is complete (has a stop reason)
120
+ if (message.stopReason && message.timestamp) {
121
+ const timeStr = formatTimestamp(message.timestamp, this.timestampFormat);
122
+ this.contentContainer.addChild(new Text(theme.fg("dim", timeStr), 1, 0));
123
+ }
114
124
  }
115
125
  }
@@ -45,6 +45,7 @@ export interface SettingsConfig {
45
45
  respectGitignoreInPicker: boolean;
46
46
  quietStartup: boolean;
47
47
  clearOnShrink: boolean;
48
+ timestampFormat: "date-time-iso" | "date-time-us";
48
49
  }
49
50
 
50
51
  export interface SettingsCallbacks {
@@ -69,6 +70,7 @@ export interface SettingsCallbacks {
69
70
  onRespectGitignoreInPickerChange: (enabled: boolean) => void;
70
71
  onQuietStartupChange: (enabled: boolean) => void;
71
72
  onClearOnShrinkChange: (enabled: boolean) => void;
73
+ onTimestampFormatChange: (format: "date-time-iso" | "date-time-us") => void;
72
74
  onCancel: () => void;
73
75
  }
74
76
 
@@ -355,6 +357,16 @@ export class SettingsSelectorComponent extends Container {
355
357
  values: ["true", "false"],
356
358
  });
357
359
 
360
+ // Timestamp format (insert after respect-gitignore-in-picker)
361
+ const gitignoreIndex = items.findIndex((item) => item.id === "respect-gitignore-in-picker");
362
+ items.splice(gitignoreIndex + 1, 0, {
363
+ id: "timestamp-format",
364
+ label: "Timestamp format",
365
+ description: "Date/time format for message timestamps",
366
+ currentValue: config.timestampFormat,
367
+ values: ["date-time-iso", "date-time-us"],
368
+ });
369
+
358
370
  // Add borders
359
371
  this.addChild(new DynamicBorder());
360
372
 
@@ -420,6 +432,9 @@ export class SettingsSelectorComponent extends Container {
420
432
  case "respect-gitignore-in-picker":
421
433
  callbacks.onRespectGitignoreInPickerChange(newValue === "true");
422
434
  break;
435
+ case "timestamp-format":
436
+ callbacks.onTimestampFormatChange(newValue as "date-time-iso" | "date-time-us");
437
+ break;
423
438
  }
424
439
  },
425
440
  callbacks.onCancel,
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Timestamp formatting for message display.
3
+ *
4
+ * Formats:
5
+ * - "time-date-iso": 10:34 2025-03-24 (default)
6
+ * - "date-time-iso": 2025-03-24 10:34
7
+ * - "time-date-us": 10:34 AM 03/24/2025
8
+ * - "date-time-us": 03/24/2025 10:34 AM
9
+ */
10
+
11
+ export type TimestampFormat = "date-time-iso" | "date-time-us";
12
+
13
+ function pad2(n: number): string {
14
+ return n.toString().padStart(2, "0");
15
+ }
16
+
17
+ function isoDate(d: Date): string {
18
+ return `${d.getFullYear()}-${pad2(d.getMonth() + 1)}-${pad2(d.getDate())}`;
19
+ }
20
+
21
+ function isoTime(d: Date): string {
22
+ return `${pad2(d.getHours())}:${pad2(d.getMinutes())}`;
23
+ }
24
+
25
+ function usDate(d: Date): string {
26
+ return `${pad2(d.getMonth() + 1)}-${pad2(d.getDate())}-${d.getFullYear()}`;
27
+ }
28
+
29
+ function usTime(d: Date): string {
30
+ const hours = d.getHours();
31
+ const period = hours >= 12 ? "PM" : "AM";
32
+ const h = hours % 12 || 12;
33
+ return `${h}:${pad2(d.getMinutes())} ${period}`;
34
+ }
35
+
36
+ /**
37
+ * Format a timestamp for message display using the specified format.
38
+ */
39
+ export function formatTimestamp(timestamp: number, format: TimestampFormat = "date-time-iso"): string {
40
+ const d = new Date(timestamp);
41
+
42
+ switch (format) {
43
+ case "date-time-iso":
44
+ return `${isoDate(d)} ${isoTime(d)}`;
45
+ case "date-time-us":
46
+ return `${usDate(d)} ${usTime(d)}`;
47
+ }
48
+ }
@@ -895,7 +895,9 @@ export class ToolExecutionComponent extends Container {
895
895
  // Server-side Anthropic web search
896
896
  text = theme.fg("toolTitle", theme.bold("web search"));
897
897
 
898
- if (this.result) {
898
+ if (process.env.PI_OFFLINE === "1") {
899
+ text += "\n\n" + theme.fg("muted", "\u{1F50C} Offline \u{2014} web search unavailable");
900
+ } else if (this.result) {
899
901
  const output = this.getTextOutput().trim();
900
902
  if (output) {
901
903
  const lines = output.split("\n");
@@ -1,15 +1,21 @@
1
- import { Container, Markdown, type MarkdownTheme, Spacer } from "@gsd/pi-tui";
1
+ import { Container, Markdown, type MarkdownTheme, Spacer, Text } from "@gsd/pi-tui";
2
2
  import { getMarkdownTheme, theme } from "../theme/theme.js";
3
+ import { formatTimestamp, type TimestampFormat } from "./timestamp.js";
3
4
 
4
5
  const OSC133_ZONE_START = "\x1b]133;A\x07";
5
6
  const OSC133_ZONE_END = "\x1b]133;B\x07";
6
7
 
7
8
  /**
8
- * Component that renders a user message
9
+ * Component that renders a user message with a right-aligned timestamp.
9
10
  */
10
11
  export class UserMessageComponent extends Container {
11
- constructor(text: string, markdownTheme: MarkdownTheme = getMarkdownTheme()) {
12
+ private timestamp: number | undefined;
13
+ private timestampFormat: TimestampFormat;
14
+
15
+ constructor(text: string, markdownTheme: MarkdownTheme = getMarkdownTheme(), timestamp?: number, timestampFormat: TimestampFormat = "date-time-iso") {
12
16
  super();
17
+ this.timestamp = timestamp;
18
+ this.timestampFormat = timestampFormat;
13
19
  this.addChild(new Spacer(1));
14
20
  this.addChild(
15
21
  new Markdown(text, 1, 1, markdownTheme, {
@@ -25,6 +31,15 @@ export class UserMessageComponent extends Container {
25
31
  return lines;
26
32
  }
27
33
 
34
+ // Insert right-aligned timestamp above the message content
35
+ if (this.timestamp) {
36
+ const timeStr = formatTimestamp(this.timestamp, this.timestampFormat);
37
+ const label = theme.fg("dim", timeStr);
38
+ const padding = Math.max(0, width - timeStr.length - 1);
39
+ const timestampLine = " ".repeat(padding) + label;
40
+ lines.splice(0, 0, timestampLine);
41
+ }
42
+
28
43
  lines[0] = OSC133_ZONE_START + lines[0];
29
44
  lines[lines.length - 1] = lines[lines.length - 1] + OSC133_ZONE_END;
30
45
  return lines;
@@ -100,6 +100,7 @@ export async function handleAgentEvent(host: InteractiveModeStateHost & {
100
100
  undefined,
101
101
  host.hideThinkingBlock,
102
102
  host.getMarkdownThemeWithSettings(),
103
+ host.settingsManager.getTimestampFormat(),
103
104
  );
104
105
  host.streamingMessage = event.message;
105
106
  host.chatContainer.addChild(host.streamingComponent);
@@ -144,13 +145,21 @@ export async function handleAgentEvent(host: InteractiveModeStateHost & {
144
145
  } else if (content.type === "webSearchResult") {
145
146
  const component = host.pendingTools.get(content.toolUseId);
146
147
  if (component) {
147
- const searchContent = content.content;
148
- const isError = searchContent && typeof searchContent === "object" && "type" in (searchContent as any) && (searchContent as any).type === "web_search_tool_result_error";
149
- component.updateResult({
150
- content: [{ type: "text", text: host.formatWebSearchResult(searchContent) }],
151
- isError: !!isError,
152
- });
153
- host.pendingTools.delete(content.toolUseId);
148
+ if (process.env.PI_OFFLINE === "1") {
149
+ component.updateResult({
150
+ content: [{ type: "text", text: "Web search disabled (offline mode)" }],
151
+ isError: false,
152
+ });
153
+ host.pendingTools.delete(content.toolUseId);
154
+ } else {
155
+ const searchContent = content.content;
156
+ const isError = searchContent && typeof searchContent === "object" && "type" in (searchContent as any) && (searchContent as any).type === "web_search_tool_result_error";
157
+ component.updateResult({
158
+ content: [{ type: "text", text: host.formatWebSearchResult(searchContent) }],
159
+ isError: !!isError,
160
+ });
161
+ host.pendingTools.delete(content.toolUseId);
162
+ }
154
163
  }
155
164
  }
156
165
  }
@@ -2099,11 +2099,13 @@ export class InteractiveMode {
2099
2099
  const userComponent = new UserMessageComponent(
2100
2100
  skillBlock.userMessage,
2101
2101
  this.getMarkdownThemeWithSettings(),
2102
+ message.timestamp,
2103
+ this.settingsManager.getTimestampFormat(),
2102
2104
  );
2103
2105
  this.chatContainer.addChild(userComponent);
2104
2106
  }
2105
2107
  } else {
2106
- const userComponent = new UserMessageComponent(textContent, this.getMarkdownThemeWithSettings());
2108
+ const userComponent = new UserMessageComponent(textContent, this.getMarkdownThemeWithSettings(), message.timestamp, this.settingsManager.getTimestampFormat());
2107
2109
  this.chatContainer.addChild(userComponent);
2108
2110
  }
2109
2111
  if (options?.populateHistory) {
@@ -2117,6 +2119,7 @@ export class InteractiveMode {
2117
2119
  message,
2118
2120
  this.hideThinkingBlock,
2119
2121
  this.getMarkdownThemeWithSettings(),
2122
+ this.settingsManager.getTimestampFormat(),
2120
2123
  );
2121
2124
  this.chatContainer.addChild(assistantComponent);
2122
2125
  break;
@@ -2795,6 +2798,7 @@ export class InteractiveMode {
2795
2798
  respectGitignoreInPicker: this.settingsManager.getRespectGitignoreInPicker(),
2796
2799
  quietStartup: this.settingsManager.getQuietStartup(),
2797
2800
  clearOnShrink: this.settingsManager.getClearOnShrink(),
2801
+ timestampFormat: this.settingsManager.getTimestampFormat(),
2798
2802
  },
2799
2803
  {
2800
2804
  onAutoCompactChange: (enabled) => {
@@ -2898,6 +2902,9 @@ export class InteractiveMode {
2898
2902
  this.settingsManager.setRespectGitignoreInPicker(enabled);
2899
2903
  this.autocompleteProvider?.setRespectGitignore(enabled);
2900
2904
  },
2905
+ onTimestampFormatChange: (format) => {
2906
+ this.settingsManager.setTimestampFormat(format);
2907
+ },
2901
2908
  onCancel: () => {
2902
2909
  done();
2903
2910
  this.ui.requestRender();
@@ -1,5 +1,5 @@
1
1
  import assert from "node:assert/strict";
2
- import { describe, it, mock } from "node:test";
2
+ import { describe, it, afterEach } from "node:test";
3
3
  import { mkdtempSync, rmSync, readFileSync, existsSync } from "node:fs";
4
4
  import { join } from "node:path";
5
5
  import { tmpdir } from "node:os";
@@ -15,84 +15,84 @@ function wait(ms: number): Promise<void> {
15
15
  }
16
16
 
17
17
  describe("MemoryStorage debounced persistence", () => {
18
- it("multiple rapid mutations only trigger one persist write", async () => {
19
- const dir = makeTmpDir();
20
- const dbPath = join(dir, "test.db");
21
- try {
22
- const storage = await MemoryStorage.create(dbPath);
23
-
24
- const initialStat = readFileSync(dbPath);
25
- const initialMtime = initialStat.length;
26
-
27
- storage.upsertThreads([
28
- { threadId: "t1", filePath: "/a.txt", fileSize: 100, fileMtime: 1000, cwd: "/proj" },
29
- ]);
30
- storage.upsertThreads([
31
- { threadId: "t2", filePath: "/b.txt", fileSize: 200, fileMtime: 2000, cwd: "/proj" },
32
- ]);
33
- storage.upsertThreads([
34
- { threadId: "t3", filePath: "/c.txt", fileSize: 300, fileMtime: 3000, cwd: "/proj" },
35
- ]);
36
-
37
- const afterMutationsBuf = readFileSync(dbPath);
38
- assert.deepEqual(
39
- afterMutationsBuf,
40
- initialStat,
41
- "File should not have been written yet (debounce window has not elapsed)",
42
- );
43
-
44
- await wait(700);
45
-
46
- const afterDebounceBuf = readFileSync(dbPath);
47
- assert.notDeepEqual(
48
- afterDebounceBuf,
49
- initialStat,
50
- "File should have been written after debounce window elapsed",
51
- );
52
-
53
- const stats = storage.getStats();
54
- assert.equal(stats.totalThreads, 3);
55
-
56
- storage.close();
57
- } finally {
18
+ let dir: string;
19
+
20
+ afterEach(() => {
21
+ if (dir) {
58
22
  rmSync(dir, { recursive: true, force: true });
59
23
  }
60
24
  });
61
25
 
26
+ it("multiple rapid mutations only trigger one persist write", async () => {
27
+ dir = makeTmpDir();
28
+ const dbPath = join(dir, "test.db");
29
+ const storage = await MemoryStorage.create(dbPath);
30
+
31
+ const initialStat = readFileSync(dbPath);
32
+ const initialMtime = initialStat.length;
33
+
34
+ storage.upsertThreads([
35
+ { threadId: "t1", filePath: "/a.txt", fileSize: 100, fileMtime: 1000, cwd: "/proj" },
36
+ ]);
37
+ storage.upsertThreads([
38
+ { threadId: "t2", filePath: "/b.txt", fileSize: 200, fileMtime: 2000, cwd: "/proj" },
39
+ ]);
40
+ storage.upsertThreads([
41
+ { threadId: "t3", filePath: "/c.txt", fileSize: 300, fileMtime: 3000, cwd: "/proj" },
42
+ ]);
43
+
44
+ const afterMutationsBuf = readFileSync(dbPath);
45
+ assert.deepEqual(
46
+ afterMutationsBuf,
47
+ initialStat,
48
+ "File should not have been written yet (debounce window has not elapsed)",
49
+ );
50
+
51
+ await wait(700);
52
+
53
+ const afterDebounceBuf = readFileSync(dbPath);
54
+ assert.notDeepEqual(
55
+ afterDebounceBuf,
56
+ initialStat,
57
+ "File should have been written after debounce window elapsed",
58
+ );
59
+
60
+ const stats = storage.getStats();
61
+ assert.equal(stats.totalThreads, 3);
62
+
63
+ storage.close();
64
+ });
65
+
62
66
  it("close() flushes pending changes immediately without waiting for debounce", async () => {
63
- const dir = makeTmpDir();
67
+ dir = makeTmpDir();
64
68
  const dbPath = join(dir, "test.db");
65
- try {
66
- const storage = await MemoryStorage.create(dbPath);
67
-
68
- const initialBuf = readFileSync(dbPath);
69
-
70
- storage.upsertThreads([
71
- { threadId: "t1", filePath: "/a.txt", fileSize: 100, fileMtime: 1000, cwd: "/proj" },
72
- ]);
73
-
74
- const beforeCloseBuf = readFileSync(dbPath);
75
- assert.deepEqual(
76
- beforeCloseBuf,
77
- initialBuf,
78
- "File should not have been written yet (debounce window has not elapsed)",
79
- );
80
-
81
- storage.close();
82
-
83
- const afterCloseBuf = readFileSync(dbPath);
84
- assert.notDeepEqual(
85
- afterCloseBuf,
86
- initialBuf,
87
- "File should have been written immediately on close()",
88
- );
89
-
90
- const reopened = await MemoryStorage.create(dbPath);
91
- const stats = reopened.getStats();
92
- assert.equal(stats.totalThreads, 1, "Data should be persisted and readable after close");
93
- reopened.close();
94
- } finally {
95
- rmSync(dir, { recursive: true, force: true });
96
- }
69
+ const storage = await MemoryStorage.create(dbPath);
70
+
71
+ const initialBuf = readFileSync(dbPath);
72
+
73
+ storage.upsertThreads([
74
+ { threadId: "t1", filePath: "/a.txt", fileSize: 100, fileMtime: 1000, cwd: "/proj" },
75
+ ]);
76
+
77
+ const beforeCloseBuf = readFileSync(dbPath);
78
+ assert.deepEqual(
79
+ beforeCloseBuf,
80
+ initialBuf,
81
+ "File should not have been written yet (debounce window has not elapsed)",
82
+ );
83
+
84
+ storage.close();
85
+
86
+ const afterCloseBuf = readFileSync(dbPath);
87
+ assert.notDeepEqual(
88
+ afterCloseBuf,
89
+ initialBuf,
90
+ "File should have been written immediately on close()",
91
+ );
92
+
93
+ const reopened = await MemoryStorage.create(dbPath);
94
+ const stats = reopened.getStats();
95
+ assert.equal(stats.totalThreads, 1, "Data should be persisted and readable after close");
96
+ reopened.close();
97
97
  });
98
98
  });
package/pkg/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@glittercowboy/gsd",
3
- "version": "2.44.0",
3
+ "version": "2.45.0",
4
4
  "piConfig": {
5
5
  "name": "gsd",
6
6
  "configDir": ".gsd"
@@ -153,6 +153,7 @@ export function pruneActivityLogs(activityDir: string, retentionDays: number): v
153
153
  const cutoff = Date.now() - retentionDays * 86_400_000;
154
154
  for (const entry of entries) {
155
155
  if (entry.seq === maxSeq) continue; // always preserve highest-seq
156
+ if (retentionDays === 0) { try { unlinkSync(entry.filePath); } catch { /* skip */ } continue; }
156
157
  try {
157
158
  const mtime = statSync(entry.filePath).mtimeMs;
158
159
  if (Math.floor(mtime) <= cutoff) unlinkSync(entry.filePath);