aimeat 1.33.2 → 1.35.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 (328) hide show
  1. package/dist/locales/en.json +437 -15
  2. package/dist/locales/fi.json +437 -15
  3. package/dist/public/cortex-bundled/aimeat-charts.js +3 -3
  4. package/dist/public/cortex-bundled/aimeat-charts.yaml +3 -3
  5. package/dist/public/cortex-bundled/aimeat-i18n.js +123 -0
  6. package/dist/public/cortex-bundled/aimeat-i18n.yaml +64 -0
  7. package/dist/public/css/views/landing.css +2 -0
  8. package/dist/public/css/views/secretary.css +464 -2
  9. package/dist/public/js/i18n.js +9 -0
  10. package/dist/public/js/services/apps.js +4 -2
  11. package/dist/public/js/services/memory.js +9 -3
  12. package/dist/public/js/services/offers.js +1 -1
  13. package/dist/public/js/services/organisms.js +49 -17
  14. package/dist/public/js/services/secretary-helpers.js +266 -17
  15. package/dist/public/js/services/secretary-policy.js +28 -2
  16. package/dist/public/js/services/secretary-rules.js +70 -0
  17. package/dist/public/js/theme.js +20 -0
  18. package/dist/public/lib/VENDORED-STYLING.md +31 -0
  19. package/dist/public/lib/aimeat-daisyui-bridge.css +48 -0
  20. package/dist/public/lib/chartjs@4.js +14 -0
  21. package/dist/public/lib/daisyui@5.css +7 -0
  22. package/dist/public/lib/tailwindcss@4.js +8 -0
  23. package/dist/public/llms-template.txt +9 -6
  24. package/dist/public/showroom.html +104 -0
  25. package/dist/public/showroom.js +247 -0
  26. package/dist/public/spa.html +18 -16
  27. package/dist/public/views/aimeat-os.js +3 -2
  28. package/dist/public/views/landing.js +50 -6
  29. package/dist/public/views/profile/agents/agent-card.js +13 -4
  30. package/dist/public/views/profile/agents/state-detector.js +6 -0
  31. package/dist/public/views/profile/agents/tab-integration.js +11 -2
  32. package/dist/public/views/profile/apps-tab.js +46 -0
  33. package/dist/public/views/profile/extensions-tab.js +4 -0
  34. package/dist/public/views/profile/inbox-tab.js +1 -1
  35. package/dist/public/views/profile/landing-page.js +8 -3
  36. package/dist/public/views/profile/memory-tab.js +37 -6
  37. package/dist/public/views/profile/organisms/home.js +32 -0
  38. package/dist/public/views/profile/organisms/workspace-list.js +36 -5
  39. package/dist/public/views/profile/organisms/workspace.js +29 -4
  40. package/dist/public/views/profile/organisms-tab.js +61 -8
  41. package/dist/public/views/secretary/calendar.js +327 -0
  42. package/dist/public/views/secretary/cards-reach.js +16 -17
  43. package/dist/public/views/secretary/cards.js +217 -79
  44. package/dist/public/views/secretary/dashboard.js +617 -0
  45. package/dist/public/views/secretary/quality.js +156 -0
  46. package/dist/public/views/secretary/use-autonomy.js +17 -2
  47. package/dist/public/views/secretary/use-freshness.js +50 -0
  48. package/dist/public/views/secretary/use-intake.js +23 -4
  49. package/dist/public/views/secretary/use-layout.js +122 -0
  50. package/dist/public/views/secretary/use-quick-actions.js +98 -0
  51. package/dist/public/views/secretary/use-specialists.js +103 -0
  52. package/dist/public/views/secretary/use-triggers.js +159 -0
  53. package/dist/public/views/secretary/use-whats-next.js +340 -0
  54. package/dist/public/views/secretary/workflow-design.js +112 -0
  55. package/dist/public/views/secretary.js +836 -44
  56. package/dist/scripts/check-no-max-tokens.d.ts +2 -0
  57. package/dist/scripts/check-no-max-tokens.d.ts.map +1 -0
  58. package/dist/scripts/check-no-max-tokens.js +71 -0
  59. package/dist/scripts/check-no-max-tokens.js.map +1 -0
  60. package/dist/src/cli/connect/mcp/tools/organisms.d.ts +2 -0
  61. package/dist/src/cli/connect/mcp/tools/organisms.d.ts.map +1 -1
  62. package/dist/src/cli/connect/mcp/tools/organisms.js +9 -1
  63. package/dist/src/cli/connect/mcp/tools/organisms.js.map +1 -1
  64. package/dist/src/cli/connect/onboarding-prompt.d.ts +3 -0
  65. package/dist/src/cli/connect/onboarding-prompt.d.ts.map +1 -1
  66. package/dist/src/cli/connect/onboarding-prompt.js +10 -3
  67. package/dist/src/cli/connect/onboarding-prompt.js.map +1 -1
  68. package/dist/src/data/aimeat-iam-package.d.ts +25 -0
  69. package/dist/src/data/aimeat-iam-package.d.ts.map +1 -0
  70. package/dist/src/data/aimeat-iam-package.js +312 -0
  71. package/dist/src/data/aimeat-iam-package.js.map +1 -0
  72. package/dist/src/data/aimeat-marketplace-package.d.ts +25 -0
  73. package/dist/src/data/aimeat-marketplace-package.d.ts.map +1 -0
  74. package/dist/src/data/aimeat-marketplace-package.js +231 -0
  75. package/dist/src/data/aimeat-marketplace-package.js.map +1 -0
  76. package/dist/src/data/app-templates.d.ts +48 -0
  77. package/dist/src/data/app-templates.d.ts.map +1 -0
  78. package/dist/src/data/app-templates.js +856 -0
  79. package/dist/src/data/app-templates.js.map +1 -0
  80. package/dist/src/data/example-packages.d.ts.map +1 -1
  81. package/dist/src/data/example-packages.js +3 -1
  82. package/dist/src/data/example-packages.js.map +1 -1
  83. package/dist/src/generated/api-types.d.ts +689 -7
  84. package/dist/src/generated/api-types.d.ts.map +1 -1
  85. package/dist/src/generated/prisma-postgres/edge.js +10 -3
  86. package/dist/src/generated/prisma-postgres/index-browser.js +7 -0
  87. package/dist/src/generated/prisma-postgres/index.d.ts +205 -2
  88. package/dist/src/generated/prisma-postgres/index.js +10 -3
  89. package/dist/src/generated/prisma-postgres/package.json +1 -1
  90. package/dist/src/generated/prisma-postgres/schema.prisma +23 -13
  91. package/dist/src/generated/prisma-postgres/wasm.js +10 -3
  92. package/dist/src/mcp/agent-onboarding.d.ts +4 -0
  93. package/dist/src/mcp/agent-onboarding.d.ts.map +1 -1
  94. package/dist/src/mcp/agent-onboarding.js +28 -2
  95. package/dist/src/mcp/agent-onboarding.js.map +1 -1
  96. package/dist/src/mcp/annotations.d.ts.map +1 -1
  97. package/dist/src/mcp/annotations.js +1 -0
  98. package/dist/src/mcp/annotations.js.map +1 -1
  99. package/dist/src/mcp/catalog/definitions.d.ts.map +1 -1
  100. package/dist/src/mcp/catalog/definitions.js +16 -1
  101. package/dist/src/mcp/catalog/definitions.js.map +1 -1
  102. package/dist/src/mcp/catalog/surfaces.js +3 -3
  103. package/dist/src/mcp/catalog/surfaces.js.map +1 -1
  104. package/dist/src/mcp/index.d.ts +3 -0
  105. package/dist/src/mcp/index.d.ts.map +1 -1
  106. package/dist/src/mcp/index.js +11 -0
  107. package/dist/src/mcp/index.js.map +1 -1
  108. package/dist/src/mcp/organisms.d.ts.map +1 -1
  109. package/dist/src/mcp/organisms.js +48 -8
  110. package/dist/src/mcp/organisms.js.map +1 -1
  111. package/dist/src/mcp/workspaces.d.ts.map +1 -1
  112. package/dist/src/mcp/workspaces.js +6 -4
  113. package/dist/src/mcp/workspaces.js.map +1 -1
  114. package/dist/src/models/agent-onboarding-schemas.d.ts +47 -0
  115. package/dist/src/models/agent-onboarding-schemas.d.ts.map +1 -1
  116. package/dist/src/models/agent-onboarding-schemas.js +117 -0
  117. package/dist/src/models/agent-onboarding-schemas.js.map +1 -1
  118. package/dist/src/models/offer-schemas.d.ts +8 -8
  119. package/dist/src/routes/agent-onboarding.d.ts +5 -0
  120. package/dist/src/routes/agent-onboarding.d.ts.map +1 -1
  121. package/dist/src/routes/agent-onboarding.js +21 -2
  122. package/dist/src/routes/agent-onboarding.js.map +1 -1
  123. package/dist/src/routes/ai.d.ts +8 -4
  124. package/dist/src/routes/ai.d.ts.map +1 -1
  125. package/dist/src/routes/ai.js +38 -14
  126. package/dist/src/routes/ai.js.map +1 -1
  127. package/dist/src/routes/app-grants.d.ts +2 -0
  128. package/dist/src/routes/app-grants.d.ts.map +1 -1
  129. package/dist/src/routes/app-grants.js +7 -1
  130. package/dist/src/routes/app-grants.js.map +1 -1
  131. package/dist/src/routes/app-templates.d.ts +16 -0
  132. package/dist/src/routes/app-templates.d.ts.map +1 -0
  133. package/dist/src/routes/app-templates.js +40 -0
  134. package/dist/src/routes/app-templates.js.map +1 -0
  135. package/dist/src/routes/apps.d.ts.map +1 -1
  136. package/dist/src/routes/apps.js +55 -5
  137. package/dist/src/routes/apps.js.map +1 -1
  138. package/dist/src/routes/auth.d.ts +3 -0
  139. package/dist/src/routes/auth.d.ts.map +1 -1
  140. package/dist/src/routes/auth.js +9 -4
  141. package/dist/src/routes/auth.js.map +1 -1
  142. package/dist/src/routes/bootstrap.d.ts.map +1 -1
  143. package/dist/src/routes/bootstrap.js +1 -0
  144. package/dist/src/routes/bootstrap.js.map +1 -1
  145. package/dist/src/routes/generator.d.ts.map +1 -1
  146. package/dist/src/routes/generator.js +3 -2
  147. package/dist/src/routes/generator.js.map +1 -1
  148. package/dist/src/routes/lib-ai.d.ts +0 -1
  149. package/dist/src/routes/lib-ai.d.ts.map +1 -1
  150. package/dist/src/routes/lib-ai.js +13 -6
  151. package/dist/src/routes/lib-ai.js.map +1 -1
  152. package/dist/src/routes/lib-header.d.ts +2 -0
  153. package/dist/src/routes/lib-header.d.ts.map +1 -1
  154. package/dist/src/routes/lib-header.js +7 -16
  155. package/dist/src/routes/lib-header.js.map +1 -1
  156. package/dist/src/routes/lib-markdown.d.ts +18 -0
  157. package/dist/src/routes/lib-markdown.d.ts.map +1 -0
  158. package/dist/src/routes/lib-markdown.js +236 -0
  159. package/dist/src/routes/lib-markdown.js.map +1 -0
  160. package/dist/src/routes/libs.d.ts +22 -0
  161. package/dist/src/routes/libs.d.ts.map +1 -1
  162. package/dist/src/routes/libs.js +133 -10
  163. package/dist/src/routes/libs.js.map +1 -1
  164. package/dist/src/routes/memory.d.ts.map +1 -1
  165. package/dist/src/routes/memory.js +21 -2
  166. package/dist/src/routes/memory.js.map +1 -1
  167. package/dist/src/routes/openrouter.d.ts +4 -0
  168. package/dist/src/routes/openrouter.d.ts.map +1 -1
  169. package/dist/src/routes/openrouter.js +17 -0
  170. package/dist/src/routes/openrouter.js.map +1 -1
  171. package/dist/src/routes/organisms.d.ts.map +1 -1
  172. package/dist/src/routes/organisms.js +107 -7
  173. package/dist/src/routes/organisms.js.map +1 -1
  174. package/dist/src/routes/portal.d.ts +9 -0
  175. package/dist/src/routes/portal.d.ts.map +1 -1
  176. package/dist/src/routes/portal.js +1 -1
  177. package/dist/src/routes/portal.js.map +1 -1
  178. package/dist/src/routes/public-stats.d.ts +3 -0
  179. package/dist/src/routes/public-stats.d.ts.map +1 -1
  180. package/dist/src/routes/public-stats.js +9 -2
  181. package/dist/src/routes/public-stats.js.map +1 -1
  182. package/dist/src/routes/secretary.d.ts +34 -0
  183. package/dist/src/routes/secretary.d.ts.map +1 -0
  184. package/dist/src/routes/secretary.js +311 -0
  185. package/dist/src/routes/secretary.js.map +1 -0
  186. package/dist/src/routes/specialists.d.ts.map +1 -1
  187. package/dist/src/routes/specialists.js +21 -0
  188. package/dist/src/routes/specialists.js.map +1 -1
  189. package/dist/src/routes/subdomains.js +1 -1
  190. package/dist/src/routes/subdomains.js.map +1 -1
  191. package/dist/src/routes/workflows.d.ts +9 -3
  192. package/dist/src/routes/workflows.d.ts.map +1 -1
  193. package/dist/src/routes/workflows.js +9 -3
  194. package/dist/src/routes/workflows.js.map +1 -1
  195. package/dist/src/server-bootstrap/routes-loader.d.ts.map +1 -1
  196. package/dist/src/server-bootstrap/routes-loader.js +4 -0
  197. package/dist/src/server-bootstrap/routes-loader.js.map +1 -1
  198. package/dist/src/server-bootstrap/service-init.d.ts.map +1 -1
  199. package/dist/src/server-bootstrap/service-init.js +7 -0
  200. package/dist/src/server-bootstrap/service-init.js.map +1 -1
  201. package/dist/src/server-bootstrap/static-files.d.ts +4 -0
  202. package/dist/src/server-bootstrap/static-files.d.ts.map +1 -1
  203. package/dist/src/server-bootstrap/static-files.js +18 -0
  204. package/dist/src/server-bootstrap/static-files.js.map +1 -1
  205. package/dist/src/services/archive.d.ts +74 -0
  206. package/dist/src/services/archive.d.ts.map +1 -0
  207. package/dist/src/services/archive.js +132 -0
  208. package/dist/src/services/archive.js.map +1 -0
  209. package/dist/src/services/cortex-seeder.d.ts +4 -1
  210. package/dist/src/services/cortex-seeder.d.ts.map +1 -1
  211. package/dist/src/services/cortex-seeder.js +25 -6
  212. package/dist/src/services/cortex-seeder.js.map +1 -1
  213. package/dist/src/services/directory.d.ts.map +1 -1
  214. package/dist/src/services/directory.js +3 -2
  215. package/dist/src/services/directory.js.map +1 -1
  216. package/dist/src/services/generator-prompt-seeds.d.ts.map +1 -1
  217. package/dist/src/services/generator-prompt-seeds.js +5 -4
  218. package/dist/src/services/generator-prompt-seeds.js.map +1 -1
  219. package/dist/src/services/message-send.d.ts.map +1 -1
  220. package/dist/src/services/message-send.js +14 -0
  221. package/dist/src/services/message-send.js.map +1 -1
  222. package/dist/src/services/onboarding-guide.d.ts +53 -0
  223. package/dist/src/services/onboarding-guide.d.ts.map +1 -0
  224. package/dist/src/services/onboarding-guide.js +81 -0
  225. package/dist/src/services/onboarding-guide.js.map +1 -0
  226. package/dist/src/services/organism-search.d.ts +6 -2
  227. package/dist/src/services/organism-search.d.ts.map +1 -1
  228. package/dist/src/services/organism-search.js +2 -2
  229. package/dist/src/services/organism-search.js.map +1 -1
  230. package/dist/src/services/owner-memory.d.ts +1 -0
  231. package/dist/src/services/owner-memory.d.ts.map +1 -1
  232. package/dist/src/services/owner-memory.js.map +1 -1
  233. package/dist/src/services/owner-session.d.ts +1 -0
  234. package/dist/src/services/owner-session.d.ts.map +1 -1
  235. package/dist/src/services/owner-session.js +10 -2
  236. package/dist/src/services/owner-session.js.map +1 -1
  237. package/dist/src/services/package-seeder.d.ts +22 -0
  238. package/dist/src/services/package-seeder.d.ts.map +1 -0
  239. package/dist/src/services/package-seeder.js +30 -0
  240. package/dist/src/services/package-seeder.js.map +1 -0
  241. package/dist/src/services/presence.d.ts +3 -0
  242. package/dist/src/services/presence.d.ts.map +1 -1
  243. package/dist/src/services/presence.js +10 -0
  244. package/dist/src/services/presence.js.map +1 -1
  245. package/dist/src/services/prompt-defaults.d.ts.map +1 -1
  246. package/dist/src/services/prompt-defaults.js +8 -3
  247. package/dist/src/services/prompt-defaults.js.map +1 -1
  248. package/dist/src/services/scheduler.d.ts +50 -2
  249. package/dist/src/services/scheduler.d.ts.map +1 -1
  250. package/dist/src/services/scheduler.js +454 -26
  251. package/dist/src/services/scheduler.js.map +1 -1
  252. package/dist/src/services/secretary-authoring.d.ts +71 -0
  253. package/dist/src/services/secretary-authoring.d.ts.map +1 -0
  254. package/dist/src/services/secretary-authoring.js +336 -0
  255. package/dist/src/services/secretary-authoring.js.map +1 -0
  256. package/dist/src/services/secretary-clarify.d.ts +57 -0
  257. package/dist/src/services/secretary-clarify.d.ts.map +1 -0
  258. package/dist/src/services/secretary-clarify.js +104 -0
  259. package/dist/src/services/secretary-clarify.js.map +1 -0
  260. package/dist/src/services/secretary-feed.d.ts +11 -0
  261. package/dist/src/services/secretary-feed.d.ts.map +1 -0
  262. package/dist/src/services/secretary-feed.js +28 -0
  263. package/dist/src/services/secretary-feed.js.map +1 -0
  264. package/dist/src/services/secretary-tick.d.ts +243 -3
  265. package/dist/src/services/secretary-tick.d.ts.map +1 -1
  266. package/dist/src/services/secretary-tick.js +273 -3
  267. package/dist/src/services/secretary-tick.js.map +1 -1
  268. package/dist/src/services/secretary-workbrief.d.ts +144 -0
  269. package/dist/src/services/secretary-workbrief.d.ts.map +1 -0
  270. package/dist/src/services/secretary-workbrief.js +315 -0
  271. package/dist/src/services/secretary-workbrief.js.map +1 -0
  272. package/dist/src/services/secretary-worktier.d.ts +118 -0
  273. package/dist/src/services/secretary-worktier.d.ts.map +1 -0
  274. package/dist/src/services/secretary-worktier.js +157 -0
  275. package/dist/src/services/secretary-worktier.js.map +1 -0
  276. package/dist/src/services/skill-bundle/generator.d.ts +3 -0
  277. package/dist/src/services/skill-bundle/generator.d.ts.map +1 -1
  278. package/dist/src/services/skill-bundle/generator.js +19 -0
  279. package/dist/src/services/skill-bundle/generator.js.map +1 -1
  280. package/dist/src/services/specialist-runner.d.ts +36 -0
  281. package/dist/src/services/specialist-runner.d.ts.map +1 -0
  282. package/dist/src/services/specialist-runner.js +91 -0
  283. package/dist/src/services/specialist-runner.js.map +1 -0
  284. package/dist/src/services/specialist.d.ts +9 -0
  285. package/dist/src/services/specialist.d.ts.map +1 -1
  286. package/dist/src/services/specialist.js +42 -0
  287. package/dist/src/services/specialist.js.map +1 -1
  288. package/dist/src/services/structure-overview.d.ts +13 -0
  289. package/dist/src/services/structure-overview.d.ts.map +1 -1
  290. package/dist/src/services/structure-overview.js +34 -11
  291. package/dist/src/services/structure-overview.js.map +1 -1
  292. package/dist/src/services/system-agent-responder.d.ts +36 -0
  293. package/dist/src/services/system-agent-responder.d.ts.map +1 -0
  294. package/dist/src/services/system-agent-responder.js +107 -0
  295. package/dist/src/services/system-agent-responder.js.map +1 -0
  296. package/dist/src/services/system-agent.d.ts +34 -1
  297. package/dist/src/services/system-agent.d.ts.map +1 -1
  298. package/dist/src/services/system-agent.js +73 -0
  299. package/dist/src/services/system-agent.js.map +1 -1
  300. package/dist/src/storage/interface.d.ts +33 -0
  301. package/dist/src/storage/interface.d.ts.map +1 -1
  302. package/dist/src/storage/interface.js.map +1 -1
  303. package/dist/src/storage/providers/mongodb/index.d.ts +37 -0
  304. package/dist/src/storage/providers/mongodb/index.d.ts.map +1 -1
  305. package/dist/src/storage/providers/mongodb/index.js +132 -12
  306. package/dist/src/storage/providers/mongodb/index.js.map +1 -1
  307. package/dist/src/storage/providers/sqlite/index.d.ts +23 -1
  308. package/dist/src/storage/providers/sqlite/index.d.ts.map +1 -1
  309. package/dist/src/storage/providers/sqlite/index.js +60 -8
  310. package/dist/src/storage/providers/sqlite/index.js.map +1 -1
  311. package/dist/src/storage/providers/sqlite/repos/memory.d.ts +29 -1
  312. package/dist/src/storage/providers/sqlite/repos/memory.d.ts.map +1 -1
  313. package/dist/src/storage/providers/sqlite/repos/memory.js +109 -10
  314. package/dist/src/storage/providers/sqlite/repos/memory.js.map +1 -1
  315. package/dist/src/storage/providers/sqlite/schema.d.ts +3 -0
  316. package/dist/src/storage/providers/sqlite/schema.d.ts.map +1 -1
  317. package/dist/src/storage/providers/sqlite/schema.js +64 -9
  318. package/dist/src/storage/providers/sqlite/schema.js.map +1 -1
  319. package/dist/src/storage/repositories/app.repository.d.ts +15 -0
  320. package/dist/src/storage/repositories/app.repository.d.ts.map +1 -1
  321. package/dist/src/storage/repositories/memory.repository.d.ts +41 -1
  322. package/dist/src/storage/repositories/memory.repository.d.ts.map +1 -1
  323. package/dist/src/storage/repositories/organism.repository.d.ts +2 -1
  324. package/dist/src/storage/repositories/organism.repository.d.ts.map +1 -1
  325. package/dist/static/app-catalog.html +469 -122
  326. package/package.json +2 -1
  327. package/prisma/schema.postgres.prisma +10 -0
  328. package/prisma/schema.prisma +12 -0
