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
@@ -0,0 +1,247 @@
1
+ import fs from 'node:fs';
2
+ import os from 'node:os';
3
+ import path from 'node:path';
4
+ import crypto from 'node:crypto';
5
+ import { execFile } from 'node:child_process';
6
+ import { promisify } from 'node:util';
7
+ import { pathToFileURL } from 'node:url';
8
+ import { collectSources } from './capability/index.mjs';
9
+
10
+ const exec = promisify(execFile);
11
+ export const SOURCES = Object.freeze(['plugin-tasks', 'task-queue', 'research-queue', 'daemon', 'workflows', 'composed-commands', 'operating-system', 'agent-platforms']);
12
+ export const coreModule = (root, name) => import(pathToFileURL(path.join(root, 'src/core', `${name}.mjs`)).href);
13
+ const digest = text => crypto.createHash('sha256').update(text).digest('hex').slice(0, 20);
14
+ export const recordId = (node, source, key) => `${source}:${digest(`${node}\0${key}`)}`;
15
+ const text = (value, max = 240) => typeof value === 'string' ? value.slice(0, max) : '';
16
+ const credentialLine = /\b(?:authorization|bearer|password|token|credential|secret|api[-_ ]?key)\b|(?:_KEY|_TOKEN|_SECRET|_PASSWORD)\b|\b(?:sk[-_]|gh[pousr]_|github_pat_|eyJ)[a-z0-9_-]{12,}/i;
17
+
18
+ function failureReceipt(event) {
19
+ const output = text(event.output_tail, 2000).split('\n')
20
+ .map(line => credentialLine.test(line) ? '[credential diagnostic omitted]' : line)
21
+ .join('\n');
22
+ return {
23
+ timed_out: Boolean(event.timed_out),
24
+ duration_ms: Number.isFinite(event.duration_ms) ? event.duration_ms : null,
25
+ output_tail: output || null,
26
+ };
27
+ }
28
+ const canCancelPending = async (tasks, queueDir) =>
29
+ tasks.TASK_CANCELLATION_SUPPORTS_EXPECTED_STATUS === true
30
+ && typeof tasks.supportsPendingTaskCancellation === 'function'
31
+ && await tasks.supportsPendingTaskCancellation(queueDir) === true;
32
+ export function automation(ctx, source, key, data) {
33
+ return { id: recordId(ctx.node_id, source, key), node_id: ctx.node_id, source,
34
+ name: key, origin: source, trigger: { kind: 'unknown', summary: 'Not reported' },
35
+ enabled: null, state: 'unknown', runner_available: null, last_run: null, actions: [], ...data };
36
+ }
37
+ export function scheduledTasks(plugins = [], ctx = { node_id: 'local' }) {
38
+ return plugins.flatMap(plugin => (Array.isArray(plugin.tasks) ? plugin.tasks : []).map(task => {
39
+ const selected_node = typeof plugin.task_nodes?.[task.command] === 'string' ? plugin.task_nodes[task.command].trim() || null : null;
40
+ const placement_state = task.placement !== 'selected-node' ? 'per-node'
41
+ : !Object.hasOwn(plugin, 'task_nodes') ? 'unknown' : selected_node ? 'selected' : 'unplaced';
42
+ return automation(ctx, 'plugin-tasks', `${plugin.id}:${task.command}`, {
43
+ name: text(task.intent || `${plugin.name || plugin.id} · ${task.command}`), origin: `plugin:${plugin.id}`,
44
+ plugin_id: plugin.id, plugin_name: plugin.name, command: task.command, intent: text(task.intent), schedule: task.schedule,
45
+ trigger: { kind: 'cron', summary: text(task.schedule) }, placement: task.placement || 'per-node',
46
+ selected_node, placement_state,
47
+ enabled: plugin.activation?.enabled ?? null, state: plugin.valid === false ? 'invalid' : plugin.activation?.enabled === false ? 'disabled' : placement_state === 'unplaced' ? 'unplaced' : 'declared',
48
+ runner_available: placement_state === 'unplaced' ? false : null,
49
+ valid: plugin.valid, last_handled_slot: task.last_run || null,
50
+ last_handled_outcome: task.last_run ? { slot: task.last_run, state: 'unknown' } : null,
51
+ });
52
+ }));
53
+ }
54
+
55
+ export async function boundedCommand(file, args, options = {}) {
56
+ try { const result = await exec(file, args, { timeout: 4000, maxBuffer: 2 * 1024 * 1024, encoding: 'utf8', windowsHide: true, ...options }); return result.stdout; }
57
+ catch (error) { const failure = new Error(error.code === 'ENOENT' ? `${file} is unavailable` : `${file} inventory failed (${error.killed ? 'timeout' : error.code || 'error'})`); failure.code = error.code; throw failure; }
58
+ }
59
+
60
+ /** Read only scheduler facts; never return commands, environments or secret-bearing arguments. */
61
+ export async function operatingSystem(ctx) {
62
+ const run = ctx.runCommand || boundedCommand;
63
+ const records = [], warnings = [];
64
+ if (ctx.platform === 'darwin') {
65
+ const dirs = [path.join(ctx.home, 'Library/LaunchAgents'), '/Library/LaunchAgents', '/Library/LaunchDaemons', '/System/Library/LaunchAgents', '/System/Library/LaunchDaemons'];
66
+ let loaded = new Map();
67
+ try { loaded = new Map((await run('/bin/launchctl', ['list'])).split('\n').slice(1).map(line => line.trim().split(/\s+/)).filter(parts => parts.length >= 3).map(([pid, exit, label]) => [label, { pid, exit }])); }
68
+ catch (error) { warnings.push(error.message); }
69
+ for (const dir of dirs) {
70
+ let entries;
71
+ try { entries = fs.readdirSync(dir, { withFileTypes: true }); } catch (error) { if (error.code !== 'ENOENT') warnings.push(`Cannot inspect ${dir}`); continue; }
72
+ const jobs = entries.filter(item => item.isFile() && item.name.endsWith('.plist'));
73
+ let cursor = 0;
74
+ await Promise.all(Array.from({ length: Math.min(4, jobs.length) }, async () => { while (cursor < jobs.length) {
75
+ const entry = jobs[cursor++];
76
+ const file = path.join(dir, entry.name);
77
+ try {
78
+ if (fs.statSync(file).size > 1024 * 1024) throw new Error('Job definition exceeds size limit');
79
+ const job = JSON.parse(await run('/usr/bin/plutil', ['-convert', 'json', '-o', '-', file]));
80
+ const label = text(job.Label || entry.name), runtime = loaded.get(label);
81
+ const kinds = [job.StartCalendarInterval && 'calendar', job.StartInterval && 'interval', job.WatchPaths && 'file-change', job.QueueDirectories && 'directory', job.KeepAlive && 'keep-alive', job.RunAtLoad && 'boot'].filter(Boolean);
82
+ // Socket/on-demand jobs are automations too; absence of a timer is not absence of a job.
83
+ records.push(automation(ctx, 'operating-system', file, { name: label, origin: `launchd:${label}`,
84
+ trigger: { kind: kinds[0] || 'on-demand', summary: job.StartInterval ? `Every ${Number(job.StartInterval)} seconds${kinds.length > 1 ? `; ${kinds.filter(kind => kind !== 'interval').join(', ')}` : ''}` : kinds.length ? kinds.join(', ') : 'On demand' },
85
+ enabled: job.Disabled === true ? false : null, state: runtime?.pid !== '-' && runtime?.pid ? 'running' : runtime ? 'loaded' : 'declared',
86
+ runner_available: runtime ? true : null, last_exit_code: runtime && runtime.exit !== '-' ? Number(runtime.exit) : null }));
87
+ } catch { warnings.push(`Cannot inspect launchd definition ${entry.name}`); }
88
+ } }));
89
+ }
90
+ } else if (ctx.platform === 'linux') {
91
+ for (const scope of ['system', 'user']) {
92
+ const scopeArgs = scope === 'user' ? ['--user'] : [];
93
+ try {
94
+ const [installed, loaded] = await Promise.all([
95
+ run('systemctl', [...scopeArgs, 'list-unit-files', '--type=timer', '--no-legend', '--no-pager']),
96
+ run('systemctl', [...scopeArgs, 'list-units', '--type=timer', '--all', '--no-legend', '--no-pager', '--plain']),
97
+ ]);
98
+ const active = new Map(loaded.trim().split('\n').map(line => line.trim().split(/\s+/)).filter(parts => parts[0]?.endsWith('.timer')).map(parts => [parts[0], parts[2]]));
99
+ for (const line of installed.trim().split('\n')) {
100
+ const [name, state] = line.trim().split(/\s+/); if (!name?.endsWith('.timer')) continue;
101
+ records.push(automation(ctx, 'operating-system', `${scope}:${name}`, { name, origin: `systemd:${scope}:${name}`, trigger: { kind: 'timer', summary: 'System timer' }, enabled: ['enabled', 'enabled-runtime', 'linked', 'linked-runtime'].includes(state) ? true : ['disabled', 'masked'].includes(state) ? false : null, state: active.get(name) || state, runner_available: active.has(name) ? true : null }));
102
+ }
103
+ } catch (error) { warnings.push(`${scope}: ${error.message}`); }
104
+ }
105
+ } else return { status: 'unsupported', records: [], error: `No operating-system adapter for ${ctx.platform}` };
106
+ try {
107
+ const cron = await run('crontab', ['-l']);
108
+ for (const [index, line] of cron.split('\n').entries()) {
109
+ const clean = line.trim(); if (!clean || clean.startsWith('#') || /^[A-Za-z_][A-Za-z0-9_]*\s*=/.test(clean)) continue;
110
+ const match = clean.match(/^(@\w+|(?:\S+\s+){4}\S+)\s+.+$/); if (!match) { warnings.push(`Unrecognized crontab line ${index + 1}`); continue; }
111
+ records.push(automation(ctx, 'operating-system', `crontab:${digest(clean)}`, { name: `Crontab job ${index + 1}`, origin: 'crontab:current-user', trigger: { kind: 'cron', summary: match[1] }, enabled: true, state: 'declared' }));
112
+ }
113
+ } catch (error) {
114
+ // Exit 1 means either no crontab or an access error; never claim empty coverage without evidence.
115
+ warnings.push(error.message);
116
+ }
117
+ records.sort((left, right) => left.id.localeCompare(right.id));
118
+ return { records, status: warnings.length ? 'partial' : 'ok', ...(warnings.length ? { error: [...new Set(warnings)].slice(0, 12).join('; ') } : {}) };
119
+ }
120
+
121
+ export async function createContext(packageRoot, options = {}) {
122
+ const config = options.config || await coreModule(packageRoot, 'config');
123
+ const active = config.getActiveBrains(options.projectRoot || process.cwd());
124
+ const brains = [active.global, active.project].filter(Boolean);
125
+ const unique = [...new Map(brains.map(brain => [path.resolve(brain.brainDir), brain])).values()];
126
+ return { packageRoot, projectRoot: options.projectRoot || process.cwd(), node_id: options.node_id || os.hostname(), home: options.home || os.homedir(), platform: options.platform || process.platform, brains: unique, config, ...options };
127
+ }
128
+
129
+ export async function sourceAdapters(ctx) {
130
+ const load = name => ctx.modules?.[name] || coreModule(ctx.packageRoot, name);
131
+ return {
132
+ 'plugin-tasks': async () => {
133
+ const store = await load('plugin-store');
134
+ const plugins = store.listInstalledPlugins(ctx.projectRoot).map(plugin => ({ ...plugin }));
135
+ if (plugins.some(plugin => plugin.tasks?.some(task => task.placement === 'selected-node'))) {
136
+ const loader = await load('plugin-loader');
137
+ const discovered = new Map(loader.discoverPlugins(ctx.projectRoot).map(plugin => [plugin.id, plugin]));
138
+ for (const plugin of plugins) {
139
+ if (!plugin.tasks?.some(task => task.placement === 'selected-node')) continue;
140
+ const source = discovered.get(plugin.id);
141
+ if (source) plugin.task_nodes = store.readPluginRecord(source)?.task_nodes || {};
142
+ }
143
+ }
144
+ const records = scheduledTasks(plugins, ctx);
145
+ const events = await load('ssss-operation-service');
146
+ const payloads = [];
147
+ for (const brain of ctx.brains) for (const event of await events.listVfsEvents({ vaultRoot: path.join(brain.brainDir, 'memory-vault') })) {
148
+ let payload = event?.payload || event?.content; if (typeof payload === 'string') { try { payload = JSON.parse(payload); } catch { continue; } }
149
+ if (payload?.kind === 'plugin.task_run' && (!payload.node_id || payload.node_id === ctx.node_id)) payloads.push({ ...payload, at: event.timestamp || event.created_at || payload.at || null });
150
+ }
151
+ const eventTime = event => Date.parse(event.at || event.slot || '') || 0;
152
+ const outcome = event => ({ at: event.at || event.slot || null, slot: event.slot || null,
153
+ state: event.ok === true ? 'success' : event.ok === false ? 'failed' : 'unknown', exit_code: event.exit_code ?? null });
154
+ for (const record of records) {
155
+ const matching = payloads.filter(event => event.plugin_id === record.plugin_id && event.command === record.command)
156
+ .sort((a, b) => eventTime(a) - eventTime(b));
157
+ const last = matching.at(-1);
158
+ if (last) {
159
+ record.last_run = outcome(last);
160
+ // The failure receipt is shown only for the record the operator asked about.
161
+ if (last.ok === false && ctx.receiptId === record.id) record.last_run.receipt = failureReceipt(last);
162
+ }
163
+ const handled = record.last_handled_slot && matching.filter(event => event.slot === record.last_handled_slot).at(-1);
164
+ if (handled) record.last_handled_outcome = outcome(handled);
165
+ }
166
+ return records;
167
+ },
168
+ 'task-queue': async () => {
169
+ const tasks = await load('task-envelope');
170
+ const queues = await Promise.all(ctx.brains.map(async (brain) => {
171
+ const queueDir = tasks.resolveQueueDir(brain.brainDir);
172
+ const canCancel = await canCancelPending(tasks, queueDir);
173
+ return tasks.listTasks(queueDir, { status: 'all' }).map((task) => {
174
+ const record = automation(ctx, 'task-queue', `${brain.layer}:${task.slug}`, { name: text(task.intent || task.slug), origin: `task:${brain.layer}:${task.slug}`, trigger: { kind: 'queue', summary: 'Queued work' }, enabled: !['completed', 'cancelled'].includes(task.status), state: task.status, owner_ref: { layer: brain.layer, slug: task.slug }, last_run: task.completed_at || task.failed_at ? { at: task.completed_at || task.failed_at, state: task.status, exit_code: null } : null });
175
+ if (canCancel && task.status === 'pending') record.actions = [{ command: 'cancel', label: 'Cancel task', args: [record.id], effect: 'write' }];
176
+ return record;
177
+ });
178
+ }));
179
+ return queues.flat();
180
+ },
181
+ 'research-queue': async () => {
182
+ const research = await load('research-queue');
183
+ const records = [];
184
+ for (const brain of ctx.brains) {
185
+ let offset = 0;
186
+ while (true) {
187
+ const page = research.listQueue({ brainDir: brain.brainDir, limit: 500, offset });
188
+ if (!Array.isArray(page.items)) throw new Error('Invalid research queue response');
189
+ records.push(...page.items.map(task => automation(ctx, 'research-queue', `${brain.layer}:${task.id}`, { name: text(task.topic), origin: `research:${brain.layer}:${task.id}`, trigger: { kind: 'queue', summary: task.research_phase || 'Research queue' }, enabled: ['pending', 'in_progress'].includes(task.status), state: task.status, last_run: task.completed_at ? { at: task.completed_at, state: task.status, exit_code: null } : null })));
190
+ offset += page.items.length;
191
+ if (offset >= page.total) break;
192
+ if (!page.items.length) throw new Error('Research pagination made no progress');
193
+ if (records.length >= 10000) return { records, status: 'partial', error: 'Research queue exceeded 10000 records' };
194
+ }
195
+ }
196
+ return records;
197
+ },
198
+ daemon: async () => {
199
+ const [health, update] = await Promise.all([load('startup-health'), load('automatic-brain-updates')]);
200
+ return ctx.brains.flatMap(brain => {
201
+ const observation = health.observeDaemon(brain.brainDir), running = observation.status === 'running';
202
+ const maintenance = update.automaticUpdateStatus(brain.brainDir);
203
+ return [automation(ctx, 'daemon', `${brain.layer}:daemon`, { name: `${brain.layer} background worker`, origin: `daemon:${brain.layer}`, trigger: { kind: 'queue', summary: 'Durable queue and maintenance loop' }, state: observation.status, runner_available: running, enabled: null }),
204
+ automation(ctx, 'daemon', `${brain.layer}:package-updates`, { name: `${brain.layer} package maintenance`, origin: `automatic-brain-updates:${brain.layer}`, trigger: { kind: 'interval', summary: `Every ${maintenance.intervalMs / 60000} minutes; failed checks retry` }, enabled: maintenance.enabled, state: maintenance.enabled ? 'configured' : 'disabled', runner_available: running, last_run: maintenance.last ? { at: maintenance.last.checkedAt ? new Date(maintenance.last.checkedAt).toISOString() : null, state: maintenance.last.failed ? 'failed' : 'success', exit_code: null } : null }),
205
+ ...['vault-watch', 'source-watch', 'session-ingest', 'cli-surfaces', 'repo-sync', 'github-sync', 'obsidian-watch'].map(name => automation(ctx, 'daemon', `${brain.layer}:${name}`, { name: `${brain.layer} ${name}`, origin: `daemon:${brain.layer}:${name}`, trigger: { kind: name.includes('watch') ? 'file-change' : name === 'session-ingest' ? 'boot' : 'maintenance', summary: 'Daemon-managed; individual registration is not reported by owner' }, state: 'unknown', runner_available: running }))];
206
+ });
207
+ },
208
+ workflows: async () => {
209
+ const vfs = await load('vfs-documents');
210
+ return ctx.brains.flatMap(brain => vfs.listVfsDocuments(path.join(brain.brainDir, 'memory-vault')).filter(doc => ['workflow', 'trigger'].includes(doc.type)).flatMap(doc => {
211
+ const triggers = doc.type === 'trigger' ? [{ ...doc, type: doc.source }] : Array.isArray(doc.triggers) && doc.triggers.length ? doc.triggers : [{ type: 'manual' }];
212
+ return triggers.map((trigger, index) => automation(ctx, 'workflows', `${brain.layer}:${doc.vfs_path}:${trigger.id || trigger.trigger_id || index}`, { name: text(doc.title || doc.name || doc.id || doc.slug), origin: `vfs:${brain.layer}:${doc.vfs_path}`, trigger: { kind: text(trigger.type), summary: text(trigger.cron || trigger.interval || trigger.event_type || trigger.type || 'Unknown trigger'), ...(trigger.timezone ? { timezone: text(trigger.timezone) } : {}) }, enabled: doc.type === 'trigger' ? doc.status === 'active' ? true : ['disabled', 'paused'].includes(doc.status) ? false : null : typeof doc.isActive === 'boolean' ? doc.isActive : null, state: 'declared', runner_available: null }));
213
+ }));
214
+ },
215
+ 'composed-commands': async () => {
216
+ const commands = await load('command-surface');
217
+ const dirs = commands.commandScopeDirectories(ctx.projectRoot, ctx.config.globalAgentDir);
218
+ return commands.listSurfaceCommands(dirs).map(command => automation(ctx, 'composed-commands', `${command.scope}:${command.name}`, { name: command.name, origin: `composable-cli:${command.scope}:${command.name}`, trigger: { kind: 'manual', summary: 'Reusable command; requires explicit automation binding' }, state: 'definition', enabled: null }));
219
+ },
220
+ 'operating-system': () => operatingSystem(ctx),
221
+ 'agent-platforms': async () => ({ status: 'unsupported', records: [], error: 'No authenticated agent-platform inventory contract is configured; provider automations cannot be inferred from local command definitions.' }),
222
+ };
223
+ }
224
+
225
+ export async function collectLocalAutomations(packageRoot, options = {}) {
226
+ const ctx = await createContext(packageRoot, options), checked_at = new Date().toISOString();
227
+ const adapters = options.adapters || await sourceAdapters(ctx);
228
+ return { node_id: ctx.node_id, ...await collectSources({ sources: SOURCES, adapters, checkedAt: checked_at }) };
229
+ }
230
+
231
+ export async function cancelAutomation(packageRoot, id, options = {}) {
232
+ const ctx = await createContext(packageRoot, options);
233
+ const tasks = ctx.modules?.['task-envelope'] || await coreModule(packageRoot, 'task-envelope');
234
+ for (const brain of ctx.brains) {
235
+ const queueDir = tasks.resolveQueueDir(brain.brainDir);
236
+ const task = tasks.listTasks(queueDir, { status: 'all' })
237
+ .find((candidate) => recordId(ctx.node_id, 'task-queue', `${brain.layer}:${candidate.slug}`) === id);
238
+ if (!task) continue;
239
+ if (task.status !== 'pending') throw new Error('Task is no longer pending');
240
+ if (!await canCancelPending(tasks, queueDir)) throw new Error('This host cannot safely cancel a pending task');
241
+ const result = await tasks.cancelTask(queueDir, task.slug, { expectedStatus: 'pending' });
242
+ if (!result.success) throw new Error(result.error || 'Task cancellation failed');
243
+ if (tasks.getTask(queueDir, task.slug)?.status !== 'cancelled') throw new Error('Task owner did not confirm cancellation');
244
+ return { success: true, id, state: 'cancelled' };
245
+ }
246
+ throw new Error('Cancellable local automation not found');
247
+ }
@@ -0,0 +1,16 @@
1
+ /** Source collection for an application-owned automation inventory. No host or transport assumptions. */
2
+ export async function collectSources({ sources, adapters, checkedAt, limit = 10000 }) {
3
+ if (!Array.isArray(sources) || !sources.every(source => typeof source === 'string') || new Set(sources).size !== sources.length) throw new Error('Unique source ids are required');
4
+ if (!adapters || typeof adapters !== 'object' || !checkedAt || !Number.isSafeInteger(limit) || limit < 1) throw new Error('Adapters, checkedAt and a positive record limit are required');
5
+ const results = await Promise.all(sources.map(async source => {
6
+ try {
7
+ if (typeof adapters[source] !== 'function') return { source, status: 'unsupported', checked_at: checkedAt, records: [], error: 'Source adapter is unavailable' };
8
+ const value = await adapters[source]();
9
+ const result = Array.isArray(value) ? { records: value, status: 'ok' } : value;
10
+ if (!result || !Array.isArray(result.records) || !['ok', 'partial', 'unsupported', 'disabled', 'error', 'unauthorized'].includes(result.status)) throw new Error('Invalid source result');
11
+ if (result.records.length > limit) return { source, status: 'partial', checked_at: checkedAt, records: result.records.slice(0, limit), error: `Source inventory exceeded ${limit} records` };
12
+ return { ...result, source, checked_at: checkedAt };
13
+ } catch (error) { return { source, status: 'error', checked_at: checkedAt, records: [], error: `Source discovery failed${typeof error.code === 'string' && /^[A-Z_0-9]+$/.test(error.code) ? ` (${error.code})` : ''}` }; }
14
+ }));
15
+ return { automations: results.flatMap(result => result.records), coverage: results.map(({ records, ...coverage }) => coverage), checked_at: checkedAt };
16
+ }
@@ -0,0 +1,130 @@
1
+ import { meshAutomationInventory, filterInventory } from './inventory.mjs';
2
+ import { cancelAutomation, SOURCES } from './adapters.mjs';
3
+ import { spawnSync } from 'node:child_process';
4
+
5
+ export const HELP = `Usage: total-recall automations <command> [options]
6
+
7
+ Commands:
8
+ list List automation records and source coverage across the mesh
9
+ status Report node/source coverage and observed automation states
10
+ show <id> Inspect one source-owned automation record
11
+ cancel <id> Cancel a pending local durable task through its owner
12
+ dream --all-brains Run dream, including decay, for every brain on this node
13
+
14
+ Options:
15
+ --local Inspect this node only (also used by authenticated peers)
16
+ --node <id|hostname> Select one known mesh node
17
+ --source <source> Filter records by source
18
+ --trigger <kind> Filter records by trigger kind
19
+ --state <state> Filter records by observed state
20
+ --receipt Include a failed plugin task receipt (show --local, terminal only)
21
+ --json Machine-readable output (also the default)
22
+ --help, -h Show this help
23
+
24
+ Sources: ${SOURCES.join(', ')}
25
+ Declarations, runner availability and observed outcomes remain separate.
26
+ Unsupported or failed sources are reported explicitly; they are never empty success.`;
27
+
28
+ export function parseArgs(argv) {
29
+ const args = argv[2] === 'automations' ? argv.slice(3) : [...argv];
30
+ if (!args.length || args.includes('--help') || args.includes('-h')) return { help: true };
31
+ const command = args.shift();
32
+ if (!['list', 'status', 'show', 'cancel', 'dream'].includes(command)) throw new Error(`Unknown command: ${command}`);
33
+ if (command === 'dream') {
34
+ if (args.filter(arg => arg === '--all-brains').length !== 1 || args.some(arg => !['--all-brains', '--json'].includes(arg))) {
35
+ throw new Error('dream requires --all-brains and accepts only --json');
36
+ }
37
+ return { command };
38
+ }
39
+ const result = { command, filters: {}, localOnly: false };
40
+ if (['show', 'cancel'].includes(command)) {
41
+ result.id = args.shift(); if (!result.id || !/^[a-z-]+:[a-f0-9]{20}$/.test(result.id)) throw new Error('A valid automation id is required');
42
+ }
43
+ while (args.length) {
44
+ const flag = args.shift();
45
+ if (flag === '--json') continue;
46
+ if (flag === '--local') { result.localOnly = true; continue; }
47
+ if (flag === '--receipt') { result.receipt = true; continue; }
48
+ const name = { '--node': 'node', '--source': 'source', '--trigger': 'trigger', '--state': 'state' }[flag];
49
+ if (!name) throw new Error(`Unknown option: ${flag}`);
50
+ const value = args.shift(); if (!value || value.startsWith('-')) throw new Error(`Missing value for ${flag}`);
51
+ if (result.filters[name]) throw new Error(`Duplicate option: ${flag}`);
52
+ result.filters[name] = value;
53
+ }
54
+ if (result.filters.source && !SOURCES.includes(result.filters.source)) throw new Error('Unknown source');
55
+ if (result.receipt && (command !== 'show' || !result.localOnly || !result.id.startsWith('plugin-tasks:'))) {
56
+ throw new Error('--receipt requires show <plugin-task-id> --local');
57
+ }
58
+ if (command === 'cancel' && (Object.keys(result.filters).length || result.localOnly)) throw new Error('cancel accepts only a local automation id and --json');
59
+ return result;
60
+ }
61
+
62
+ /** Core owns dream execution. Check support before an old core can ignore the flag. */
63
+ export function runDream(spawn = spawnSync) {
64
+ const options = { shell: false, encoding: 'utf8', timeout: 30000, maxBuffer: 4 * 1024 * 1024, windowsHide: true };
65
+ const failure = (error, child = {}, results = []) => ({
66
+ ok: false, exit_code: Number.isInteger(child.status) && child.status !== 0 ? child.status : 1,
67
+ child_exit_code: child.status ?? null, signal: child.signal || null, results, error,
68
+ });
69
+ try {
70
+ const help = spawn('total-recall', ['dream', '--help'], options);
71
+ if (help.error || help.signal || help.status !== 0) return failure(`Cannot check core dream support: ${help.error?.message || help.stderr || help.signal || 'help failed'}`, help);
72
+ if (!String(help.stdout).includes('--all-brains')) return failure('Core dream does not support --all-brains. Update Total Recall before this task can run.', help);
73
+ const child = spawn('total-recall', ['dream', '--all-brains', '--json'], { ...options, timeout: 1800000 });
74
+ if (child.error || child.signal) return failure(`Core dream did not complete: ${child.error?.message || child.signal}`, child);
75
+ let report;
76
+ try {
77
+ report = JSON.parse(child.stdout);
78
+ } catch {
79
+ // Core log lines may surround one JSON report.
80
+ const reports = String(child.stdout || '').split('\n').flatMap(line => {
81
+ try { const value = JSON.parse(line); return Array.isArray(value) || Array.isArray(value?.results) || Array.isArray(value?.brains) ? [value] : []; } catch { return []; }
82
+ });
83
+ if (reports.length === 1) report = reports[0];
84
+ }
85
+ const results = Array.isArray(report) ? report : report?.results ?? report?.brains;
86
+ if (!Array.isArray(results) || !results.length || results.some(result => !result || typeof result !== 'object' || Array.isArray(result)
87
+ || !(typeof result.ok === 'boolean' || typeof result.success === 'boolean' || ['ok', 'success', 'completed', 'failed', 'error', 'skipped'].includes(result.status) || ['ok', 'success', 'completed', 'failed', 'error', 'skipped'].includes(result.state)))) {
88
+ return failure(`Core dream returned no per-brain results (exit ${child.status}). Update Total Recall if --all-brains is unavailable. ${String(child.stderr || '').trim()}`.trim(), child);
89
+ }
90
+ if (child.status !== 0 || report?.ok === false || report?.success === false || results.some(result => result.ok === false || result.success === false || result.error
91
+ || (Number.isInteger(result.exit_code) && result.exit_code !== 0) || ['failed', 'error'].includes(result.status) || ['failed', 'error'].includes(result.state))) {
92
+ return failure(`Core dream failed (exit ${child.status}). ${String(child.stderr || '').trim()}`.trim(), child, results);
93
+ }
94
+ return { ok: true, exit_code: 0, child_exit_code: 0, results };
95
+ } catch (error) {
96
+ return failure(`Cannot run core dream: ${error.message}`);
97
+ }
98
+ }
99
+
100
+ export async function run(argv = [], dependencies = {}) {
101
+ const parsed = parseArgs(argv), write = dependencies.write || (output => process.stdout.write(output));
102
+ if (parsed.help) { write(`${HELP}\n`); return; }
103
+ if (parsed.command === 'dream') {
104
+ const result = runDream(dependencies.spawnSync);
105
+ write(`${JSON.stringify(result)}\n`);
106
+ if (!result.ok) (dependencies.setExitCode || (code => { process.exitCode = code; }))(result.exit_code);
107
+ return result;
108
+ }
109
+ if (parsed.receipt && !process.stdin.isTTY) throw new Error('--receipt requires a local terminal');
110
+ const root = dependencies.packageRoot || process.env.TR_PACKAGE_ROOT;
111
+ if (!root) throw new Error('TR_PACKAGE_ROOT is required');
112
+ if (parsed.command === 'cancel') {
113
+ const result = await (dependencies.cancel || cancelAutomation)(root, parsed.id);
114
+ write(`${JSON.stringify(result)}\n`); return result;
115
+ }
116
+ let inventory = await (dependencies.inventory || meshAutomationInventory)(root, {
117
+ localOnly: parsed.localOnly,
118
+ ...(parsed.receipt ? { receiptId: parsed.id } : {}),
119
+ });
120
+ inventory = filterInventory(inventory, parsed.filters);
121
+ let result = inventory;
122
+ if (parsed.command === 'show') {
123
+ const records = inventory.nodes.flatMap(node => node.automations).filter(record => record.id === parsed.id);
124
+ if (records.length !== 1) throw new Error(records.length ? 'Automation id is ambiguous' : 'Automation not found');
125
+ result = { schema_version: 1, checked_at: inventory.checked_at, automation: records[0] };
126
+ }
127
+ if (parsed.command === 'status') result = { ...inventory, nodes: inventory.nodes.map(node => ({ ...node, counts: node.automations.reduce((counts, record) => ({ ...counts, [record.state]: (counts[record.state] || 0) + 1 }), {}), automations: undefined })) };
128
+ write(`${JSON.stringify(result)}\n`); return result;
129
+ }
130
+ export default run;
@@ -1,4 +1,4 @@
1
- /** Pure cron parsing shared by plugin authoring and scheduling. */
1
+ /** Five-field cron parsing and matching for manifest plugin tasks. */
2
2
  const FIELD_RANGES = [
3
3
  [0, 59], // minute
4
4
  [0, 23], // hour
@@ -53,5 +53,3 @@ export function cronMatches(cron, date) {
53
53
  if (cron.dowStar) return domOk;
54
54
  return domOk || dowOk;
55
55
  }
56
-
57
-
@@ -0,0 +1,88 @@
1
+ import os from 'node:os';
2
+ import { collectLocalAutomations, coreModule, SOURCES, scheduledTasks, recordId } from './adapters.mjs';
3
+ export { scheduledTasks } from './adapters.mjs';
4
+
5
+ const MAX_PEER_BYTES = 4 * 1024 * 1024;
6
+ export function parseInventoryOutput(output) {
7
+ if (typeof output !== 'string' || Buffer.byteLength(output) > MAX_PEER_BYTES) throw new Error('Invalid inventory output');
8
+ try { return JSON.parse(output); } catch {
9
+ // Host logs may surround command output. Accept one versioned inventory,
10
+ // never guess between multiple command results or parse a logger payload.
11
+ const values = output.trim().split('\n').flatMap(line => { try { const value = JSON.parse(line); return value?.schema_version === 1 && Array.isArray(value.nodes) ? [value] : []; } catch { return []; } });
12
+ if (values.length !== 1) throw new Error('Expected one versioned inventory result');
13
+ return values[0];
14
+ }
15
+ }
16
+ const unavailableCoverage = (status, checked_at) => SOURCES.map(source => ({ source, status, checked_at }));
17
+ function verifyLocalResult(value) {
18
+ if (!value || !Array.isArray(value.automations) || !Array.isArray(value.coverage)) throw new Error('Invalid local inventory');
19
+ if (value.automations.length > 10000 * SOURCES.length) throw new Error('Peer inventory exceeds record limit');
20
+ const statuses = new Set(['ok', 'partial', 'unsupported', 'disabled', 'error', 'unauthorized', 'offline']);
21
+ for (const coverage of value.coverage) if (!SOURCES.includes(coverage.source) || !statuses.has(coverage.status)) throw new Error('Invalid peer coverage');
22
+ for (const record of value.automations) if (typeof record.id !== 'string' || !SOURCES.includes(record.source) || typeof record.name !== 'string') throw new Error('Invalid peer automation');
23
+ return value;
24
+ }
25
+ function nodeResult(base, value) {
26
+ const missing = SOURCES.filter(source => !value.coverage.some(item => item.source === source));
27
+ const coverage = [...value.coverage, ...missing.map(source => ({ source, status: 'unsupported', checked_at: base.checked_at, error: 'Peer did not report this source' }))];
28
+ // Remote mutation is never advertised through a local-only control.
29
+ const automations = value.automations.map(record => ({ ...record, node_id: base.node_id, actions: base.self ? record.actions || [] : [] }));
30
+ return { ...base, status: coverage.every(source => ['ok', 'disabled'].includes(source.status)) ? 'ok' : 'partial', automations, coverage };
31
+ }
32
+
33
+ /** The plugin owns composition; every source and peer failure remains visible. */
34
+ export async function meshAutomationInventory(packageRoot, options = {}) {
35
+ const checked_at = new Date().toISOString();
36
+ const mesh = options.mesh || await coreModule(packageRoot, 'mesh');
37
+ const self = options.self || mesh.getMeshSelf?.() || { hostname: os.hostname(), self: true };
38
+ const selfId = self.ip || self.hostname || os.hostname();
39
+ let nodes = options.localOnly ? [{ ...self, self: true }] : options.nodes || mesh.listEnrichedMeshNodes();
40
+ if (!nodes.some(node => node.self || (node.ip && node.ip === self.ip))) nodes = [{ ...self, self: true }, ...nodes];
41
+ nodes = [...new Map(nodes.map(node => [node.ip || node.hostname, node])).values()];
42
+ const local = options.local || await collectLocalAutomations(packageRoot, { ...options, node_id: selfId });
43
+ const execPeer = options.execPeer || mesh.execMeshCommand;
44
+ let authorization = options.authorization;
45
+ if (!options.localOnly && authorization === undefined) {
46
+ try { authorization = await (await coreModule(packageRoot, 'mesh-auth')).getMeshSyncAuthorization(); } catch { authorization = null; }
47
+ }
48
+ const peerUrl = options.peerUrl || (await coreModule(packageRoot, 'plugin-peers')).meshPeerUrl;
49
+ const fetchImpl = options.fetchImpl || (await coreModule(packageRoot, 'throttled-fetch')).throttledFetch;
50
+ const records = await Promise.all(nodes.map(async node => {
51
+ const node_id = node.ip || node.hostname;
52
+ const base = { node_id, hostname: node.hostname, ip: node.ip, self: Boolean(node.self || node_id === selfId), online: Boolean(node.self || node.online), checked_at, automations: [], coverage: [] };
53
+ if (base.self) return nodeResult(base, verifyLocalResult(local));
54
+ const unavailable = (status, error) => ({ ...base, status, ...(error ? { error } : {}), coverage: unavailableCoverage(status === 'unreachable' ? 'error' : status, checked_at) });
55
+ if (!node.online) return unavailable('offline');
56
+ const port = node.brain_port || Number(process.env.TR_SERVER_PORT || process.env.PORT || 3000);
57
+ try {
58
+ if (execPeer) {
59
+ try {
60
+ // Mesh owns the authenticated transport. The command is fixed and read-only.
61
+ // A mesh-sync token is not a PAT for the generic plugin-run HTTP route.
62
+ const result = await execPeer(node_id, 'total-recall automations list --local --json', { timeoutMs: 15000 });
63
+ if (result.success && result.exitCode === 0) {
64
+ const inventory = parseInventoryOutput(result.stdout);
65
+ if (inventory.schema_version !== 1 || !Array.isArray(inventory.nodes) || inventory.nodes.length !== 1 || inventory.nodes[0].self !== true) throw new Error('Unsupported peer inventory');
66
+ return nodeResult(base, verifyLocalResult(inventory.nodes[0]));
67
+ }
68
+ } catch { /* Retain metadata through its separate mesh-auth contract below. */ }
69
+ }
70
+ if (!authorization) return unavailable('unauthorized', 'Full peer inventory is unavailable; mesh metadata authorization is unavailable');
71
+ // Old or unreachable CLI hosts may still expose plugin declarations.
72
+ const fallback = await fetchImpl(peerUrl(node.ip, '/api/mesh/plugins/installed', port), { headers: { Authorization: authorization } }, 5000);
73
+ if (!fallback.ok) return unavailable(fallback.status === 404 ? 'unsupported' : [401, 403].includes(fallback.status) ? 'unauthorized' : 'error', `HTTP ${fallback.status}`);
74
+ const data = await fallback.json();
75
+ if (!Array.isArray(data.plugins)) throw new Error('Invalid legacy peer response');
76
+ return nodeResult(base, { automations: scheduledTasks(data.plugins, { node_id }), coverage: SOURCES.map(source => ({ source, status: source === 'plugin-tasks' ? 'partial' : 'unsupported', checked_at,
77
+ error: source === 'plugin-tasks' ? 'Peer metadata reports declarations only; placement and outcome evidence may be missing' : 'Full peer inventory is unavailable' })) });
78
+ } catch (error) { return unavailable('unreachable', error.name === 'SyntaxError' ? 'Invalid peer JSON' : error.message); }
79
+ }));
80
+ return { schema_version: 1, checked_at, complete: records.every(node => node.status === 'ok'), nodes: records };
81
+ }
82
+
83
+ export function filterInventory(inventory, filters = {}) {
84
+ let nodes = inventory.nodes;
85
+ if (filters.node) nodes = nodes.filter(node => [node.node_id, node.hostname, node.ip].includes(filters.node));
86
+ if (filters.node && !nodes.length) throw new Error('Unknown node');
87
+ return { ...inventory, nodes: nodes.map(node => ({ ...node, automations: node.automations.filter(record => (!filters.source || record.source === filters.source) && (!filters.trigger || record.trigger?.kind === filters.trigger) && (!filters.state || record.state === filters.state)) })) };
88
+ }