aimeat 1.23.2 → 1.24.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 (239) hide show
  1. package/dist/locales/en.json +580 -21
  2. package/dist/locales/fi.json +592 -33
  3. package/dist/public/components/ContactCard.js +28 -0
  4. package/dist/public/css/views/admin.css +12 -0
  5. package/dist/public/css/views/agents-detail.css +62 -10
  6. package/dist/public/css/views/landing.css +87 -0
  7. package/dist/public/css/views/offers.css +96 -0
  8. package/dist/public/css/views/portfolio.css +18 -0
  9. package/dist/public/css/views/profile.css +153 -8
  10. package/dist/public/css/views/start.css +96 -0
  11. package/dist/public/css/views/workflows.css +111 -0
  12. package/dist/public/img/business-hero.png +0 -0
  13. package/dist/public/img/toimitus.png +0 -0
  14. package/dist/public/js/components/tag-cloud.js +46 -31
  15. package/dist/public/js/components/tag-editor.js +2 -2
  16. package/dist/public/js/recents.js +40 -0
  17. package/dist/public/js/services/admin.js +6 -0
  18. package/dist/public/js/services/agents.js +34 -0
  19. package/dist/public/js/services/offers.js +152 -0
  20. package/dist/public/js/services/packages.js +1 -0
  21. package/dist/public/js/services/workflows.js +57 -0
  22. package/dist/public/llms-template.txt +7 -0
  23. package/dist/public/spa.html +35 -3
  24. package/dist/public/views/admin/subdomains-tab.js +182 -0
  25. package/dist/public/views/admin.js +2 -0
  26. package/dist/public/views/business.js +119 -0
  27. package/dist/public/views/how-it-works.js +159 -0
  28. package/dist/public/views/landing.js +235 -0
  29. package/dist/public/views/portfolio.js +120 -23
  30. package/dist/public/views/pricing.js +75 -0
  31. package/dist/public/views/profile/access-tab.js +124 -51
  32. package/dist/public/views/profile/agents/agent-card.js +68 -37
  33. package/dist/public/views/profile/agents/shared-board.js +56 -22
  34. package/dist/public/views/profile/agents/tab-activity.js +24 -12
  35. package/dist/public/views/profile/agents/tab-agent-config.js +31 -1
  36. package/dist/public/views/profile/agents/tab-data-access.js +9 -13
  37. package/dist/public/views/profile/agents/tab-integration.js +27 -1
  38. package/dist/public/views/profile/agents/tab-messages.js +6 -11
  39. package/dist/public/views/profile/agents/tab-quality.js +45 -5
  40. package/dist/public/views/profile/agents-tab.js +41 -6
  41. package/dist/public/views/profile/apps-tab.js +7 -1
  42. package/dist/public/views/profile/knowledge-tab.js +4 -1
  43. package/dist/public/views/profile/landing-page.js +428 -123
  44. package/dist/public/views/profile/memory-tab.js +409 -211
  45. package/dist/public/views/profile/nodes-tab.js +18 -3
  46. package/dist/public/views/profile/offers-tab.js +310 -0
  47. package/dist/public/views/profile/organisms-tab.js +289 -28
  48. package/dist/public/views/profile/packages-tab.js +152 -16
  49. package/dist/public/views/profile/portfolio-tab.js +98 -31
  50. package/dist/public/views/profile/workflows-form.js +220 -0
  51. package/dist/public/views/profile/workflows-tab.js +244 -0
  52. package/dist/public/views/profile.js +4 -0
  53. package/dist/public/views/start-flows.js +281 -0
  54. package/dist/public/views/start.js +258 -0
  55. package/dist/src/cli/connect/mcp/tools/index.d.ts.map +1 -1
  56. package/dist/src/cli/connect/mcp/tools/index.js +2 -0
  57. package/dist/src/cli/connect/mcp/tools/index.js.map +1 -1
  58. package/dist/src/cli/connect/mcp/tools/workflows.d.ts +12 -0
  59. package/dist/src/cli/connect/mcp/tools/workflows.d.ts.map +1 -0
  60. package/dist/src/cli/connect/mcp/tools/workflows.js +37 -0
  61. package/dist/src/cli/connect/mcp/tools/workflows.js.map +1 -0
  62. package/dist/src/cli/connect/tool-call.d.ts.map +1 -1
  63. package/dist/src/cli/connect/tool-call.js +37 -0
  64. package/dist/src/cli/connect/tool-call.js.map +1 -1
  65. package/dist/src/generated/api-types.d.ts +1474 -66
  66. package/dist/src/generated/api-types.d.ts.map +1 -1
  67. package/dist/src/generated/prisma-postgres/edge.js +15 -3
  68. package/dist/src/generated/prisma-postgres/index-browser.js +12 -0
  69. package/dist/src/generated/prisma-postgres/index.d.ts +1476 -160
  70. package/dist/src/generated/prisma-postgres/index.js +15 -3
  71. package/dist/src/generated/prisma-postgres/package.json +1 -1
  72. package/dist/src/generated/prisma-postgres/schema.prisma +11 -0
  73. package/dist/src/generated/prisma-postgres/wasm.js +15 -3
  74. package/dist/src/mcp/annotations.d.ts.map +1 -1
  75. package/dist/src/mcp/annotations.js +3 -0
  76. package/dist/src/mcp/annotations.js.map +1 -1
  77. package/dist/src/mcp/catalog/definitions.d.ts.map +1 -1
  78. package/dist/src/mcp/catalog/definitions.js +27 -0
  79. package/dist/src/mcp/catalog/definitions.js.map +1 -1
  80. package/dist/src/mcp/catalog/scopes.d.ts.map +1 -1
  81. package/dist/src/mcp/catalog/scopes.js +5 -1
  82. package/dist/src/mcp/catalog/scopes.js.map +1 -1
  83. package/dist/src/mcp/catalog/surfaces.d.ts.map +1 -1
  84. package/dist/src/mcp/catalog/surfaces.js +1 -0
  85. package/dist/src/mcp/catalog/surfaces.js.map +1 -1
  86. package/dist/src/mcp/index.d.ts.map +1 -1
  87. package/dist/src/mcp/index.js +2 -0
  88. package/dist/src/mcp/index.js.map +1 -1
  89. package/dist/src/mcp/workflows.d.ts +18 -0
  90. package/dist/src/mcp/workflows.d.ts.map +1 -0
  91. package/dist/src/mcp/workflows.js +68 -0
  92. package/dist/src/mcp/workflows.js.map +1 -0
  93. package/dist/src/middleware/subdomain.d.ts +28 -0
  94. package/dist/src/middleware/subdomain.d.ts.map +1 -0
  95. package/dist/src/middleware/subdomain.js +32 -0
  96. package/dist/src/middleware/subdomain.js.map +1 -0
  97. package/dist/src/models/offer-schemas.d.ts +236 -0
  98. package/dist/src/models/offer-schemas.d.ts.map +1 -0
  99. package/dist/src/models/offer-schemas.js +112 -0
  100. package/dist/src/models/offer-schemas.js.map +1 -0
  101. package/dist/src/models/workflow-schemas.d.ts +220 -0
  102. package/dist/src/models/workflow-schemas.d.ts.map +1 -0
  103. package/dist/src/models/workflow-schemas.js +102 -0
  104. package/dist/src/models/workflow-schemas.js.map +1 -0
  105. package/dist/src/routes/agent-tasks.d.ts.map +1 -1
  106. package/dist/src/routes/agent-tasks.js +49 -0
  107. package/dist/src/routes/agent-tasks.js.map +1 -1
  108. package/dist/src/routes/agents.d.ts.map +1 -1
  109. package/dist/src/routes/agents.js +146 -1
  110. package/dist/src/routes/agents.js.map +1 -1
  111. package/dist/src/routes/apps-backup.d.ts +20 -0
  112. package/dist/src/routes/apps-backup.d.ts.map +1 -0
  113. package/dist/src/routes/apps-backup.js +165 -0
  114. package/dist/src/routes/apps-backup.js.map +1 -0
  115. package/dist/src/routes/ghii.d.ts.map +1 -1
  116. package/dist/src/routes/ghii.js +4 -0
  117. package/dist/src/routes/ghii.js.map +1 -1
  118. package/dist/src/routes/instances.d.ts +2 -1
  119. package/dist/src/routes/instances.d.ts.map +1 -1
  120. package/dist/src/routes/instances.js +59 -1
  121. package/dist/src/routes/instances.js.map +1 -1
  122. package/dist/src/routes/memory.d.ts.map +1 -1
  123. package/dist/src/routes/memory.js +5 -0
  124. package/dist/src/routes/memory.js.map +1 -1
  125. package/dist/src/routes/packages.d.ts.map +1 -1
  126. package/dist/src/routes/packages.js +32 -0
  127. package/dist/src/routes/packages.js.map +1 -1
  128. package/dist/src/routes/permissions.d.ts +12 -0
  129. package/dist/src/routes/permissions.d.ts.map +1 -1
  130. package/dist/src/routes/permissions.js +35 -3
  131. package/dist/src/routes/permissions.js.map +1 -1
  132. package/dist/src/routes/portal.d.ts +3 -0
  133. package/dist/src/routes/portal.d.ts.map +1 -1
  134. package/dist/src/routes/portal.js +12 -0
  135. package/dist/src/routes/portal.js.map +1 -1
  136. package/dist/src/routes/public-stats.d.ts +15 -0
  137. package/dist/src/routes/public-stats.d.ts.map +1 -0
  138. package/dist/src/routes/public-stats.js +90 -0
  139. package/dist/src/routes/public-stats.js.map +1 -0
  140. package/dist/src/routes/sse.d.ts +7 -2
  141. package/dist/src/routes/sse.d.ts.map +1 -1
  142. package/dist/src/routes/sse.js +35 -5
  143. package/dist/src/routes/sse.js.map +1 -1
  144. package/dist/src/routes/stats.d.ts.map +1 -1
  145. package/dist/src/routes/stats.js +13 -0
  146. package/dist/src/routes/stats.js.map +1 -1
  147. package/dist/src/routes/subdomains.d.ts +33 -0
  148. package/dist/src/routes/subdomains.d.ts.map +1 -0
  149. package/dist/src/routes/subdomains.js +208 -0
  150. package/dist/src/routes/subdomains.js.map +1 -0
  151. package/dist/src/routes/workflows.d.ts +30 -0
  152. package/dist/src/routes/workflows.d.ts.map +1 -0
  153. package/dist/src/routes/workflows.js +178 -0
  154. package/dist/src/routes/workflows.js.map +1 -0
  155. package/dist/src/server-bootstrap/routes-loader.d.ts +2 -0
  156. package/dist/src/server-bootstrap/routes-loader.d.ts.map +1 -1
  157. package/dist/src/server-bootstrap/routes-loader.js +19 -2
  158. package/dist/src/server-bootstrap/routes-loader.js.map +1 -1
  159. package/dist/src/server-bootstrap/service-init.d.ts +2 -0
  160. package/dist/src/server-bootstrap/service-init.d.ts.map +1 -1
  161. package/dist/src/server-bootstrap/service-init.js +6 -0
  162. package/dist/src/server-bootstrap/service-init.js.map +1 -1
  163. package/dist/src/server.d.ts.map +1 -1
  164. package/dist/src/server.js +5 -0
  165. package/dist/src/server.js.map +1 -1
  166. package/dist/src/services/apps-backup-export.d.ts +22 -0
  167. package/dist/src/services/apps-backup-export.d.ts.map +1 -0
  168. package/dist/src/services/apps-backup-export.js +136 -0
  169. package/dist/src/services/apps-backup-export.js.map +1 -0
  170. package/dist/src/services/apps-backup-import.d.ts +120 -0
  171. package/dist/src/services/apps-backup-import.d.ts.map +1 -0
  172. package/dist/src/services/apps-backup-import.js +259 -0
  173. package/dist/src/services/apps-backup-import.js.map +1 -0
  174. package/dist/src/services/component-registrar.d.ts +17 -0
  175. package/dist/src/services/component-registrar.d.ts.map +1 -1
  176. package/dist/src/services/component-registrar.js +63 -5
  177. package/dist/src/services/component-registrar.js.map +1 -1
  178. package/dist/src/services/handbooks/agent.d.ts +1 -1
  179. package/dist/src/services/handbooks/agent.d.ts.map +1 -1
  180. package/dist/src/services/handbooks/agent.js +10 -0
  181. package/dist/src/services/handbooks/agent.js.map +1 -1
  182. package/dist/src/services/handbooks/appdev.d.ts +1 -1
  183. package/dist/src/services/handbooks/appdev.d.ts.map +1 -1
  184. package/dist/src/services/handbooks/appdev.js +5 -2
  185. package/dist/src/services/handbooks/appdev.js.map +1 -1
  186. package/dist/src/services/scheduler.d.ts +6 -0
  187. package/dist/src/services/scheduler.d.ts.map +1 -1
  188. package/dist/src/services/scheduler.js +22 -0
  189. package/dist/src/services/scheduler.js.map +1 -1
  190. package/dist/src/services/schema-validator.d.ts +9 -0
  191. package/dist/src/services/schema-validator.d.ts.map +1 -1
  192. package/dist/src/services/schema-validator.js +16 -0
  193. package/dist/src/services/schema-validator.js.map +1 -1
  194. package/dist/src/services/workflow/engine.d.ts +84 -0
  195. package/dist/src/services/workflow/engine.d.ts.map +1 -0
  196. package/dist/src/services/workflow/engine.js +545 -0
  197. package/dist/src/services/workflow/engine.js.map +1 -0
  198. package/dist/src/services/workflow/eval-context.d.ts +23 -0
  199. package/dist/src/services/workflow/eval-context.d.ts.map +1 -0
  200. package/dist/src/services/workflow/eval-context.js +52 -0
  201. package/dist/src/services/workflow/eval-context.js.map +1 -0
  202. package/dist/src/services/workflow/lifecycle.d.ts +38 -0
  203. package/dist/src/services/workflow/lifecycle.d.ts.map +1 -0
  204. package/dist/src/services/workflow/lifecycle.js +99 -0
  205. package/dist/src/services/workflow/lifecycle.js.map +1 -0
  206. package/dist/src/services/workflow/signal-eval.d.ts +70 -0
  207. package/dist/src/services/workflow/signal-eval.d.ts.map +1 -0
  208. package/dist/src/services/workflow/signal-eval.js +174 -0
  209. package/dist/src/services/workflow/signal-eval.js.map +1 -0
  210. package/dist/src/services/workflow/store.d.ts +89 -0
  211. package/dist/src/services/workflow/store.d.ts.map +1 -0
  212. package/dist/src/services/workflow/store.js +284 -0
  213. package/dist/src/services/workflow/store.js.map +1 -0
  214. package/dist/src/storage/interface.d.ts +13 -3
  215. package/dist/src/storage/interface.d.ts.map +1 -1
  216. package/dist/src/storage/interface.js.map +1 -1
  217. package/dist/src/storage/providers/mongodb/index.d.ts +10 -1
  218. package/dist/src/storage/providers/mongodb/index.d.ts.map +1 -1
  219. package/dist/src/storage/providers/mongodb/index.js +76 -0
  220. package/dist/src/storage/providers/mongodb/index.js.map +1 -1
  221. package/dist/src/storage/providers/sqlite/index.d.ts +8 -1
  222. package/dist/src/storage/providers/sqlite/index.d.ts.map +1 -1
  223. package/dist/src/storage/providers/sqlite/index.js +61 -0
  224. package/dist/src/storage/providers/sqlite/index.js.map +1 -1
  225. package/dist/src/storage/providers/sqlite/schema.d.ts.map +1 -1
  226. package/dist/src/storage/providers/sqlite/schema.js +11 -0
  227. package/dist/src/storage/providers/sqlite/schema.js.map +1 -1
  228. package/dist/src/storage/repositories/index.d.ts +1 -0
  229. package/dist/src/storage/repositories/index.d.ts.map +1 -1
  230. package/dist/src/storage/repositories/package.repository.d.ts +2 -0
  231. package/dist/src/storage/repositories/package.repository.d.ts.map +1 -1
  232. package/dist/src/storage/repositories/subdomain-site.repository.d.ts +19 -0
  233. package/dist/src/storage/repositories/subdomain-site.repository.d.ts.map +1 -0
  234. package/dist/src/storage/repositories/subdomain-site.repository.js +2 -0
  235. package/dist/src/storage/repositories/subdomain-site.repository.js.map +1 -0
  236. package/dist/static/app-catalog.html +1139 -28
  237. package/package.json +1 -1
  238. package/prisma/schema.postgres.prisma +11 -0
  239. package/prisma/schema.prisma +11 -0