@@ -4,10 +4,16 @@
4
4
  * main component focused on state + logic (and under the file-size limit). Each export is a PURE render
5
5
  * function taking a props bag — no hooks, no state — so the view owns all state/handlers and passes
6
6
  * them in. Cards: contextSwitcher · hirePanel · chatCard · findCard · noteCard · decisionsCard ·
7
- * brainCard · operatingCard · historyCard · metaCard. See views/secretary.js + docs/plans/2026-06-23-secretary-feature.md.
7
+ * brainCard · operatingCard · historyCard · metaCard · whatsNextCard. See views/secretary.js + docs/plans/2026-06-23-secretary-feature.md.
8
8
  * @structure one exported render function per card (props in → htm out)
9
9
  * @usage import { chatCard, findCard, ... } from '/views/secretary/cards.js'; ... ${chatCard({...})}
10
10
  * @version-history
11
+ * v0.10.0 — 2026-06-28 — G7: the delegate control gains a workflow picker (run an Agent Workflow chaining specialists).
12
+ * v0.9.0 — 2026-06-28 — G10: feedCard groups entries by day (Today / Yesterday / date) with per-day counts.
13
+ * v0.8.0 — 2026-06-28 — B4: routineStepRow gains the delegate control (pick a target agent → create an
14
+ * agent task) + a "Check result" action on delegated steps.
15
+ * v0.7.0 — 2026-06-27 — B2: replace guidedPlanCard with whatsNextCard (Routine propose/advance,
16
+ * band-gated steps + per-step approve/run); guided-plan flow folded into "What's next".
11
17
  * v0.6.0 — 2026-06-24 — P3-A: chatCard gains a doc/image attach control (📎) + an in-flight /
