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
@@ -10,7 +10,7 @@
10
10
  import fs from 'node:fs';
11
11
  import path from 'node:path';
12
12
  import { createRequire } from 'node:module';
13
- import { readPluginsDir, globalPluginsDir, PACKAGE_ROOT, resolvePluginFile } from './plugin-loader.mjs';
13
+ import { readPluginsDir, globalPluginsDir, PACKAGE_ROOT, resolvePluginFile, validatePluginManifest } from './plugin-loader.mjs';
14
14
  import { DEFAULT_PLUGIN_IDS, REQUIRED_INSTALLATION_PLUGIN_IDS } from './default-plugins.mjs';
15
15
  import { comparePackageVersions } from './package-version.mjs';
16
16
  import { preparePluginDependencies } from './plugin-dependencies.mjs';
@@ -113,14 +113,39 @@ export function inspectRequiredPlugins(brainDir, { pluginsDir, sharedBrainDir =
113
113
  return { status: errors.length ? 'failed' : 'ready', errors, source, installations };
114
114
  }
115
115
 
116
- /** Only a copy that declares an older release than the bundled one is refreshed; damaged same-release copies still fail. */
116
+ const LEGACY_PRESENTATION_FIELDS = ['card', 'card_face', 'card_layout'];
117
+
118
+ function hasLegacyPresentation(manifest) {
119
+ return LEGACY_PRESENTATION_FIELDS.some(field => Object.hasOwn(manifest, field))
120
+ || (Array.isArray(manifest.ui?.elements) && manifest.ui.elements.some(element => ['card', 'card-face'].includes(element?.kind)));
121
+ }
122
+
123
+ function hasPluginFiles(directory, files) {
124
+ return files.every(file => fs.statSync(resolvePluginFile(directory, file)).isFile());
125
+ }
126
+
127
+ function runtimeFiles(manifest) {
128
+ return ['package.json', ...(manifest.cli ? [manifest.cli.handler] : []), ...Object.values(manifest.runtime?.modules || {})];
129
+ }
130
+
131
+ /** Refresh older copies and migrate the retired presentation of an otherwise intact same-release copy. */
117
132
  function isStaleInstall(target, source) {
118
133
  try {
119
134
  // A link is its owner's checkout. Replacing it would delete that repository's files, .git included.
120
135
  if (fs.lstatSync(target).isSymbolicLink()) return false;
121
- const installed = JSON.parse(fs.readFileSync(path.join(target, 'plugin.json'), 'utf8')).version;
122
- const bundled = JSON.parse(fs.readFileSync(path.join(source, 'plugin.json'), 'utf8')).version;
123
- return comparePackageVersions(installed, bundled) === -1;
136
+ const installed = JSON.parse(fs.readFileSync(path.join(target, 'plugin.json'), 'utf8'));
137
+ const bundled = JSON.parse(fs.readFileSync(path.join(source, 'plugin.json'), 'utf8'));
138
+ if (comparePackageVersions(installed.version, bundled.version) === -1) return true;
139
+ if (installed.version !== bundled.version || installed.id !== bundled.id || bundled.id !== path.basename(source)
140
+ || installed.cli?.command !== bundled.cli?.command || !hasLegacyPresentation(installed)
141
+ || hasLegacyPresentation(bundled) || !bundled.ui?.home || !validatePluginManifest(bundled).valid) return false;
142
+
143
+ const migrated = { ...installed, ui: bundled.ui };
144
+ for (const field of LEGACY_PRESENTATION_FIELDS) delete migrated[field];
145
+ if (!validatePluginManifest(migrated).valid || !hasPluginFiles(target, runtimeFiles(installed))) return false;
146
+ return hasPluginFiles(source, [
147
+ ...runtimeFiles(bundled), bundled.ui.design_tokens, ...bundled.ui.elements.map(element => element.module),
148
+ ]);
124
149
  } catch { return false; }
125
150
  }
126
151
 
@@ -165,7 +190,7 @@ function installDefaultsInto(brainDir, sourceDir) {
165
190
  fs.mkdirSync(path.dirname(target), { recursive: true });
166
191
  fs.cpSync(source, target, { recursive: true, force: false, errorOnExist: true });
167
192
  } else if (isStaleInstall(target, source)) {
168
- // A vendored copy that no longer validates (or predates the bundled release) is replaced; node_modules stays.
193
+ // Keep installed dependencies when refreshing the bundled plugin files.
169
194
  for (const entry of fs.readdirSync(target)) if (entry !== 'node_modules') fs.rmSync(path.join(target, entry), { recursive: true, force: true });
170
195
  for (const entry of fs.readdirSync(source)) if (entry !== 'node_modules') fs.cpSync(path.join(source, entry), path.join(target, entry), { recursive: true });
171
196
  }
@@ -195,23 +220,45 @@ export function auditProjectPluginCopies(projectRoot, { sharedDir = globalPlugin
195
220
  return { copies: [], count: 0, sourceDir };
196
221
  }
197
222
  const copies = [];
198
- for (const id of DEFAULT_PLUGIN_IDS) {
223
+ const realpath = (p) => { try { return fs.realpathSync(p); } catch { return null; } };
224
+ // A link in a repository that resolves to the same plugin as the shared
225
+ // install only shadows it: state and records split between brains and the
226
+ // repository can drift onto another checkout. Defaults never belong to a
227
+ // repository, so any linked default is a shadow too.
228
+ const isShadowLink = (id, copyDir, shared) => {
229
+ if (!fs.lstatSync(copyDir).isSymbolicLink() || !fs.existsSync(shared)) return false;
230
+ return DEFAULT_PLUGIN_IDS.includes(id) || realpath(copyDir) === realpath(shared);
231
+ };
232
+ const entries = fs.readdirSync(pluginsDir).filter((name) => !name.startsWith('.'));
233
+ const ids = [...new Set([...DEFAULT_PLUGIN_IDS, ...entries])];
234
+ for (const id of ids) {
199
235
  const copyDir = path.join(pluginsDir, id);
200
- if (!fs.existsSync(copyDir)) continue;
236
+ if (!fs.lstatSync(copyDir, { throwIfNoEntry: false })) continue;
201
237
  const source = path.join(sourceDir, id);
202
238
  const shared = path.join(sharedDir, id);
239
+ const linked = fs.lstatSync(copyDir).isSymbolicLink();
240
+ // The source checkout a shared link points at is not a copy.
241
+ if (!linked && fs.existsSync(shared) && realpath(shared) === realpath(copyDir)) continue;
242
+ const shadow = isShadowLink(id, copyDir, shared);
243
+ // Nothing is installed per repository. A plugin found only here must be
244
+ // installed in the shared folder before its repository entry can go.
245
+ const repoOnly = !fs.existsSync(shared);
203
246
  const row = {
204
247
  id, dir: copyDir,
205
248
  sourceDir: fs.existsSync(source) ? source : null,
206
249
  sharedDir: fs.existsSync(shared) ? shared : null,
207
250
  edited: null, version: null, sourceVersion: null, sharedVersion: null,
208
- linked: fs.lstatSync(copyDir).isSymbolicLink(),
251
+ linked,
252
+ shadow,
253
+ repoOnly,
254
+ target: fs.lstatSync(copyDir).isSymbolicLink() ? fs.readlinkSync(copyDir) : null,
209
255
  };
210
256
  const version = (dir) => { try { return JSON.parse(fs.readFileSync(path.join(dir, 'plugin.json'), 'utf8')).version; } catch { return null; } };
211
257
  row.version = version(copyDir);
212
258
  row.sourceVersion = row.sourceDir ? version(row.sourceDir) : null;
213
259
  row.sharedVersion = row.sharedDir ? version(row.sharedDir) : null;
214
- row.edited = row.sourceDir ? !sameTree(copyDir, row.sourceDir) : null;
260
+ // A link is owned by its target checkout, so its tree is never "edited" here; a dangling link has no tree.
261
+ row.edited = row.linked || !fs.existsSync(copyDir) ? null : row.sourceDir ? !sameTree(copyDir, row.sourceDir) : null;
215
262
  // Older copies shadow the shared install. Version skew identifies stale
216
263
  // candidates for archival but does not prove the local source is disposable.
217
264
  row.stale = Boolean(row.version && row.sharedVersion && comparePackageVersions(row.version, row.sharedVersion) < 0);
@@ -0,0 +1,23 @@
1
+ /** Shared rule policy. Diagnostics contain counts and limits, never rule text. */
2
+ export const RULE_SOFT_LIMIT = 300;
3
+ export const RULE_HARD_LIMIT = 800;
4
+ let rejections = 0;
5
+
6
+ export function ruleLengthStats() {
7
+ return { rejections, scope: 'process' };
8
+ }
9
+
10
+ export function checkRuleLength(data, body, { allowLong = false } = {}) {
11
+ const errors = [], warnings = [];
12
+ const rule = data.type === 'rule' || (data.type === 'memory' &&
13
+ ['invariants', 'preferences', 'anti-patterns'].includes(data.category));
14
+ if (!rule || data.tags?.includes('context:policy')) return { errors, warnings };
15
+ const length = String(body || '').trim().length;
16
+ if (length > RULE_HARD_LIMIT && allowLong !== true) {
17
+ rejections++;
18
+ errors.push(`Rule is ${length} characters (limit ${RULE_HARD_LIMIT}). Shorten the rule. Save history and examples as a fact, or use the explicit allow-long exception.`);
19
+ } else if (length > RULE_SOFT_LIMIT) {
20
+ warnings.push(`Rule is ${length} characters. Keep rules brief (under ${RULE_SOFT_LIMIT} characters). Save history and examples as a fact.`);
21
+ }
22
+ return { errors, warnings };
23
+ }
@@ -11,7 +11,7 @@ let configOwner, configError;
11
11
  try { configOwner = await loadPluginModule('meta-harness', 'reasoning-runtime'); }
12
12
  catch (error) { configError = error; }
13
13
  function reasoningConfigOwner() {
14
- if (!configOwner) throw new Error(`Meta Harness reasoning is unavailable: ${configError?.message || 'install the plugin'}`);
14
+ if (!configOwner) throw new Error(`Metaharness reasoning is unavailable: ${configError?.message || 'install the plugin'}`);
15
15
  return configOwner;
16
16
  }
17
17
 
@@ -7,14 +7,13 @@ import config from './config.mjs';
7
7
  import { getNodes } from './vault-cache.mjs';
8
8
  import { logger } from './logger.mjs';
9
9
  import { loadQueue, updateQueueItem } from './research-queue.mjs';
10
- import { transitionTaskStatus } from './task-envelope.mjs';
10
+ import { transitionTaskStatus, getTask } from './task-envelope.mjs';
11
11
 
12
12
  /**
13
13
  * Total Recall Task Scheduler
14
14
  *
15
15
  * A priority queue that dispatches tasks to cognitive layer engines.
16
- * The queue is NEVER empty — when explicit tasks run out, the scheduler
17
- * auto-generates idle improvement tasks from vault analysis.
16
+ * An empty queue stays empty. Automations schedules maintenance explicitly.
18
17
  *
19
18
  * Task categories map to cognitive layers:
20
19
  * conscious-enforcement → Conscious Layer (weight 1.0)
@@ -34,7 +33,6 @@ export const LAYER_WEIGHTS = Object.freeze({
34
33
  'skill-engineering': 0.5,
35
34
  'proactive-research': 0.4,
36
35
  'self-evaluation': 0.3,
37
- 'exploration': 0.2,
38
36
  });
39
37
 
40
38
  // ─── Priority Queue ─────────────────────────────────────────────────────────────
@@ -198,9 +196,8 @@ const RESEARCH_PHASE_COUNT = Object.keys(RESEARCH_PHASES).length;
198
196
  let _idleCycleCounter = 0;
199
197
 
200
198
  /**
201
- * Generate an idle improvement task when the explicit queue is empty.
202
- * Purely local maintenance, round-robin: inference, post-mortem, clarity
203
- * review, memory compaction. Idle ticks never research on their own; research
199
+ * Generate a maintenance candidate for an explicit scheduled run.
200
+ * Purely local maintenance: inference, clarity review and compaction. Research
204
201
  * only runs for topics a human asked for or the project gate approved.
205
202
  */
206
203
  export function generateIdleTask({ vaultDir, sessionsDir }) {
@@ -208,7 +205,6 @@ export function generateIdleTask({ vaultDir, sessionsDir }) {
208
205
  // Absolutely no automated/proactive web searches or staleness checks that make internet queries.
209
206
  const cleanStrategies = [
210
207
  () => generateInferenceTask(vaultDir),
211
- () => generatePostMortemTask(sessionsDir),
212
208
  () => generateClarityReviewTask(vaultDir),
213
209
  () => generateMemoryCompactionTask(vaultDir),
214
210
  ];
@@ -224,6 +220,26 @@ export function generateIdleTask({ vaultDir, sessionsDir }) {
224
220
  }
225
221
  }
226
222
 
223
+ /** Called by an automations manifest task, never by queue exhaustion. */
224
+ export async function enqueueScheduledIdleTasks({ vaultDir, queueDir, now = new Date(),
225
+ leader = async () => (await import('./leader-election.mjs')).isLeader() } = {}) {
226
+ if (!await leader()) return { enqueued: [], skipped: 'not-leader' };
227
+ const tasks = [generateInferenceTask(vaultDir), generateClarityReviewTask(vaultDir), generateMemoryCompactionTask(vaultDir)];
228
+ const enqueued = [];
229
+ for (const task of tasks) {
230
+ if (task.slug.startsWith('idle-')) continue;
231
+ const kind = task.slug.startsWith('inference-') ? 'inference' : task.slug.startsWith('clarity-') ? 'clarity-review' : 'memory-compaction';
232
+ const identity = crypto.createHash('sha256').update(String(task.target)).digest('hex').slice(0, 12);
233
+ task.slug = `${kind}-${now.toISOString().slice(0, 10)}-${identity}`;
234
+ if (getTask(queueDir, task.slug) || fs.existsSync(path.join(queueDir, 'archive', `${task.slug}.md`))) continue;
235
+ task.created_by = 'automations';
236
+ task.payload = { scheduledIdle: true };
237
+ persistTaskToDisk(task, queueDir);
238
+ enqueued.push(task.slug);
239
+ }
240
+ return { enqueued };
241
+ }
242
+
227
243
  /**
228
244
  * Pick a random active memory node and create a clarity review task.
229
245
  */
@@ -259,7 +275,7 @@ function generateMemoryCompactionTask(vaultDir) {
259
275
  status: 'pending',
260
276
  created_by: 'scheduler-idle',
261
277
  reason: `Idle task: scan vault for fragmented nodes to merge into comprehensive master documents.`,
262
- body: `Scan for highly overlapping or fragmented memory nodes and fuse them into comprehensive master nodes, archiving the fragments.`,
278
+ body: `File memory-cleanup proposals for overlapping memory nodes. Keep canonical nodes unchanged until proposal review.`,
263
279
  };
264
280
  }
265
281
 
@@ -344,23 +360,6 @@ function generatePostMortemTask(sessionsDir) {
344
360
  };
345
361
  }
346
362
 
347
- /**
348
- * Generate a cutoff audit task — scans vault for nodes with intrinsic LLM
349
- * knowledge that may have drifted since the model's training cutoff.
350
- */
351
- function generateCutoffAuditTask() {
352
- return {
353
- type: 'task',
354
- slug: `cutoff-audit-${Date.now().toString(36)}`,
355
- priority: 60,
356
- category: 'cutoff-audit',
357
- status: 'pending',
358
- created_by: 'scheduler-idle',
359
- reason: 'Idle task: scan vault for training-cutoff assumption drift',
360
- body: 'Identify memory nodes containing time-sensitive claims based on intrinsic LLM knowledge. Flag high-drift items (API versions, pricing, model specs, framework changes) for verification against current real-world sources.',
361
- };
362
- }
363
-
364
363
  function makeFallbackTask(category, reason) {
365
364
  return {
366
365
  type: 'task',
@@ -385,7 +384,7 @@ function makeFallbackTask(category, reason) {
385
384
  * @param {string} opts.sessionsDir Path to .agent/skills/total-recall/sessions/
386
385
  * @returns {{ queue: TaskQueue, stats: object }}
387
386
  */
388
- export function createScheduler({ queueDir, vaultDir, sessionsDir }) {
387
+ export function createScheduler({ queueDir, vaultDir, sessionsDir, localOnly = false }) {
389
388
  const queue = new TaskQueue();
390
389
 
391
390
  // Load explicit tasks from disk
@@ -397,7 +396,7 @@ export function createScheduler({ queueDir, vaultDir, sessionsDir }) {
397
396
  // Optional remote vault sync job (env-configured only)
398
397
  try {
399
398
  const { remoteVaultSync } = config;
400
- if (remoteVaultSync.enabled) {
399
+ if (!localOnly && remoteVaultSync.enabled) {
401
400
  const statusFile = path.join(path.dirname(remoteVaultSync.vaultDir), 'sync-status.json');
402
401
  let lastRunMs = 0;
403
402
  if (fs.existsSync(statusFile)) {
@@ -442,7 +441,7 @@ export function createScheduler({ queueDir, vaultDir, sessionsDir }) {
442
441
  : 60 * 60 * 1000; // 1 hour default
443
442
 
444
443
  let resetCount = 0;
445
- for (const item of loadQueue()) {
444
+ for (const item of localOnly ? [] : loadQueue()) {
446
445
  if (item.status !== 'failed') continue;
447
446
  if ((item.attempts || 0) >= MAX_RESEARCH_ATTEMPTS) continue;
448
447
  const failedAt = new Date(item.updated_at || item.created_at || 0).getTime();
@@ -469,7 +468,7 @@ export function createScheduler({ queueDir, vaultDir, sessionsDir }) {
469
468
  }
470
469
 
471
470
  // User requests run before autonomous background research; oldest first within each.
472
- const researchItems = loadQueue()
471
+ const researchItems = (localOnly ? [] : loadQueue())
473
472
  .filter((i) => i.status === 'pending' && RESEARCH_PHASES[i.research_phase || 'acquisition'])
474
473
  .sort((a, b) => {
475
474
  const ua = a.origin === 'autonomous' ? 1 : 0;
@@ -532,27 +531,20 @@ export function createScheduler({ queueDir, vaultDir, sessionsDir }) {
532
531
  * Get the next task.
533
532
  *
534
533
  * Default: only explicit (and research-queue) tasks — never invent work.
535
- * Idle generation requires TR_IDLE_TASKS=1 or opts.allowIdle === true.
534
+ * Automations is the only recurring maintenance trigger.
536
535
  *
537
536
  * @param {{ allowIdle?: boolean }} [opts]
538
537
  * @returns {{ task: object|null, source: 'explicit'|'idle'|'empty' }}
539
538
  */
540
539
  next(opts = {}) {
540
+ if (opts.localOnly) {
541
+ const local = queue._items.findIndex(({ task }) => ['lesson-review', 'skill-manager'].includes(task.executor) || ['lesson-review', 'self-evaluation', 'skill-engineering'].includes(task.category));
542
+ return local < 0 ? { task: null, source: 'empty' } : { task: queue._items.splice(local, 1)[0].task, source: 'explicit' };
543
+ }
541
544
  const explicit = queue.dequeue();
542
545
  if (explicit) return { task: explicit, source: 'explicit' };
543
546
 
544
- const allowIdle =
545
- opts.allowIdle === true ||
546
- process.env.TR_IDLE_TASKS === '1' ||
547
- process.env.TR_IDLE_TASKS === 'true';
548
-
549
- if (!allowIdle) {
550
- return { task: null, source: 'empty' };
551
- }
552
-
553
- const idle = generateIdleTask({ vaultDir, sessionsDir });
554
- persistTaskToDisk(idle, queueDir);
555
- return { task: idle, source: 'idle' };
547
+ return { task: null, source: 'empty' };
556
548
  },
557
549
  };
558
550
  }
@@ -41,8 +41,7 @@ export const TaskSchema = z.object({
41
41
  'system2-deliberation',
42
42
  'skill-engineering',
43
43
  'proactive-research',
44
- 'self-evaluation',
45
- 'exploration'
44
+ 'self-evaluation'
46
45
  ]),
47
46
  status: z.enum(['pending', 'in_progress', 'done', 'failed']),
48
47
  target: z.string().optional(),
@@ -1035,6 +1034,8 @@ export const PluginRecordSchema = z.object({
1035
1034
  task_runs: z.record(z.string()).optional(),
1036
1035
  /** Explicit mesh node for commands with selected-node placement. */
1037
1036
  task_nodes: z.record(z.string().min(1)).optional(),
1037
+ runtime_enabled: z.boolean().optional(),
1038
+ runtime_on_use: z.boolean().optional(),
1038
1039
  }).passthrough();
1039
1040
 
1040
1041
  const SECRET_KEY_PATTERN = /^(.*_)?(secret|token|password|api[_-]?key|private[_-]?key|credentials|auth[_-]?header|bearer)$/i;
@@ -98,7 +98,8 @@ export async function semanticSearch(query, {
98
98
  tags = null,
99
99
  modality = null,
100
100
  importance = null,
101
- priority = null
101
+ priority = null,
102
+ rankResults = null
102
103
  } = {}) {
103
104
  const k = Math.min(Number(top_k) || 5, 20);
104
105
 
@@ -234,7 +235,7 @@ export async function semanticSearch(query, {
234
235
  }
235
236
 
236
237
  // Slice top results
237
- for (const { node, score } of blendedRanked.slice(0, k)) {
238
+ for (const { node, score } of blendedRanked.slice(0, rankResults ? undefined : k)) {
238
239
  if (node) {
239
240
  const similarity = similarityBySlug.get(node.slug);
240
241
  results.push({
@@ -297,7 +298,7 @@ export async function semanticSearch(query, {
297
298
  }
298
299
 
299
300
  results.sort((a, b) => b.score - a.score);
300
- const finalResults = results.slice(0, k);
301
+ const finalResults = (rankResults ? rankResults(results) : results).slice(0, k);
301
302
  if (!queryEmbedding || vaultEntries.length === 0) {
302
303
  finalResults.degradedTextSearch = true;
303
304
  // Say WHICH failure this is. The caller renders remediation from it, and
@@ -0,0 +1,148 @@
1
+ /** Repair this installation's macOS server LaunchAgent. Never manages systemd. */
2
+ import fs from 'node:fs';
3
+ import os from 'node:os';
4
+ import path from 'node:path';
5
+ import { fileURLToPath } from 'node:url';
6
+ import { spawnSync } from 'node:child_process';
7
+ import { processIdentity } from './startup-health.mjs';
8
+
9
+ const PACKAGE_ROOT = fileURLToPath(new URL('../..', import.meta.url));
10
+ const LABEL = 'com.totalrecall.server';
11
+ const corePathEnv = new Set(['AGENT_DIR', 'TR_SECRETS_BRAIN', 'TR_SERVER_PID_FILE']);
12
+ const inside = (root, value) => value === root || value.startsWith(root + path.sep);
13
+ const real = value => { try { return fs.realpathSync(value); } catch { return path.resolve(value); } };
14
+
15
+ export function stableNodePath(env = process.env) {
16
+ for (const dir of (env.PATH || '').split(path.delimiter)) {
17
+ if (!dir || !path.isAbsolute(dir)) continue;
18
+ const candidate = path.join(dir, 'node');
19
+ if (candidate.split(path.sep).includes('Cellar')) continue;
20
+ try { fs.accessSync(candidate, fs.constants.X_OK); if (fs.statSync(candidate).isFile()) return candidate; } catch {}
21
+ }
22
+ throw new Error('No stable node executable on PATH. Add the node symlink directory to PATH.');
23
+ }
24
+
25
+ function convert(input, format, exec) {
26
+ const result = exec('plutil', ['-convert', format, '-o', '-', '-'], { input, encoding: 'utf8', timeout: 5000 });
27
+ if (result.status !== 0 || result.error) throw new Error(`Cannot convert server plist to ${format}.`);
28
+ return result.stdout;
29
+ }
30
+
31
+ /** Detect foreign installations without naming any operator repository. */
32
+ function checkoutFor(value, oldRoot, packageRoot) {
33
+ if (inside(packageRoot, value) || inside(real(packageRoot), value)) return null;
34
+ if (oldRoot && real(oldRoot) !== real(packageRoot) && inside(oldRoot, value)) return oldRoot;
35
+ for (let dir = value; ; dir = path.dirname(dir)) {
36
+ try {
37
+ if (JSON.parse(fs.readFileSync(path.join(dir, 'package.json'), 'utf8')).name === 'total-recall-brain'
38
+ && real(dir) !== real(packageRoot)) return dir;
39
+ } catch {}
40
+ if (dir === path.dirname(dir)) return null;
41
+ }
42
+ }
43
+
44
+ export function serverEnvironment(existing, { packageRoot, oldRoot }) {
45
+ const env = {};
46
+ for (const [key, value] of Object.entries(existing || {})) {
47
+ if (typeof value !== 'string') throw new Error(`Server environment ${key} must be a string.`);
48
+ if (key === 'PATH') {
49
+ env[key] = value.split(path.delimiter).map(part => {
50
+ const foreign = path.isAbsolute(part) && checkoutFor(part, oldRoot, packageRoot);
51
+ return foreign ? path.join(packageRoot, path.relative(foreign, part)) : part;
52
+ }).join(path.delimiter);
53
+ continue;
54
+ }
55
+ const foreign = path.isAbsolute(value) && checkoutFor(value, oldRoot, packageRoot);
56
+ if (!foreign) env[key] = value;
57
+ else if (corePathEnv.has(key)) env[key] = path.join(packageRoot, path.relative(foreign, value));
58
+ // Obsolete settings must not retain a path into another installation.
59
+ }
60
+ return env;
61
+ }
62
+
63
+ function publicPlist(plist) {
64
+ const copy = structuredClone(plist);
65
+ for (const key of Object.keys(copy.EnvironmentVariables || {})) {
66
+ if (/password|secret(?!s_brain)|token|api.?key|credential/i.test(key)) copy.EnvironmentVariables[key] = '[redacted]';
67
+ }
68
+ return copy;
69
+ }
70
+
71
+ function plistDiff(before, after) {
72
+ const lines = [];
73
+ const walk = (a, b, key) => {
74
+ if (JSON.stringify(a) === JSON.stringify(b)) return;
75
+ if (a && b && !Array.isArray(a) && !Array.isArray(b) && typeof a === 'object' && typeof b === 'object') {
76
+ for (const part of new Set([...Object.keys(a), ...Object.keys(b)])) walk(a[part], b[part], key ? `${key}.${part}` : part);
77
+ } else {
78
+ if (a !== undefined) lines.push(`- ${key}: ${JSON.stringify(a)}`);
79
+ if (b !== undefined) lines.push(`+ ${key}: ${JSON.stringify(b)}`);
80
+ }
81
+ };
82
+ walk(publicPlist(before), publicPlist(after), '');
83
+ return lines.join('\n') || 'No plist changes.';
84
+ }
85
+
86
+ export async function ensureServerService({ dryRun = false, platform = process.platform, home = os.homedir(),
87
+ packageRoot = PACKAGE_ROOT, env = process.env, exec = spawnSync, identity = processIdentity,
88
+ uid = process.getuid?.(), sleep = ms => new Promise(resolve => setTimeout(resolve, ms)), attempts = 40 } = {}) {
89
+ if (platform !== 'darwin') return { status: 'unchanged', reason: 'server-release owns the server on systemd hosts; no changes made.' };
90
+ packageRoot = path.resolve(packageRoot);
91
+ const plistPath = path.join(home, 'Library/LaunchAgents', `${LABEL}.plist`);
92
+ const oldBytes = fs.existsSync(plistPath) ? fs.readFileSync(plistPath) : null;
93
+ const existing = oldBytes ? JSON.parse(convert(oldBytes, 'json', exec)) : {};
94
+ const template = fs.readFileSync(path.join(packageRoot, 'templates', `${LABEL}.plist`), 'utf8');
95
+ const desired = JSON.parse(convert(template, 'json', exec));
96
+ const substitute = value => typeof value === 'string' ? value.replaceAll('__ROOT__', packageRoot).replaceAll('__HOME__', home)
97
+ : Array.isArray(value) ? value.map(substitute) : value && typeof value === 'object'
98
+ ? Object.fromEntries(Object.entries(value).map(([key, val]) => [key, substitute(val)])) : value;
99
+ const plist = substitute(desired);
100
+ plist.WorkingDirectory = packageRoot;
101
+ plist.ProgramArguments[0] = stableNodePath(env);
102
+ plist.EnvironmentVariables = { ...plist.EnvironmentVariables,
103
+ ...serverEnvironment(existing.EnvironmentVariables, { packageRoot, oldRoot: existing.WorkingDirectory }) };
104
+ const diff = plistDiff(existing, plist);
105
+ if (dryRun) return { status: 'dry_run', plistPath, diff };
106
+
107
+ const xml = convert(JSON.stringify(plist), 'xml1', exec);
108
+ const domain = `gui/${uid}`;
109
+ const service = `${domain}/${LABEL}`;
110
+ const run = args => exec('launchctl', args, { encoding: 'utf8', timeout: 10000 });
111
+ const ok = result => result.status === 0 && !result.error;
112
+ const must = args => { if (!ok(run(args))) throw new Error(`launchctl ${args[0]} failed for ${service}.`); };
113
+ const agentDir = plist.EnvironmentVariables.AGENT_DIR || path.join(home, '.agent');
114
+ const pidFile = plist.EnvironmentVariables.TR_SERVER_PID_FILE || path.join(agentDir, 'skills/total-recall/server.pid');
115
+ const entry = path.join(packageRoot, 'src/server/index.mjs');
116
+ const previous = identity(pidFile, entry);
117
+ if (previous.status === 'unknown') throw new Error('Server process identity is unknown. Nothing changed.');
118
+ const loaded = ok(run(['print', service]));
119
+ if (!loaded && ['running', 'conflict'].includes(previous.status)) throw new Error('A server runs outside this LaunchAgent. Nothing changed.');
120
+ fs.mkdirSync(path.dirname(plistPath), { recursive: true });
121
+ for (const log of [plist.StandardOutPath, plist.StandardErrorPath]) if (log) fs.mkdirSync(path.dirname(log), { recursive: true });
122
+ const pending = `${plistPath}.${process.pid}.tmp`;
123
+ try {
124
+ fs.writeFileSync(pending, xml, { mode: 0o600 });
125
+ fs.renameSync(pending, plistPath);
126
+ if (loaded) {
127
+ must(['bootout', service]);
128
+ let retired = false;
129
+ for (let i = 0; i < attempts; i++) {
130
+ if (!ok(run(['print', service]))) { retired = true; break; }
131
+ await sleep(250);
132
+ }
133
+ if (!retired) throw new Error('LaunchAgent did not retire.');
134
+ }
135
+ must(['bootstrap', domain, plistPath]);
136
+ for (let i = 0; i < attempts; i++) {
137
+ const observed = identity(pidFile, entry);
138
+ if (observed.status === 'running' && (!loaded || observed.pid !== previous.pid)) return { status: 'ready', plistPath, pid: observed.pid, entry: observed.entry };
139
+ await sleep(250);
140
+ }
141
+ throw new Error('Server process verification failed after launchd reload.');
142
+ } catch (error) {
143
+ // Keep the previous definition available for operator recovery. Never report success.
144
+ if (oldBytes !== null) fs.writeFileSync(plistPath, oldBytes, { mode: 0o600 });
145
+ else fs.rmSync(plistPath, { force: true });
146
+ throw error;
147
+ } finally { fs.rmSync(pending, { force: true }); }
148
+ }
@@ -4,6 +4,7 @@ import os from 'os';
4
4
  import crypto from 'crypto';
5
5
  import { atomicWrite } from './vault.mjs';
6
6
  import { logger } from './logger.mjs';
7
+ import { readLessonEntries } from './lesson-sessions.mjs';
7
8
 
8
9
  /**
9
10
  * Total Recall Session Watcher
@@ -30,6 +31,12 @@ const HOME = os.homedir();
30
31
  * of unified SSSS session entries.
31
32
  */
32
33
  const SOURCES = [
34
+ {
35
+ name: 'openclaw',
36
+ root: path.join(HOME, '.openclaw', 'agents'),
37
+ filter: filename => filename.endsWith('.jsonl'),
38
+ adapter: file => parseClaudeCode(file).map(entry => ({ ...entry, source: 'openclaw' })),
39
+ },
33
40
  {
34
41
  name: 'claude-code',
35
42
  root: path.join(HOME, '.claude', 'projects'),
@@ -248,6 +255,15 @@ export function parseClaudeCode(filePath) {
248
255
  */
249
256
  export function parseCodex(filePath) {
250
257
  const raw = fs.readFileSync(filePath, 'utf8');
258
+ if (/"type"\s*:\s*"(?:response_item|event_msg)"/.test(raw)) {
259
+ let parentId = null;
260
+ return readLessonEntries(filePath).map(message => {
261
+ const entry = createSessionEntry({ ...message, parentId, source: 'codex',
262
+ type: message.role === 'user' ? 'task' : message.role === 'tool' ? 'tool_call' : 'observation' });
263
+ parentId = entry.id;
264
+ return entry;
265
+ });
266
+ }
251
267
  const lines = raw.split('\n').filter(Boolean);
252
268
  const entries = [];
253
269
  let prevId = null;
@@ -661,7 +677,9 @@ export function writeSession(entries, sessionsDir, sourceFile) {
661
677
  // Skip if already ingested and unchanged
662
678
  if (fs.existsSync(sessionFile)) {
663
679
  try {
664
- if (fs.readFileSync(sessionFile, 'utf8') === jsonl) {
680
+ const previous = fs.readFileSync(sessionFile, 'utf8');
681
+ const semantic = rows => JSON.stringify(rows.map(({ role, type, content, source, cwd }) => ({ role, type, content, source, cwd })));
682
+ if (previous === jsonl || semantic(previous.trim().split('\n').filter(Boolean).map(line => JSON.parse(line))) === semantic(entries)) {
665
683
  return null;
666
684
  }
667
685
  } catch { /* ignore */ }
@@ -0,0 +1,16 @@
1
+ import { discoverPlugins } from './plugin-loader.mjs';
2
+ import { runPluginCommand } from './plugin-runner.mjs';
3
+
4
+ /** Skill engineering belongs to skill-manager. Missing operations fail closed. */
5
+ export async function requestSkillGap(topic, evidence, { projectRoot = process.cwd(), discover = discoverPlugins, run = runPluginCommand } = {}) {
6
+ if (typeof topic !== 'string' || !topic.trim() || typeof evidence !== 'string' || !evidence.trim()) {
7
+ throw new Error('Skill gap requires a topic and an evidence reference');
8
+ }
9
+ const plugin = discover(projectRoot).find(item => item.id === 'skill-manager' && item.valid);
10
+ if (!plugin?.manifest.cli?.subcommands?.some(item => item.name === 'gap')) {
11
+ throw new Error('Skill-manager gap is unavailable. Install an owner version that provides: total-recall skill-manager gap "<topic>" --evidence <ref>');
12
+ }
13
+ const result = await run(plugin, { subcommand: 'gap', args: [topic.trim(), '--evidence', evidence], cwd: projectRoot });
14
+ if (!result.ok || result.truncated) throw new Error(`Skill-manager gap failed: ${result.stderr || result.output || result.exitCode}`);
15
+ return { success: true, output: result.stdout || result.output, executor: 'skill-manager' };
16
+ }
@@ -12,7 +12,8 @@ import fs from 'node:fs';
12
12
  import path from 'node:path';
13
13
  import crypto from 'node:crypto';
14
14
  import matter from './frontmatter.mjs';
15
- import { createEngine } from '@ssss/cli/engine';
15
+ import { AsyncLocalStorage } from 'node:async_hooks';
16
+ import { createEngine, resolveContainedPath } from '@ssss/cli/engine';
16
17
  import { createValidator } from '@ssss/cli/validator';
17
18
  import {
18
19
  composeRegistryLayers,
@@ -20,6 +21,7 @@ import {
20
21
  resolvePrimitiveDefinition,
21
22
  } from '@ssss/cli/registry';
22
23
  import { detectDirectWrites } from '@ssss/cli/guard';
24
+ import { checkRuleLength } from './rule-length.mjs';
23
25
  import { validateMemoryNode } from './total-recall-memory-validator.mjs';
24
26
  import {
25
27
  TOTAL_RECALL_HOST_EXTENSION,
@@ -66,6 +68,7 @@ const DIRECT_WRITE_APPROVED = [
66
68
 
67
69
  let cachedEngine = null;
68
70
  let cachedRegistryKey = '';
71
+ const writePolicy = new AsyncLocalStorage();
69
72
 
70
73
  export function getKernelMode() {
71
74
  // Default to package-kernel cutover for core types (memory/workflow/low-risk).
@@ -187,7 +190,27 @@ export function getTotalRecallEngine(options = {}) {
187
190
  const registrySet = createTotalRecallRegistrySet(options);
188
191
  const key = `${[...registrySet.types.keys()].sort().join(',')}|${options.leaseStore || ''}`;
189
192
  if (!cachedEngine || cachedRegistryKey !== key || options.forceNew) {
190
- const validator = createValidator({ registrySet });
193
+ const baseValidator = createValidator({ registrySet });
194
+ const validator = {
195
+ ...baseValidator,
196
+ validateData(data, callOptions) {
197
+ const result = baseValidator.validateData(data, callOptions);
198
+ const context = writePolicy.getStore();
199
+ if (context?.envelope.type !== 'patch') return result;
200
+ // The kernel calls validateData with the merged frontmatter. Check the
201
+ // replacement body against that category and those exception tags.
202
+ // A metadata-only patch keeps the current document body.
203
+ const { envelope, vaultRoot, options } = context;
204
+ const body = envelope.patches.__body__ === undefined
205
+ ? matter(fs.readFileSync(resolveContainedPath(vaultRoot, envelope.path), 'utf8')).content
206
+ : String(envelope.patches.__body__);
207
+ const policy = checkRuleLength(data, body, options);
208
+ context.warnings.push(...policy.warnings);
209
+ return { ...result, valid: result.valid && !policy.errors.length,
210
+ errors: [...result.errors, ...policy.errors],
211
+ field_errors: [...result.field_errors, ...policy.errors.map(issue => ({ field: '__body__', issue }))] };
212
+ },
213
+ };
191
214
  cachedEngine = createEngine({
192
215
  registrySet,
193
216
  validator,
@@ -277,6 +300,9 @@ export function prepareEnvelopeForKernel(envelope, options = {}) {
277
300
  return { envelope: env, warnings, errors: [`Content parsing error: ${error.message}`] };
278
301
  }
279
302
  const data = { ...parsed.data };
303
+ const length = checkRuleLength(data, parsed.content, options);
304
+ errors.push(...length.errors);
305
+ warnings.push(...length.warnings);
280
306
 
281
307
  // Package 0.9 universal frontmatter.
282
308
  if (!data.title && data.name) data.title = data.name;
@@ -392,11 +418,13 @@ export async function processViaPackageKernel(envelope, vaultRoot, options = {})
392
418
 
393
419
  const eventsDir = path.join(vaultRoot, '.events');
394
420
  if (!env.dry_run && !fs.existsSync(eventsDir)) fs.mkdirSync(eventsDir, { recursive: true });
395
- const response = await engine.processOperation(env, vaultRoot, {
421
+ const context = { envelope: env, vaultRoot, options, warnings: [] };
422
+ const response = await writePolicy.run(context, () => engine.processOperation(env, vaultRoot, {
396
423
  ...options,
397
424
  vaultRoot,
398
425
  principal: options.principal || mapTrPrincipal(env, options, vaultRoot),
399
- });
426
+ }));
427
+ prepared.warnings.push(...context.warnings);
400
428
 
401
429
  if (prepared.warnings.length && response?.validation) {
402
430
  response.validation.warnings = [