total-recall-brain 3.44.0 → 3.46.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 (502) hide show
  1. package/bin/total-recall.mjs +10 -6
  2. package/docs/ARCHITECTURE.md +10 -7
  3. package/docs/reference/cli-reference.md +13 -8
  4. package/frontend/dist/assets/index-BRYE1jmv.css +1 -0
  5. package/frontend/dist/assets/index-D1goIPjC.js +5598 -0
  6. package/frontend/dist/index.html +2 -2
  7. package/frontend/dist/sw.js +5 -4
  8. package/frontend/src/App.tsx +185 -238
  9. package/frontend/src/api/auth-inventory.ts +62 -0
  10. package/frontend/src/api/memory.ts +13 -8
  11. package/frontend/src/api/plugin-credentials.ts +23 -0
  12. package/frontend/src/api/plugins.ts +37 -53
  13. package/frontend/src/api/workspace-drawers.ts +97 -0
  14. package/frontend/src/components/BrainSelector.tsx +9 -3
  15. package/frontend/src/components/plugins/PluginPanel.tsx +83 -42
  16. package/frontend/src/components/plugins/PluginSettings.tsx +10 -20
  17. package/frontend/src/components/plugins/PluginWorkspace.tsx +367 -0
  18. package/frontend/src/components/plugins/ScopedPluginCommands.tsx +142 -0
  19. package/frontend/src/components/plugins/plugin-frame.ts +44 -33
  20. package/frontend/src/components/plugins/scoped-plugin-operations.ts +28 -0
  21. package/frontend/src/components/workspace/DrawerChat.tsx +110 -0
  22. package/frontend/src/components/workspace/DrawerLayout.tsx +196 -0
  23. package/frontend/src/components/workspace/DrawerMarkup.tsx +49 -0
  24. package/frontend/src/components/workspace/PluginChunkLibrary.tsx +92 -0
  25. package/frontend/src/components/workspace/PluginHome.tsx +76 -0
  26. package/frontend/src/components/workspace/WorkspaceDrawers.tsx +96 -0
  27. package/frontend/src/components/workspace/WorkspacePage.tsx +95 -0
  28. package/frontend/src/components/workspace/usePluginDesign.ts +38 -0
  29. package/frontend/src/index.css +409 -136
  30. package/frontend/src/pages/HelpPage.tsx +15 -46
  31. package/frontend/src/pages/MemoryPage.tsx +19 -36
  32. package/frontend/src/pages/SettingsPage.tsx +1 -1
  33. package/metadata.plugin.schema.json +53 -227
  34. package/package.json +1 -1
  35. package/scaffold/.agent/skills/plugin/SKILL.md +13 -11
  36. package/scaffold/.agent/skills/plugin/evals/README.md +14 -21
  37. package/scaffold/.agent/skills/plugin/evals/cases/01-fabricated-seed.mjs +15 -18
  38. package/scaffold/.agent/skills/plugin/evals/cases/02-reassuring-default.mjs +19 -24
  39. package/scaffold/.agent/skills/plugin/evals/cases/03-declared-template.mjs +12 -20
  40. package/scaffold/.agent/skills/plugin/evals/cases/04-home-collects-credential.mjs +35 -0
  41. package/scaffold/.agent/skills/plugin/evals/cases/05-host-leak-in-scaffold.mjs +8 -28
  42. package/scaffold/.agent/skills/plugin/evals/cases/06-correct-plugin.mjs +85 -47
  43. package/scaffold/.agent/skills/plugin/evals/run.mjs +17 -18
  44. package/scaffold/.agent/skills/plugin/prompts/05-credentials.md +4 -4
  45. package/scaffold/.agent/skills/plugin/prompts/07-scaffold.md +2 -2
  46. package/scaffold/.agent/skills/plugin/prompts/08-verify.md +4 -4
  47. package/scaffold/.agent/skills/plugin/references/anti-patterns.md +2 -2
  48. package/scaffold/.agent/skills/plugin/references/generative-home.md +38 -0
  49. package/scaffold/.agent/skills/plugin/references/scaffold.md +5 -5
  50. package/scaffold/.agent/skills/plugin/references/surfaces.md +13 -4
  51. package/scaffold/.agent/skills/plugin/scripts/record.mjs +75 -153
  52. package/scaffold/.agent/skills/plugin/subagents/plugin-reviewer.md +4 -4
  53. package/scaffold/.agent/skills/total-recall/plugins/auth/DESIGN.md +76 -0
  54. package/scaffold/.agent/skills/total-recall/plugins/auth/README.md +3 -1
  55. package/scaffold/.agent/skills/total-recall/plugins/auth/cli.mjs +20 -15
  56. package/scaffold/.agent/skills/total-recall/plugins/auth/package-lock.json +7 -7
  57. package/scaffold/.agent/skills/total-recall/plugins/auth/package.json +2 -1
  58. package/scaffold/.agent/skills/total-recall/plugins/auth/plugin.json +13 -51
  59. package/scaffold/.agent/skills/total-recall/plugins/auth/src/cli-secret.mjs +20 -1
  60. package/scaffold/.agent/skills/total-recall/plugins/auth/src/secrets-store.mjs +12 -1
  61. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/access-overview.md +17 -0
  62. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/agent-login.md +20 -0
  63. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/baseline-audit.md +22 -0
  64. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/credential-repository-binding.md +17 -0
  65. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/credential-store-maintenance.md +17 -0
  66. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/dashboard-password.md +18 -0
  67. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/dashboard-sessions.md +18 -0
  68. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/endpoint-probe.md +23 -0
  69. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/google-sign-in.md +21 -0
  70. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/mesh-machines.md +16 -0
  71. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/passkey-enrollment.md +21 -0
  72. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/registered-brains.md +16 -0
  73. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/scoped-access-keys.md +17 -0
  74. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/secret-inventory.md +25 -0
  75. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/signing-key-rotation.md +22 -0
  76. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/home.js +375 -0
  77. package/scaffold/.agent/skills/total-recall/plugins/automations/BRICK.md +7 -0
  78. package/scaffold/.agent/skills/total-recall/plugins/automations/DESIGN.md +53 -0
  79. package/scaffold/.agent/skills/total-recall/plugins/automations/LICENSE +21 -0
  80. package/scaffold/.agent/skills/total-recall/plugins/automations/README.md +66 -0
  81. package/scaffold/.agent/skills/total-recall/plugins/automations/adapters.mjs +247 -0
  82. package/scaffold/.agent/skills/total-recall/plugins/automations/capability/index.mjs +16 -0
  83. package/scaffold/.agent/skills/total-recall/plugins/automations/cli.mjs +130 -0
  84. package/{src/core/plugin-cron.mjs → scaffold/.agent/skills/total-recall/plugins/automations/cron.mjs} +1 -3
  85. package/scaffold/.agent/skills/total-recall/plugins/automations/inventory.mjs +88 -0
  86. package/scaffold/.agent/skills/total-recall/plugins/automations/package-lock.json +7661 -0
  87. package/scaffold/.agent/skills/total-recall/plugins/automations/package.json +36 -0
  88. package/scaffold/.agent/skills/total-recall/plugins/automations/plugin.json +151 -0
  89. package/scaffold/.agent/skills/total-recall/plugins/automations/scheduler.mjs +246 -0
  90. package/scaffold/.agent/skills/total-recall/plugins/automations/ui/automations.js +2 -0
  91. package/scaffold/.agent/skills/total-recall/plugins/automations/ui/chunks/control-ledger.md +42 -0
  92. package/scaffold/.agent/skills/total-recall/plugins/automations/ui/chunks/local-inventory-triage.md +17 -0
  93. package/scaffold/.agent/skills/total-recall/plugins/automations/ui/chunks/pending-control.md +39 -0
  94. package/scaffold/.agent/skills/total-recall/plugins/automations/ui/chunks/run-evidence.md +41 -0
  95. package/scaffold/.agent/skills/total-recall/plugins/automations/ui/chunks/schedule-vs-run-evidence.md +17 -0
  96. package/scaffold/.agent/skills/total-recall/plugins/automations/ui/chunks/source-coverage.md +41 -0
  97. package/scaffold/.agent/skills/total-recall/plugins/automations/ui/home.js +278 -0
  98. package/scaffold/.agent/skills/total-recall/plugins/code-quality/DESIGN.md +53 -0
  99. package/scaffold/.agent/skills/total-recall/plugins/code-quality/cli.mjs +23 -0
  100. package/scaffold/.agent/skills/total-recall/plugins/code-quality/commands/run-core.mjs +5 -3
  101. package/scaffold/.agent/skills/total-recall/plugins/code-quality/core/check.mjs +61 -7
  102. package/scaffold/.agent/skills/total-recall/plugins/code-quality/core/report-data.mjs +40 -14
  103. package/scaffold/.agent/skills/total-recall/plugins/code-quality/core/report.mjs +15 -40
  104. package/scaffold/.agent/skills/total-recall/plugins/code-quality/package-lock.json +7 -7
  105. package/scaffold/.agent/skills/total-recall/plugins/code-quality/package.json +2 -1
  106. package/scaffold/.agent/skills/total-recall/plugins/code-quality/plugin.json +40 -40
  107. package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/chunks/config.md +15 -0
  108. package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/chunks/detect.md +15 -0
  109. package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/chunks/gate.md +15 -0
  110. package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/chunks/init.md +15 -0
  111. package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/chunks/report.md +17 -0
  112. package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/chunks/run.md +17 -0
  113. package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/chunks/snapshot.md +15 -0
  114. package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/code-quality-report.mjs +55 -23
  115. package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/home.mjs +214 -0
  116. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/DESIGN.md +146 -0
  117. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/package-lock.json +7 -7
  118. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/package.json +2 -1
  119. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/plugin.json +51 -34
  120. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/src/command.mjs +1 -1
  121. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/create.md +35 -0
  122. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/history.md +35 -0
  123. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/library.md +49 -0
  124. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/list.md +42 -0
  125. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/promote.md +40 -0
  126. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/read.md +25 -0
  127. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/remove.md +26 -0
  128. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/rollback.md +26 -0
  129. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/show.md +53 -0
  130. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/status.md +40 -0
  131. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/test-path.md +38 -0
  132. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/test.md +46 -0
  133. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/update.md +32 -0
  134. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/home.js +533 -0
  135. package/scaffold/.agent/skills/total-recall/plugins/embeddings/DESIGN.md +110 -0
  136. package/scaffold/.agent/skills/total-recall/plugins/embeddings/package-lock.json +7 -7
  137. package/scaffold/.agent/skills/total-recall/plugins/embeddings/package.json +2 -1
  138. package/scaffold/.agent/skills/total-recall/plugins/embeddings/plugin.json +13 -10
  139. package/scaffold/.agent/skills/total-recall/plugins/embeddings/ui/chunks/benchmark.md +49 -0
  140. package/scaffold/.agent/skills/total-recall/plugins/embeddings/ui/chunks/coverage.md +53 -0
  141. package/scaffold/.agent/skills/total-recall/plugins/embeddings/ui/chunks/models.md +43 -0
  142. package/scaffold/.agent/skills/total-recall/plugins/embeddings/ui/chunks/pull.md +41 -0
  143. package/scaffold/.agent/skills/total-recall/plugins/embeddings/ui/chunks/status.md +59 -0
  144. package/scaffold/.agent/skills/total-recall/plugins/embeddings/ui/home.js +353 -0
  145. package/scaffold/.agent/skills/total-recall/plugins/git/DESIGN.md +31 -0
  146. package/scaffold/.agent/skills/total-recall/plugins/git/README.md +136 -0
  147. package/scaffold/.agent/skills/total-recall/plugins/{git-sentinel → git}/cli.mjs +140 -24
  148. package/scaffold/.agent/skills/total-recall/plugins/{git-sentinel → git}/package-lock.json +9 -9
  149. package/scaffold/.agent/skills/total-recall/plugins/{git-sentinel → git}/package.json +4 -2
  150. package/scaffold/.agent/skills/total-recall/plugins/git/plugin.json +151 -0
  151. package/scaffold/.agent/skills/total-recall/plugins/git/src/lib/context.mjs +94 -0
  152. package/scaffold/.agent/skills/total-recall/plugins/git/src/lib/phase3-spec-support.mjs +50 -0
  153. package/scaffold/.agent/skills/total-recall/plugins/git/src/lib/runtime.mjs +40 -0
  154. package/scaffold/.agent/skills/total-recall/plugins/git/src/lib/spec-support.mjs +51 -0
  155. package/scaffold/.agent/skills/total-recall/plugins/git/src/ops/_support.mjs +195 -0
  156. package/scaffold/.agent/skills/total-recall/plugins/git/src/ops/auth.mjs +201 -0
  157. package/scaffold/.agent/skills/total-recall/plugins/git/src/ops/bisect.mjs +40 -0
  158. package/scaffold/.agent/skills/total-recall/plugins/git/src/ops/cli-meta.mjs +159 -0
  159. package/scaffold/.agent/skills/total-recall/plugins/git/src/ops/commit-memory.mjs +54 -0
  160. package/scaffold/.agent/skills/total-recall/plugins/git/src/ops/commit.mjs +46 -0
  161. package/scaffold/.agent/skills/total-recall/plugins/git/src/ops/fleet.mjs +174 -0
  162. package/scaffold/.agent/skills/total-recall/plugins/git/src/ops/force-push.mjs +58 -0
  163. package/scaffold/.agent/skills/total-recall/plugins/git/src/ops/group.mjs +119 -0
  164. package/scaffold/.agent/skills/total-recall/plugins/git/src/ops/handoff.mjs +59 -0
  165. package/scaffold/.agent/skills/total-recall/plugins/git/src/ops/message.mjs +22 -0
  166. package/scaffold/.agent/skills/total-recall/plugins/git/src/ops/resolve.mjs +60 -0
  167. package/scaffold/.agent/skills/total-recall/plugins/git/src/ops/rules.mjs +81 -0
  168. package/scaffold/.agent/skills/total-recall/plugins/git/src/ops/secret-firewall.mjs +92 -0
  169. package/scaffold/.agent/skills/total-recall/plugins/git/src/ops/undo.mjs +156 -0
  170. package/scaffold/.agent/skills/total-recall/plugins/git/src/ops/unmerged.mjs +182 -0
  171. package/scaffold/.agent/skills/total-recall/plugins/git/src/ops/why.mjs +16 -0
  172. package/scaffold/.agent/skills/total-recall/plugins/git/ui/chunks/change-comparison.md +27 -0
  173. package/scaffold/.agent/skills/total-recall/plugins/git/ui/chunks/commit-identity.md +22 -0
  174. package/scaffold/.agent/skills/total-recall/plugins/git/ui/chunks/create-worktree.md +25 -0
  175. package/scaffold/.agent/skills/total-recall/plugins/git/ui/chunks/registered-worktrees.md +22 -0
  176. package/scaffold/.agent/skills/total-recall/plugins/git/ui/chunks/remove-worktree.md +23 -0
  177. package/scaffold/.agent/skills/total-recall/plugins/git/ui/chunks/repository-ledger.md +25 -0
  178. package/scaffold/.agent/skills/total-recall/plugins/git/ui/chunks/unmerged-work.md +22 -0
  179. package/scaffold/.agent/skills/total-recall/plugins/git/ui/chunks/upstream-divergence.md +17 -0
  180. package/scaffold/.agent/skills/total-recall/plugins/git/ui/chunks/worktree-conflict-triage.md +17 -0
  181. package/scaffold/.agent/skills/total-recall/plugins/git/ui/chunks/worktree-terminal.md +22 -0
  182. package/scaffold/.agent/skills/total-recall/plugins/git/ui/home.js +273 -0
  183. package/scaffold/.agent/skills/total-recall/plugins/mesh/DESIGN.md +35 -0
  184. package/scaffold/.agent/skills/total-recall/plugins/mesh/README.md +4 -5
  185. package/scaffold/.agent/skills/total-recall/plugins/mesh/cli.mjs +9 -3
  186. package/scaffold/.agent/skills/total-recall/plugins/mesh/package-lock.json +7 -7
  187. package/scaffold/.agent/skills/total-recall/plugins/mesh/package.json +2 -1
  188. package/scaffold/.agent/skills/total-recall/plugins/mesh/plugin.json +37 -39
  189. package/scaffold/.agent/skills/total-recall/plugins/mesh/src/cli/mesh.mjs +5 -3
  190. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/active-device-dispatch.md +22 -0
  191. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/control-probe.md +25 -0
  192. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/control-server.md +22 -0
  193. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/credential-readiness.md +23 -0
  194. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/elected-leader.md +22 -0
  195. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/enrollment-key.md +22 -0
  196. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/file-receipt.md +25 -0
  197. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/fleet-execution.md +23 -0
  198. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/fleet-presence.md +23 -0
  199. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/interactive-ssh.md +22 -0
  200. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/local-enrollment.md +23 -0
  201. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/mesh-policy.md +23 -0
  202. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/network-atlas.md +25 -0
  203. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/node-roster.md +26 -0
  204. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/node-selection-proof.md +17 -0
  205. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/owner-observations.md +23 -0
  206. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/peer-path.md +23 -0
  207. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/pinned-leader.md +24 -0
  208. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/reachability-evidence-ladder.md +17 -0
  209. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/recorded-login.md +23 -0
  210. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/remote-execution.md +22 -0
  211. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/secret-grants.md +26 -0
  212. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/{card.js → home.js} +93 -22
  213. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/DESIGN.md +86 -0
  214. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/README.md +44 -9
  215. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/capability/BRICK.md +1 -1
  216. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/capability/index.mjs +18 -6
  217. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/cli.mjs +128 -24
  218. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/package-lock.json +7 -7
  219. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/package.json +3 -2
  220. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/plugin.json +188 -34
  221. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/skills/meta-harness/SKILL.md +17 -3
  222. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/adoption.mjs +2 -2
  223. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/alerts.mjs +3 -3
  224. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/cascade.mjs +92 -18
  225. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/chat.mjs +80 -0
  226. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/control.mjs +145 -0
  227. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/coordinator.mjs +42 -21
  228. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/dispatch-request.mjs +4 -2
  229. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/dispatch.mjs +33 -9
  230. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/documentation.mjs +55 -11
  231. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/executor.mjs +26 -4
  232. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/hermes.mjs +29 -1
  233. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/index.mjs +1 -1
  234. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/included-usage.mjs +1 -1
  235. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/jobs.mjs +84 -0
  236. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/learner.mjs +3 -12
  237. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/maintenance.mjs +17 -0
  238. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/mcp-server.mjs +228 -0
  239. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/process-manager.mjs +25 -2
  240. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/reasoning.mjs +1 -1
  241. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/remote-operation.mjs +5 -1
  242. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/review.mjs +34 -3
  243. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/reviews.mjs +25 -0
  244. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/router.mjs +1 -1
  245. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/session/claude.mjs +319 -0
  246. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/session/codex.mjs +387 -0
  247. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/session/result.mjs +67 -0
  248. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/session/resume.mjs +373 -0
  249. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/session/run.mjs +223 -0
  250. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/session-jobs.mjs +72 -0
  251. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/setup.mjs +6 -3
  252. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/termination.mjs +16 -12
  253. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/threads.mjs +32 -1
  254. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/usage-queue.mjs +1 -1
  255. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/verify-ssss.mjs +3 -3
  256. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/worker.mjs +285 -40
  257. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/worktree.mjs +76 -9
  258. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/adapter-docs-freshness.md +16 -0
  259. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/chat-handoff.md +26 -0
  260. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/fleet-maintenance.md +21 -0
  261. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/harness-inventory.md +21 -0
  262. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/included-access.md +18 -0
  263. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/included-usage-verification.md +15 -0
  264. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/independent-review.md +17 -0
  265. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/managed-execution.md +20 -0
  266. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/official-documentation.md +18 -0
  267. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/quota-recovery.md +21 -0
  268. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/review-routing-decision.md +16 -0
  269. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/route-work.md +18 -0
  270. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/routing-evidence.md +18 -0
  271. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/run-ledger.md +18 -0
  272. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/home.js +198 -0
  273. package/scaffold/.agent/skills/total-recall/plugins/openwiki/DESIGN.md +75 -0
  274. package/scaffold/.agent/skills/total-recall/plugins/openwiki/README.md +2 -0
  275. package/scaffold/.agent/skills/total-recall/plugins/openwiki/cli.mjs +64 -32
  276. package/scaffold/.agent/skills/total-recall/plugins/openwiki/package-lock.json +7 -7
  277. package/scaffold/.agent/skills/total-recall/plugins/openwiki/package.json +2 -1
  278. package/scaffold/.agent/skills/total-recall/plugins/openwiki/plugin.json +10 -44
  279. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/generate.mjs +5 -4
  280. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/graph.mjs +3 -4
  281. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/ingest.mjs +23 -18
  282. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/mesh-vaults.mjs +8 -3
  283. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/refresh-diagnostics.mjs +44 -0
  284. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/refresh.mjs +123 -113
  285. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/search.mjs +3 -5
  286. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/token.mjs +21 -47
  287. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/upstream-watcher.mjs +17 -6
  288. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/auto-refresh.md +18 -0
  289. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/bootstrap-pages.md +18 -0
  290. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/generate-wiki.md +21 -0
  291. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/generator-settings.md +18 -0
  292. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/host-probe.md +18 -0
  293. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/ingest-preview.md +18 -0
  294. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/link-hygiene.md +21 -0
  295. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/link-topology.md +19 -0
  296. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/passage-search.md +19 -0
  297. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/propagation-plan.md +18 -0
  298. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/provider-credentials.md +18 -0
  299. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/refresh-report.md +18 -0
  300. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/task-evidence.md +22 -0
  301. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/upstream-record.md +18 -0
  302. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/watch-upstream.md +18 -0
  303. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/wiki-atlas.md +19 -0
  304. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/panel.js +261 -513
  305. package/scaffold/.agent/skills/total-recall/plugins/security/DESIGN.md +84 -0
  306. package/scaffold/.agent/skills/total-recall/plugins/security/README.md +4 -2
  307. package/scaffold/.agent/skills/total-recall/plugins/security/cli.mjs +7 -19
  308. package/scaffold/.agent/skills/total-recall/plugins/security/package-lock.json +7 -7
  309. package/scaffold/.agent/skills/total-recall/plugins/security/package.json +2 -3
  310. package/scaffold/.agent/skills/total-recall/plugins/security/plugin.json +19 -52
  311. package/scaffold/.agent/skills/total-recall/plugins/security/ui/chunks/device-evidence.md +21 -0
  312. package/scaffold/.agent/skills/total-recall/plugins/security/ui/chunks/evidence-desk.md +18 -0
  313. package/scaffold/.agent/skills/total-recall/plugins/security/ui/chunks/guided-device-review.md +17 -0
  314. package/scaffold/.agent/skills/total-recall/plugins/security/ui/chunks/host-and-network.md +21 -0
  315. package/scaffold/.agent/skills/total-recall/plugins/security/ui/chunks/https-headers.md +17 -0
  316. package/scaffold/.agent/skills/total-recall/plugins/security/ui/chunks/mesh-coverage.md +18 -0
  317. package/scaffold/.agent/skills/total-recall/plugins/security/ui/chunks/private-security-tools.md +16 -0
  318. package/scaffold/.agent/skills/total-recall/plugins/security/ui/chunks/single-origin-header-check.md +17 -0
  319. package/scaffold/.agent/skills/total-recall/plugins/security/ui/chunks/source-review.md +21 -0
  320. package/scaffold/.agent/skills/total-recall/plugins/security/ui/chunks/ssh-permission-plan.md +17 -0
  321. package/scaffold/.agent/skills/total-recall/plugins/security/ui/home.js +283 -0
  322. package/scaffold/.agent/skills/total-recall/plugins/ssss/DESIGN.md +93 -0
  323. package/scaffold/.agent/skills/total-recall/plugins/ssss/package-lock.json +2 -2
  324. package/scaffold/.agent/skills/total-recall/plugins/ssss/package.json +2 -1
  325. package/scaffold/.agent/skills/total-recall/plugins/ssss/plugin.json +5 -3
  326. package/scaffold/.agent/skills/total-recall/plugins/ssss/ui/chunks/conformance.md +26 -0
  327. package/scaffold/.agent/skills/total-recall/plugins/ssss/ui/chunks/registry.md +37 -0
  328. package/scaffold/.agent/skills/total-recall/plugins/ssss/ui/chunks/repair.md +42 -0
  329. package/scaffold/.agent/skills/total-recall/plugins/ssss/ui/chunks/scaffold.md +33 -0
  330. package/scaffold/.agent/skills/total-recall/plugins/ssss/ui/chunks/status.md +43 -0
  331. package/scaffold/.agent/skills/total-recall/plugins/ssss/ui/chunks/validate.md +34 -0
  332. package/scaffold/.agent/skills/total-recall/plugins/ssss/ui/chunks/validation-diagnostics.md +17 -0
  333. package/scaffold/.agent/skills/total-recall/plugins/ssss/ui/chunks/workspace-registry-preflight.md +17 -0
  334. package/scaffold/.agent/skills/total-recall/plugins/ssss/ui/home.js +348 -0
  335. package/scaffold/.agent/skills/total-recall/references/operations.md +3 -1
  336. package/src/cli/agent.mjs +1 -1
  337. package/src/cli/api.mjs +3 -3
  338. package/src/cli/brief.mjs +3 -0
  339. package/src/cli/command.mjs +41 -2
  340. package/src/cli/config.mjs +16 -0
  341. package/src/cli/connect.mjs +2 -7
  342. package/src/cli/dream.mjs +93 -69
  343. package/src/cli/harness.mjs +4 -4
  344. package/src/cli/help.mjs +1 -1
  345. package/src/cli/init.mjs +0 -25
  346. package/src/cli/lessons.mjs +51 -0
  347. package/src/cli/memory-plugin.mjs +1 -1
  348. package/src/cli/plugin/chunks.mjs +145 -0
  349. package/src/cli/plugin/copies.mjs +64 -14
  350. package/src/cli/plugin/create.mjs +30 -59
  351. package/src/cli/plugin/index.mjs +31 -16
  352. package/src/cli/plugin/install.mjs +10 -15
  353. package/src/cli/plugin/remove.mjs +1 -1
  354. package/src/cli/plugin/search.mjs +2 -2
  355. package/src/cli/preflight.mjs +19 -6
  356. package/src/cli/proposals.mjs +1 -1
  357. package/src/cli/recall.mjs +66 -23
  358. package/src/cli/remember.mjs +3 -14
  359. package/src/cli/server.mjs +18 -0
  360. package/src/cli/setup.mjs +2 -9
  361. package/src/cli/start.mjs +1 -0
  362. package/src/cli/startup.mjs +19 -0
  363. package/src/cli/task.mjs +9 -2
  364. package/src/cli/update.mjs +6 -2
  365. package/src/core/access-ledger.mjs +78 -0
  366. package/src/core/agent-manager.mjs +2 -2
  367. package/src/core/app-deploy/design-tokens.mjs +14 -9
  368. package/src/core/app-deploy/ui-elements.mjs +1 -1
  369. package/src/core/brain-locate.mjs +15 -0
  370. package/src/core/brain-registry.mjs +5 -0
  371. package/src/core/brain-updates.mjs +35 -11
  372. package/src/core/claude-hooks.mjs +3 -1
  373. package/src/core/cleanup-task.mjs +15 -0
  374. package/src/core/cli-commands.mjs +2 -0
  375. package/src/core/cli-maintenance.mjs +4 -1
  376. package/src/core/cli-semantic-index.mjs +23 -3
  377. package/src/core/context-compiler.mjs +20 -0
  378. package/src/core/daemon-control.mjs +5 -1
  379. package/src/core/daemon-loop.mjs +39 -62
  380. package/src/core/dashboard-bundle.mjs +261 -0
  381. package/src/core/default-plugins.mjs +1 -1
  382. package/src/core/dream.mjs +33 -105
  383. package/src/core/ensure-dependencies.mjs +152 -0
  384. package/src/core/fast-recall.mjs +2 -2
  385. package/src/core/field-evaluation.mjs +23 -0
  386. package/src/core/gate-mode.mjs +1 -1
  387. package/src/core/harness-hooks.mjs +14 -2
  388. package/src/core/lesson-hooks.mjs +74 -0
  389. package/src/core/lesson-memory.mjs +24 -0
  390. package/src/core/lesson-sessions.mjs +52 -0
  391. package/src/core/lessons.mjs +96 -0
  392. package/src/core/memory-brain.mjs +30 -8
  393. package/src/core/meta-harness.mjs +2 -2
  394. package/src/core/optimizer.mjs +66 -165
  395. package/src/core/plugin-activation.mjs +63 -20
  396. package/src/core/plugin-contracts/{card.mjs → manifest.mjs} +26 -57
  397. package/src/core/plugin-contracts/startup-check.mjs +49 -0
  398. package/src/core/plugin-contracts/ui.mjs +9 -3
  399. package/src/core/plugin-distribution.mjs +6 -6
  400. package/src/core/plugin-lifecycle.mjs +58 -0
  401. package/src/core/plugin-loader.mjs +21 -8
  402. package/src/core/plugin-runner.mjs +21 -10
  403. package/src/core/plugin-runtime.mjs +40 -1
  404. package/src/core/plugin-startup-checks.mjs +44 -0
  405. package/src/core/plugin-state.mjs +19 -5
  406. package/src/core/plugin-store.mjs +64 -33
  407. package/src/core/post-mortem.mjs +52 -36
  408. package/src/core/preflight-gate.mjs +23 -2
  409. package/src/core/project-id.mjs +15 -5
  410. package/src/core/proposal-applier.mjs +31 -2
  411. package/src/core/repo-sync.mjs +4 -6
  412. package/src/core/required-plugins.mjs +57 -10
  413. package/src/core/rule-length.mjs +23 -0
  414. package/src/core/runtime.mjs +1 -1
  415. package/src/core/scheduler.mjs +35 -43
  416. package/src/core/schema.mjs +3 -2
  417. package/src/core/search.mjs +4 -3
  418. package/src/core/server-service.mjs +148 -0
  419. package/src/core/session-watcher.mjs +19 -1
  420. package/src/core/skill-gap.mjs +16 -0
  421. package/src/core/ssss-kernel-bridge.mjs +32 -4
  422. package/src/core/ssss-operation-service.mjs +1 -0
  423. package/src/core/startup-health.mjs +34 -4
  424. package/src/core/surface.mjs +65 -54
  425. package/src/core/task-executors.mjs +54 -106
  426. package/src/core/testing/plugin-fixture.mjs +22 -21
  427. package/src/core/throttled-fetch.mjs +25 -18
  428. package/src/core/ui-chunk-choice.mjs +77 -0
  429. package/src/core/ui-chunk.registry.json +23 -0
  430. package/src/core/ui-chunks.mjs +434 -0
  431. package/src/core/validated-write.mjs +1 -0
  432. package/src/core/vault-cache.mjs +58 -59
  433. package/src/core/vector-field.mjs +134 -192
  434. package/src/core/workspace-compositions.mjs +151 -0
  435. package/src/core/workspace-drawers.mjs +79 -0
  436. package/src/server/api.mjs +4 -27
  437. package/src/server/index.mjs +28 -21
  438. package/src/server/invoke-core-child.mjs +24 -0
  439. package/src/server/invoke-core-operations.mjs +102 -0
  440. package/src/server/memory-events.mjs +31 -0
  441. package/src/server/plugin-brain-targets.mjs +89 -0
  442. package/src/server/rest.mjs +2 -0
  443. package/src/server/route-inventory.mjs +3 -2
  444. package/src/server/route-manifest.json +47 -55
  445. package/src/server/routes/_shared.mjs +7 -14
  446. package/src/server/routes/brains.mjs +29 -62
  447. package/src/server/routes/context.mjs +0 -41
  448. package/src/server/routes/dashboard.mjs +26 -0
  449. package/src/server/routes/invoke.mjs +26 -1
  450. package/src/server/routes/plugins.mjs +154 -45
  451. package/src/server/routes/ssss.mjs +0 -169
  452. package/src/server/routes/system.mjs +0 -15
  453. package/src/server/routes/tasks.mjs +0 -26
  454. package/src/server/routes/ui-chunks.mjs +192 -0
  455. package/src/server/routes/vault.mjs +2 -23
  456. package/frontend/dist/assets/index-DD4qONvH.js +0 -5607
  457. package/frontend/dist/assets/index-DtwsDyFM.css +0 -1
  458. package/frontend/src/components/plugins/card/CardEngine.tsx +0 -108
  459. package/frontend/src/components/plugins/card/CardScenes.tsx +0 -103
  460. package/frontend/src/components/plugins/card/ExecutionPicker.tsx +0 -64
  461. package/frontend/src/components/plugins/card/args.ts +0 -28
  462. package/frontend/src/components/plugins/card/card.css +0 -32
  463. package/frontend/src/components/plugins/card/cli-line.ts +0 -13
  464. package/frontend/src/components/plugins/card/contract.ts +0 -91
  465. package/frontend/src/components/plugins/card/format.ts +0 -49
  466. package/frontend/src/components/plugins/card/runner-context.ts +0 -11
  467. package/frontend/src/components/plugins/card/runner.tsx +0 -43
  468. package/frontend/src/components/plugins/card/theme.ts +0 -35
  469. package/frontend/src/components/plugins/card/use-source.ts +0 -22
  470. package/frontend/src/components/plugins/card/widgets.tsx +0 -94
  471. package/frontend/src/components/plugins/workspace/WorkspaceHost.tsx +0 -23
  472. package/frontend/src/pages/PluginsPage.tsx +0 -1719
  473. package/scaffold/.agent/skills/plugin/evals/cases/04-card-collects-credential.mjs +0 -47
  474. package/scaffold/.agent/skills/plugin/prompts/06-card.md +0 -46
  475. package/scaffold/.agent/skills/plugin/references/card.md +0 -90
  476. package/scaffold/.agent/skills/plugin/subagents/card-designer.md +0 -60
  477. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/DESIGN.md +0 -67
  478. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/card.js +0 -1179
  479. package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/DESIGN.md +0 -32
  480. package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/card.js +0 -588
  481. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/card.js +0 -575
  482. package/scaffold/.agent/skills/total-recall/plugins/embeddings/ui/DESIGN.md +0 -32
  483. package/scaffold/.agent/skills/total-recall/plugins/embeddings/ui/card.js +0 -482
  484. package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/README.md +0 -53
  485. package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/plugin.json +0 -129
  486. package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/ui/DESIGN.md +0 -100
  487. package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/ui/card.js +0 -637
  488. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/DESIGN.md +0 -217
  489. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/DESIGN.md +0 -32
  490. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/card.js +0 -1276
  491. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/DESIGN.md +0 -45
  492. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/card.js +0 -1401
  493. package/scaffold/.agent/skills/total-recall/plugins/security/scripts/build-ui.mjs +0 -4
  494. package/scaffold/.agent/skills/total-recall/plugins/security/ui/DESIGN.md +0 -41
  495. package/scaffold/.agent/skills/total-recall/plugins/security/ui/card.js +0 -396
  496. package/scaffold/.agent/skills/total-recall/plugins/security/ui/panel.js +0 -98
  497. package/scaffold/.agent/skills/total-recall/plugins/ssss/ui/DESIGN.md +0 -15
  498. package/scaffold/.agent/skills/total-recall/plugins/ssss/ui/card.js +0 -182
  499. package/src/core/append-log.mjs +0 -131
  500. package/src/core/plugin-tasks.mjs +0 -173
  501. package/templates/onboarding-interview.md +0 -82
  502. /package/scaffold/.agent/skills/total-recall/plugins/{git-sentinel → git}/LICENSE +0 -0