12
18
  * filed status line, driven by the intake hook's handleAttach.
13
19
  * v0.5.0 — 2026-06-24 — P2-E: noteCard shows the cross-context route banner (auto-route to a
@@ -22,17 +28,17 @@ import { h } from 'preact';
22
28
  import htm from 'htm';
23
29
  const html = htm.bind(h);
24
30
  import { t } from '/js/i18n.js';
25
- import { escHtml } from '/js/utils.js';
26
31
  import { CopyButton } from '/components/CopyButton.js';
27
- import { SECRETARY_CAPABILITIES, BANDS } from '/js/services/secretary-policy.js';
28
- import { buildInterviewPrompt } from '/js/services/secretary-helpers.js';
32
+ import { Markdown } from '/components/Markdown.js';
33
+ import { SECRETARY_CAPABILITIES, BANDS, autonomyLevelOf } from '/js/services/secretary-policy.js';
34
+ import { buildInterviewPrompt, groupFeedByDay } from '/js/services/secretary-helpers.js';
29
35
 
30
36
  /** Context "hats" switcher chips + add. */
31
37
  export function contextSwitcher(p) {
32
38
  return html`
33
39
  <div class="sec-ctx-bar">
34
40
  ${p.contexts.map((c) => html`
35
- <button class="sec-ctx-chip ${c.id === p.activeId ? 'active' : ''}" key=${c.id} onClick=${() => p.switchContext(c.id)}>${escHtml(c.name)}</button>`)}
41
+ <button class="sec-ctx-chip ${c.id === p.activeId ? 'active' : ''}" key=${c.id} onClick=${() => p.switchContext(c.id)}>${(c.name)}</button>`)}
36
42
  <button class="sec-ctx-add" title=${t('secretary.addContext')} onClick=${p.openAdd}>+</button>
