oh-my-opencode 4.13.0 → 4.14.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 (445) hide show
  1. package/.agents/skills/codex-qa/SKILL.md +15 -0
  2. package/.agents/skills/codex-qa/references/logging-debug.md +12 -0
  3. package/.agents/skills/opencode-qa/SKILL.md +17 -0
  4. package/.agents/skills/opencode-qa/references/tui-tmux.md +17 -0
  5. package/.agents/skills/work-with-pr/SKILL.md +18 -10
  6. package/.opencode/skills/work-with-pr/SKILL.md +18 -10
  7. package/README.md +2 -2
  8. package/dist/cli/doctor/checks/telemetry.d.ts +2 -0
  9. package/dist/cli/doctor/framework/constants.d.ts +1 -0
  10. package/dist/cli/doctor/framework/doctor-target.d.ts +1 -1
  11. package/dist/cli/index.js +24651 -16452
  12. package/dist/cli-node/index.js +24651 -16452
  13. package/dist/config/schema/oh-my-opencode-config.d.ts +1 -0
  14. package/dist/features/team-mode/test-support/async-test-helpers.d.ts +19 -0
  15. package/dist/hooks/atlas/final-wave-approval-gate.d.ts +1 -0
  16. package/dist/hooks/atlas/subagent-completion-reminder.d.ts +30 -0
  17. package/dist/hooks/atlas/types.d.ts +2 -0
  18. package/dist/hooks/atlas/verification-reminders.d.ts +3 -0
  19. package/dist/hooks/team-session-events/team-idle-wake-hint.d.ts +1 -0
  20. package/dist/index.d.ts +1 -0
  21. package/dist/index.js +33232 -19559
  22. package/dist/mcp/context7.d.ts +9 -8
  23. package/dist/oh-my-opencode.schema.json +4 -0
  24. package/dist/shared/posthog.d.ts +17 -10
  25. package/dist/shared/telemetry-product-identity.d.ts +2 -0
  26. package/dist/skills/coding-agent-sessions/SKILL.md +128 -0
  27. package/dist/skills/coding-agent-sessions/agents/openai.yaml +4 -0
  28. package/dist/skills/coding-agent-sessions/references/all-platforms.md +71 -0
  29. package/dist/skills/coding-agent-sessions/references/claude.md +32 -0
  30. package/dist/skills/coding-agent-sessions/references/codex.md +30 -0
  31. package/dist/skills/coding-agent-sessions/references/opencode.md +43 -0
  32. package/dist/skills/coding-agent-sessions/references/senpi.md +17 -0
  33. package/dist/skills/coding-agent-sessions/scripts/agent_sessions/__init__.py +1 -0
  34. package/dist/skills/coding-agent-sessions/scripts/agent_sessions/claude.py +66 -0
  35. package/dist/skills/coding-agent-sessions/scripts/agent_sessions/cli.py +283 -0
  36. package/dist/skills/coding-agent-sessions/scripts/agent_sessions/codex.py +105 -0
  37. package/dist/skills/coding-agent-sessions/scripts/agent_sessions/file_scanners.py +275 -0
  38. package/dist/skills/coding-agent-sessions/scripts/agent_sessions/jsonio.py +55 -0
  39. package/dist/skills/coding-agent-sessions/scripts/agent_sessions/kiro_scanner.py +91 -0
  40. package/dist/skills/coding-agent-sessions/scripts/agent_sessions/opencode.py +289 -0
  41. package/dist/skills/coding-agent-sessions/scripts/agent_sessions/scanners.py +92 -0
  42. package/dist/skills/coding-agent-sessions/scripts/agent_sessions/sqlite_optional_scanners.py +203 -0
  43. package/dist/skills/coding-agent-sessions/scripts/agent_sessions/sqlite_scanners.py +177 -0
  44. package/dist/skills/coding-agent-sessions/scripts/agent_sessions/timeparse.py +51 -0
  45. package/dist/skills/coding-agent-sessions/scripts/agent_sessions/transcript.py +149 -0
  46. package/dist/skills/coding-agent-sessions/scripts/agent_sessions/types.py +57 -0
  47. package/dist/skills/coding-agent-sessions/scripts/find-agent-sessions.py +19 -0
  48. package/dist/skills/frontend/ATTRIBUTION.md +52 -8
  49. package/dist/skills/frontend/SKILL.md +29 -8
  50. package/dist/skills/frontend/references/design/README.md +29 -12
  51. package/dist/skills/frontend/references/design/_INDEX.md +3 -3
  52. package/dist/skills/frontend/references/design/design-system-architecture.md +22 -19
  53. package/dist/skills/frontend/references/designpowers/EVIDENCE.md +89 -0
  54. package/dist/skills/frontend/references/designpowers/README.md +48 -0
  55. package/dist/skills/frontend/references/designpowers/UPSTREAM.md +80 -0
  56. package/dist/skills/frontend/references/designpowers/lane-a-direction.md +64 -0
  57. package/dist/skills/frontend/references/designpowers/lane-b-execution.md +65 -0
  58. package/dist/skills/frontend/references/designpowers/lane-c-review.md +65 -0
  59. package/dist/skills/frontend/references/designpowers/lane-d-memory.md +83 -0
  60. package/dist/skills/frontend/references/designpowers/orchestration.md +80 -0
  61. package/dist/skills/frontend/references/designpowers/routing.md +79 -0
  62. package/dist/skills/frontend/references/designpowers/vendor/LICENSE +21 -0
  63. package/dist/skills/frontend/references/designpowers/vendor/agents/accessibility-reviewer.md +83 -0
  64. package/dist/skills/frontend/references/designpowers/vendor/agents/content-writer.md +132 -0
  65. package/dist/skills/frontend/references/designpowers/vendor/agents/design-builder.md +109 -0
  66. package/dist/skills/frontend/references/designpowers/vendor/agents/design-critic.md +89 -0
  67. package/dist/skills/frontend/references/designpowers/vendor/agents/design-lead.md +113 -0
  68. package/dist/skills/frontend/references/designpowers/vendor/agents/design-scout.md +78 -0
  69. package/dist/skills/frontend/references/designpowers/vendor/agents/design-strategist.md +121 -0
  70. package/dist/skills/frontend/references/designpowers/vendor/agents/heuristic-evaluator.md +268 -0
  71. package/dist/skills/frontend/references/designpowers/vendor/agents/inspiration-scout.md +107 -0
  72. package/dist/skills/frontend/references/designpowers/vendor/agents/motion-designer.md +120 -0
  73. package/dist/skills/frontend/references/designpowers/vendor/skills/accessible-content/SKILL.md +101 -0
  74. package/dist/skills/frontend/references/designpowers/vendor/skills/adaptive-interfaces/SKILL.md +109 -0
  75. package/dist/skills/frontend/references/designpowers/vendor/skills/cognitive-accessibility/SKILL.md +107 -0
  76. package/dist/skills/frontend/references/designpowers/vendor/skills/design-debate/SKILL.md +199 -0
  77. package/dist/skills/frontend/references/designpowers/vendor/skills/design-debt-tracker/SKILL.md +174 -0
  78. package/dist/skills/frontend/references/designpowers/vendor/skills/design-handoff/SKILL.md +125 -0
  79. package/dist/skills/frontend/references/designpowers/vendor/skills/design-md/SKILL.md +106 -0
  80. package/dist/skills/frontend/references/designpowers/vendor/skills/design-retrospective/SKILL.md +266 -0
  81. package/dist/skills/frontend/references/designpowers/vendor/skills/design-review/SKILL.md +123 -0
  82. package/dist/skills/frontend/references/designpowers/vendor/skills/design-system-alignment/SKILL.md +120 -0
  83. package/dist/skills/frontend/references/designpowers/vendor/skills/designpowers-critique/SKILL.md +164 -0
  84. package/dist/skills/frontend/references/designpowers/vendor/skills/heuristic-evaluation/SKILL.md +85 -0
  85. package/dist/skills/frontend/references/designpowers/vendor/skills/inclusive-personas/SKILL.md +98 -0
  86. package/dist/skills/frontend/references/designpowers/vendor/skills/inspiration-scouting/SKILL.md +165 -0
  87. package/dist/skills/frontend/references/designpowers/vendor/skills/interaction-design/SKILL.md +122 -0
  88. package/dist/skills/frontend/references/designpowers/vendor/skills/motion-choreography/SKILL.md +81 -0
  89. package/dist/skills/frontend/references/designpowers/vendor/skills/research-planning/SKILL.md +96 -0
  90. package/dist/skills/frontend/references/designpowers/vendor/skills/responsive-patterns/SKILL.md +77 -0
  91. package/dist/skills/frontend/references/designpowers/vendor/skills/synthetic-user-testing/SKILL.md +192 -0
  92. package/dist/skills/frontend/references/designpowers/vendor/skills/taste-feedback/SKILL.md +165 -0
  93. package/dist/skills/frontend/references/designpowers/vendor/skills/taste-report/SKILL.md +78 -0
  94. package/dist/skills/frontend/references/designpowers/vendor/skills/token-architecture/SKILL.md +75 -0
  95. package/dist/skills/frontend/references/designpowers/vendor/skills/ui-composition/SKILL.md +117 -0
  96. package/dist/skills/frontend/references/designpowers/vendor/skills/usability-testing/SKILL.md +78 -0
  97. package/dist/skills/frontend/references/designpowers/vendor/skills/verification-before-shipping/SKILL.md +125 -0
  98. package/dist/skills/frontend/references/designpowers/vendor/skills/voice-and-tone/SKILL.md +79 -0
  99. package/dist/skills/frontend/references/designpowers/vendor/skills/writing-design-plans/SKILL.md +119 -0
  100. package/dist/skills/frontend/references/ui-ux-db/scripts/core.py +0 -0
  101. package/dist/skills/git-master/SKILL.md +4 -0
  102. package/dist/skills/review-work/SKILL.md +3 -3
  103. package/dist/skills/start-work/SKILL.md +7 -5
  104. package/dist/skills/ultraresearch/SKILL.md +4 -252
  105. package/dist/skills/ulw-plan/SKILL.md +8 -6
  106. package/dist/skills/ulw-plan/references/full-workflow.md +11 -6
  107. package/dist/skills/ulw-plan/references/intent-clear.md +3 -3
  108. package/dist/skills/ulw-plan/references/intent-unclear.md +1 -1
  109. package/dist/skills/{ultraresearch → ulw-research}/ATTRIBUTION.md +1 -1
  110. package/dist/skills/ulw-research/SKILL.md +260 -0
  111. package/dist/skills/visual-qa/SKILL.md +105 -14
  112. package/dist/skills/visual-qa/scripts/skill-prompt-contract.test.ts +120 -1
  113. package/dist/testing/create-plugin-module.d.ts +2 -0
  114. package/dist/tui.js +23917 -16117
  115. package/docs/reference/github-attachment-upload.md +51 -0
  116. package/docs/reference/web-terminal-visual-qa.md +81 -0
  117. package/package.json +20 -14
  118. package/packages/lsp-core/src/lsp/process.ts +4 -1
  119. package/packages/lsp-core/src/mcp.ts +1 -0
  120. package/packages/lsp-daemon/dist/cli.js +5 -1
  121. package/packages/lsp-daemon/dist/index.js +5 -1
  122. package/packages/lsp-daemon/dist/proxy.js +1 -0
  123. package/packages/lsp-tools-mcp/dist/cli.js +5 -1
  124. package/packages/lsp-tools-mcp/dist/lsp/manager.js +4 -1
  125. package/packages/lsp-tools-mcp/dist/mcp.js +5 -1
  126. package/packages/lsp-tools-mcp/dist/tools.js +4 -1
  127. package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
  128. package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +323 -62
  129. package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
  130. package/packages/omo-codex/plugin/components/bootstrap/scripts/bootstrap.ps1 +37 -68
  131. package/packages/omo-codex/plugin/components/bootstrap/scripts/node-dispatch.ps1 +75 -0
  132. package/packages/omo-codex/plugin/components/bootstrap/src/cli.ts +1 -1
  133. package/packages/omo-codex/plugin/components/bootstrap/src/setup.ts +2 -18
  134. package/packages/omo-codex/plugin/components/codegraph/dist/cli.js +575 -334
  135. package/packages/omo-codex/plugin/components/codegraph/dist/serve.js +204 -39
  136. package/packages/omo-codex/plugin/components/codegraph/package.json +2 -2
  137. package/packages/omo-codex/plugin/components/codegraph/src/hook-types.ts +7 -1
  138. package/packages/omo-codex/plugin/components/codegraph/src/hook.ts +103 -3
  139. package/packages/omo-codex/plugin/components/codegraph/src/mcp-bridge.ts +114 -0
  140. package/packages/omo-codex/plugin/components/codegraph/src/serve-invocation.ts +29 -0
  141. package/packages/omo-codex/plugin/components/codegraph/src/serve.ts +31 -57
  142. package/packages/omo-codex/plugin/components/codegraph/src/session-start-worker.ts +7 -4
  143. package/packages/omo-codex/plugin/components/codegraph/test/hook.test.ts +43 -9
  144. package/packages/omo-codex/plugin/components/codegraph/test/serve-mcp-bridge.test.ts +146 -0
  145. package/packages/omo-codex/plugin/components/codegraph/test/serve.test.ts +12 -7
  146. package/packages/omo-codex/plugin/components/codegraph/test/session-start-worker-flow.test.ts +71 -1
  147. package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
  148. package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
  149. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
  150. package/packages/omo-codex/plugin/components/lsp/dist/cli.js +4 -1
  151. package/packages/omo-codex/plugin/components/lsp/package.json +1 -1
  152. package/packages/omo-codex/plugin/components/rules/dist/cli.js +2 -2
  153. package/packages/omo-codex/plugin/components/rules/package.json +1 -1
  154. package/packages/omo-codex/plugin/components/rules/src/sparkshell-awareness.ts +2 -2
  155. package/packages/omo-codex/plugin/components/rules/test/sparkshell-awareness.test.ts +11 -2
  156. package/packages/omo-codex/plugin/components/start-work-continuation/directive.md +6 -6
  157. package/packages/omo-codex/plugin/components/start-work-continuation/package.json +1 -1
  158. package/packages/omo-codex/plugin/components/start-work-continuation/test/codex-hook.test.ts +23 -0
  159. package/packages/omo-codex/plugin/components/teammode/dist/cli.js +22 -4
  160. package/packages/omo-codex/plugin/components/teammode/package.json +1 -1
  161. package/packages/omo-codex/plugin/components/teammode/skills/teammode/SKILL.md +40 -2
  162. package/packages/omo-codex/plugin/components/teammode/skills/teammode/scripts/team-guide.mjs +32 -5
  163. package/packages/omo-codex/plugin/components/teammode/skills/teammode/scripts/team.mjs +7 -3
  164. package/packages/omo-codex/plugin/components/teammode/src/codex-hook.ts +19 -4
  165. package/packages/omo-codex/plugin/components/teammode/test/thread-title-hook.test.ts +32 -2
  166. package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
  167. package/packages/omo-codex/plugin/components/ultrawork/README.md +1 -1
  168. package/packages/omo-codex/plugin/components/ultrawork/agents/explorer.toml +1 -1
  169. package/packages/omo-codex/plugin/components/ultrawork/agents/plan.toml +2 -2
  170. package/packages/omo-codex/plugin/components/ultrawork/directive.md +23 -7
  171. package/packages/omo-codex/plugin/components/ultrawork/dist/cli.js +1 -1
  172. package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
  173. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/SKILL.md +6 -4
  174. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/full-workflow.md +11 -6
  175. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/intent-clear.md +3 -3
  176. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/intent-unclear.md +1 -1
  177. package/packages/omo-codex/plugin/components/ultrawork/src/codex-hook.ts +1 -1
  178. package/packages/omo-codex/plugin/components/ultrawork/test/codex-hook-trigger-policy.test.ts +24 -0
  179. package/packages/omo-codex/plugin/components/ultrawork/test/package-smoke.test.ts +6 -1
  180. package/packages/omo-codex/plugin/components/ulw-loop/AGENTS.md +1 -1
  181. package/packages/omo-codex/plugin/components/ulw-loop/README.md +25 -21
  182. package/packages/omo-codex/plugin/components/ulw-loop/biome.json +1 -1
  183. package/packages/omo-codex/plugin/components/ulw-loop/directive.md +381 -0
  184. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-steering.js +14 -1
  185. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli.js +145 -14
  186. package/packages/omo-codex/plugin/components/ulw-loop/dist/codex-hook.d.ts +6 -3
  187. package/packages/omo-codex/plugin/components/ulw-loop/dist/codex-hook.js +16 -6
  188. package/packages/omo-codex/plugin/components/ulw-loop/dist/ultrawork-directive.d.ts +5 -0
  189. package/packages/omo-codex/plugin/components/ulw-loop/dist/ultrawork-directive.js +104 -0
  190. package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +1 -1
  191. package/packages/omo-codex/plugin/components/ulw-loop/package.json +2 -1
  192. package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/references/full-workflow.md +19 -11
  193. package/packages/omo-codex/plugin/components/ulw-loop/src/cli-steering.ts +14 -1
  194. package/packages/omo-codex/plugin/components/ulw-loop/src/cli.ts +4 -2
  195. package/packages/omo-codex/plugin/components/ulw-loop/src/codex-hook.ts +28 -6
  196. package/packages/omo-codex/plugin/components/ulw-loop/src/ultrawork-directive.ts +113 -0
  197. package/packages/omo-codex/plugin/components/ulw-loop/test/cli-entrypoint.test.ts +33 -2
  198. package/packages/omo-codex/plugin/components/ulw-loop/test/cli-steering-kind-guidance.test.ts +31 -0
  199. package/packages/omo-codex/plugin/components/ulw-loop/test/codex-hook.test.ts +13 -0
  200. package/packages/omo-codex/plugin/components/ulw-loop/test/package-smoke.test.ts +36 -0
  201. package/packages/omo-codex/plugin/components/ulw-loop/test/skill-contract.test.ts +12 -0
  202. package/packages/omo-codex/plugin/components/ulw-loop/test/ultrawork-directive.test.ts +64 -0
  203. package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +2 -1
  204. package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +2 -1
  205. package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +2 -1
  206. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-codegraph-init-guidance.json +2 -1
  207. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +2 -1
  208. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +2 -1
  209. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +2 -1
  210. package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +2 -1
  211. package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +2 -1
  212. package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +2 -1
  213. package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +2 -1
  214. package/packages/omo-codex/plugin/hooks/session-start-checking-codegraph-bootstrap.json +2 -1
  215. package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +2 -1
  216. package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +2 -1
  217. package/packages/omo-codex/plugin/hooks/stop-checking-start-work-continuation.json +2 -1
  218. package/packages/omo-codex/plugin/hooks/subagent-stop-checking-start-work-continuation.json +2 -1
  219. package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +2 -1
  220. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +2 -1
  221. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +2 -1
  222. package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +2 -1
  223. package/packages/omo-codex/plugin/package-lock.json +13 -13
  224. package/packages/omo-codex/plugin/package.json +1 -1
  225. package/packages/omo-codex/plugin/scripts/auto-update.mjs +9 -5
  226. package/packages/omo-codex/plugin/scripts/materialize-shared-upstreams.mjs +1 -0
  227. package/packages/omo-codex/plugin/scripts/migrate-codex-config/context7-placeholder-guard.mjs +131 -0
  228. package/packages/omo-codex/plugin/scripts/migrate-codex-config/multi-agent-mode-guard.mjs +60 -0
  229. package/packages/omo-codex/plugin/scripts/migrate-codex-config/multi-agent-v2-guard.mjs +3 -10
  230. package/packages/omo-codex/plugin/scripts/migrate-codex-config/root-settings.mjs +31 -1
  231. package/packages/omo-codex/plugin/scripts/migrate-codex-config/subagent-limit-guard.mjs +73 -0
  232. package/packages/omo-codex/plugin/scripts/migrate-codex-config.mjs +20 -3
  233. package/packages/omo-codex/plugin/scripts/sync-skills.mjs +30 -8
  234. package/packages/omo-codex/plugin/skills/coding-agent-sessions/SKILL.md +128 -0
  235. package/packages/omo-codex/plugin/skills/coding-agent-sessions/agents/openai.yaml +4 -0
  236. package/packages/omo-codex/plugin/skills/coding-agent-sessions/references/all-platforms.md +71 -0
  237. package/packages/omo-codex/plugin/skills/coding-agent-sessions/references/claude.md +32 -0
  238. package/packages/omo-codex/plugin/skills/coding-agent-sessions/references/codex.md +30 -0
  239. package/packages/omo-codex/plugin/skills/coding-agent-sessions/references/opencode.md +43 -0
  240. package/packages/omo-codex/plugin/skills/coding-agent-sessions/references/senpi.md +17 -0
  241. package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/agent_sessions/__init__.py +1 -0
  242. package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/agent_sessions/claude.py +66 -0
  243. package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/agent_sessions/cli.py +283 -0
  244. package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/agent_sessions/codex.py +105 -0
  245. package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/agent_sessions/file_scanners.py +275 -0
  246. package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/agent_sessions/jsonio.py +55 -0
  247. package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/agent_sessions/kiro_scanner.py +91 -0
  248. package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/agent_sessions/opencode.py +289 -0
  249. package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/agent_sessions/scanners.py +92 -0
  250. package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/agent_sessions/sqlite_optional_scanners.py +203 -0
  251. package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/agent_sessions/sqlite_scanners.py +177 -0
  252. package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/agent_sessions/timeparse.py +51 -0
  253. package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/agent_sessions/transcript.py +149 -0
  254. package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/agent_sessions/types.py +57 -0
  255. package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/find-agent-sessions.py +19 -0
  256. package/packages/omo-codex/plugin/skills/frontend/ATTRIBUTION.md +52 -8
  257. package/packages/omo-codex/plugin/skills/frontend/SKILL.md +29 -8
  258. package/packages/omo-codex/plugin/skills/frontend/references/design/README.md +29 -12
  259. package/packages/omo-codex/plugin/skills/frontend/references/design/_INDEX.md +3 -3
  260. package/packages/omo-codex/plugin/skills/frontend/references/design/design-system-architecture.md +22 -19
  261. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/EVIDENCE.md +89 -0
  262. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/README.md +48 -0
  263. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/UPSTREAM.md +80 -0
  264. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/lane-a-direction.md +64 -0
  265. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/lane-b-execution.md +65 -0
  266. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/lane-c-review.md +65 -0
  267. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/lane-d-memory.md +83 -0
  268. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/orchestration.md +80 -0
  269. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/routing.md +79 -0
  270. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/LICENSE +21 -0
  271. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/agents/accessibility-reviewer.md +83 -0
  272. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/agents/content-writer.md +132 -0
  273. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/agents/design-builder.md +109 -0
  274. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/agents/design-critic.md +89 -0
  275. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/agents/design-lead.md +113 -0
  276. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/agents/design-scout.md +78 -0
  277. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/agents/design-strategist.md +121 -0
  278. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/agents/heuristic-evaluator.md +268 -0
  279. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/agents/inspiration-scout.md +107 -0
  280. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/agents/motion-designer.md +120 -0
  281. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/accessible-content/SKILL.md +101 -0
  282. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/adaptive-interfaces/SKILL.md +109 -0
  283. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/cognitive-accessibility/SKILL.md +107 -0
  284. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/design-debate/SKILL.md +199 -0
  285. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/design-debt-tracker/SKILL.md +174 -0
  286. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/design-handoff/SKILL.md +125 -0
  287. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/design-md/SKILL.md +106 -0
  288. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/design-retrospective/SKILL.md +266 -0
  289. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/design-review/SKILL.md +123 -0
  290. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/design-system-alignment/SKILL.md +120 -0
  291. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/designpowers-critique/SKILL.md +164 -0
  292. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/heuristic-evaluation/SKILL.md +85 -0
  293. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/inclusive-personas/SKILL.md +98 -0
  294. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/inspiration-scouting/SKILL.md +165 -0
  295. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/interaction-design/SKILL.md +122 -0
  296. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/motion-choreography/SKILL.md +81 -0
  297. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/research-planning/SKILL.md +96 -0
  298. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/responsive-patterns/SKILL.md +77 -0
  299. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/synthetic-user-testing/SKILL.md +192 -0
  300. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/taste-feedback/SKILL.md +165 -0
  301. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/taste-report/SKILL.md +78 -0
  302. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/token-architecture/SKILL.md +75 -0
  303. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/ui-composition/SKILL.md +117 -0
  304. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/usability-testing/SKILL.md +78 -0
  305. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/verification-before-shipping/SKILL.md +125 -0
  306. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/voice-and-tone/SKILL.md +79 -0
  307. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/writing-design-plans/SKILL.md +119 -0
  308. package/packages/omo-codex/plugin/skills/frontend/references/ui-ux-db/scripts/core.py +0 -0
  309. package/packages/omo-codex/plugin/skills/git-master/SKILL.md +4 -0
  310. package/packages/omo-codex/plugin/skills/init-deep/SKILL.md +4 -0
  311. package/packages/omo-codex/plugin/skills/refactor/SKILL.md +4 -0
  312. package/packages/omo-codex/plugin/skills/remove-ai-slops/SKILL.md +4 -0
  313. package/packages/omo-codex/plugin/skills/review-work/SKILL.md +12 -4
  314. package/packages/omo-codex/plugin/skills/start-work/SKILL.md +14 -8
  315. package/packages/omo-codex/plugin/skills/teammode/SKILL.md +40 -2
  316. package/packages/omo-codex/plugin/skills/teammode/scripts/team-guide.mjs +32 -5
  317. package/packages/omo-codex/plugin/skills/teammode/scripts/team.mjs +7 -3
  318. package/packages/omo-codex/plugin/skills/ultraresearch/SKILL.md +4 -250
  319. package/packages/omo-codex/plugin/skills/ulw-loop/references/full-workflow.md +19 -11
  320. package/packages/omo-codex/plugin/skills/ulw-plan/SKILL.md +6 -4
  321. package/packages/omo-codex/plugin/skills/ulw-plan/references/full-workflow.md +11 -6
  322. package/packages/omo-codex/plugin/skills/ulw-plan/references/intent-clear.md +3 -3
  323. package/packages/omo-codex/plugin/skills/ulw-plan/references/intent-unclear.md +1 -1
  324. package/packages/{shared-skills/skills/ultraresearch → omo-codex/plugin/skills/ulw-research}/ATTRIBUTION.md +1 -1
  325. package/packages/omo-codex/plugin/skills/ulw-research/SKILL.md +262 -0
  326. package/packages/omo-codex/plugin/skills/ulw-research/agents/openai.yaml +2 -0
  327. package/packages/omo-codex/plugin/skills/visual-qa/SKILL.md +109 -14
  328. package/packages/omo-codex/plugin/test/aggregate-hooks.test.mjs +23 -0
  329. package/packages/omo-codex/plugin/test/aggregate-manifest.test.mjs +1 -0
  330. package/packages/omo-codex/plugin/test/auto-update-release-notes.test.mjs +1 -0
  331. package/packages/omo-codex/plugin/test/auto-update-restart-notice.test.mjs +24 -1
  332. package/packages/omo-codex/plugin/test/bootstrap-binlinks.test.mjs +23 -5
  333. package/packages/omo-codex/plugin/test/bootstrap-hooks.test.mjs +38 -0
  334. package/packages/omo-codex/plugin/test/bootstrap-ps-guard.test.mjs +25 -0
  335. package/packages/omo-codex/plugin/test/bootstrap-setup.test.mjs +1 -7
  336. package/packages/omo-codex/plugin/test/migrate-codex-config.test.mjs +206 -6
  337. package/packages/omo-codex/plugin/test/subagent-limit-migration.test.mjs +44 -0
  338. package/packages/omo-codex/plugin/test/sync-skills-orchestration.test.mjs +50 -1
  339. package/packages/omo-codex/plugin/test/sync-skills-test-support.mjs +10 -7
  340. package/packages/omo-codex/plugin/test/sync-skills.test.mjs +28 -2
  341. package/packages/omo-codex/plugin/test/teammode-communication.test.mjs +20 -0
  342. package/packages/omo-codex/plugin/test/teammode-thread-links.test.mjs +117 -0
  343. package/packages/omo-codex/plugin/test/teammode-worktree.test.mjs +5 -2
  344. package/packages/omo-codex/plugin/test/ulw-research-skill-contract.test.mjs +285 -0
  345. package/packages/omo-codex/scripts/install-bin-links.test.mjs +6 -1
  346. package/packages/omo-codex/scripts/install-cache-copy.test.mjs +51 -0
  347. package/packages/omo-codex/scripts/install-config.test.mjs +198 -17
  348. package/packages/omo-codex/scripts/install-dist/install-local.mjs +701 -282
  349. package/packages/omo-codex/scripts/install-local-git-bash-preflight.test.mjs +24 -15
  350. package/packages/omo-codex/scripts/install-local.test.mjs +5 -1
  351. package/packages/omo-codex/scripts/install-mcp-context7-runtime.test.mjs +84 -0
  352. package/packages/shared-skills/skills/coding-agent-sessions/SKILL.md +128 -0
  353. package/packages/shared-skills/skills/coding-agent-sessions/agents/openai.yaml +4 -0
  354. package/packages/shared-skills/skills/coding-agent-sessions/references/all-platforms.md +71 -0
  355. package/packages/shared-skills/skills/coding-agent-sessions/references/claude.md +32 -0
  356. package/packages/shared-skills/skills/coding-agent-sessions/references/codex.md +30 -0
  357. package/packages/shared-skills/skills/coding-agent-sessions/references/opencode.md +43 -0
  358. package/packages/shared-skills/skills/coding-agent-sessions/references/senpi.md +17 -0
  359. package/packages/shared-skills/skills/coding-agent-sessions/scripts/agent_sessions/__init__.py +1 -0
  360. package/packages/shared-skills/skills/coding-agent-sessions/scripts/agent_sessions/claude.py +66 -0
  361. package/packages/shared-skills/skills/coding-agent-sessions/scripts/agent_sessions/cli.py +283 -0
  362. package/packages/shared-skills/skills/coding-agent-sessions/scripts/agent_sessions/codex.py +105 -0
  363. package/packages/shared-skills/skills/coding-agent-sessions/scripts/agent_sessions/file_scanners.py +275 -0
  364. package/packages/shared-skills/skills/coding-agent-sessions/scripts/agent_sessions/jsonio.py +55 -0
  365. package/packages/shared-skills/skills/coding-agent-sessions/scripts/agent_sessions/kiro_scanner.py +91 -0
  366. package/packages/shared-skills/skills/coding-agent-sessions/scripts/agent_sessions/opencode.py +289 -0
  367. package/packages/shared-skills/skills/coding-agent-sessions/scripts/agent_sessions/scanners.py +92 -0
  368. package/packages/shared-skills/skills/coding-agent-sessions/scripts/agent_sessions/sqlite_optional_scanners.py +203 -0
  369. package/packages/shared-skills/skills/coding-agent-sessions/scripts/agent_sessions/sqlite_scanners.py +177 -0
  370. package/packages/shared-skills/skills/coding-agent-sessions/scripts/agent_sessions/timeparse.py +51 -0
  371. package/packages/shared-skills/skills/coding-agent-sessions/scripts/agent_sessions/transcript.py +149 -0
  372. package/packages/shared-skills/skills/coding-agent-sessions/scripts/agent_sessions/types.py +57 -0
  373. package/packages/shared-skills/skills/coding-agent-sessions/scripts/find-agent-sessions.py +19 -0
  374. package/packages/shared-skills/skills/frontend/ATTRIBUTION.md +52 -8
  375. package/packages/shared-skills/skills/frontend/SKILL.md +29 -8
  376. package/packages/shared-skills/skills/frontend/references/design/README.md +29 -12
  377. package/packages/shared-skills/skills/frontend/references/design/_INDEX.md +3 -3
  378. package/packages/shared-skills/skills/frontend/references/design/design-system-architecture.md +22 -19
  379. package/packages/shared-skills/skills/frontend/references/designpowers/EVIDENCE.md +89 -0
  380. package/packages/shared-skills/skills/frontend/references/designpowers/README.md +48 -0
  381. package/packages/shared-skills/skills/frontend/references/designpowers/UPSTREAM.md +80 -0
  382. package/packages/shared-skills/skills/frontend/references/designpowers/lane-a-direction.md +64 -0
  383. package/packages/shared-skills/skills/frontend/references/designpowers/lane-b-execution.md +65 -0
  384. package/packages/shared-skills/skills/frontend/references/designpowers/lane-c-review.md +65 -0
  385. package/packages/shared-skills/skills/frontend/references/designpowers/lane-d-memory.md +83 -0
  386. package/packages/shared-skills/skills/frontend/references/designpowers/orchestration.md +80 -0
  387. package/packages/shared-skills/skills/frontend/references/designpowers/routing.md +79 -0
  388. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/LICENSE +21 -0
  389. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/agents/accessibility-reviewer.md +83 -0
  390. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/agents/content-writer.md +132 -0
  391. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/agents/design-builder.md +109 -0
  392. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/agents/design-critic.md +89 -0
  393. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/agents/design-lead.md +113 -0
  394. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/agents/design-scout.md +78 -0
  395. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/agents/design-strategist.md +121 -0
  396. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/agents/heuristic-evaluator.md +268 -0
  397. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/agents/inspiration-scout.md +107 -0
  398. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/agents/motion-designer.md +120 -0
  399. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/accessible-content/SKILL.md +101 -0
  400. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/adaptive-interfaces/SKILL.md +109 -0
  401. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/cognitive-accessibility/SKILL.md +107 -0
  402. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/design-debate/SKILL.md +199 -0
  403. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/design-debt-tracker/SKILL.md +174 -0
  404. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/design-handoff/SKILL.md +125 -0
  405. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/design-md/SKILL.md +106 -0
  406. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/design-retrospective/SKILL.md +266 -0
  407. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/design-review/SKILL.md +123 -0
  408. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/design-system-alignment/SKILL.md +120 -0
  409. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/designpowers-critique/SKILL.md +164 -0
  410. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/heuristic-evaluation/SKILL.md +85 -0
  411. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/inclusive-personas/SKILL.md +98 -0
  412. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/inspiration-scouting/SKILL.md +165 -0
  413. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/interaction-design/SKILL.md +122 -0
  414. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/motion-choreography/SKILL.md +81 -0
  415. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/research-planning/SKILL.md +96 -0
  416. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/responsive-patterns/SKILL.md +77 -0
  417. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/synthetic-user-testing/SKILL.md +192 -0
  418. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/taste-feedback/SKILL.md +165 -0
  419. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/taste-report/SKILL.md +78 -0
  420. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/token-architecture/SKILL.md +75 -0
  421. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/ui-composition/SKILL.md +117 -0
  422. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/usability-testing/SKILL.md +78 -0
  423. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/verification-before-shipping/SKILL.md +125 -0
  424. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/voice-and-tone/SKILL.md +79 -0
  425. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/writing-design-plans/SKILL.md +119 -0
  426. package/packages/shared-skills/skills/frontend/references/ui-ux-db/scripts/core.py +0 -0
  427. package/packages/shared-skills/skills/git-master/SKILL.md +4 -0
  428. package/packages/shared-skills/skills/review-work/SKILL.md +3 -3
  429. package/packages/shared-skills/skills/start-work/SKILL.md +7 -5
  430. package/packages/shared-skills/skills/ultraresearch/SKILL.md +4 -252
  431. package/packages/shared-skills/skills/ulw-plan/SKILL.md +8 -6
  432. package/packages/shared-skills/skills/ulw-plan/references/full-workflow.md +11 -6
  433. package/packages/shared-skills/skills/ulw-plan/references/intent-clear.md +3 -3
  434. package/packages/shared-skills/skills/ulw-plan/references/intent-unclear.md +1 -1
  435. package/packages/{omo-codex/plugin/skills/ultraresearch → shared-skills/skills/ulw-research}/ATTRIBUTION.md +1 -1
  436. package/packages/shared-skills/skills/ulw-research/SKILL.md +260 -0
  437. package/packages/shared-skills/skills/visual-qa/SKILL.md +105 -14
  438. package/packages/shared-skills/skills/visual-qa/scripts/skill-prompt-contract.test.ts +120 -1
  439. package/script/qa/web-terminal-redaction.d.mts +13 -0
  440. package/script/qa/web-terminal-redaction.mjs +43 -0
  441. package/script/qa/web-terminal-renderer.mjs +218 -0
  442. package/script/qa/web-terminal-visual-qa.mjs +264 -0
  443. package/packages/omo-codex/plugin/skills/ultimate-browsing/scripts/tests/test_cookie_domain_filter.py +0 -110
  444. package/packages/omo-codex/plugin/skills/ultimate-browsing/scripts/tests/test_extract_cookies.py +0 -245
  445. package/packages/omo-codex/plugin/test/ultraresearch-skill-contract.test.mjs +0 -204