@@ -0,0 +1,96 @@
1
+ /**
2
+ * @file start.css
3
+ * @description Styles for the /v1/start diagnosis page (st- prefix): hero,
4
+ * question cards with big option buttons, the answer trail, the verdict card,
5
+ * the playbook checklist (code blocks, prompt block, doors) and print rules
6
+ * so "Print / save as PDF" emits just the playbook. Theme tokens only.
7
+ * @version-history
8
+ * v1.0.0 — 2026-06-11 — Initial: jira entrance styles + print rules.
9
+ * v1.0.1 — 2026-06-12 — Scope print rules to body.st-active: view CSS is global (spa.html
10
+ * preload), so the unscoped `body * { visibility: hidden }` blanked printing on every view
11
+ * (e.g. the public workspace viewer printed 14 empty pages).
12
+ */
13
+
14
+ .st { max-width: 760px; margin: 0 auto; padding: 2rem 1.25rem 3rem; color: var(--text); }
15
+
16
+ /* ── Hero (intro phase) ── */
17
+ .st-hero { text-align: center; padding: 3rem 0 1.5rem; }
18
+ .st-h1 { font-size: 2.2rem; font-weight: 800; letter-spacing: -0.5px; margin: 0 0 .7rem; }
19
+ .st-hero-sub { color: var(--text-dim); font-size: 1.08rem; margin: 0 auto 1.6rem; max-width: 560px; }
20
+ .st-start-btn { font-size: 1.05rem; padding: .75rem 2rem; }
21
+ .st-hero-meta { margin-top: 1rem; font-size: .85rem; color: var(--muted); }
22
+
23
+ /* ── Compact header + trail (after intro) ── */
24
+ .st-header { margin-bottom: 1.5rem; }
25
+ .st-header-title { font-size: 1rem; font-weight: 700; color: var(--text-dim); margin-bottom: .6rem; }
26
+ .st-trail { display: flex; flex-wrap: wrap; gap: .4rem; }
27
+ .st-trail-chip { font-size: .78rem; padding: .25rem .6rem; border: 1px solid var(--border); border-radius: 999px; background: var(--card); color: var(--text-dim); max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
28
+
29
+ /* ── Question card ── */
30
+ .st-q { padding: .5rem 0; }
31
+ .st-q-title { font-size: 1.45rem; font-weight: 800; margin: 0 0 1.2rem; }
32
+ .st-opts { display: flex; flex-direction: column; gap: .7rem; }
33
+ .st-opt { text-align: left; font-size: 1rem; padding: .9rem 1.1rem; border: 1px solid var(--border); border-radius: 12px; background: var(--card); color: var(--text); cursor: pointer; transition: border-color .15s, transform .05s; font-family: inherit; }
34
+ .st-opt:hover { border-color: var(--accent); }
35
+ .st-opt:active { transform: scale(.99); }
36
+ .st-back { margin-top: 1.2rem; background: none; border: none; color: var(--text-dim); cursor: pointer; font-size: .88rem; padding: .3rem 0; font-family: inherit; }
37
+ .st-back:hover { color: var(--text); text-decoration: underline; }
38
+
39
+ /* ── Verdict ── */
40
+ .st-verdict { text-align: center; padding: .5rem 0; }
41
+ .st-verdict-label { font-size: .85rem; text-transform: uppercase; letter-spacing: 2px; color: var(--muted); margin-bottom: .7rem; }
42
+ .st-verdict-card { border: 2px solid var(--accent); border-radius: 14px; background: var(--card); padding: 1.6rem 1.5rem; margin-bottom: 1.2rem; }
43
+ .st-verdict-name { font-size: 1.7rem; font-weight: 800; margin-bottom: .6rem; }
44
+ .st-verdict-desc { color: var(--text-dim); font-size: 1.02rem; margin: 0 auto .8rem; max-width: 540px; }
45
+ .st-verdict-score { font-size: .85rem; color: var(--muted); }
46
+ .st-verdict-actions { display: flex; gap: .8rem; justify-content: center; flex-wrap: wrap; margin-bottom: .9rem; }
47
+ .st-verdict-note { color: var(--text-dim); font-size: .92rem; margin: 0; }
48
+
49
+ /* ── Playbook ── */
50
+ .st-pb-head { margin-bottom: 1.5rem; }
51
+ .st-pb-title { font-size: 1.7rem; font-weight: 800; margin: 0 0 .4rem; }
52
+ .st-pb-sub { color: var(--text-dim); margin: 0 0 .5rem; }
53
+ .st-pb-tier { font-size: .9rem; font-weight: 700; color: var(--accent); margin: 0; }
54
+ .st-pb-section { margin-bottom: 1.4rem; border: 1px solid var(--border); border-radius: 12px; background: var(--card); padding: 1rem 1.2rem; }
55
+ .st-pb-section h3 { margin: 0 0 .7rem; font-size: 1.05rem; }
56
+ .st-pb-items { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: .6rem; }
57
+ .st-pb-item { font-size: .95rem; }
58
+ .st-pb-check { display: flex; gap: .55rem; align-items: flex-start; cursor: pointer; }
59
+ .st-pb-check input { margin-top: .25rem; accent-color: var(--accent); flex: none; }
60
+ .st-pb-check input:checked + span { color: var(--text-dim); text-decoration: line-through; }
61
+ .st-pb-quote, .st-pb-prompt blockquote { margin: .3rem 0; padding: .6rem .9rem; border-left: 3px solid var(--accent); background: var(--bg-surface, var(--bg-dim)); border-radius: 6px; font-size: .92rem; }
62
+ .st-pb-code { display: flex; gap: .6rem; align-items: flex-start; margin-top: .4rem; }
63
+ .st-pb-code pre { flex: 1; margin: 0; padding: .65rem .9rem; border: 1px solid var(--border); border-radius: 8px; background: var(--bg-surface, var(--bg-dim)); font-size: .82rem; overflow-x: auto; white-space: pre-wrap; word-break: break-all; }
64
+ .st-pb-copy { flex: none; }
65
+ .st-pb-prompt { margin-top: .4rem; }
66
+ .st-pb-prompt .btn-primary { margin-top: .5rem; }
67
+ .st-pb-link { color: var(--accent); font-weight: 700; text-decoration: none; font-size: .92rem; }
68
+ .st-pb-link:hover { text-decoration: underline; }
69
+ .st-pb-actions { display: flex; gap: .8rem; flex-wrap: wrap; align-items: center; margin: 1.4rem 0; }
70
+
71
+ /* ── Doors ── */
72
+ .st-doors { margin-top: 2rem; padding-top: 1.4rem; border-top: 1px solid var(--border); }
73
+ .st-doors-title { font-size: 1.15rem; margin: 0 0 .3rem; }
74
+ .st-doors-sub { color: var(--text-dim); font-size: .9rem; margin: 0 0 1rem; }
75
+ .st-doors-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: .9rem; }
76
+ @media (max-width: 700px) { .st-doors-grid { grid-template-columns: 1fr; } }
77
+ .st-door { display: flex; flex-direction: column; gap: .3rem; border: 1px solid var(--border); border-radius: 12px; background: var(--card); padding: 1rem 1.1rem; text-decoration: none; color: var(--text); }
78
+ .st-door:hover { border-color: var(--accent); }
79
+ .st-door-name { font-weight: 700; }
80
+ .st-door-desc { font-size: .85rem; color: var(--text-dim); }
81
+
82
+ /* ── Footer ── */
83
+ .st-footer { margin-top: 2.5rem; padding-top: 1.2rem; border-top: 1px solid var(--border); text-align: center; font-size: .85rem; color: var(--text-dim); }
84
+ .st-footer a { color: var(--text-dim); }
85
+ .st-footer a:hover { color: var(--text); }
86
+
87
+ /* ── Print: emit only the playbook ──
88
+ * Scoped to body.st-active (added by start.js while the view is mounted): view CSS is preloaded
89
+ * globally in spa.html, so an unscoped `body *` rule here would blank printing on every view. */
90
+ @media print {
91
+ body.st-active * { visibility: hidden; }
92
+ body.st-active .st-print-area, body.st-active .st-print-area * { visibility: visible; }
93
+ body.st-active .st-print-area { position: absolute; top: 0; left: 0; width: 100%; }
94
+ body.st-active .st-no-print, body.st-active .st-no-print * { display: none !important; }
95
+ body.st-active .st-pb-section { break-inside: avoid; }
96
+ }
@@ -0,0 +1,111 @@
1
+ /**
2
+ * @file workflows.css
3
+ * @description Styles for Profile › Workflows (workflows-tab.js): the list of workflows with a
4
+ * health sparkline, the blueprint graph + recent runs detail, and the single-run per-step
5
+ * timeline. Prefix: wf-. Theme-token driven (no hardcoded colors) so it flips with dark/light.
6
+ * @version-history
7
+ * v1.0.0 -- 2026-06-13 -- Phase 9: initial workflows tab styles.
8
+ */
9
+
10
+ .wf-tab { display: flex; flex-direction: column; gap: 1.1rem; }
11
+ .wf-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 1rem; }
12
+ .wf-loading, .wf-empty { color: var(--text-dim); padding: 0.75rem 0; font-size: 0.92rem; }
13
+ .wf-error {
14
+ background: var(--danger-bg); color: var(--danger-fg);
15
+ border: 1px solid var(--danger-border, var(--border)); border-radius: var(--radius-sm); padding: 0.6rem 0.85rem;
16
+ }
17
+ .wf-muted { color: var(--text-dim); font-size: 0.82rem; }
18
+ .wf-section-title { font-size: 1rem; font-weight: 700; color: var(--text); margin: 0.5rem 0 0.1rem; }
19
+
20
+ /* ── badges ── */
21
+ .wf-badge {
22
+ display: inline-block; padding: 0.1rem 0.5rem; border-radius: var(--radius-full, 999px);
23
+ font-size: 0.72rem; font-weight: 700; line-height: 1.5;
24
+ }
25
+ .wf-badge--ok { background: var(--success-bg); color: var(--success-fg); }
26
+ .wf-badge--err { background: var(--danger-bg); color: var(--danger-fg); }
27
+ .wf-badge--run { background: var(--info-bg); color: var(--info-fg); }
28
+ .wf-badge--muted { background: var(--bg-dim); color: var(--text-dim); }
29
+
30
+ /* ── list ── */
31
+ .wf-card-list { display: flex; flex-direction: column; gap: 0.75rem; }
32
+ .wf-card {
33
+ display: flex; align-items: center; justify-content: space-between; gap: 1rem;
34
+ background: var(--card); border: 1px solid var(--border); border-radius: var(--radius); padding: 0.85rem 1rem;
35
+ }
36
+ .wf-card-main { flex: 1; cursor: pointer; display: flex; flex-direction: column; gap: 0.25rem; }
37
+ .wf-card-title { font-weight: 700; color: var(--text); display: flex; align-items: center; gap: 0.5rem; }
38
+ .wf-card-meta { font-size: 0.82rem; color: var(--text-dim); }
39
+ .wf-card-actions { display: flex; gap: 0.4rem; white-space: nowrap; }
40
+
41
+ /* ── sparkline ── */
42
+ .wf-spark { display: inline-flex; gap: 2px; margin-top: 0.2rem; align-items: flex-end; }
43
+ .wf-spark-bar { width: 7px; height: 14px; border-radius: 2px; display: inline-block; }
44
+ .wf-spark-bar--ok { background: var(--success-fg); }
45
+ .wf-spark-bar--err { background: var(--danger-fg); }
46
+ .wf-spark-bar--none { background: var(--bg-dim); }
47
+
48
+ /* ── detail ── */
49
+ .wf-detail-head { display: flex; align-items: center; gap: 0.75rem; flex-wrap: wrap; }
50
+ .wf-detail-title { font-size: 1.1rem; font-weight: 700; color: var(--text); flex: 1; }
51
+ .wf-detail-actions { display: flex; gap: 0.4rem; }
52
+
53
+ .wf-graph { display: flex; flex-direction: column; gap: 0.5rem; }
54
+ .wf-node {
55
+ background: var(--card); border: 1px solid var(--border); border-radius: var(--radius-sm);
56
+ padding: 0.6rem 0.8rem; display: flex; flex-direction: column; gap: 0.15rem;
57
+ }
58
+ .wf-node-id { font-weight: 700; color: var(--text); }
59
+ .wf-node-agent { font-size: 0.82rem; color: var(--text-dim); }
60
+ .wf-node-io { font-size: 0.78rem; color: var(--text-dim); font-family: var(--font-mono, monospace); }
61
+ .wf-node-dep { font-size: 0.74rem; color: var(--accent); }
62
+
63
+ .wf-table { width: 100%; border-collapse: collapse; font-size: 0.9rem; }
64
+ .wf-table td { padding: 0.5rem 0.6rem; border-bottom: 1px solid var(--border); color: var(--text); }
65
+ .wf-run-row { cursor: pointer; }
66
+ .wf-run-row:hover { background: var(--bg-dim); }
67
+
68
+ /* ── run timeline ── */
69
+ .wf-steps { display: flex; flex-direction: column; gap: 0.5rem; }
70
+ .wf-step {
71
+ background: var(--card); border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 0.55rem 0.8rem;
72
+ }
73
+ .wf-step-row { display: flex; align-items: center; gap: 0.6rem; }
74
+ .wf-step-id { font-weight: 600; color: var(--text); }
75
+ .wf-observed {
76
+ margin: 0.4rem 0 0; padding: 0.5rem 0.65rem; background: var(--bg-dim); border-radius: var(--radius-sm);
77
+ font-size: 0.76rem; color: var(--text-dim); overflow-x: auto; white-space: pre-wrap;
78
+ }
79
+ .wf-inspections {
80
+ margin-top: 0.5rem; padding: 0.5rem 0.7rem; background: var(--warn-bg); color: var(--warn-fg);
81
+ border-radius: var(--radius-sm); font-size: 0.82rem;
82
+ }
83
+
84
+ /* ── create/edit form ── */
85
+ .wf-form { display: flex; flex-direction: column; gap: 0.8rem; }
86
+ .wf-field { display: flex; flex-direction: column; gap: 0.25rem; }
87
+ .wf-field > span { font-size: 0.82rem; font-weight: 600; color: var(--text-dim); }
88
+ .wf-field input[type="text"], .wf-field input[type="number"], .wf-field select,
89
+ .wf-field-row input, .wf-field-row select {
90
+ background: var(--bg-input, var(--bg-dim)); color: var(--text);
91
+ border: 1px solid var(--border); border-radius: var(--radius-sm);
92
+ padding: 0.4rem 0.55rem; font: inherit;
93
+ }
94
+ .wf-field-row { display: flex; gap: 0.5rem; align-items: center; flex-wrap: wrap; }
95
+ .wf-field-row > input, .wf-field-row > select { flex: 1; min-width: 8rem; }
96
+ .wf-form-section {
97
+ border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 0.7rem 0.85rem;
98
+ display: flex; flex-direction: column; gap: 0.55rem;
99
+ }
100
+ .wf-form-section-head { display: flex; justify-content: space-between; align-items: center; font-weight: 700; color: var(--text); }
101
+ .wf-step-edit {
102
+ border-left: 2px solid var(--accent-soft, var(--border)); padding-left: 0.7rem;
103
+ display: flex; flex-direction: column; gap: 0.4rem;
104
+ }
105
+ .wf-step-opts { font-size: 0.82rem; color: var(--text-dim); }
106
+ .wf-step-after { display: flex; flex-wrap: wrap; gap: 0.6rem; align-items: center; font-size: 0.82rem; }
107
+ .wf-inline { display: inline-flex; align-items: center; gap: 0.3rem; color: var(--text); }
108
+ .wf-inline input[type="number"] { width: 4.5rem; background: var(--bg-input, var(--bg-dim)); color: var(--text); border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 0.2rem 0.4rem; }
109
+ .wf-llm-toggle { margin-top: 0.2rem; font-size: 0.9rem; }
110
+ .wf-form-actions { display: flex; justify-content: flex-end; gap: 0.5rem; margin-top: 0.4rem; }
111
+ .wf-err-list { margin: 0; padding-left: 1.1rem; }
Binary file
@@ -1,31 +1,46 @@
1
- import { h } from 'preact';
2
- import htm from 'htm';
3
- const html = htm.bind(h);
4
- import { t } from '/js/i18n.js';
5
-
6
- /**
7
- * TagCloud — clickable tag filter pills.
8
- * @param {Object} props
9
- * @param {string[]} props.tags — all available tags (will be sorted)
10
- * @param {Set<string>} props.selected — currently active filter tags
11
- * @param {(tag: string) => void} props.onToggle — called when a tag is clicked
12
- * @param {() => void} props.onClear — called when clear button is clicked
13
- */
14
- export default function TagCloud({ tags, selected, onToggle, onClear }) {
15
- if (!tags || tags.length === 0) return null;
16
- const sorted = [...tags].sort();
17
- return html`
18
- <div class="tag-cloud">
19
- ${sorted.map(tag => html`
20
- <button key=${tag}
21
- class="tag-pill ${selected.has(tag) ? 'active' : ''}"
22
- onClick=${() => onToggle(tag)}>
23
- ${tag}
24
- </button>
25
- `)}
26
- ${selected.size > 0 && html`
27
- <button class="tag-pill tag-clear" onClick=${onClear}>\u2715 ${t('tags.clear') || 'Clear'}</button>
28
- `}
29
- </div>
30
- `;
31
- }
1
+ import { h } from 'preact';
2
+ import { useState } from 'preact/hooks';
3
+ import htm from 'htm';
4
+ const html = htm.bind(h);
5
+ import { t } from '/js/i18n.js';
6
+
7
+ /**
8
+ * TagCloud — clickable tag filter pills.
9
+ * @param {Object} props
10
+ * @param {string[]} props.tags — available tags. Pre-sorted order is respected when
11
+ * `limit` is set (pass most-used first); otherwise sorted alphabetically.
12
+ * @param {Set<string>} props.selected — currently active filter tags
13
+ * @param {(tag: string) => void} props.onToggle — called when a tag is clicked
14
+ * @param {() => void} props.onClear — called when clear button is clicked
15
+ * @param {number} [props.limit] — show only the first N tags behind a "show all" toggle.
16
+ * Selected tags always stay visible so an active filter can't hide its own pill.
17
+ */
18
+ export default function TagCloud({ tags, selected, onToggle, onClear, limit }) {
19
+ const [showAll, setShowAll] = useState(false);
20
+ if (!tags || tags.length === 0) return null;
21
+ const ordered = limit ? [...tags] : [...tags].sort();
22
+ const capped = limit && !showAll && ordered.length > limit;
23
+ const visible = capped ? ordered.filter((tag, i) => i < limit || selected.has(tag)) : ordered;
24
+ return html`
25
+ <div class="tag-cloud">
26
+ ${visible.map(tag => html`
27
+ <button key=${tag}
28
+ class="tag-pill ${selected.has(tag) ? 'active' : ''}"
29
+ onClick=${() => onToggle(tag)}>
30
+ ${tag}
31
+ </button>
32
+ `)}
33
+ ${capped && html`
34
+ <button class="tag-pill tag-more" onClick=${() => setShowAll(true)}>
35
+ ${(t('profile.memory.showAllTags') || 'Show all ({n})').replace('{n}', String(ordered.length))}
36
+ </button>
37
+ `}
38
+ ${limit && showAll && ordered.length > limit && html`
39
+ <button class="tag-pill tag-more" onClick=${() => setShowAll(false)}>${t('profile.memory.fewerTags') || 'Show fewer'}</button>
40
+ `}
41
+ ${selected.size > 0 && html`
42
+ <button class="tag-pill tag-clear" onClick=${onClear}>✕ ${t('tags.clear') || 'Clear'}</button>
43
+ `}
44
+ </div>
45
+ `;
46
+ }
@@ -29,8 +29,8 @@ export default function TagEditor({ tags, onSave, maxTags = 20 }) {
29
29
  <div class="tag-editor">
30
30
  <div class="tag-editor-pills">
31
31
  ${tags.map(tag => html`
32
- <span class="tag-pill active" key=${tag} onClick=${() => removeTag(tag)}>
33
- ${tag} \u2715
32
+ <span class="tag-pill tag-removable" key=${tag} onClick=${() => removeTag(tag)}>
33
+ ${tag} <span class="tag-x">\u2715</span>
34
34
  </span>
35
35
  `)}
36
36
  </div>
@@ -0,0 +1,40 @@
1
+ /**
2
+ * @file recents.js
3
+ * @description "Continue" list backing store — the last opened things (workspaces, apps,
4
+ * organisms, …) across types, so the profile home can offer one-click returns with real
5
+ * display names. Device-local by design (localStorage): what you opened HERE.
6
+ * @structure
7
+ * - recordRecent(item) — upsert by type+id to the front, capped at 12
8
+ * - listRecents(n) — newest first
9
+ * @usage
10
+ * import { recordRecent, listRecents } from '/js/recents.js';
11
+ * recordRecent({ type: 'workspace', id: orgId + '/' + wsId, label: wsName, sub: orgName, data: { orgId, wsId } });
12
+ * @version-history
13
+ * v1.0.0 — 2026-06-10 — Initial: localStorage-backed cross-type recents for the home dashboard.
14
+ */
15
+
16
+ const KEY = 'aimeat.recents';
17
+ const CAP = 12;
18
+
19
+ function readAll() {
20
+ try {
21
+ const raw = localStorage.getItem(KEY);
22
+ const list = raw ? JSON.parse(raw) : [];
23
+ return Array.isArray(list) ? list : [];
24
+ } catch { return []; }
25
+ }
26
+
27
+ /** Record a visit. item: { type, id, label, sub?, data? } — type+id is the identity. */
28
+ export function recordRecent(item) {
29
+ if (!item || !item.type || !item.id || !item.label) return;
30
+ try {
31
+ const list = readAll().filter(x => !(x.type === item.type && x.id === item.id));
32
+ list.unshift({ type: item.type, id: item.id, label: item.label, sub: item.sub || '', data: item.data || {}, at: new Date().toISOString() });
33
+ localStorage.setItem(KEY, JSON.stringify(list.slice(0, CAP)));
34
+ } catch { /* recents are a convenience — never break the caller */ }
35
+ }
36
+
37
+ /** Newest-first recents, capped at n. */
38
+ export function listRecents(n = 5) {
39
+ return readAll().slice(0, n);
40
+ }
@@ -269,3 +269,9 @@ export const getAdminAgentTasks = (params = {}) => {
269
269
 
270
270
  // ── Sharing Groups (admin) ──
271
271
  export const getAdminSharingGroups = () => apiGet('/v1/admin/sharing-groups');
272
+
273
+ // ── Subdomain mappings (operator) ──
274
+ export const getSubdomainSites = () => apiGet('/v1/admin/subdomains');
275
+ export const createSubdomainSite = (body) => apiPost('/v1/admin/subdomains', body);
276
+ export const updateSubdomainSite = (sub, updates) => apiPatch(`/v1/admin/subdomains/${encodeURIComponent(sub)}`, updates);
277
+ export const deleteSubdomainSite = (sub) => apiDelete(`/v1/admin/subdomains/${encodeURIComponent(sub)}`);
@@ -11,6 +11,40 @@ export async function listAgents(owner) {
11
11
  return owner ? list.filter(a => a.owner === owner) : list;
12
12
  }
13
13
 
14
+ /** Workspace-contract advertising via owner-managed agent tags (colon-free — the server tag
15
+ * pattern allows only [a-z0-9._-]): the tag 'workspace-contract' marks an agent as a contract
16
+ * provider, and 'contract.<name>' tags name the contract(s) it serves. Convention documented in
17
+ * docs/agent-workspace-contracts.md; agents set tags via aimeat_agent_tags_set / PATCH tags. */
18
+ export const offersWorkspaceContract = (a) => (a?.tags || []).includes('workspace-contract');
19
+
20
+ /** The contract names an agent advertises ('contract.<name>' tags, prefix stripped). */
21
+ export const contractNamesOf = (a) => (a?.tags || [])
22
+ .filter(tg => String(tg).startsWith('contract.'))
23
+ .map(tg => String(tg).slice('contract.'.length));
24
+
25
+ /** One-click contract adoption: queue the agreed adopt-contract TASK for one of the owner's
26
+ * agents. The agent recognises it from scope[kind]='adopt-contract' (NOT the title), joins the
27
+ * organism if needed, provisions its contract's spaces itself (workspace_update add_spaces from
28
+ * its OWN contract declaration — §2 of the guide), and completes the task with what was added.
29
+ * Convention: docs/agent-workspace-contracts.md §7c — agreed with the crewaimeat side 2026-06-10. */
30
+ export async function adoptContractTask(agentName, { organismId, ws, contract }) {
31
+ const { createTask } = await import('/js/services/agent-tasks.js');
32
+ return createTask(agentName, {
33
+ title: `adopt-contract: ${contract || 'workspace-contract'} → ${ws}`,
34
+ description: `Adopt your '${contract || ''}' contract into workspace ${ws} of organism ${organismId}: join the organism if needed, provision the contract's spaces (workspace_update add_spaces from your own contract declaration), then complete this task with what was added.`,
35
+ // 'queued' is REQUIRED: without it the task is created as a draft and never auto-activates.
36
+ // A task-runner-mode agent flips queued → active immediately (push over the tunnel); other
37
+ // modes keep the standard queued → owner-start gate. (crewaimeat live-test finding 2026-06-10.)
38
+ status: 'queued',
39
+ scope: [
40
+ { name: 'kind', value: 'adopt-contract', type: 'text' },
41
+ { name: 'organism_id', value: organismId, type: 'text' },
42
+ { name: 'ws', value: ws, type: 'text' },
43
+ ...(contract ? [{ name: 'contract', value: contract, type: 'text' }] : []),
44
+ ],
45
+ });
46
+ }
47
+
14
48
  /** List chat session agents (name starts with 'session-'). */
15
49
  export async function listChatSessions(owner) {
16
50
  const agents = await listAgents(owner);
@@ -0,0 +1,152 @@
1
+ /**
2
+ * @file offers.js
3
+ * @description Frontend service for the Agent Offers surface ("what can I do with my agents"). Reads
4
+ * the owner aggregate feed + per-agent offers, and the mode-aware Ask: a schedule-born offer triggers
5
+ * its schedule; a task-runner/autonomous agent runs a task; an interactive/workstation agent gets a
6
+ * paste-ready prompt (AIMEAT's prompt-driven flow). See docs/plans/2026-06-12-agent-offers-*.md.
7
+ * @structure listOffers / getAgentOffers / publishOffers · ask(agentEntry, offer, inputs) · buildAskPrompt
8
+ * @usage import * as offers from '/js/services/offers.js';
9
+ * @version-history
10
+ * v1.0.0 -- 2026-06-12 -- Initial: Do feed + mode-aware Ask (run / copy-prompt / schedule-trigger).
11
+ * v1.1.0 -- 2026-06-12 -- Billable offers: setOfferBilling (patch one offer's price + visibility).
12
+ * v1.2.0 -- 2026-06-12 -- Inbox fixes: deliverable read from the AGENT namespace (prefix + task-tag
13
+ * fallback, returns a string); Ask task title carries the user's request (findable in the queue).
14
+ * v1.3.0 -- 2026-06-12 -- Offer task carries ONLY the user's request (title + description); the offer
15
+ * is referenced via scope.offer_id/offer_title — no more restuffing offer.ask/example (which made
16
+ * the agent treat its own boilerplate as the request).
17
+ */
18
+ import { apiGet, apiPost, apiPut } from '/js/api.js';
19
+ import { copyToClipboard } from '/js/utils.js';
20
+ import { createTask, rateTask } from '/js/services/agent-tasks.js';
21
+
22
+ /** The goal-first feed: every agent's offers + mode/availability. */
23
+ export async function listOffers() {
24
+ return apiGet('/v1/offers');
25
+ }
26
+
27
+ /** One agent's published offers. */
28
+ export async function getAgentOffers(name) {
29
+ return apiGet(`/v1/agents/${encodeURIComponent(name)}/offers`);
30
+ }
31
+
32
+ /** Publish/replace an agent's offers (agent self or owner). */
33
+ export async function publishOffers(name, doc) {
34
+ return apiPut(`/v1/agents/${encodeURIComponent(name)}/offers`, doc);
35
+ }
36
+
37
+ /** Owner edits ONE offer's billing fields (price + visibility), preserving the rest of the doc.
38
+ * Re-reads the agent's current offers first (avoid clobbering a stale feed), patches, re-publishes.
39
+ * `price` is `{ morsels, unit }` or `null` (not for sale); `visibility` is private|unlisted|public. */
40
+ export async function setOfferBilling(name, offerId, { price, visibility }) {
41
+ const cur = await getAgentOffers(name);
42
+ const offers = (cur?.data?.offers || []).map(o => o.id === offerId
43
+ ? { ...o, ...(price !== undefined ? { price } : {}), ...(visibility !== undefined ? { visibility } : {}) }
44
+ : o);
45
+ return publishOffers(name, { offers });
46
+ }
47
+
48
+ /** The Inbox feed: everything that came back across all agents (non-draft tasks, newest first). */
49
+ export async function listDeliverables() {
50
+ return apiGet('/v1/deliverables');
51
+ }
52
+
53
+ /** Fetch a task's deliverable from the AGENT's memory namespace (owner→agent read).
54
+ * Deliverables live under the agent's GAII, not the owner's, so we read via
55
+ * `?agent=<gaii>`. Primary handle is the recorded `deliverableKey`; fallback is the
56
+ * `task:<id>` tag the runner stamps on every write (works even when the agent never
57
+ * set deliverableKey — e.g. CrewAI agents that only publish to memory). Returns the
58
+ * deliverable value as a string, or null if nothing was found. Mirrors the proven
59
+ * read in agents-tasks-subtab.js. */
60
+ export async function getDeliverableContent({ agentGaii, deliverableKey, taskId }) {
61
+ if (!agentGaii) return null;
62
+ const enc = encodeURIComponent;
63
+ const reqs = [];
64
+ if (deliverableKey) reqs.push(apiGet(`/v1/memory?agent=${enc(agentGaii)}&prefix=${enc(deliverableKey)}&per_page=5`).catch(() => null));
65
+ if (taskId) reqs.push(apiGet(`/v1/memory?agent=${enc(agentGaii)}&tags=${enc('task:' + taskId)}&per_page=50`).catch(() => null));
66
+ const results = await Promise.all(reqs);
67
+ const items = [];
68
+ const seen = new Set();
69
+ for (const r of results) {
70
+ const list = r?.data?.items || r?.data || [];
71
+ for (const it of (Array.isArray(list) ? list : [])) {
72
+ if (it.key && !seen.has(it.key)) { seen.add(it.key); items.push(it); }
73
+ }
74
+ }
75
+ if (!items.length) return null;
76
+ const len = (v) => (typeof v === 'string' ? v.length : 0);
77
+ // Prefer the exact deliverableKey, then an *output key, then the longest text value.
78
+ const pick = items.find(i => i.key === deliverableKey)
79
+ || items.find(i => /(latest_)?output$/.test(i.key))
80
+ || items.slice().sort((a, b) => len(b.value) - len(a.value))[0];
81
+ const v = pick?.value;
82
+ if (v == null) return null;
83
+ return typeof v === 'string' ? v : JSON.stringify(v, null, 2);
84
+ }
85
+
86
+ /** Rate a done task's deliverable via the LOCKED rate endpoint (→ agents.<agent>.statistics.*).
87
+ * Owner ratings bypass source-grounding; we still send source_grounded:true (the owner saw it). */
88
+ export async function rateDeliverable(agent, taskId, { stars, comment, context = 'other' }) {
89
+ return rateTask(agent, taskId, { stars, context, comment, source_grounded: true });
90
+ }
91
+
92
+ /** Compose the paste-ready prompt for an interactive/workstation agent (prompt-driven Ask). */
93
+ export function buildAskPrompt(agentEntry, offer, inputs) {
94
+ const lines = [
95
+ `You are the agent "${agentEntry.agent}". I'm asking you to perform one of your offers.`,
96
+ ``,
97
+ `OFFER: ${offer.title}`,
98
+ `WHAT I'M ASKING: ${offer.ask}`,
99
+ ];
100
+ if (offer.example) lines.push(`EXAMPLE OF A REQUEST LIKE THIS: ${offer.example}`);
101
+ if (inputs && String(inputs).trim()) lines.push(``, `MY REQUEST: ${String(inputs).trim()}`);
102
+ if (offer.deliverable?.format) lines.push(``, `DELIVER: a ${offer.deliverable.format}${offer.deliverable.location?.space ? ` in ${offer.deliverable.location.space}` : ''}.`);
103
+ lines.push(``, `Do exactly this offer and nothing outside its scope. When done, write the deliverable and tell me where it is.`);
104
+ return lines.join('\n');
105
+ }
106
+
107
+ function scheduleIdOf(offer) {
108
+ const sb = offer?.availability?.scheduleBorn;
109
+ if (!sb) return null;
110
+ return typeof sb === 'object' ? (sb.scheduleId || null) : null; // string form is a human label only
111
+ }
112
+
113
+ /**
114
+ * Mode-aware Ask. Branch order: schedule-born first (independent of mode), then by agent mode.
115
+ * Returns one of:
116
+ * { kind: 'triggered' } — schedule-born → ran the schedule now
117
+ * { kind: 'task', taskId, agent } — task-runner/autonomous → created a queued task
118
+ * { kind: 'prompt', copied: true, prompt } — interactive/workstation → copied a paste-ready prompt
119
+ */
120
+ export async function ask(agentEntry, offer, inputs) {
121
+ const scheduleId = scheduleIdOf(offer);
122
+ if (scheduleId) {
123
+ const r = await apiPost(`/v1/schedules/${encodeURIComponent(scheduleId)}/trigger`, {});
124
+ return { kind: 'triggered', ok: r?.ok !== false, error: r?.error };
125
+ }
126
+
127
+ const mode = agentEntry.mode || 'interactive';
128
+ if (mode === 'task-runner' || mode === 'autonomous') {
129
+ // The agent ALREADY owns the offer (it published it). Do NOT restuff offer.ask/example into the
130
+ // task — that makes the agent treat its own boilerplate as the request (e.g. jokes ABOUT four
131
+ // comedians instead of jokes on the topic). The task carries ONLY the user's request as title +
132
+ // description; the offer is referenced structurally via scope (the runtime resolves it by offer_id).
133
+ const reqText = inputs ? String(inputs).trim() : '';
134
+ const title = reqText ? (reqText.length > 80 ? reqText.slice(0, 80) + '…' : reqText) : offer.title;
135
+ const r = await createTask(agentEntry.agent, {
136
+ title,
137
+ description: reqText,
138
+ status: 'queued', // REQUIRED so a task-runner auto-activates it (other modes keep the owner-start gate)
139
+ scope: [
140
+ { name: 'kind', value: 'offer', type: 'text' },
141
+ { name: 'offer_id', value: offer.id, type: 'text' },
142
+ { name: 'offer_title', value: offer.title, type: 'text' },
143
+ ],
144
+ });
145
+ return { kind: 'task', taskId: r?.data?.task?.id || r?.data?.id, agent: agentEntry.agent, ok: r?.ok !== false, error: r?.error };
146
+ }
147
+
148
+ // interactive / workstation → prompt-driven
149
+ const prompt = buildAskPrompt(agentEntry, offer, inputs);
150
+ await copyToClipboard(prompt);
151
+ return { kind: 'prompt', copied: true, prompt };
152
+ }
@@ -27,6 +27,7 @@ export const createPackage = (data) => apiPost('/v1/packages', data);
27
27
  export const createVersion = (groupId, data) => apiPost(`/v1/packages/${enc(groupId)}/versions`, data);
28
28
  export const updatePackage = (groupId, data) => apiPatch(`/v1/packages/${enc(groupId)}`, data);
29
29
  export const archiveVersion = (groupId, version) => apiDelete(`/v1/packages/${enc(groupId)}/versions/${enc(version)}`);
30
+ export const archivePackageGroup = (groupId) => apiDelete(`/v1/packages/${enc(groupId)}`);
30
31
 
31
32
  // ── Instances ──
32
33
  export const listInstances = (params) => apiGet('/v1/instances' + buildQuery(params));
@@ -0,0 +1,57 @@
1
+ /**
2
+ * @file workflows.js
3
+ * @description Frontend API service for Agent Workflows (Profile › Workflows tab). Wraps the
4
+ * /v1/workflows endpoints (list / get / blueprint / runs / run / health). All functions return
5
+ * the AIMEAT envelope; callers read `res.data`.
6
+ * @usage import { listWorkflows, getBlueprint, runWorkflow } from '/js/services/workflows.js';
7
+ * @version-history
8
+ * v1.0.0 -- 2026-06-13 -- Phase 9: initial workflows service for the profile tab.
9
+ */
10
+ import { apiGet, apiPost, apiPut, apiDelete } from '/js/api.js';
11
+
12
+ /** Create/update a workflow definition (PUT /v1/workflows/:id). Returns the envelope. */
13
+ export async function putWorkflow(id, def) {
14
+ return apiPut(`/v1/workflows/${encodeURIComponent(id)}`, def);
15
+ }
16
+
17
+ export async function deleteWorkflow(id) {
18
+ return apiDelete(`/v1/workflows/${encodeURIComponent(id)}`);
19
+ }
20
+
21
+ /** Read one agent's published offers (to pick a workflow-compatible offer in the form). */
22
+ export async function getAgentOffers(agentName) {
23
+ return apiGet(`/v1/agents/${encodeURIComponent(agentName)}/offers`);
24
+ }
25
+
26
+ /** List the owner's workflow definitions: { workflows, count }. */
27
+ export async function listWorkflows() {
28
+ return apiGet('/v1/workflows');
29
+ }
30
+
31
+ export async function getWorkflow(id) {
32
+ return apiGet(`/v1/workflows/${encodeURIComponent(id)}`);
33
+ }
34
+
35
+ /** Derived structural graph: { workflowId, nodes, edges }. */
36
+ export async function getBlueprint(id) {
37
+ return apiGet(`/v1/workflows/${encodeURIComponent(id)}/blueprint`);
38
+ }
39
+
40
+ /** Run-health trend over recent runs: { sample, lastStatus, steps:[{stepId,green,red}] , … }. */
41
+ export async function getHealth(id) {
42
+ return apiGet(`/v1/workflows/${encodeURIComponent(id)}/health`);
43
+ }
44
+
45
+ /** List runs (newest first): { runs, count }. */
46
+ export async function listRuns(id) {
47
+ return apiGet(`/v1/workflows/${encodeURIComponent(id)}/runs`);
48
+ }
49
+
50
+ export async function getRun(id, runId) {
51
+ return apiGet(`/v1/workflows/${encodeURIComponent(id)}/runs/${encodeURIComponent(runId)}`);
52
+ }
53
+
54
+ /** Start a run. mode: 'signals-only' | 'full'. Returns { runId, mode }. */
55
+ export async function runWorkflow(id, mode, vars) {
56
+ return apiPost(`/v1/workflows/${encodeURIComponent(id)}/run`, { mode, ...(vars ? { vars } : {}) });
57
+ }
@@ -385,6 +385,13 @@ for completeness but are NOT needed for typical app building:
385
385
  - Packages (versioned bundles), Knowledge packages
386
386
  - Federation (node peering, cross-node routing)
387
387
  - Agent collaboration (shared memory, organisms)
388
+ - Agent Workflows: declared, ordered agent pipelines with per-step input/output signals checked
389
+ after each step, so the owner sees whether each step PRODUCED (not just fired). One trigger
390
+ (schedule / manual / event) drives the chain; each step names an agent + an offer and inherits
391
+ that offer's signals + deliverable location. Connected agents use aimeat_workflow_save / _get /
392
+ _run (signals-only = check vs memory, no dispatch; full = execute). Stored in owner memory
393
+ (workflows.def.* / workflows.run.*); API under /v1/workflows. Plan:
394
+ docs/plans/2026-06-13-agent-workflows-node-plan.md.
388
395
  - Organism workspaces: an organism can hold manifest-driven workspaces of markdown documents
389
396
  (a wiki) and schema-locked record lists, with a draft -> publish -> version flow. Connected
390
397
  agents use the aimeat_workspace_* MCP tools (list / read / write / publish / object_delete /