37
43
  </div>`;
38
44
  }
@@ -48,8 +54,8 @@ export function hirePanel(p) {
48
54
  <p class="sec-desc">${t('secretary.hireIntro')}</p>
49
55
  <div class="sec-opt">
50
56
  <div class="sec-opt-h">${t('secretary.optionA')}</div>
51
- <div class="sec-prompt-box">${buildInterviewPrompt(p.owner)}</div>
52
- <${CopyButton} text=${buildInterviewPrompt(p.owner)} className="btn-outline btn-sm" label=${t('secretary.copyPrompt')} copiedLabel=${'✓ ' + t('secretary.copied')} />
57
+ <div class="sec-prompt-box">${buildInterviewPrompt(p.owner, p.current)}</div>
58
+ <${CopyButton} text=${buildInterviewPrompt(p.owner, p.current)} className="btn-outline btn-sm" label=${t('secretary.copyPrompt')} copiedLabel=${'✓ ' + t('secretary.copied')} />
53
59
  </div>
54
60
  <div class="sec-opt">
55
61
  <div class="sec-opt-h">${t('secretary.optionB')}</div>
@@ -69,21 +75,21 @@ export function chatCard(p) {
69
75
  const canAttach = typeof p.onAttach === 'function' && p.canAttach !== false;
70
76
  return html`
71
77
  <section class="sec-card sec-chat">
72
- <h2 class="sec-h2">${t('secretary.chatTitle')} · ${escHtml(p.activeName)}</h2>
78
+ <h2 class="sec-h2">${t('secretary.chatTitle')} · ${(p.activeName)}</h2>
73
79
  <div class="sec-chat-log">
74
80
  ${p.chat.length === 0
75
81
  ? html`<div class="sec-hint">${t('secretary.chatEmpty')}</div>`
76
- : p.chat.map((m, i) => html`<div class="sec-msg sec-msg-${m.role}" key=${i}>${escHtml(m.content)}</div>`)}
82
+ : p.chat.map((m, i) => html`<div class="sec-msg sec-msg-${m.role}" key=${i}>${(m.content)}</div>`)}
77
83
  ${p.chatSending ? html`<div class="sec-msg sec-msg-assistant sec-msg-pending">…</div>` : null}
78
84
  </div>
79
85
  ${p.routeSuggestion ? html`
80
86
  <div class="sec-route-hint">
81
- <span>${t('secretary.routeSuggest')} <strong>${escHtml(p.routeSuggestion.name)}</strong></span>
87
+ <span>${t('secretary.routeSuggest')} <strong>${(p.routeSuggestion.name)}</strong></span>
82
88
  <button class="btn-ghost btn-sm" onClick=${() => p.switchContext(p.routeSuggestion.id)}>${t('secretary.routeSwitch')}</button>
83
89
  </div>` : null}
84
90
  ${canAttach && p.attaching ? html`<div class="sec-hint sec-attach-status">${t('secretary.attaching')}</div>` : null}
85
91
  ${canAttach && !p.attaching && p.attachResult ? html`
86
- <div class="sec-route-hint"><span>${t('secretary.attachFiled')} <strong>${escHtml(p.attachResult.wsName)}</strong>${p.attachResult.name ? html` — ${escHtml(p.attachResult.name)}` : null}</span></div>` : null}
92
+ <div class="sec-route-hint"><span>${t('secretary.attachFiled')} <strong>${(p.attachResult.wsName)}</strong>${p.attachResult.name ? html` — ${(p.attachResult.name)}` : null}</span></div>` : null}
87
93
  <div class="sec-chat-input">
88
94
  <textarea rows="2" placeholder=${t('secretary.chatPlaceholder')} value=${p.chatInput}
89
95
  onInput=${(e) => p.setChatInput(e.target.value)}
@@ -123,10 +129,10 @@ export function findCard(p) {
123
129
  ? html`<div class="sec-hint">${t('secretary.findEmpty')}</div>`
124
130
  : p.findResults.map((e, i) => html`
125
131
  <div class="sec-find-row" key=${i}>
126
- <span class="sec-find-type">${escHtml(e.type)}</span>
132
+ <span class="sec-find-type">${(e.type)}</span>
127
133
  <div class="sec-find-main">
128
- <div class="sec-find-title">${e.url ? html`<a href=${e.url} target="_blank" rel="noreferrer">${escHtml(e.title)}</a>` : escHtml(e.title)}</div>
129
- ${e.description ? html`<div class="sec-find-desc">${escHtml(String(e.description).slice(0, 160))}</div>` : null}
134
+ <div class="sec-find-title">${e.url ? html`<a href=${e.url} target="_blank" rel="noreferrer">${(e.title)}</a>` : (e.title)}</div>
135
+ ${e.description ? html`<div class="sec-find-desc">${(String(e.description).slice(0, 160))}</div>` : null}
130
136
  </div>
131
137
  </div>`)}
132
138
  </div>`}