@@ -0,0 +1,203 @@
1
+ from __future__ import annotations
2
+
3
+ import sqlite3
4
+ from collections.abc import Iterable
5
+ from pathlib import Path
6
+
7
+ from .jsonio import as_map, parse_json_text, text
8
+ from .timeparse import file_time, unix_millis
9
+ from .transcript import content_text, existing, flat_parallel, recent
10
+ from .types import JsonMap, Session
11
+
12
+ SqlValue = str | int | float | bytes | None
13
+ SqlRow = tuple[SqlValue, ...]
14
+
15
+
16
+ def scan_kilo_cli(extra_roots: tuple[Path, ...], workers: int) -> list[Session]:
17
+ paths = existing([Path.home() / ".local" / "share" / "kilo" / "kilo.db", *(root / "kilo.db" for root in extra_roots)])
18
+ return flat_parallel(recent(paths), workers, lambda path: _message_table_sessions(path, "kilo-cli", "message"))
19
+
20
+
21
+ def scan_hermes(extra_roots: tuple[Path, ...], workers: int) -> list[Session]:
22
+ paths = existing([Path.home() / ".hermes" / "state.db", *(root / "state.db" for root in extra_roots)])
23
+ return flat_parallel(recent(paths), workers, lambda path: _message_table_sessions(path, "hermes", "messages"))
24
+
25
+
26
+ def scan_goose(extra_roots: tuple[Path, ...], workers: int) -> list[Session]:
27
+ defaults = [
28
+ Path.home() / ".local" / "share" / "goose" / "sessions" / "sessions.db",
29
+ Path.home() / "Library" / "Application Support" / "goose" / "sessions" / "sessions.db",
30
+ ]
31
+ paths = existing([*defaults, *(root / "sessions.db" for root in extra_roots)])
32
+ return flat_parallel(recent(paths), workers, lambda path: _message_table_sessions(path, "goose", "messages"))
33
+
34
+
35
+ def scan_crush(extra_roots: tuple[Path, ...], workers: int) -> list[Session]:
36
+ paths = existing([Path.home() / ".local" / "share" / "crush" / "crush.db", *(root / "crush.db" for root in extra_roots)])
37
+ return flat_parallel(recent(paths), workers, _crush_sessions)
38
+
39
+
40
+ def scan_zed(extra_roots: tuple[Path, ...], workers: int) -> list[Session]:
41
+ paths = existing([Path.home() / "Library" / "Application Support" / "Zed" / "threads" / "threads.db", *(root / "threads.db" for root in extra_roots)])
42
+ return flat_parallel(recent(paths), workers, _zed_sessions)
43
+
44
+
45
+ def _message_table_sessions(path: Path, platform: str, table: str) -> list[Session]:
46
+ try:
47
+ with sqlite3.connect(path) as conn:
48
+ rows = _fetch_all(conn, f"select session_id, role, data, created_at from {table} order by created_at")
49
+ except sqlite3.Error:
50
+ return []
51
+ return _group_message_rows(platform, path, rows)
52
+
53
+
54
+ def _crush_sessions(path: Path) -> list[Session]:
55
+ try:
56
+ with sqlite3.connect(path) as conn:
57
+ rows = _fetch_all(conn, "select session_id, role, parts, created_at from messages order by created_at")
58
+ except sqlite3.Error:
59
+ return []
60
+ return _group_message_rows("crush", path, rows)
61
+
62
+
63
+ def _zed_sessions(path: Path) -> list[Session]:
64
+ try:
65
+ with sqlite3.connect(path) as conn:
66
+ rows = _fetch_all(conn, "select id, data_type, data, updated_at from threads")
67
+ except sqlite3.Error:
68
+ return []
69
+ sessions: list[Session] = []
70
+ for row in rows:
71
+ if _row_text(row, 1) != "json":
72
+ continue
73
+ data = _json_blob(_row_bytes(row, 2))
74
+ messages = _json_messages(data)
75
+ first_user, last_user = _message_edges(messages)
76
+ if not first_user:
77
+ continue
78
+ sid = _row_text(row, 0) or path.stem
79
+ sessions.append(Session("zed", sid, str(path), None, _row_text(row, 3) or file_time(path), _row_text(row, 3) or file_time(path), "zed.dev", _zed_model(data), first_user, {"message_count": len(messages)}, last_user_message=last_user))
80
+ return sessions
81
+
82
+
83
+ def _group_message_rows(platform: str, path: Path, rows: Iterable[SqlRow]) -> list[Session]:
84
+ grouped: dict[str, list[JsonMap]] = {}
85
+ stamps: dict[str, str] = {}
86
+ for row in rows:
87
+ sid = _row_text(row, 0)
88
+ if sid is None:
89
+ continue
90
+ message = _message_json(row)
91
+ if message is None:
92
+ continue
93
+ if sid not in grouped:
94
+ grouped[sid] = []
95
+ grouped[sid].append(message)
96
+ if sid not in stamps:
97
+ stamps[sid] = _stamp(row, 3) or file_time(path) or ""
98
+ sessions: list[Session] = []
99
+ for sid, messages in grouped.items():
100
+ first_user, last_user = _message_edges(messages)
101
+ if not first_user:
102
+ continue
103
+ sessions.append(Session(platform, sid, str(path), None, stamps.get(sid) or file_time(path), file_time(path), _provider(messages), _model(messages), first_user, {"message_count": len(messages)}, last_user_message=last_user))
104
+ return sessions
105
+
106
+
107
+ def _message_json(row: SqlRow) -> JsonMap | None:
108
+ role = _row_text(row, 1)
109
+ raw = _row_json(row, 2)
110
+ if raw is None:
111
+ return {"role": role or "", "content": _row_text(row, 2) or ""}
112
+ if "role" not in raw:
113
+ raw["role"] = role or text(raw.get("role")) or ""
114
+ return raw
115
+
116
+
117
+ def _message_edges(messages: list[JsonMap]) -> tuple[str, str]:
118
+ first_user = last_user = ""
119
+ for message in messages:
120
+ if text(message.get("role")) != "user":
121
+ continue
122
+ prompt = _content(message)
123
+ if prompt:
124
+ first_user = first_user or prompt
125
+ last_user = prompt
126
+ return first_user, last_user
127
+
128
+
129
+ def _content(message: JsonMap) -> str:
130
+ for key in ("content", "parts", "text"):
131
+ value = message.get(key)
132
+ parsed = parse_json_text(value) if isinstance(value, str) else value
133
+ result = content_text(parsed) or (value if isinstance(value, str) else "")
134
+ if result:
135
+ return result
136
+ return ""
137
+
138
+
139
+ def _json_messages(data: JsonMap | None) -> list[JsonMap]:
140
+ if data is None:
141
+ return []
142
+ for key in ("messages", "turns", "entries"):
143
+ value = data.get(key)
144
+ if isinstance(value, list):
145
+ return [item for item in value if isinstance(item, dict)]
146
+ return []
147
+
148
+
149
+ def _model(messages: list[JsonMap]) -> str | None:
150
+ for message in messages:
151
+ model = text(message.get("modelID")) or text(message.get("model_id")) or text(message.get("model"))
152
+ if model:
153
+ return model
154
+ return None
155
+
156
+
157
+ def _provider(messages: list[JsonMap]) -> str | None:
158
+ for message in messages:
159
+ provider = text(message.get("providerID")) or text(message.get("provider_id")) or text(message.get("provider"))
160
+ if provider:
161
+ return provider
162
+ return None
163
+
164
+
165
+ def _zed_model(data: JsonMap | None) -> str | None:
166
+ model = as_map(data.get("model")) if data is not None else None
167
+ return text(model.get("model")) if model is not None else None
168
+
169
+
170
+ def _fetch_all(conn: sqlite3.Connection, sql: str) -> list[SqlRow]:
171
+ rows: list[SqlRow] = conn.execute(sql).fetchall()
172
+ return rows
173
+
174
+
175
+ def _row_json(row: SqlRow, index: int) -> JsonMap | None:
176
+ value = _row_text(row, index)
177
+ return as_map(parse_json_text(value)) if value is not None else None
178
+
179
+
180
+ def _json_blob(value: bytes | None) -> JsonMap | None:
181
+ if value is None:
182
+ return None
183
+ try:
184
+ return as_map(parse_json_text(value.decode()))
185
+ except UnicodeDecodeError:
186
+ return None
187
+
188
+
189
+ def _row_text(row: SqlRow, index: int) -> str | None:
190
+ value = row[index] if index < len(row) else None
191
+ return text(value) if not isinstance(value, bytes) else None
192
+
193
+
194
+ def _row_bytes(row: SqlRow, index: int) -> bytes | None:
195
+ value = row[index] if index < len(row) else None
196
+ return value if isinstance(value, bytes) else None
197
+
198
+
199
+ def _stamp(row: SqlRow, index: int) -> str | None:
200
+ value = row[index] if index < len(row) else None
201
+ if isinstance(value, int):
202
+ return unix_millis(value) if value > 10_000_000_000 else None
203
+ return value if isinstance(value, str) else None
@@ -0,0 +1,177 @@
1
+ from __future__ import annotations
2
+
3
+ import sqlite3
4
+ from pathlib import Path
5
+ from typing import TypeAlias
6
+
7
+ from .jsonio import as_map, parse_json_text, text
8
+ from .timeparse import file_time, unix_millis
9
+ from .transcript import content_text, env_path, existing, flat_parallel, recent
10
+ from .types import Json, JsonMap, Session
11
+
12
+ SqlValue: TypeAlias = str | int | float | bytes | None
13
+ SqlRow: TypeAlias = tuple[SqlValue, ...]
14
+
15
+
16
+ def scan_kodu(extra_roots: tuple[Path, ...], workers: int) -> list[Session]:
17
+ appdata = env_path("APPDATA")
18
+ roots = _roots(
19
+ [
20
+ Path.home() / "Library" / "Application Support" / "Code" / "User" / "globalStorage" / "kodu-ai.claude-dev-experimental",
21
+ Path.home() / ".config" / "Code" / "User" / "globalStorage" / "kodu-ai.claude-dev-experimental",
22
+ *(path / "Code" / "User" / "globalStorage" / "kodu-ai.claude-dev-experimental" for path in (appdata,) if path is not None),
23
+ ],
24
+ extra_roots,
25
+ ("kodu-ai.claude-dev-experimental",),
26
+ )
27
+ paths = [root / "db" / "Azad.db" for root in roots if (root / "db" / "Azad.db").exists()]
28
+ return flat_parallel(recent(paths), workers, _kodu_db)
29
+
30
+
31
+ def scan_cursor_cli(extra_roots: tuple[Path, ...], workers: int) -> list[Session]:
32
+ roots = _roots([Path.home() / ".cursor"], extra_roots, (".cursor",))
33
+ paths = [path for root in roots for path in (root / "chats").glob("*/*/store.db")]
34
+ return flat_parallel(recent(paths), workers, _cursor_db)
35
+
36
+
37
+ def _kodu_db(path: Path) -> list[Session]:
38
+ try:
39
+ with sqlite3.connect(path) as conn:
40
+ tasks = _fetch_all(
41
+ conn,
42
+ "select id, name, dir_absolute_path, created_at, updated_at, tokens_in, tokens_out, cache_reads, cache_writes, cost from tasks"
43
+ )
44
+ return [_kodu_session(path, conn, row) for row in tasks]
45
+ except sqlite3.Error:
46
+ return []
47
+
48
+
49
+ def _kodu_session(path: Path, conn: sqlite3.Connection, row: SqlRow) -> Session:
50
+ sid = _row_text(row, 0) or ""
51
+ messages = _fetch_all(
52
+ conn,
53
+ "select role, content, model_id, started_at, finished_at, tokens_in, tokens_out, cache_reads, cache_writes, cost from messages where task_id = ? order by started_at",
54
+ (sid,),
55
+ )
56
+ first_user = last_user = ""
57
+ model = None
58
+ for message in messages:
59
+ model = model or _row_text(message, 2)
60
+ if _row_text(message, 0) == "user":
61
+ prompt = _content(_row_text(message, 1))
62
+ first_user = first_user or prompt
63
+ last_user = prompt
64
+ return Session(
65
+ "kodu",
66
+ sid,
67
+ str(path),
68
+ _row_text(row, 2),
69
+ unix_millis(_row_int(row, 3)),
70
+ unix_millis(_row_int(row, 4)) or file_time(path),
71
+ None,
72
+ model,
73
+ first_user,
74
+ _usage(row, (5, "input"), (6, "output"), (7, "cacheRead"), (8, "cacheWrite"), (9, "cost_total")),
75
+ last_user_message=last_user,
76
+ )
77
+
78
+
79
+ def _cursor_db(path: Path) -> list[Session]:
80
+ try:
81
+ with sqlite3.connect(path) as conn:
82
+ rows = _fetch_all(conn, "select data from blobs")
83
+ except sqlite3.Error:
84
+ return []
85
+ first_user = last_user = ""
86
+ for row in rows:
87
+ data = _json_blob(_row_bytes(row, 0))
88
+ if data is None or data.get("role") != "user":
89
+ continue
90
+ prompt = _cursor_prompt(_content(data.get("content")))
91
+ if prompt:
92
+ first_user = first_user or prompt
93
+ last_user = prompt
94
+ if not first_user:
95
+ return []
96
+ return [
97
+ Session(
98
+ "cursor-cli",
99
+ path.parent.name,
100
+ str(path),
101
+ None,
102
+ file_time(path),
103
+ file_time(path),
104
+ "cursor",
105
+ None,
106
+ first_user,
107
+ {"blob_count": len(rows)},
108
+ last_user_message=last_user,
109
+ )
110
+ ]
111
+
112
+
113
+ def _content(value: Json | None) -> str:
114
+ parsed = parse_json_text(value) if isinstance(value, str) else value
115
+ return content_text(parsed) or (value if isinstance(value, str) else "")
116
+
117
+
118
+ def _json_blob(value: bytes | None) -> JsonMap | None:
119
+ if value is None:
120
+ return None
121
+ try:
122
+ decoded = value.decode()
123
+ except UnicodeDecodeError:
124
+ return None
125
+ return as_map(parse_json_text(decoded))
126
+
127
+
128
+ def _cursor_prompt(value: str) -> str:
129
+ start = value.find("<user_query>")
130
+ end = value.find("</user_query>")
131
+ if start >= 0 and end > start:
132
+ return value[start + len("<user_query>") : end].strip()
133
+ if value.lstrip().startswith("<user_info>"):
134
+ return ""
135
+ return value.strip()
136
+
137
+
138
+ def _usage(row: SqlRow, *fields: tuple[int, str]) -> JsonMap:
139
+ result: JsonMap = {}
140
+ for index, key in fields:
141
+ value = _row_number(row, index)
142
+ if value is not None:
143
+ result[key] = value
144
+ return result
145
+
146
+
147
+ def _fetch_all(conn: sqlite3.Connection, sql: str, params: tuple[str, ...] = ()) -> list[SqlRow]:
148
+ rows: list[SqlRow] = conn.execute(sql, params).fetchall()
149
+ return rows
150
+
151
+
152
+ def _row_text(row: SqlRow, index: int) -> str | None:
153
+ value = row[index] if index < len(row) else None
154
+ return text(value) if not isinstance(value, bytes) else None
155
+
156
+
157
+ def _row_bytes(row: SqlRow, index: int) -> bytes | None:
158
+ value = row[index] if index < len(row) else None
159
+ return value if isinstance(value, bytes) else None
160
+
161
+
162
+ def _row_number(row: SqlRow, index: int) -> int | float | None:
163
+ value = row[index] if index < len(row) else None
164
+ return value if isinstance(value, int | float) else None
165
+
166
+
167
+ def _row_int(row: SqlRow, index: int) -> int | None:
168
+ value = row[index] if index < len(row) else None
169
+ return value if isinstance(value, int) else None
170
+
171
+
172
+ def _roots(defaults: list[Path], extra_roots: tuple[Path, ...], children: tuple[str, ...]) -> list[Path]:
173
+ candidates = [*defaults]
174
+ for root in extra_roots:
175
+ candidates.append(root)
176
+ candidates.extend(root / child for child in children)
177
+ return existing(candidates)
@@ -0,0 +1,51 @@
1
+ from __future__ import annotations
2
+
3
+ from datetime import datetime, timedelta, timezone
4
+ from pathlib import Path
5
+
6
+
7
+ def date_bound(value: str | None, end: bool = False) -> datetime | None:
8
+ if value is None:
9
+ return None
10
+ text = value.strip().lower()
11
+ now = datetime.now(timezone.utc)
12
+ if text == "today":
13
+ base = now.replace(hour=0, minute=0, second=0, microsecond=0)
14
+ elif text == "yesterday":
15
+ base = (now - timedelta(days=1)).replace(hour=0, minute=0, second=0, microsecond=0)
16
+ elif text.endswith("d") and text[:-1].isdigit():
17
+ base = (now - timedelta(days=int(text[:-1]))).replace(hour=0, minute=0, second=0, microsecond=0)
18
+ else:
19
+ parts = [int(part) for part in text.split("-")]
20
+ base = datetime(parts[0], parts[1] if len(parts) > 1 else 1, parts[2] if len(parts) > 2 else 1, tzinfo=timezone.utc)
21
+ if not end:
22
+ return base
23
+ if text in {"today", "yesterday"} or text.endswith("d") or len(text.split("-")) == 3:
24
+ return base + timedelta(days=1)
25
+ if len(text.split("-")) == 2:
26
+ return datetime(base.year + (base.month // 12), (base.month % 12) + 1, 1, tzinfo=timezone.utc)
27
+ return datetime(base.year + 1, 1, 1, tzinfo=timezone.utc)
28
+
29
+
30
+ def parse_stamp(value: str | None) -> datetime | None:
31
+ if value is None:
32
+ return None
33
+ try:
34
+ return datetime.fromisoformat(value.replace("Z", "+00:00")).astimezone(timezone.utc)
35
+ except ValueError:
36
+ return None
37
+
38
+
39
+ def unix_seconds(value: int | float | None) -> str | None:
40
+ return datetime.fromtimestamp(value, timezone.utc).isoformat() if value is not None else None
41
+
42
+
43
+ def unix_millis(value: int | None) -> str | None:
44
+ return datetime.fromtimestamp(value / 1000, timezone.utc).isoformat() if value is not None else None
45
+
46
+
47
+ def file_time(path: Path) -> str | None:
48
+ try:
49
+ return datetime.fromtimestamp(path.stat().st_mtime, timezone.utc).isoformat()
50
+ except OSError:
51
+ return None
@@ -0,0 +1,149 @@
1
+ from __future__ import annotations
2
+
3
+ import os
4
+ from concurrent.futures import ThreadPoolExecutor, as_completed
5
+ from heapq import nlargest
6
+ from pathlib import Path
7
+ from typing import Callable
8
+
9
+ from .jsonio import as_map, iter_jsonl, parse_json_text, text
10
+ from .timeparse import file_time
11
+ from .types import Json, JsonMap, Session
12
+
13
+ MAX_PLATFORM_FILES = 2000
14
+
15
+
16
+ def jsonl_parallel(paths: list[Path], workers: int, platform: str, fallback_id: Callable[[Path], str]) -> list[Session]:
17
+ if not paths:
18
+ return []
19
+ sessions: list[Session] = []
20
+ with ThreadPoolExecutor(max_workers=min(workers, max(len(paths), 1))) as pool:
21
+ futures = [pool.submit(jsonl_session, platform, path, fallback_id(path)) for path in paths]
22
+ for future in as_completed(futures):
23
+ sessions.append(future.result())
24
+ return sessions
25
+
26
+
27
+ def flat_parallel(paths: list[Path], workers: int, read: Callable[[Path], list[Session]]) -> list[Session]:
28
+ if not paths:
29
+ return []
30
+ sessions: list[Session] = []
31
+ with ThreadPoolExecutor(max_workers=min(workers, max(len(paths), 1))) as pool:
32
+ futures = [pool.submit(read, path) for path in paths]
33
+ for future in as_completed(futures):
34
+ sessions.extend(future.result())
35
+ return sessions
36
+
37
+
38
+ def jsonl_session(platform: str, path: Path, fallback_id: str) -> Session:
39
+ sid = fallback_id
40
+ cwd = provider = model = first_user = parent = agent = None
41
+ last_user = ""
42
+ created = updated = None
43
+ usage: JsonMap = {}
44
+ for data in iter_jsonl(path):
45
+ event_type = data.get("type")
46
+ session_line_id = text(data.get("id")) if event_type == "session" else None
47
+ sid = text(data.get("sessionId")) or session_line_id or sid
48
+ cwd = cwd or text(data.get("cwd"))
49
+ created = created or text(data.get("timestamp"))
50
+ updated = text(data.get("timestamp")) or updated
51
+ provider = provider or text(data.get("provider"))
52
+ model = model or text(data.get("modelId")) or text(data.get("model"))
53
+ payload = as_map(data.get("payload"))
54
+ if event_type == "session_meta" and payload is not None:
55
+ sid = text(payload.get("id")) or sid
56
+ cwd = cwd or text(payload.get("cwd"))
57
+ provider = provider or text(payload.get("model_provider"))
58
+ source_parent, source_agent = spawn_info(payload.get("source"))
59
+ parent = parent or source_parent
60
+ agent = agent or source_agent or nick_role(text(payload.get("agent_nickname")), text(payload.get("agent_role")))
61
+ message = as_map(data.get("message")) or payload or {}
62
+ provider = provider or text(message.get("provider"))
63
+ model = model or text(message.get("model"))
64
+ prompt = user_text(data, message)
65
+ if prompt:
66
+ first_user = first_user or prompt
67
+ last_user = prompt
68
+ merge_usage(usage, as_map(message.get("usage")) or as_map(data.get("usage")))
69
+ return Session(platform, sid, str(path), cwd, created or file_time(path), updated or created or file_time(path), provider, model, first_user or "", usage, parent, agent, last_user)
70
+
71
+
72
+ def spawn_info(source: Json | None) -> tuple[str | None, str | None]:
73
+ data = as_map(parse_json_text(source) if isinstance(source, str) else source)
74
+ if data is None:
75
+ return None, None
76
+ subagent = data.get("subagent")
77
+ if isinstance(subagent, str):
78
+ return None, subagent
79
+ subagent_map = as_map(subagent)
80
+ spawn = as_map(subagent_map.get("thread_spawn")) if subagent_map is not None else None
81
+ if spawn is None:
82
+ return None, None
83
+ return text(spawn.get("parent_thread_id")), nick_role(text(spawn.get("agent_nickname")), text(spawn.get("agent_role")))
84
+
85
+
86
+ def nick_role(nickname: str | None, role: str | None) -> str | None:
87
+ if nickname and role:
88
+ return f"{nickname} ({role})"
89
+ return nickname or role
90
+
91
+
92
+ def user_text(data: JsonMap, message: JsonMap) -> str:
93
+ if data.get("type") == "user":
94
+ value = content_text(data.get("content"))
95
+ if value:
96
+ return value
97
+ if message.get("role") == "user":
98
+ return content_text(message.get("content"))
99
+ return ""
100
+
101
+
102
+ def content_text(value: Json | None) -> str:
103
+ if isinstance(value, str):
104
+ return value
105
+ if isinstance(value, list):
106
+ parts = [text(item.get("text")) or text(item.get("content")) or "" for item in value if isinstance(item, dict)]
107
+ return "\n".join(part for part in parts if part)
108
+ return ""
109
+
110
+
111
+ def merge_usage(target: JsonMap, value: JsonMap | None) -> None:
112
+ if value is None:
113
+ return
114
+ for key in ("totalTokens", "total_tokens", "input", "output", "cacheRead", "cacheWrite"):
115
+ if key in value:
116
+ target[key] = value[key]
117
+ cost = as_map(value.get("cost"))
118
+ if cost is not None and "total" in cost:
119
+ target["cost_total"] = cost["total"]
120
+
121
+
122
+ def existing(paths: list[Path]) -> list[Path]:
123
+ seen: set[Path] = set()
124
+ result: list[Path] = []
125
+ for path in paths:
126
+ if str(path) and path.exists() and path not in seen:
127
+ seen.add(path)
128
+ result.append(path)
129
+ return result
130
+
131
+
132
+ def recent(paths: list[Path]) -> list[Path]:
133
+ return nlargest(MAX_PLATFORM_FILES, paths, key=modified_time)
134
+
135
+
136
+ def modified_time(path: Path) -> float:
137
+ try:
138
+ return path.stat().st_mtime
139
+ except OSError:
140
+ return 0.0
141
+
142
+
143
+ def stem_id(path: Path, marker: str) -> str:
144
+ return path.stem.split(marker)[-1].split("_")[-1]
145
+
146
+
147
+ def env_path(name: str) -> Path | None:
148
+ value = os.environ.get(name)
149
+ return Path(value).expanduser() if value else None
@@ -0,0 +1,57 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from pathlib import Path
5
+ from typing import TypeAlias
6
+
7
+
8
+ Json: TypeAlias = str | int | float | bool | None | list["Json"] | dict[str, "Json"]
9
+ JsonMap: TypeAlias = dict[str, Json]
10
+
11
+
12
+ @dataclass(frozen=True, slots=True)
13
+ class Options:
14
+ platforms: frozenset[str]
15
+ roots: tuple[Path, ...]
16
+ queries: tuple[str, ...]
17
+ date_from: str | None
18
+ date_to: str | None
19
+ cwd: str | None
20
+ model: str | None
21
+ limit: int
22
+ workers: int
23
+ include_subagents: bool
24
+
25
+
26
+ @dataclass(frozen=True, slots=True)
27
+ class Session:
28
+ platform: str
29
+ id: str
30
+ path: str
31
+ cwd: str | None
32
+ created_at: str | None
33
+ updated_at: str | None
34
+ provider: str | None
35
+ model: str | None
36
+ first_user_message: str
37
+ usage: JsonMap
38
+ parent_id: str | None = None
39
+ agent: str | None = None
40
+ last_user_message: str = ""
41
+
42
+ def to_json(self) -> JsonMap:
43
+ return {
44
+ "platform": self.platform,
45
+ "id": self.id,
46
+ "path": self.path,
47
+ "cwd": self.cwd,
48
+ "created_at": self.created_at,
49
+ "updated_at": self.updated_at,
50
+ "provider": self.provider,
51
+ "model": self.model,
52
+ "first_user_message": self.first_user_message[:300],
53
+ "last_user_message": (self.last_user_message or self.first_user_message)[:300],
54
+ "usage": self.usage,
55
+ "parent_id": self.parent_id,
56
+ "agent": self.agent,
57
+ }
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env python3
2
+ # /// script
3
+ # requires-python = ">=3.11"
4
+ # ///
5
+ # --- How to run ---
6
+ # python3 scripts/find-agent-sessions.py list --limit 20
7
+ # python3 scripts/find-agent-sessions.py search "commit" --from 7d
8
+ # python3 scripts/find-agent-sessions.py get <session-id>
9
+ from __future__ import annotations
10
+
11
+ import sys
12
+ import runpy
13
+ from pathlib import Path
14
+
15
+ sys.path.insert(0, str(Path(__file__).resolve().parent))
16
+
17
+
18
+ if __name__ == "__main__":
19
+ _ = runpy.run_module("agent_sessions.cli", run_name="__main__")