@@ -1,24 +1,25 @@
1
1
  #!/usr/bin/env node
2
- import { execFileSync } from 'node:child_process';
3
- import { realpathSync } from 'node:fs';
2
+ import { execFileSync, spawnSync } from 'node:child_process';
3
+ import { readdirSync, realpathSync } from 'node:fs';
4
4
  import path from 'node:path';
5
+ import { fileURLToPath, pathToFileURL } from 'node:url';
5
6
  import { parseArgs } from 'node:util';
6
7
 
7
8
  const GIT_TIMEOUT_MS = 15000;
8
9
  const GIT_MAX_BUFFER = 64 * 1024 * 1024;
9
- const VERBS = ['audit', 'diff', 'identity', 'worktree-list', 'worktree-create', 'worktree-remove', 'help'];
10
+ const VERBS = ['audit', 'diff', 'identity', 'worktree-list', 'worktree-create', 'worktree-remove'];
10
11
 
11
12
  /**
12
13
  * Run git without throwing. Never trims stdout (porcelain rows begin with
13
14
  * significant spaces) and never forwards stderr to the caller's terminal.
14
15
  * @returns {{ ok: boolean, code: number|null, stdout: string, stderr: string, missing: boolean }}
15
16
  */
16
- export function git(args, cwd = process.cwd()) {
17
+ export function git(args, cwd = process.cwd(), input) {
17
18
  try {
18
19
  const stdout = execFileSync('git', args, {
19
20
  cwd,
20
21
  encoding: 'utf8',
21
- stdio: ['ignore', 'pipe', 'pipe'],
22
+ ...(input === undefined ? { stdio: ['ignore', 'pipe', 'pipe'] } : { input, stdio: ['pipe', 'pipe', 'pipe'] }),
22
23
  timeout: GIT_TIMEOUT_MS,
23
24
  maxBuffer: GIT_MAX_BUFFER,
24
25
  env: { ...process.env, LC_ALL: 'C', GIT_OPTIONAL_LOCKS: '0', GIT_TERMINAL_PROMPT: '0' },
@@ -210,14 +211,20 @@ function printIdentity(r) {
210
211
  console.log('');
211
212
  }
212
213
 
213
- function usage() {
214
- return `Usage: total-recall git-sentinel [operation] [--json]
215
- audit | identity
216
- diff [--patch] [--cached] [--base <ref>]
217
- worktree list
218
- worktree create <path> [--base <ref>]
219
- worktree remove <path> [--force]
220
- worktree-list | worktree-create | worktree-remove (separate operation effects)`;
214
+ function usage(operations = {}) {
215
+ const features = Object.entries(operations).sort(([a], [b]) => a.localeCompare(b))
216
+ .map(([name, op]) => ` ${(op.usage || name).split('\n')[0].padEnd(46)} ${op.summary}`).join('\n');
217
+ return `Usage: total-recall git <command> [arguments] [--json]
218
+
219
+ Every git command works here: anything that is not listed below runs git itself, with your
220
+ arguments, git's hooks, output and exit status. Example: total-recall git pull --rebase.
221
+ Git's own help for a command: total-recall git help <command>.
222
+
223
+ Plugin operations:
224
+ audit | identity Repository state; commit identity and its history
225
+ diff --json [--patch] [--cached] [--base <ref>] The card's diff (plain diff is git's)
226
+ worktree-list | worktree-create <path> [--base <ref>] | worktree-remove <path> [--force]
227
+ ${features ? features + '\n' : ''} --help This help; <operation> --help for one operation`;
221
228
  }
222
229
 
223
230
  function gitResult(args, cwd) {
@@ -247,7 +254,11 @@ function worktrees(cwd) {
247
254
  }
248
255
 
249
256
  function worktreeOperation(action, values, target, cwd) {
250
- if (action === 'worktree-list') return { ok: true, worktrees: worktrees(cwd) };
257
+ if (action === 'worktree-list') {
258
+ const registered = worktrees(cwd);
259
+ const root = git(['rev-parse', '--show-toplevel'], cwd);
260
+ return { ok: true, worktrees: registered, current: root.ok ? root.stdout.replace(/\n$/, '') : null };
261
+ }
251
262
  const targetPath = path.resolve(cwd, target);
252
263
  if (action === 'worktree-create') {
253
264
  const commit = resolveCommit(values.base ?? 'HEAD', cwd);
@@ -303,36 +314,141 @@ function printAudit(r) {
303
314
  console.log(` Head Commit: ${fmt(r.lastCommit, unk)}\n`);
304
315
  }
305
316
 
317
+ /**
318
+ * Feature operations live in src/ops/<name>.mjs, one file per feature. Each module may export:
319
+ * - `operations`: { <name>: { summary, usage, run(args, ctx) } }; `run` returns an exit status.
320
+ * - `guards`: [{ name, before(args, ctx) }] run before git's own commands, in file order. `before`
321
+ * returns nothing to allow, `{ args }` to rewrite the arguments, or `{ refuse: <message> }`.
322
+ * An optional `after(args, ctx, status)` runs after git finishes; its failure is reported, never fatal.
323
+ * `ctx` is { cwd, env, json, git(args) -> spawnSync result with captured output }.
324
+ * Help is built from this registry, so every operation is in `--help`.
325
+ */
326
+ const OPS_DIR = path.join(path.dirname(fileURLToPath(import.meta.url)), 'src', 'ops');
327
+ let GIT_COMMANDS;
328
+ function isGitCommand(name) {
329
+ if (!GIT_COMMANDS) GIT_COMMANDS = new Set(String(spawnSync('git', ['--list-cmds=main,others,alias,nohelpers'], { encoding: 'utf8' }).stdout || '').split('\n').filter(Boolean));
330
+ return GIT_COMMANDS.has(name);
331
+ }
332
+
333
+ export async function loadRegistry(dir = OPS_DIR) {
334
+ const operations = {}, guards = [];
335
+ let files = [];
336
+ try { files = readdirSync(dir).filter(f => f.endsWith('.mjs') && !f.includes('.spec.') && !f.includes('.test.')).sort(); } catch { /* no feature modules */ }
337
+ for (const file of files) {
338
+ // One module that fails to load disables only its own operations; git and every other operation keep working.
339
+ let mod;
340
+ try { mod = await import(pathToFileURL(path.join(dir, file)).href); }
341
+ catch (error) {
342
+ const name = file.replace(/\.mjs$/, '');
343
+ if (!operations[name]) operations[name] = { summary: `unavailable: ${String(error.message).split('\n')[0]}`, usage: name, file, broken: true,
344
+ run: () => { console.error(`${name} is unavailable: ${error.message.split('\n')[0]}`); return 1; } };
345
+ continue;
346
+ }
347
+ for (const [name, op] of Object.entries(mod.operations || {})) {
348
+ if (operations[name]) throw new Error(`Operation "${name}" is defined twice (${file})`);
349
+ operations[name] = { ...op, file };
350
+ }
351
+ for (const guard of mod.guards || []) guards.push({ ...guard, file });
352
+ }
353
+ return { operations, guards };
354
+ }
355
+
356
+ function context(cwd, json) {
357
+ return {
358
+ cwd, env: process.env, json,
359
+ git: (args, options = {}) => spawnSync('git', args, { cwd, env: process.env, encoding: 'utf8', maxBuffer: GIT_MAX_BUFFER, ...options }),
360
+ };
361
+ }
362
+
363
+ /**
364
+ * Plugin operations: audit, identity, help, the checked commit, the hyphenated worktree-* operations
365
+ * and `diff` with --json or --base (the card's diff). Everything else is git's own CLI.
366
+ * `commit` stays a plugin operation only in its checked form (-m/--message, -a/--all, paths).
367
+ * Any other git commit flag (--amend, --fixup, -S and the rest) goes to git's own commit.
368
+ */
369
+ export function isPassthrough(args, featureOps = []) {
370
+ const [first] = args;
371
+ if (first === undefined) return false;
372
+ if (featureOps.includes(first)) return false;
373
+ if (first.startsWith('-')) return !['--json', '--help', '-h'].includes(first);
374
+ if (['audit', 'identity', 'worktree-list', 'worktree-create', 'worktree-remove'].includes(first)) return false;
375
+ if (first === 'diff') return !args.includes('--json') && !args.some(a => a === '--base' || a.startsWith('--base='));
376
+ return true;
377
+ }
378
+
306
379
  export async function run(argv = []) {
307
- // argv: ["node", "total-recall", "git-sentinel", "<subcommand>", ...flags]
380
+ // argv: ["node", "total-recall", "git", "<subcommand>", ...flags]
308
381
  // Never process.exit(): a host running this in-process would be stopped too.
309
382
  const clean = Array.isArray(argv) ? argv.slice(3) : [];
383
+ const registry = await loadRegistry();
384
+ const cwd0 = process.cwd();
385
+ const featureOp = registry.operations[clean[0]];
386
+ const wantsOpHelp = clean.includes('--help') || clean.includes('-h');
387
+ // Guards see every command, plugin operations included (a plugin `commit` is still a commit).
388
+ // Each guard decides from args[0] whether the command concerns it.
389
+ const runGuards = async (args, phase, status) => {
390
+ for (const guard of registry.guards) {
391
+ if (phase === 'before') {
392
+ const verdict = await guard.before?.(args, context(cwd0, false));
393
+ if (verdict?.refuse) return { refuse: `${args[0]} refused by ${guard.name}: ${verdict.refuse}` };
394
+ if (verdict?.args) args = verdict.args;
395
+ } else if (guard.after) {
396
+ try { await guard.after(args, context(cwd0, false), status); }
397
+ catch (error) { console.error(`${guard.name} after ${args[0]}: ${error.message}`); }
398
+ }
399
+ }
400
+ return { args };
401
+ };
402
+ // `-h` on a plugin operation that is also a git command (commit, bundle) is git's own usage;
403
+ // `--help` shows the plugin operation's help.
404
+ const gitUsage = featureOp && clean.includes('-h') && !clean.includes('--help') && isGitCommand(clean[0]);
405
+ if (featureOp && !wantsOpHelp || gitUsage) {
406
+ if (gitUsage) {
407
+ const ran = spawnSync('git', clean, { cwd: cwd0, stdio: 'inherit', env: process.env });
408
+ process.exitCode = ran.status ?? 1;
409
+ return;
410
+ }
411
+ const checked = await runGuards(clean, 'before');
412
+ if (checked.refuse) { console.error(checked.refuse); process.exitCode = 1; return; }
413
+ const status = await featureOp.run(checked.args.slice(1).filter(a => a !== '--json'), context(cwd0, clean.includes('--json')));
414
+ process.exitCode = typeof status === 'number' ? status : 0;
415
+ await runGuards(checked.args, 'after', process.exitCode);
416
+ return;
417
+ }
418
+ if (featureOp) { console.log(`total-recall git ${clean[0]} — ${featureOp.summary}\n${featureOp.usage || ''}`.trimEnd()); return; }
419
+ // The whole git CLI: every command that is not a plugin operation runs git itself, with the
420
+ // caller's arguments unchanged (unless a guard rewrites them), git's own hooks, output and exit status.
421
+ if (isPassthrough(clean, Object.keys(registry.operations))) {
422
+ const checked = await runGuards(clean, 'before');
423
+ if (checked.refuse) { console.error(`git ${checked.refuse}`); process.exitCode = 1; return; }
424
+ const ran = spawnSync('git', checked.args, { cwd: cwd0, stdio: 'inherit', env: process.env });
425
+ if (ran.error) console.error(`git could not start: ${ran.error.message}`);
426
+ process.exitCode = ran.status ?? 1;
427
+ await runGuards(checked.args, 'after', process.exitCode);
428
+ return;
429
+ }
310
430
  const isJson = clean.includes('--json');
311
431
  const wantsHelp = clean.includes('--help') || clean.includes('-h');
312
432
  let [action = 'audit', ...args] = clean.filter(arg => arg !== '--json');
313
- if (action === 'worktree') {
314
- const [verb = 'list', ...rest] = args;
315
- action = `worktree-${verb}`;
316
- args = rest;
317
- }
318
433
  const fail = (message, code = 1, extra = {}) => {
319
434
  process.exitCode = code;
320
435
  if (isJson) console.log(JSON.stringify({ ok: false, error: message, ...extra }, null, 2));
321
436
  else console.error(message);
322
437
  };
323
438
 
324
- if (wantsHelp || action === 'help') {
325
- console.log(usage());
439
+ if (wantsHelp) {
440
+ console.log(usage(registry.operations));
326
441
  return;
327
442
  }
328
443
  if (!VERBS.includes(action)) {
329
- fail(`Unknown git-sentinel command "${action}". ${usage()}`, 2);
444
+ fail(`Unknown git plugin command "${action}". ${usage()}`, 2);
330
445
  return;
331
446
  }
332
447
 
333
448
  const options = action === 'diff' ? { patch: { type: 'boolean' }, cached: { type: 'boolean' }, base: { type: 'string' } }
334
449
  : action === 'worktree-create' ? { base: { type: 'string' } }
335
- : action === 'worktree-remove' ? { force: { type: 'boolean' } } : {};
450
+ : action === 'worktree-remove' ? { force: { type: 'boolean' } }
451
+ : {};
336
452
  const targetRequired = action === 'worktree-create' || action === 'worktree-remove';
337
453
  let parsed;
338
454
  try {
@@ -1,18 +1,18 @@
1
1
  {
2
- "name": "tr-plugin-git-sentinel",
3
- "version": "1.1.5",
2
+ "name": "tr-plugin-git",
3
+ "version": "2.2.0",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
- "name": "tr-plugin-git-sentinel",
9
- "version": "1.1.5",
8
+ "name": "tr-plugin-git",
9
+ "version": "2.2.0",
10
10
  "license": "MIT",
11
11
  "dependencies": {
12
12
  "@gregiteen/ssss-cli": "0.14.5"
13
13
  },
14
14
  "devDependencies": {
15
- "total-recall-brain": "3.43.3",
15
+ "total-recall-brain": "3.45.0",
16
16
  "vitest": "^4.1.10"
17
17
  }
18
18
  },
@@ -6533,9 +6533,9 @@
6533
6533
  }
6534
6534
  },
6535
6535
  "node_modules/total-recall-brain": {
6536
- "version": "3.43.3",
6537
- "resolved": "https://registry.npmjs.org/total-recall-brain/-/total-recall-brain-3.43.3.tgz",
6538
- "integrity": "sha512-yjfPN/BQxEEa+iodyFXQov/6fRt1pZg/7RcmgsbpALwBt6Ki3JJjT3tzArBC7NxHQmXgGYyKnCYId6xe/W2rPg==",
6536
+ "version": "3.45.0",
6537
+ "resolved": "https://registry.npmjs.org/total-recall-brain/-/total-recall-brain-3.45.0.tgz",
6538
+ "integrity": "sha512-HDYfROazZbsLHQsFPnlBcSpe1HL1QEi7JG8x/eNRUI06RxVQsZWl8LwBo2lTWjWRDrKmCy7BUmSXQDuWF3lrEw==",
6539
6539
  "dev": true,
6540
6540
  "license": "MIT",
6541
6541
  "workspaces": [
@@ -6543,7 +6543,7 @@
6543
6543
  ],
6544
6544
  "dependencies": {
6545
6545
  "@simplewebauthn/server": "^13.3.2",
6546
- "@ssss/cli": "npm:@gregiteen/ssss-cli@0.14.4",
6546
+ "@ssss/cli": "npm:@gregiteen/ssss-cli@0.14.5",
6547
6547
  "bcrypt": "^6.0.0",
6548
6548
  "better-sqlite3": "^12.11.1",
6549
6549
  "cookie-parser": "^1.4.7",
@@ -1,6 +1,6 @@
1
1
  {
2
- "name": "tr-plugin-git-sentinel",
3
- "version": "1.1.5",
2
+ "name": "tr-plugin-git",
3
+ "version": "2.2.0",
4
4
  "type": "module",
5
5
  "description": "Reports the state of the current git repository: branch, dirty files, unpushed commits and stashes.",
6
6
  "scripts": {
@@ -11,6 +11,8 @@
11
11
  "files": [
12
12
  "cli.mjs",
13
13
  "plugin.json",
14
+ "DESIGN.md",
15
+ "src/",
14
16
  "README.md",
15
17
  "LICENSE",
16
18
  "ui/"
@@ -0,0 +1,151 @@
1
+ {
2
+ "$schema": "https://github.com/gregiteen/total-recall/blob/main/metadata.plugin.schema.json",
3
+ "id": "git",
4
+ "name": "Git",
5
+ "version": "2.2.0",
6
+ "description": "The whole git CLI through Total Recall: sign-in from the auth store, guarded commits and pushes, undo, fleet state, and the intent behind every change.",
7
+ "author": "Total Recall",
8
+ "license": "MIT",
9
+ "use_cases": [
10
+ "software-development"
11
+ ],
12
+ "gate": {
13
+ "tasks": ["Run any git command", "Commit or push with identity, secret and rule checks", "Sign git in through the auth store", "Undo a destructive git command", "Check repository state across the mesh", "Keep the git CLI current on every node"],
14
+ "owned_commands": [
15
+ { "pattern": "(^|[;&|(]\\s*)git(\\s+-C\\s+\\S+)?\\s+[a-z]", "use": "total-recall git <same git command and arguments>" }
16
+ ]
17
+ },
18
+ "tasks": [
19
+ { "intent": "Check and update the git CLI", "schedule": "17 6 * * *", "command": "cli update --scheduled", "placement": "per-node" }
20
+ ],
21
+ "cli": {
22
+ "answers_help": true,
23
+ "command": "git",
24
+ "handler": "./cli.mjs",
25
+ "subcommands": [
26
+ {
27
+ "name": "audit",
28
+ "description": "Summarise branch, worktree, upstream and stash state (--json for machine output)",
29
+ "effect": "read"
30
+ },
31
+ {
32
+ "name": "diff",
33
+ "description": "Read a stat or patch for unstaged, staged or base-relative changes",
34
+ "effect": "read",
35
+ "args": [
36
+ { "name": "patch", "flag": "--patch", "type": "boolean", "label": "Show patch" },
37
+ { "name": "cached", "flag": "--cached", "type": "boolean", "label": "Use staged changes" },
38
+ { "name": "base", "flag": "--base", "type": "string", "label": "Base ref" }
39
+ ]
40
+ },
41
+ { "name": "commit", "description": "Check identity, conflicts, HEAD, secrets and repository rules, then run git's own commit with your arguments", "effect": "write", "timeout_ms": 600000, "args": [
42
+ { "name": "args", "type": "string", "label": "git commit arguments", "positional": true }
43
+ ] },
44
+ { "name": "push", "description": "Check outgoing commits for secrets and rules, turn --force into --force-with-lease, then run git's own push", "effect": "write", "timeout_ms": 600000, "args": [
45
+ { "name": "args", "type": "string", "label": "git push arguments", "positional": true }
46
+ ] },
47
+ { "name": "credential-helper", "description": "Git credential helper: give git the mapped auth-store credential (get); store and erase do nothing", "effect": "read" },
48
+ { "name": "auth", "description": "Sign-in: status (live check, no secret shown), map <host> <KEY>, setup (helper entries for this machine)", "effect": "write", "args": [
49
+ { "name": "action", "type": "string", "label": "status | map | setup", "positional": true }
50
+ ] },
51
+ { "name": "cli", "description": "Git CLI metadata (version, path, install source, upstream, release notes); --all-nodes for the mesh; cli update updates git through its installer", "effect": "write", "timeout_ms": 600000 },
52
+ { "name": "undo", "description": "Restore refs, index and files from the snapshot taken before a destructive git command; --list shows snapshots", "effect": "destructive", "args": [
53
+ { "name": "event", "type": "string", "label": "Snapshot", "positional": true },
54
+ { "name": "list", "flag": "--list", "type": "boolean", "label": "List snapshots" }
55
+ ] },
56
+ { "name": "fleet", "description": "Dirty, unpushed, behind, diverged, stale stashes and abandoned worktrees across registered repositories; --all-nodes for the mesh", "effect": "read", "timeout_ms": 600000 },
57
+ { "name": "unmerged", "description": "Branches with commits not in the default branch, worktrees with uncommitted changes and detached worktrees holding commits on no branch; --registered for every registered repository", "effect": "read", "output": "json", "timeout_ms": 600000, "args": [
58
+ { "name": "registered", "flag": "--registered", "type": "boolean", "label": "Every registered repository" }
59
+ ] },
60
+ { "name": "where", "description": "Machines and checkouts that contain a commit", "effect": "read", "args": [
61
+ { "name": "commit", "type": "string", "label": "Commit", "required": true, "positional": true }
62
+ ] },
63
+ { "name": "why", "description": "Blame one line plus the session, tracker item, decision and rules recorded when it was committed", "effect": "read", "args": [
64
+ { "name": "location", "type": "string", "label": "file:line", "required": true, "positional": true }
65
+ ] },
66
+ { "name": "group", "description": "Group a dirty tree into commits by the agent session that wrote each change; --apply commits the groups", "effect": "write" },
67
+ { "name": "message", "description": "Draft a commit message from the staged diff, the active tracker and its action log", "effect": "read" },
68
+ { "name": "bisect-agent", "description": "Find the first bad commit with the repository's quality gate as the test", "effect": "write", "timeout_ms": 600000, "args": [
69
+ { "name": "good", "type": "string", "label": "Good commit", "required": true, "positional": true },
70
+ { "name": "bad", "type": "string", "label": "Bad commit", "required": true, "positional": true }
71
+ ] },
72
+ { "name": "resolve", "description": "Propose a resolution for each conflicted file from both sides' recorded intent; --apply writes it", "effect": "write" },
73
+ { "name": "handoff", "description": "Pack a branch, its tracker and related memory into one SSSS bundle for another agent or machine", "effect": "write", "args": [
74
+ { "name": "branch", "type": "string", "label": "Branch", "required": true, "positional": true },
75
+ { "name": "out", "flag": "--out", "type": "string", "label": "Output file" }
76
+ ] },
77
+ { "name": "worktree-list", "description": "Read registered worktrees for the current repository", "effect": "read" },
78
+ { "name": "worktree-create", "description": "Create a detached worktree at a specified path and base ref", "effect": "write", "args": [
79
+ { "name": "path", "type": "string", "label": "Worktree path", "required": true, "positional": true },
80
+ { "name": "base", "flag": "--base", "type": "string", "label": "Base ref" }
81
+ ] },
82
+ { "name": "worktree-remove", "description": "Remove an owned linked worktree, with explicit force for dirty content", "effect": "destructive", "args": [
83
+ { "name": "path", "type": "string", "label": "Worktree path", "required": true, "positional": true },
84
+ { "name": "force", "flag": "--force", "type": "boolean", "label": "Allow removal of dirty content" }
85
+ ] },
86
+ { "name": "worktree", "description": "Compatibility form: worktree list, create or remove", "effect": "destructive" },
87
+ {
88
+ "name": "identity",
89
+ "description": "Show who commits here and which identities the history publishes; exits 1 on a missing or machine-derived identity (--json for machine output)",
90
+ "effect": "read"
91
+ }
92
+ ]
93
+ },
94
+ "ui": {
95
+ "design_tokens": "DESIGN.md",
96
+ "home": "repository",
97
+ "elements": [
98
+ {
99
+ "id": "repository",
100
+ "kind": "panel",
101
+ "tag": "tr-git-home",
102
+ "module": "ui/home.js",
103
+ "description": "Repository audit, diff stats, and linked worktrees",
104
+ "tokens": ["color-text", "color-surface", "color-border", "spacing-md", "radius-md"],
105
+ "optional_tokens": [
106
+ "color-background", "color-accent", "color-muted", "color-danger",
107
+ "typography-body-font-family", "typography-heading-font-family", "typography-mono-font-family"
108
+ ]
109
+ }
110
+ ]
111
+ },
112
+ "auth": {
113
+ "plugin": "auth",
114
+ "methods": [
115
+ "passkey",
116
+ "google-oauth2"
117
+ ],
118
+ "session_verification": true
119
+ },
120
+ "deploy": {
121
+ "targets": [
122
+ "ssss-app",
123
+ "nextjs",
124
+ "react",
125
+ "flask"
126
+ ],
127
+ "required_ssss_version": ">=0.9.3",
128
+ "access_grants": [
129
+ "auth:session:verify",
130
+ "ssss:vault:read",
131
+ "ssss:vault:write",
132
+ "ssss:events:append"
133
+ ]
134
+ },
135
+ "branding": {
136
+ "name": "Git Hygiene",
137
+ "color": "#b45309",
138
+ "accent": "#f59e0b",
139
+ "badge": "Repository Hygiene",
140
+ "font": "space-grotesk"
141
+ },
142
+ "startup_check": { "command": "unmerged", "args": ["--json"], "timeout_ms": 20000 },
143
+ "status": {
144
+ "command": "audit",
145
+ "refresh_seconds": 60
146
+ },
147
+ "distribution": {
148
+ "tier": "official",
149
+ "license": "open"
150
+ }
151
+ }
@@ -0,0 +1,94 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import crypto from 'node:crypto';
4
+ import { spawnSync } from 'node:child_process';
5
+ import { createRequire } from 'node:module';
6
+ import { pathToFileURL } from 'node:url';
7
+
8
+ const require = createRequire(import.meta.url);
9
+ export function git(ctx, args, options) {
10
+ const result = ctx.git(args, options);
11
+ if ((result.status ?? result.code) !== 0 || result.error) throw new Error(`Git ${args[0]} failed`);
12
+ return String(result.stdout ?? '');
13
+ }
14
+ export function tr(ctx, args, options = {}) {
15
+ return spawnSync(ctx.env.GIT_PLUGIN_TR_BIN || 'total-recall', args, {
16
+ cwd: ctx.cwd, env: ctx.env, encoding: 'utf8', shell: false,
17
+ timeout: 30000, maxBuffer: 16 * 1024 * 1024, ...options,
18
+ });
19
+ }
20
+ export function trJSON(ctx, args) {
21
+ const result = tr(ctx, args);
22
+ if (result.error || result.status !== 0) throw new Error(`Total Recall ${args[0]} failed`);
23
+ try { return JSON.parse(result.stdout); } catch { throw new Error(`Total Recall ${args[0]} returned invalid JSON`); }
24
+ }
25
+ export function repository(ctx) {
26
+ return git(ctx, ['rev-parse', '--path-format=absolute', '--git-common-dir']).trim();
27
+ }
28
+ export async function ledger(ctx, kind = 'commits', required = false) {
29
+ const dir = ctx.env.TR_PLUGIN_STATE_DIR;
30
+ if (!dir) {
31
+ if (required) throw new Error('TR_PLUGIN_STATE_DIR must be supplied by the Total Recall host');
32
+ return null;
33
+ }
34
+ if (!path.isAbsolute(dir)) throw new Error('TR_PLUGIN_STATE_DIR must be absolute');
35
+ let modulePath;
36
+ const root = ctx.env.TR_PACKAGE_ROOT;
37
+ if (root) {
38
+ if (!path.isAbsolute(root) || JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8')).name !== 'total-recall-brain') throw new Error('Invalid Total Recall state host');
39
+ modulePath = path.join(root, 'src/core/plugin-state-store.mjs');
40
+ } else modulePath = require.resolve('total-recall-brain/src/core/plugin-state-store.mjs');
41
+ const { PluginStateStore } = await import(pathToFileURL(modulePath).href);
42
+ const key = crypto.createHash('sha256').update(repository(ctx)).digest('hex');
43
+ return new PluginStateStore(path.join(dir, `${kind}-${key}.jsonl`), 'git');
44
+ }
45
+ export function session(env) { return env.CLAUDE_SESSION_ID || env.CODEX_SESSION_ID || env.TR_SESSION_ID || null; }
46
+ export function trailers(message) {
47
+ // Trailers must be in the final paragraph. Body prose is not attribution.
48
+ const block = message.trim().split(/\n\s*\n/).at(-1) || '';
49
+ const result = {};
50
+ let key;
51
+ for (const line of block.split('\n')) {
52
+ const match = /^([\w-]+):\s*(.*)$/.exec(line);
53
+ if (match) { key = match[1].toLowerCase(); (result[key] ||= []).push(match[2]); }
54
+ else if (/^\s+/.test(line) && key) result[key][result[key].length - 1] += ` ${line.trim()}`;
55
+ else return {};
56
+ }
57
+ return result;
58
+ }
59
+ export function intent(message) {
60
+ const rows = trailers(message);
61
+ return {
62
+ session: rows['agent-session']?.[0] || rows['session-id']?.[0] || rows.session?.[0] || null,
63
+ trackerItems: [...new Set(message.match(/\b(?:[A-Z][A-Z0-9_]*-[A-Z]*\d[\w.-]*|P\d+\.\d+|R\d+)\b/g) || [])],
64
+ decisions: [...(rows.decision || []), ...message.split('\n').filter(row => /^Decision\s*:/i.test(row)).map(row => row.replace(/^Decision\s*:\s*/i, ''))].filter((row, i, all) => all.indexOf(row) === i),
65
+ rules: rows.rules || rows.rule || [], trailers: rows,
66
+ };
67
+ }
68
+ export async function commitContext(ctx, sha) {
69
+ const message = git(ctx, ['show', '-s', '--format=%B', sha]);
70
+ const store = await ledger(ctx);
71
+ const record = store?.read([]).findLast(row => row.type === 'git.commit_context' && row.sha === sha) || null;
72
+ return { sha, message: message.trimEnd(), recorded: record, trailers: trailers(message), ...intent(message),
73
+ ...(record ? { session: record.session, trackerItems: record.trackerItems, decisions: record.decisions, rules: record.rules } : {}) };
74
+ }
75
+ export function output(ctx, value, text) { console.log(ctx.json ? JSON.stringify(value, null, 2) : text); }
76
+ export function operation(summary, usage, run) {
77
+ return { summary, usage, async run(args, ctx) {
78
+ try { return await run(args, ctx); }
79
+ catch (error) { if (ctx.json) console.log(JSON.stringify({ ok: false, error: error.message })); else console.error(error.message); return 1; }
80
+ } };
81
+ }
82
+ export function activePlan(ctx) {
83
+ const root = git(ctx, ['rev-parse', '--show-toplevel']).trim();
84
+ const base = path.join(root, 'docs/projects/in-progress');
85
+ if (!fs.existsSync(base)) return { tracker: null, plan: null, items: [], actionLog: '', reason: 'No active plan' };
86
+ const dirs = fs.readdirSync(base, { withFileTypes: true }).filter(row => row.isDirectory());
87
+ const trackers = dirs.flatMap(dir => fs.readdirSync(path.join(base, dir.name)).filter(name => name.endsWith('_PROJECT_TRACKER.md')).map(name => path.join(base, dir.name, name)));
88
+ if (trackers.length !== 1) throw new Error('Expected one active project tracker');
89
+ const tracker = trackers[0];
90
+ const plan = tracker.replace('_PROJECT_TRACKER.md', '_DEVELOPMENT_PLAN.md');
91
+ const body = fs.readFileSync(tracker, 'utf8');
92
+ const planBody = fs.existsSync(plan) ? fs.readFileSync(plan, 'utf8') : '';
93
+ return { tracker, plan, body, planBody, items: body.split('\n').filter(row => /^- \[[ xX]\]/.test(row)), actionLog: body.split(/^## Action Log\s*$/m)[1]?.trim() || '' };
94
+ }
@@ -0,0 +1,50 @@
1
+ import fs from 'node:fs';
2
+ import os from 'node:os';
3
+ import path from 'node:path';
4
+ import { spawnSync } from 'node:child_process';
5
+ import { fileURLToPath } from 'node:url';
6
+ import { vi } from 'vitest';
7
+
8
+ export function fixture() {
9
+ const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'git-phase3-spec-'));
10
+ const repo = path.join(tmp, 'repo'); fs.mkdirSync(repo);
11
+ const cwd = fs.realpathSync(repo);
12
+ const env = { ...process.env, GIT_CONFIG_GLOBAL: '/dev/null', GIT_CONFIG_SYSTEM: '/dev/null', GIT_CONFIG_NOSYSTEM: '1', GIT_AUTHOR_NAME: 'Test Agent', GIT_AUTHOR_EMAIL: 'agent@example.com', GIT_COMMITTER_NAME: 'Test Agent', GIT_COMMITTER_EMAIL: 'agent@example.com', TR_PLUGIN_STATE_DIR: path.join(tmp, 'state'), TR_PACKAGE_ROOT: fileURLToPath(new URL('../../node_modules/total-recall-brain', import.meta.url)), CODEX_SESSION_ID: 'session-one' };
13
+ delete env.CLAUDE_SESSION_ID;
14
+ delete env.GIT_INDEX_FILE;
15
+ // Specs run this checkout's CLI, never whatever version happens to be installed.
16
+ const CLI = new URL('../../cli.mjs', import.meta.url).href;
17
+ const RUN = `import(${JSON.stringify(CLI)}).then(m => m.run(['node', 'total-recall', 'git', ...process.argv.slice(1)])).then(() => process.exit(process.exitCode ?? 0))`;
18
+ const git = (args, options = {}) => spawnSync(process.execPath, ['--input-type=module', '-e', RUN, ...args], { cwd, env, encoding: 'utf8', maxBuffer: 16 * 1024 * 1024, ...options });
19
+ // Fixture setup uses plain git: setup is not the code under test, so no guard or record runs for it.
20
+ const raw = (args, options = {}) => spawnSync('git', args, { cwd, env, encoding: 'utf8', maxBuffer: 16 * 1024 * 1024, ...options });
21
+ const g = (...args) => { const r = raw(args); if (r.status !== 0) throw new Error(`Fixture git ${args[0]}: ${r.stderr}`); return r.stdout; };
22
+ g('init', '-q', '-b', 'main');
23
+ g('config', '--local', 'user.name', 'Test Agent');
24
+ g('config', '--local', 'user.email', 'agent@example.com');
25
+ g('config', '--local', 'commit.gpgsign', 'false');
26
+ const write = (name, content) => { fs.mkdirSync(path.dirname(path.join(cwd, name)), { recursive: true }); fs.writeFileSync(path.join(cwd, name), content); };
27
+ const commit = (message = 'Initial', file = 'a.txt', body = 'one\ntwo\nthree\nfour\nfive\n') => { write(file, body); g('add', '--', file); g('commit', '-qm', message); return g('rev-parse', 'HEAD').trim(); };
28
+ const responses = path.join(tmp, 'responses.json');
29
+ const calls = path.join(tmp, 'calls.jsonl');
30
+ const bin = path.join(tmp, 'total-recall-stub');
31
+ fs.writeFileSync(responses, '{}');
32
+ fs.writeFileSync(bin, `#!/usr/bin/env node
33
+ const fs=require('node:fs'),cp=require('node:child_process');
34
+ const args=process.argv.slice(2);fs.appendFileSync(${JSON.stringify(calls)},JSON.stringify(args)+'\\n');
35
+ const map=JSON.parse(fs.readFileSync(${JSON.stringify(responses)},'utf8'));
36
+ if(args[0]==='git'){const r=cp.spawnSync(process.execPath,['--input-type=module','-e',${JSON.stringify(RUN)},...args.slice(1)],{env:process.env,encoding:'utf8',input:fs.readFileSync(0)});process.stdout.write(r.stdout||'');process.stderr.write(r.stderr||'');process.exitCode=r.status??1;}
37
+ else if(args[0]==='auth'&&args[2]==='list'&&!map['auth secret']){process.stdout.write(JSON.stringify({keys:[]}));}
38
+ else if(args[0]==='auth'&&args[2]==='scan'&&!map['auth secret']){fs.readFileSync(0);process.stdout.write(JSON.stringify({ok:true,leak:false,keys:[]}));}
39
+ else if(args[0]==='code-quality'&&map.gateFile){const ok=fs.readFileSync(map.gateFile,'utf8').includes('good');process.stdout.write(JSON.stringify({ok}));process.exitCode=ok?0:1;}
40
+ else{const r=map[args.slice(0,2).join(' ')]||map[args[0]]||{status:0,body:{}};process.stdout.write(typeof r.body==='string'?r.body:JSON.stringify(r.body));process.exitCode=r.status??0;}
41
+ `, { mode: 0o755 });
42
+ env.GIT_PLUGIN_TR_BIN = bin;
43
+ const set = map => fs.writeFileSync(responses, JSON.stringify(map));
44
+ const readCalls = () => fs.existsSync(calls) ? fs.readFileSync(calls, 'utf8').trim().split('\n').filter(Boolean).map(row => JSON.parse(row)) : [];
45
+ const out = vi.spyOn(console, 'log').mockImplementation(() => {});
46
+ vi.spyOn(console, 'error').mockImplementation(() => {});
47
+ const ctx = { cwd, env, json: true, git };
48
+ const result = () => JSON.parse(out.mock.calls.at(-1)[0]);
49
+ return { tmp, cwd, env, ctx, g, git, write, commit, set, readCalls, result, cleanup() { vi.restoreAllMocks(); fs.rmSync(tmp, { recursive: true, force: true }); } };
50
+ }
@@ -0,0 +1,40 @@
1
+ import { spawnSync } from 'node:child_process';
2
+ import { readFileSync } from 'node:fs';
3
+ import { createRequire } from 'node:module';
4
+ import path from 'node:path';
5
+ import { pathToFileURL } from 'node:url';
6
+
7
+ const require = createRequire(import.meta.url);
8
+
9
+ /** The host owns the state path and the SSSS implementation. */
10
+ export async function stateStore(ctx, name) {
11
+ const dir = ctx.env.TR_PLUGIN_STATE_DIR;
12
+ if (!dir || !path.isAbsolute(dir)) throw new Error('TR_PLUGIN_STATE_DIR must be supplied by the Total Recall host');
13
+ const root = ctx.env.TR_PACKAGE_ROOT;
14
+ let modulePath;
15
+ if (root) {
16
+ if (!path.isAbsolute(root) || JSON.parse(readFileSync(path.join(root, 'package.json'), 'utf8')).name !== 'total-recall-brain') {
17
+ throw new Error('Invalid Total Recall state host');
18
+ }
19
+ modulePath = path.join(root, 'src/core/plugin-state-store.mjs');
20
+ } else modulePath = require.resolve('total-recall-brain/src/core/plugin-state-store.mjs');
21
+ const { PluginStateStore } = await import(pathToFileURL(modulePath).href);
22
+ return new PluginStateStore(path.join(dir, name), 'git');
23
+ }
24
+
25
+ /** Never forward service output or errors. Auth output can contain a secret. */
26
+ export function tr(args, ctx) {
27
+ return spawnSync(ctx.env.GIT_PLUGIN_TR_BIN || 'total-recall', args, {
28
+ cwd: ctx.cwd, env: ctx.env, encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'],
29
+ timeout: 30000, maxBuffer: 16 * 1024 * 1024, shell: false,
30
+ });
31
+ }
32
+
33
+ export function jsonResult(result, reason) {
34
+ if (result.status !== 0 || result.error || result.signal) throw new Error(reason);
35
+ try { return JSON.parse(result.stdout); } catch { throw new Error(reason); }
36
+ }
37
+
38
+ export function emit(ctx, value, text) {
39
+ console.log(ctx.json ? JSON.stringify(value, null, 2) : text);
40
+ }