@@ -142,14 +148,14 @@ export function noteCard(p) {
142
148
  <textarea class="sec-paste" rows="3" placeholder=${t('secretary.notePlaceholder')} value=${p.noteText} onInput=${(e) => p.setNoteText(e.target.value)}></textarea>
143
149
  ${p.route && p.route.confidence === 'high' ? html`
144
150
  <div class="sec-route-hint">
145
- <span>${t('secretary.routeBelongs')} <strong>${escHtml(p.route.name)}</strong></span>
151
+ <span>${t('secretary.routeBelongs')} <strong>${(p.route.name)}</strong></span>
146
152
  <button class="btn-outline btn-sm" disabled=${p.noteSaving} onClick=${p.autoRouteNote}>${t('secretary.routeFileThere')}</button>
147
153
  </div>` : p.route && p.route.confidence === 'low' ? html`
148
154
  <div class="sec-route-hint"><span class="sec-hint">${t('secretary.routeUnsure')}</span></div>` : null}
149
155
  <div class="sec-note-bar">
150
156
  <label class="sec-hint">${t('secretary.noteInto')}</label>
151
157
  <select class="sec-band" value=${p.effectiveWsId} onChange=${(e) => p.setNoteWsId(e.target.value)}>
152
- ${p.wsList.map((w) => html`<option value=${w.id} selected=${p.effectiveWsId === w.id}>${escHtml(w.name)}</option>`)}
158
+ ${p.wsList.map((w) => html`<option value=${w.id} selected=${p.effectiveWsId === w.id}>${(w.name)}</option>`)}
153
159
  </select>
154
160
  <button class="btn-primary" disabled=${!p.noteText.trim() || p.noteSaving} onClick=${p.saveNote}>${p.noteSaving ? t('secretary.noteSaving') : t('secretary.noteSave')}</button>
155
161
  ${p.wsList.length >= 2 ? html`<button class="btn-outline btn-sm" disabled=${!p.noteText.trim() || p.noteSaving} onClick=${p.askDecision} title=${t('secretary.askInInboxHint')}>${t('secretary.askInInbox')}</button>` : null}
@@ -167,9 +173,9 @@ export function decisionsCard(p) {
167
173
  const dec = p.pendingDecisions[pid];
168
174
  const answer = p.decisionAnswers[pid];
169
175
  return html`<li class="sec-hist-row" key=${pid}>
170
- <span class="sec-hist-purpose">${escHtml((dec.body || dec.text || dec.question || '').slice(0, 60))}</span>
176
+ <span class="sec-hist-purpose">${((dec.body || dec.text || dec.question || '').slice(0, 60))}</span>
171
177
  ${answer
172
- ? html`<button class="btn-primary btn-sm" onClick=${() => p.applyDecision(pid)}>${t('secretary.decisionApply')}: ${escHtml(answer)}</button>`
178
+ ? html`<button class="btn-primary btn-sm" onClick=${() => p.applyDecision(pid)}>${t('secretary.decisionApply')}: ${(answer)}</button>`
173
179
  : html`<span class="sec-hint">${t('secretary.decisionAwaiting')}</span>`}
174
180
  <button class="btn-ghost btn-sm" onClick=${() => p.dismissDecision(pid)}>${t('secretary.cancel')}</button>
175
181
  </li>`;
@@ -182,28 +188,61 @@ export function decisionsCard(p) {
182
188
  export function brainCard(p) {
183
189
  const brain = p.brain;
184
190
  const active = p.active;
191
+ const d = p.brainDraft; // C2: when set, the brain is in inline-edit mode
185
192
  return html`
186
193
  <section class="sec-card">
187
194
  <div class="sec-card-head">
188
195
  <div class="sec-status"><span class="sec-dot"></span> ${t('secretary.hiredStatus')}</div>
189
- <button class="btn-ghost btn-sm" onClick=${p.openEdit}>${t('secretary.rerun')}</button>
196
+ ${!d ? html`<div class="sec-brain-actions">
197
+ <button class="btn-ghost btn-sm" onClick=${p.startBrainEdit}>${t('secretary.editBrain')}</button>
198
+ <button class="btn-ghost btn-sm" onClick=${p.openEdit}>${t('secretary.rerun')}</button>
199
+ </div>` : null}
190
200
  </div>
191
201
  <h2 class="sec-h2">${t('secretary.brain')}</h2>
192
- <p class="sec-purpose">${escHtml(brain.purpose)}</p>
193
- ${Array.isArray(brain.rules) && brain.rules.length > 0 && html`<ul class="sec-rules">${brain.rules.map((r) => html`<li key=${r.id}>${escHtml(r.description)}</li>`)}</ul>`}
202
+ ${d ? html`
203
+ <textarea class="sec-input" rows="3" value=${d.purpose} onInput=${(e) => p.setBrainDraft({ ...d, purpose: e.target.value })}></textarea>
204
+ <div class="sec-h3">${t('secretary.rules')}</div>
205
+ <ul class="sec-rule-edit">
206
+ ${d.rules.map((r, i) => html`
207
+ <li class="sec-rule-row" key=${i}>
208
+ <input class="sec-input" value=${r.description} onInput=${(e) => p.setBrainDraft({ ...d, rules: d.rules.map((x, j) => (j === i ? { ...x, description: e.target.value } : x)) })} />
209
+ <button class="btn-ghost btn-sm" title=${t('secretary.remove')} onClick=${() => p.setBrainDraft({ ...d, rules: d.rules.filter((_, j) => j !== i) })}>✕</button>
210
+ </li>`)}
211
+ </ul>
212
+ <button class="btn-ghost btn-sm" onClick=${() => p.setBrainDraft({ ...d, rules: [...d.rules, { id: '', description: '' }] })}>+ ${t('secretary.addRule')}</button>
213
+ <div class="sec-actions">
214
+ <button class="btn-ghost btn-sm" onClick=${p.cancelBrainEdit}>${t('secretary.cancel')}</button>
215
+ <button class="btn-primary btn-sm" disabled=${p.savingBrain} onClick=${p.saveBrain}>${p.savingBrain ? t('secretary.saving') : t('secretary.save')}</button>
216
+ </div>`
217
+ : html`
218
+ <p class="sec-purpose">${(brain.purpose)}</p>
219
+ ${Array.isArray(brain.rules) && brain.rules.length > 0 && html`<ul class="sec-rules">${brain.rules.map((r) => html`<li key=${r.id}>${(r.description)}</li>`)}</ul>`}`}
194
220
  ${active.organismName && html`
195
221
  <h2 class="sec-h2">${t('secretary.selfOrganism')}</h2>
196
- <p class="sec-orgname">🗂 ${escHtml(active.organismName)}</p>
197
- ${Array.isArray(active.workspaces) && html`<ul class="sec-ws">${active.workspaces.map((w, i) => html`<li key=${i}><strong>${escHtml(w.name)}</strong>${w.purpose ? html` — ${escHtml(w.purpose)}` : null}</li>`)}</ul>`}`}
222
+ <p class="sec-orgname">🗂 ${(active.organismName)}</p>
223
+ ${Array.isArray(active.workspaces) && html`<ul class="sec-ws">${active.workspaces.map((w, i) => html`<li key=${i}><strong>${(w.name)}</strong>${w.purpose ? html` — ${(w.purpose)}` : null}</li>`)}</ul>`}`}
198
224
  </section>`;
199
225
  }
200
226
 
201
227
  /** Operating model: stop-spending + daily budget + per-capability autonomy bands. */
202
228
  export function operatingCard(p) {
203
229
  const policy = p.policy;
230
+ const level = autonomyLevelOf(policy.bands); // 'suggest' | 'assist' — the single toggle's state
204
231
  return html`
205
232
  <section class="sec-card">
206
233
  <h2 class="sec-h2">${t('secretary.howIWork')}</h2>
234
+
235
+ ${/* ONE autonomy toggle (collapses the per-capability band sprawl). Heavy work is always a Work
236
+ Brief a Builder executes — never something the cheap Secretary does on its own. */ ''}
237
+ <div class="sec-autonomy">
238
+ ${[['suggest', 'secretary.autonomy.suggest', 'secretary.autonomy.suggestHint'],
239
+ ['assist', 'secretary.autonomy.assist', 'secretary.autonomy.assistHint']].map(([val, label, hint]) => html`
240
+ <label class=${'sec-auto-opt' + (level === val ? ' sec-auto-opt--on' : '')} key=${val}>
241
+ <input type="radio" name="sec-autonomy" checked=${level === val} onChange=${() => p.setAutonomy(val)} />
242
+ <span><strong>${t(label)}</strong><br/><span class="sec-hint">${t(hint)}</span></span>
243
+ </label>`)}
244
+ </div>
245
+
207
246
  <label class="sec-stop ${policy.stopSpending ? 'on' : ''}">
208
247
  <input type="checkbox" checked=${policy.stopSpending} onChange=${p.toggleStop} />
209
248
  <span><strong>${t('secretary.stopSpending')}</strong><br/><span class="sec-hint">${t('secretary.stopSpendingHint')}</span></span>
@@ -213,18 +252,24 @@ export function operatingCard(p) {
213
252
  <input type="number" min="0" class="sec-budget-in" value=${policy.dailyMorselBudget == null ? '' : policy.dailyMorselBudget} placeholder=${t('secretary.noLimit')} onChange=${(e) => p.setBudget(e.target.value)} />
214
253
  <span class="sec-hint">${t('secretary.dailyBudgetHint')}</span>
215
254
  </div>
216
- <p class="sec-hint sec-bands-note">${t('secretary.bandsNote')}</p>
217
- <ul class="sec-caps">
218
- ${SECRETARY_CAPABILITIES.map((c) => html`
219
- <li class="sec-cap" key=${c.id}>
220
- <span class="sec-cap-label">${t('secretary.cap.' + c.id)}${c.costs ? html`<span class="sec-cap-tag">${t('secretary.capCosts')}</span>` : null}</span>
221
- ${c.enterprise
222
- ? html`<span class="sec-cap-locked sec-cap-ent">${t('secretary.enterprise')}</span>`
223
- : c.locked
224
- ? html`<span class="sec-cap-locked">${t('secretary.band.' + policy.bands[c.id])} · ${t('secretary.locked')}</span>`
225
- : html`<select class="sec-band" value=${policy.bands[c.id]} onChange=${(e) => p.setBand(c.id, e.target.value)}>${BANDS.map((b) => html`<option value=${b} selected=${policy.bands[c.id] === b}>${t('secretary.band.' + b)}</option>`)}</select>`}
226
- </li>`)}
227
- </ul>
255
+
256
+ ${/* Per-capability bands are still here for power users, tucked behind an Advanced disclosure so the
257
+ default surface is just the one toggle above. */ ''}
258
+ <details class="sec-adv">
259
+ <summary>${t('secretary.advancedBands')}</summary>
260
+ <p class="sec-hint sec-bands-note">${t('secretary.bandsNote')}</p>
261
+ <ul class="sec-caps">
262
+ ${SECRETARY_CAPABILITIES.map((c) => html`
263
+ <li class="sec-cap" key=${c.id}>
264
+ <span class="sec-cap-label">${t('secretary.cap.' + c.id)}${c.costs ? html`<span class="sec-cap-tag">${t('secretary.capCosts')}</span>` : null}</span>
265
+ ${c.enterprise
266
+ ? html`<span class="sec-cap-locked sec-cap-ent">${t('secretary.enterprise')}</span>`
267
+ : c.locked
268
+ ? html`<span class="sec-cap-locked">${t('secretary.band.' + policy.bands[c.id])} · ${t('secretary.locked')}</span>`
269
+ : html`<select class="sec-band" value=${policy.bands[c.id]} onChange=${(e) => p.setBand(c.id, e.target.value)}>${BANDS.map((b) => html`<option value=${b} selected=${policy.bands[c.id] === b}>${t('secretary.band.' + b)}</option>`)}</select>`}
270
+ </li>`)}
271
+ </ul>
272
+ </details>
228
273
  </section>`;
229
274
  }
230
275
 
@@ -236,58 +281,148 @@ export function historyCard(p) {
236
281
  <ul class="sec-hist">
237
282
  ${p.brainHistory.map((snap, i) => html`
238
283
  <li class="sec-hist-row" key=${i}>
239
- <span class="sec-hist-purpose">${escHtml((snap.purpose || '').slice(0, 80))}</span>
284
+ <span class="sec-hist-purpose">${((snap.purpose || '').slice(0, 80))}</span>
240
285
  <button class="btn-ghost btn-sm" disabled=${p.applying} onClick=${() => p.restore(snap)}>${t('secretary.restore')}</button>
241
286
  </li>`)}
242
287
  </ul>
243
288
  </section>`;
244
289
  }
245
290
 
246
- /** Guided playbook (Phase 3c): propose steps → approve → execute (file + discover) → result. */
247
- export function guidedPlanCard(p) {
291
+ /** A single Routine step row (B2 + B4): capability + band + summary + result, with the approve/run/delegate control. */
292
+ function routineStepRow(p, r, s) {
293
+ const next = p.nextPendingStep(r);
294
+ const isNext = next && next.id === s.id;
295
+ const busy = p.busyStepId === s.id;
296
+ const runLabel = s.band === 'off' ? t('secretary.next.skip') : s.band === 'act' ? t('secretary.next.run') : t('secretary.next.approve');
297
+ const isDelegate = s.capability === 'delegate';
298
+ const agents = p.agents || [];
299
+ const workflows = p.workflows || [];
300
+ // Unblur the delegation target by ROLE: node-local Specialists vs connected big-AI Builders. The Secretary
301
+ // (the watcher) is never a delegation target. Same handler/value (agent name) — the optgroups just label
302
+ // which kind of agent each is, so "pick a specialist" no longer lumps Builders + specialists together.
303
+ const isSpecialist = (a) => (a.tags || []).includes('system:specialist');
304
+ const isSecretary = (a) => (a.tags || []).includes('system:secretary') || a.name === 'secretary';
305
+ const specialistAgents = agents.filter((a) => isSpecialist(a));
306
+ const builderAgents = agents.filter((a) => !isSpecialist(a) && !isSecretary(a));
307
+ // B4: delegate to one agent (agent task) · G7: OR run an Agent Workflow chaining specialists.
308
+ const delegateControl = html`
309
+ <div class="sec-delegate">
310
+ ${(specialistAgents.length + builderAgents.length) > 0 ? html`
311
+ <select class="sec-band" value=${p.delegateAgent} onChange=${(e) => p.setDelegateAgent(e.target.value)}>
312
+ <option value="" selected=${!p.delegateAgent}>${t('secretary.next.delegatePick')}</option>
313
+ ${specialistAgents.length ? html`<optgroup label=${t('secretary.next.delegateSpecialists')}>
314
+ ${specialistAgents.map((a) => html`<option value=${a.name} selected=${p.delegateAgent === a.name}>${(a.name)}</option>`)}
315
+ </optgroup>` : null}
316
+ ${builderAgents.length ? html`<optgroup label=${t('secretary.next.delegateBuilders')}>
317
+ ${builderAgents.map((a) => html`<option value=${a.name} selected=${p.delegateAgent === a.name}>${(a.name)}</option>`)}
318
+ </optgroup>` : null}
319
+ </select>
320
+ <button class="btn-primary btn-sm" disabled=${busy || !p.delegateAgent} onClick=${() => p.approveStep(r, s, { agentName: p.delegateAgent })}>${busy ? t('secretary.next.running') : t('secretary.next.delegateGo')}</button>` : null}
321
+ ${workflows.length > 0 ? html`
322
+ <select class="sec-band" value=${p.delegateWorkflow} onChange=${(e) => p.setDelegateWorkflow(e.target.value)}>
323
+ <option value="" selected=${!p.delegateWorkflow}>${t('secretary.next.delegateWorkflowPick')}</option>
324
+ ${workflows.map((w) => html`<option value=${w.id} selected=${p.delegateWorkflow === w.id}>${((w.title && (w.title.en_US || w.title)) || w.id)}</option>`)}
325
+ </select>
326
+ <button class="btn-outline btn-sm" disabled=${busy || !p.delegateWorkflow} onClick=${() => p.approveStep(r, s, { workflowId: p.delegateWorkflow, workflowName: (workflows.find((w) => w.id === p.delegateWorkflow) || {}).title?.en_US })}>${busy ? t('secretary.next.running') : t('secretary.next.delegateWorkflowGo')}</button>` : null}
327
+ ${p.onDesignWorkflow ? html`<button class="btn-ghost btn-sm" disabled=${busy} title=${t('secretary.wf.title')} onClick=${() => p.onDesignWorkflow(s)}>${t('secretary.next.delegateDesignWf')}</button>` : null}
328
+ ${agents.length === 0 && workflows.length === 0 && !p.onDesignWorkflow ? html`<span class="sec-hint">${t('secretary.next.delegateNoAgents')}</span>` : null}
329
+ </div>`;
330
+ return html`
331
+ <li class="sec-step-row ${s.status}" key=${s.id}>
332
+ <div class="sec-step-main">
333
+ <div class="sec-step-tags">
334
+ <span class="sec-step-cap">${t('secretary.cap.' + s.capability)}</span>
335
+ <span class="sec-band-tag band-${s.band}">${t('secretary.band.' + s.band)}</span>
336
+ </div>
337
+ <div class="sec-step-summary">${(s.summary)}</div>
338
+ ${s.result ? html`<div class="sec-hint">→ ${(s.result.summary)}</div>` : null}
339
+ ${s.status === 'delegated' && s.result && (s.result.taskId || s.result.runId) ? html`
340
+ <button class="btn-ghost btn-sm" disabled=${p.checkingStepId === s.id} onClick=${() => p.checkDelegateResult(r, s)}>${p.checkingStepId === s.id ? t('secretary.next.running') : t('secretary.next.checkResult')}</button>` : null}
341
+ </div>
342
+ ${s.status === 'pending'
343
+ ? (isNext
344
+ ? (isDelegate
345
+ ? delegateControl
346
+ : html`<button class="btn-primary btn-sm" disabled=${busy} onClick=${() => p.approveStep(r, s)}>${busy ? t('secretary.next.running') : runLabel}</button>`)
347
+ : html`<span class="sec-hint">${t('secretary.next.queued')}</span>`)
348
+ : html`<span class="sec-step-status sec-${s.status}">${t('secretary.next.status.' + s.status)}</span>`}
349
+ </li>`;
350
+ }
351
+
352
+ /** B2 "What's next": propose a NEW routine from a goal, or walk the selected one step-by-step (band-gated). */
353
+ export function whatsNextCard(p) {
354
+ const r = p.selected;
248
355
  return html`
249
- <section class="sec-card sec-plan">
250
- <h2 class="sec-h2">${t('secretary.plan.title')}</h2>
251
- <p class="sec-hint">${t('secretary.plan.hint')}</p>
252
- ${!p.steps && !p.result ? html`
253
- <textarea class="sec-paste" rows="2" placeholder=${t('secretary.plan.placeholder')} value=${p.goal} onInput=${(e) => p.setGoal(e.target.value)}></textarea>
356
+ <section class="sec-card sec-next">
357
+ <h2 class="sec-h2">${t('secretary.next.cardTitle')}</h2>
358
+ <p class="sec-hint">${t('secretary.next.hint')}</p>
359
+ ${!r ? html`
360
+ <p class="sec-hint">${t('secretary.next.explain')}</p>
361
+ ${p.actionItems && p.actionItems.length ? html`<div class="sec-next-followups">↑ ${t('secretary.next.followups', { n: p.actionItems.length })}</div>` : null}
362
+ ${p.activeRoutines && p.activeRoutines.length ? html`
363
+ <div class="sec-h3">${t('secretary.next.continueTitle')}</div>
364
+ <ul class="sec-routine-list">
365
+ ${p.activeRoutines.map((rt) => {
366
+ const ns = p.nextPendingStep(rt);
367
+ return html`
368
+ <li class="sec-routine-row" key=${rt.id}>
369
+ <div class="sec-routine-main">
370
+ <div class="sec-routine-title">${(rt.title)}</div>
371
+ <div class="sec-hint">${ns ? `${t('secretary.next.nextStep')}: ${ns.summary}` : t('secretary.next.allSettled')}</div>
372
+ </div>
373
+ <button class="btn-outline btn-sm" onClick=${() => p.advance(rt)}>${t('secretary.next.advance')}</button>
374
+ </li>`;
375
+ })}
376
+ </ul>` : null}
377
+ <div class="sec-h3">${t('secretary.next.startNewTitle')}</div>
378
+ <textarea class="sec-paste" rows="2" placeholder=${t('secretary.next.placeholder')} value=${p.goal} onInput=${(e) => p.setGoal(e.target.value)}></textarea>
254
379
  <div class="sec-actions">
255
- <button class="btn-primary" disabled=${!p.goal.trim() || p.planning} onClick=${p.planIt}>${p.planning ? t('secretary.plan.planning') : t('secretary.plan.go')}</button>
256
- </div>` : null}
257
- ${p.steps && !p.result ? html`
258
- <div class="sec-plan-steps">
259
- ${p.steps.summary ? html`<p class="sec-purpose">${escHtml(p.steps.summary)}</p>` : null}
260
- <ol class="sec-rules">
261
- ${p.steps.steps.map((s, i) => html`<li key=${i}><strong>${escHtml(s.title)}</strong>${s.detail ? html` — ${escHtml(s.detail)}` : null}</li>`)}
262
- </ol>
263
- <div class="sec-actions">
264
- <button class="btn-ghost btn-sm" onClick=${p.cancelPlan}>${t('secretary.cancel')}</button>
265
- <button class="btn-primary" disabled=${p.running} onClick=${p.runPlan}>${p.running ? t('secretary.plan.running') : t('secretary.plan.approve')}</button>
380
+ <button class="btn-primary" disabled=${!p.goal.trim() || p.proposing} onClick=${p.proposeRoutine}>${p.proposing ? t('secretary.next.proposing') : t('secretary.next.propose')}</button>
381
+ </div>` : html`
382
+ <div class="sec-routine">
383
+ <div class="sec-routine-head">
384
+ <div>
385
+ <div class="sec-routine-title">${(r.title)}</div>
386
+ ${r.purpose ? html`<div class="sec-hint">${(r.purpose)}</div>` : null}
387
+ </div>
388
+ ${r.status === 'done' ? html`<span class="sec-step-status sec-done">${t('secretary.next.status.done')}</span>` : null}
266
389
  </div>
267
- </div>` : null}
268
- ${p.result ? html`
269
- <div class="sec-plan-result">
270
- <div class="sec-status"><span class="sec-dot"></span> ${t('secretary.plan.ran')}</div>
271
- ${p.result.wsName ? html`<p class="sec-hint">${t('secretary.plan.filed')} <strong>${escHtml(p.result.wsName)}</strong></p>` : null}
272
- <p class="sec-hint">${t('secretary.plan.found')} ${p.result.found}</p>
273
- <button class="btn-ghost btn-sm" onClick=${p.resetPlan}>${t('secretary.plan.new')}</button>
274
- </div>` : null}
390
+ <div class="sec-routine-cadence">
391
+ <label class="sec-hint">${t('secretary.next.repeats')}</label>
392
+ <select class="sec-band" value=${r.cadence || ''} onChange=${(e) => p.setRoutineCadence(r, e.target.value)}>
393
+ <option value="" selected=${!r.cadence}>${t('secretary.next.cadence.none')}</option>
394
+ <option value="daily" selected=${r.cadence === 'daily'}>${t('secretary.next.cadence.daily')}</option>
395
+ <option value="weekly" selected=${r.cadence === 'weekly'}>${t('secretary.next.cadence.weekly')}</option>
396
+ </select>
397
+ ${r.cadence && r.nextRunAt ? html`<span class="sec-hint">${t('secretary.next.nextRun')}: ${new Date(r.nextRunAt).toLocaleDateString()}</span>` : null}
398
+ </div>
399
+ <ul class="sec-step-list">${r.steps.map((s) => routineStepRow(p, r, s))}</ul>
400
+ <div class="sec-actions sec-routine-actions">
401
+ <button class="btn-ghost btn-sm" onClick=${() => p.setSelectedId(null)}>${t('secretary.next.startNew')}</button>
402
+ <button class="btn-ghost btn-sm" onClick=${() => p.deleteRoutine(r)}>${t('secretary.next.discard')}</button>
403
+ </div>
404
+ </div>`}
275
405
  </section>`;
276
406
  }
277
407
 
278
- /** Home feed (Phase 4): what the Secretary did on its own (autonomous briefings). */
408
+ /** Home feed (Phase 4 + G10): what the Secretary did on its own, grouped by day (today + previous days). */
279
409
  export function feedCard(p) {
280
410
  return html`
281
411
  <section class="sec-card sec-feed">
282
412
  <h2 class="sec-h2">${t('secretary.feed.title')}</h2>
283
413
  ${p.feed.length === 0
284
414
  ? html`<div class="sec-hint">${t('secretary.feed.empty')}</div>`
285
- : html`<ul class="sec-feed-list">
286
- ${p.feed.map((it, i) => html`<li class="sec-feed-item" key=${it.id || i}>
287
- <div class="sec-feed-meta">${it.contextName ? escHtml(it.contextName) + ' · ' : ''}${it.ts ? new Date(it.ts).toLocaleString() : ''}</div>
288
- <div class="sec-feed-text">${escHtml(it.text || '')}</div>
289
- </li>`)}
290
- </ul>`}
415
+ : groupFeedByDay(p.feed).map((g) => html`
416
+ <div class="sec-feed-day" key=${g.key}>
417
+ <div class="sec-feed-day-head">${(g.label)} <span class="sec-feed-day-count">${g.items.length}</span></div>
418
+ <ul class="sec-feed-list">
419
+ ${g.items.map((it, i) => html`<li class="sec-feed-item" key=${it.id || i}>
420
+ <div class="sec-feed-meta">${it.contextName ? (it.contextName) + ' · ' : ''}${it.ts ? new Date(it.ts).toLocaleTimeString() : ''}</div>
421
+ <div class="sec-feed-text"><${Markdown} text=${it.text || ''} /></div>
422
+ ${it.href ? html`<a class="sec-feed-link" href=${it.href} target="_blank" rel="noopener">${t('secretary.next.openResult')} ↗</a>` : null}
423
+ </li>`)}
424
+ </ul>
425
+ </div>`)}
291
426
  </section>`;
292
427
  }
293
428
 
@@ -303,8 +438,8 @@ export function automationCard(p) {
303
438
  : html`
304
439
  <div class="sec-auto-row">
305
440
  <div>
306
- <div><strong>${escHtml(s.displayName || t('secretary.auto.scheduleName'))}</strong>${s.enabled ? null : html` <span class="sec-hint">(${t('secretary.auto.paused')})</span>`}</div>
307
- <div class="sec-hint">${t('secretary.auto.nextRun')}: ${s.nextRunAt ? new Date(s.nextRunAt).toLocaleString() : '—'}${s.cron ? ' · ' + escHtml(s.cron) : ''}</div>
441
+ <div><strong>${(s.displayName || t('secretary.auto.scheduleName'))}</strong>${s.enabled ? null : html` <span class="sec-hint">(${t('secretary.auto.paused')})</span>`}</div>
442
+ <div class="sec-hint">${t('secretary.auto.nextRun')}: ${s.nextRunAt ? new Date(s.nextRunAt).toLocaleString() : '—'}${s.cron ? ' · ' + (s.cron) : ''}</div>
308
443
  ${p.budgetInfo ? html`<div class="sec-hint">${t('secretary.auto.budgetLeft')}: ${p.budgetInfo.remaining} / ${p.budgetInfo.budget}</div>` : null}
309
444
  </div>
310
445
  <div class="sec-auto-actions">
@@ -335,8 +470,8 @@ export function goalsCard(p) {
335
470
  : html`<ul class="sec-goal-list">
336
471
  ${p.goals.map((g) => html`<li class="sec-goal-row ${g.status === 'done' ? 'done' : ''}" key=${g.id}>
337
472
  <div class="sec-goal-main">
338
- <div class="sec-goal-title">${escHtml(g.title)}</div>
339
- ${g.why ? html`<div class="sec-hint">${escHtml(g.why)}</div>` : null}
473
+ <div class="sec-goal-title">${(g.title)}</div>
474
+ ${g.why ? html`<div class="sec-hint">${(g.why)}</div>` : null}
340
475
  </div>
341
476
  <button class="btn-ghost btn-sm" onClick=${() => p.completeGoal(g)}>${g.status === 'done' ? t('secretary.learn.reopen') : t('secretary.learn.done')}</button>
342
477
  <button class="btn-ghost btn-sm" onClick=${() => p.deleteGoal(g)}>✕</button>
@@ -375,7 +510,7 @@ export function decisionLogCard(p) {
375
510
  <label class="sec-hint">${t('secretary.learn.goalRef')}</label>
376
511
  <select class="sec-band" value=${f.goalRef} onChange=${(e) => p.setDecForm({ ...f, goalRef: e.target.value })}>
377
512
  <option value="">—</option>
378
- ${p.goals.filter((g) => g.status !== 'done').map((g) => html`<option value=${'secretary.goal.' + g.id} selected=${f.goalRef === 'secretary.goal.' + g.id}>${escHtml(g.title)}</option>`)}
513
+ ${p.goals.filter((g) => g.status !== 'done').map((g) => html`<option value=${'secretary.goal.' + g.id} selected=${f.goalRef === 'secretary.goal.' + g.id}>${(g.title)}</option>`)}
379
514
  </select>
380
515
  <label class="sec-hint">${t('secretary.learn.revisitIn')}</label>
381
516
  <input class="sec-input sec-input-sm" type="number" min="0" value=${f.revisitDays} onInput=${(e) => p.setDecForm({ ...f, revisitDays: e.target.value })} />
@@ -387,10 +522,10 @@ export function decisionLogCard(p) {
387
522
  : html`<ul class="sec-goal-list">
388
523
  ${p.decisions.map((d) => html`<li class="sec-goal-row" key=${d.id}>
389
524
  <div class="sec-goal-main">
390
- <div class="sec-goal-title">${escHtml(d.decision)}${d.chosen ? html` <span class="sec-hint">→ ${escHtml(d.chosen)}</span>` : null}</div>
525
+ <div class="sec-goal-title">${(d.decision)}${d.chosen ? html` <span class="sec-hint">→ ${(d.chosen)}</span>` : null}</div>
391
526
  ${d.status === 'reviewed' && d.verdict
392
- ? html`<div class="sec-hint">${escHtml(d.verdict)}</div>`
393
- : (d.expectedOutcome ? html`<div class="sec-hint">${t('secretary.learn.expected')}: ${escHtml(d.expectedOutcome)}</div>` : null)}
527
+ ? html`<div class="sec-hint">${(d.verdict)}</div>`
528
+ : (d.expectedOutcome ? html`<div class="sec-hint">${t('secretary.learn.expected')}: ${(d.expectedOutcome)}</div>` : null)}
394
529
  </div>
395
530
  ${scoreChip(d)}
396
531
  <button class="btn-ghost btn-sm" onClick=${() => p.deleteDecision(d)}>✕</button>
@@ -409,11 +544,14 @@ export function metaCard(p) {
409
544
  <section class="sec-card sec-meta-card">
410
545
  <dl class="sec-meta">
411
546
  <dt>${t('secretary.identity')}</dt>
412
- <dd><code>${escHtml(p.secretary.gaii)}</code></dd>
547
+ <dd><code>${(p.secretary.gaii)}</code></dd>
413
548
  <dt title=${t('secretary.reliabilityHint')}>${t('secretary.reliability')}</dt>
414
549
  <dd>${relChip}</dd>
415
550
  <dt>${t('secretary.scopes')}</dt>
416
- <dd class="sec-scopes">${(p.secretary.default_scopes || []).map((s) => html`<span class="sec-scope" key=${s}>${s}</span>`)}</dd>
551
+ <dd class="sec-scopes">
552
+ ${(p.secretary.default_scopes || []).map((s) => html`<span class="sec-scope" key=${s}>${s}</span>`)}
553
+ <a class="sec-perm-link" href="/v1/profile?tab=agents">${t('secretary.managePermissions')} ↗</a>
554
+ </dd>
417
555
  </dl>
418
556
  </section>`;
419
557
  }