aimeat 1.33.2 → 1.34.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 (291) hide show
  1. package/dist/locales/en.json +388 -14
  2. package/dist/locales/fi.json +388 -14
  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 +412 -2
  9. package/dist/public/js/services/apps.js +4 -2
  10. package/dist/public/js/services/memory.js +9 -3
  11. package/dist/public/js/services/offers.js +1 -1
  12. package/dist/public/js/services/organisms.js +49 -17
  13. package/dist/public/js/services/secretary-helpers.js +262 -17
  14. package/dist/public/js/services/secretary-policy.js +1 -0
  15. package/dist/public/js/services/secretary-rules.js +70 -0
  16. package/dist/public/js/theme.js +20 -0
  17. package/dist/public/lib/VENDORED-STYLING.md +31 -0
  18. package/dist/public/lib/aimeat-daisyui-bridge.css +48 -0
  19. package/dist/public/lib/chartjs@4.js +14 -0
  20. package/dist/public/lib/daisyui@5.css +7 -0
  21. package/dist/public/lib/tailwindcss@4.js +8 -0
  22. package/dist/public/llms-template.txt +9 -6
  23. package/dist/public/showroom.html +104 -0
  24. package/dist/public/showroom.js +247 -0
  25. package/dist/public/spa.html +18 -16
  26. package/dist/public/views/aimeat-os.js +3 -2
  27. package/dist/public/views/landing.js +50 -6
  28. package/dist/public/views/profile/agents/agent-card.js +7 -0
  29. package/dist/public/views/profile/agents/state-detector.js +6 -0
  30. package/dist/public/views/profile/agents/tab-integration.js +6 -0
  31. package/dist/public/views/profile/apps-tab.js +46 -0
  32. package/dist/public/views/profile/extensions-tab.js +4 -0
  33. package/dist/public/views/profile/inbox-tab.js +1 -1
  34. package/dist/public/views/profile/landing-page.js +8 -3
  35. package/dist/public/views/profile/memory-tab.js +37 -6
  36. package/dist/public/views/profile/organisms/home.js +32 -0
  37. package/dist/public/views/profile/organisms/workspace-list.js +36 -5
  38. package/dist/public/views/profile/organisms/workspace.js +29 -4
  39. package/dist/public/views/profile/organisms-tab.js +61 -8
  40. package/dist/public/views/secretary/calendar.js +327 -0
  41. package/dist/public/views/secretary/cards-reach.js +16 -17
  42. package/dist/public/views/secretary/cards.js +173 -66
  43. package/dist/public/views/secretary/dashboard.js +551 -0
  44. package/dist/public/views/secretary/quality.js +156 -0
  45. package/dist/public/views/secretary/use-autonomy.js +17 -2
  46. package/dist/public/views/secretary/use-freshness.js +50 -0
  47. package/dist/public/views/secretary/use-intake.js +23 -4
  48. package/dist/public/views/secretary/use-layout.js +122 -0
  49. package/dist/public/views/secretary/use-quick-actions.js +98 -0
  50. package/dist/public/views/secretary/use-specialists.js +103 -0
  51. package/dist/public/views/secretary/use-triggers.js +159 -0
  52. package/dist/public/views/secretary/use-whats-next.js +340 -0
  53. package/dist/public/views/secretary/workflow-design.js +112 -0
  54. package/dist/public/views/secretary.js +663 -39
  55. package/dist/scripts/check-no-max-tokens.d.ts +2 -0
  56. package/dist/scripts/check-no-max-tokens.d.ts.map +1 -0
  57. package/dist/scripts/check-no-max-tokens.js +71 -0
  58. package/dist/scripts/check-no-max-tokens.js.map +1 -0
  59. package/dist/src/data/aimeat-iam-package.d.ts +25 -0
  60. package/dist/src/data/aimeat-iam-package.d.ts.map +1 -0
  61. package/dist/src/data/aimeat-iam-package.js +312 -0
  62. package/dist/src/data/aimeat-iam-package.js.map +1 -0
  63. package/dist/src/data/aimeat-marketplace-package.d.ts +25 -0
  64. package/dist/src/data/aimeat-marketplace-package.d.ts.map +1 -0
  65. package/dist/src/data/aimeat-marketplace-package.js +231 -0
  66. package/dist/src/data/aimeat-marketplace-package.js.map +1 -0
  67. package/dist/src/data/app-templates.d.ts +48 -0
  68. package/dist/src/data/app-templates.d.ts.map +1 -0
  69. package/dist/src/data/app-templates.js +856 -0
  70. package/dist/src/data/app-templates.js.map +1 -0
  71. package/dist/src/data/example-packages.d.ts.map +1 -1
  72. package/dist/src/data/example-packages.js +3 -1
  73. package/dist/src/data/example-packages.js.map +1 -1
  74. package/dist/src/generated/api-types.d.ts +380 -5
  75. package/dist/src/generated/api-types.d.ts.map +1 -1
  76. package/dist/src/generated/prisma-postgres/edge.js +10 -3
  77. package/dist/src/generated/prisma-postgres/index-browser.js +7 -0
  78. package/dist/src/generated/prisma-postgres/index.d.ts +205 -2
  79. package/dist/src/generated/prisma-postgres/index.js +10 -3
  80. package/dist/src/generated/prisma-postgres/package.json +1 -1
  81. package/dist/src/generated/prisma-postgres/schema.prisma +23 -13
  82. package/dist/src/generated/prisma-postgres/wasm.js +10 -3
  83. package/dist/src/mcp/annotations.d.ts.map +1 -1
  84. package/dist/src/mcp/annotations.js +1 -0
  85. package/dist/src/mcp/annotations.js.map +1 -1
  86. package/dist/src/mcp/catalog/definitions.d.ts.map +1 -1
  87. package/dist/src/mcp/catalog/definitions.js +16 -1
  88. package/dist/src/mcp/catalog/definitions.js.map +1 -1
  89. package/dist/src/mcp/catalog/surfaces.js +3 -3
  90. package/dist/src/mcp/catalog/surfaces.js.map +1 -1
  91. package/dist/src/mcp/index.d.ts +3 -0
  92. package/dist/src/mcp/index.d.ts.map +1 -1
  93. package/dist/src/mcp/index.js +11 -0
  94. package/dist/src/mcp/index.js.map +1 -1
  95. package/dist/src/mcp/organisms.d.ts.map +1 -1
  96. package/dist/src/mcp/organisms.js +48 -8
  97. package/dist/src/mcp/organisms.js.map +1 -1
  98. package/dist/src/mcp/workspaces.d.ts.map +1 -1
  99. package/dist/src/mcp/workspaces.js +6 -4
  100. package/dist/src/mcp/workspaces.js.map +1 -1
  101. package/dist/src/models/offer-schemas.d.ts +8 -8
  102. package/dist/src/routes/ai.d.ts +8 -4
  103. package/dist/src/routes/ai.d.ts.map +1 -1
  104. package/dist/src/routes/ai.js +38 -14
  105. package/dist/src/routes/ai.js.map +1 -1
  106. package/dist/src/routes/app-grants.d.ts +2 -0
  107. package/dist/src/routes/app-grants.d.ts.map +1 -1
  108. package/dist/src/routes/app-grants.js +7 -1
  109. package/dist/src/routes/app-grants.js.map +1 -1
  110. package/dist/src/routes/app-templates.d.ts +16 -0
  111. package/dist/src/routes/app-templates.d.ts.map +1 -0
  112. package/dist/src/routes/app-templates.js +40 -0
  113. package/dist/src/routes/app-templates.js.map +1 -0
  114. package/dist/src/routes/apps.d.ts.map +1 -1
  115. package/dist/src/routes/apps.js +55 -5
  116. package/dist/src/routes/apps.js.map +1 -1
  117. package/dist/src/routes/auth.d.ts +3 -0
  118. package/dist/src/routes/auth.d.ts.map +1 -1
  119. package/dist/src/routes/auth.js +9 -4
  120. package/dist/src/routes/auth.js.map +1 -1
  121. package/dist/src/routes/bootstrap.d.ts.map +1 -1
  122. package/dist/src/routes/bootstrap.js +1 -0
  123. package/dist/src/routes/bootstrap.js.map +1 -1
  124. package/dist/src/routes/generator.d.ts.map +1 -1
  125. package/dist/src/routes/generator.js +3 -2
  126. package/dist/src/routes/generator.js.map +1 -1
  127. package/dist/src/routes/lib-ai.d.ts +0 -1
  128. package/dist/src/routes/lib-ai.d.ts.map +1 -1
  129. package/dist/src/routes/lib-ai.js +13 -6
  130. package/dist/src/routes/lib-ai.js.map +1 -1
  131. package/dist/src/routes/lib-header.d.ts +2 -0
  132. package/dist/src/routes/lib-header.d.ts.map +1 -1
  133. package/dist/src/routes/lib-header.js +7 -16
  134. package/dist/src/routes/lib-header.js.map +1 -1
  135. package/dist/src/routes/lib-markdown.d.ts +18 -0
  136. package/dist/src/routes/lib-markdown.d.ts.map +1 -0
  137. package/dist/src/routes/lib-markdown.js +236 -0
  138. package/dist/src/routes/lib-markdown.js.map +1 -0
  139. package/dist/src/routes/libs.d.ts +22 -0
  140. package/dist/src/routes/libs.d.ts.map +1 -1
  141. package/dist/src/routes/libs.js +133 -10
  142. package/dist/src/routes/libs.js.map +1 -1
  143. package/dist/src/routes/memory.d.ts.map +1 -1
  144. package/dist/src/routes/memory.js +21 -2
  145. package/dist/src/routes/memory.js.map +1 -1
  146. package/dist/src/routes/openrouter.d.ts +4 -0
  147. package/dist/src/routes/openrouter.d.ts.map +1 -1
  148. package/dist/src/routes/openrouter.js +17 -0
  149. package/dist/src/routes/openrouter.js.map +1 -1
  150. package/dist/src/routes/organisms.d.ts.map +1 -1
  151. package/dist/src/routes/organisms.js +107 -7
  152. package/dist/src/routes/organisms.js.map +1 -1
  153. package/dist/src/routes/portal.d.ts +9 -0
  154. package/dist/src/routes/portal.d.ts.map +1 -1
  155. package/dist/src/routes/portal.js +1 -1
  156. package/dist/src/routes/portal.js.map +1 -1
  157. package/dist/src/routes/public-stats.d.ts +3 -0
  158. package/dist/src/routes/public-stats.d.ts.map +1 -1
  159. package/dist/src/routes/public-stats.js +9 -2
  160. package/dist/src/routes/public-stats.js.map +1 -1
  161. package/dist/src/routes/secretary.d.ts +29 -0
  162. package/dist/src/routes/secretary.d.ts.map +1 -0
  163. package/dist/src/routes/secretary.js +220 -0
  164. package/dist/src/routes/secretary.js.map +1 -0
  165. package/dist/src/routes/specialists.d.ts.map +1 -1
  166. package/dist/src/routes/specialists.js +21 -0
  167. package/dist/src/routes/specialists.js.map +1 -1
  168. package/dist/src/routes/subdomains.js +1 -1
  169. package/dist/src/routes/subdomains.js.map +1 -1
  170. package/dist/src/routes/workflows.d.ts +9 -3
  171. package/dist/src/routes/workflows.d.ts.map +1 -1
  172. package/dist/src/routes/workflows.js +9 -3
  173. package/dist/src/routes/workflows.js.map +1 -1
  174. package/dist/src/server-bootstrap/routes-loader.d.ts.map +1 -1
  175. package/dist/src/server-bootstrap/routes-loader.js +4 -0
  176. package/dist/src/server-bootstrap/routes-loader.js.map +1 -1
  177. package/dist/src/server-bootstrap/service-init.d.ts.map +1 -1
  178. package/dist/src/server-bootstrap/service-init.js +7 -0
  179. package/dist/src/server-bootstrap/service-init.js.map +1 -1
  180. package/dist/src/server-bootstrap/static-files.d.ts +4 -0
  181. package/dist/src/server-bootstrap/static-files.d.ts.map +1 -1
  182. package/dist/src/server-bootstrap/static-files.js +18 -0
  183. package/dist/src/server-bootstrap/static-files.js.map +1 -1
  184. package/dist/src/services/archive.d.ts +74 -0
  185. package/dist/src/services/archive.d.ts.map +1 -0
  186. package/dist/src/services/archive.js +132 -0
  187. package/dist/src/services/archive.js.map +1 -0
  188. package/dist/src/services/cortex-seeder.d.ts +4 -1
  189. package/dist/src/services/cortex-seeder.d.ts.map +1 -1
  190. package/dist/src/services/cortex-seeder.js +25 -6
  191. package/dist/src/services/cortex-seeder.js.map +1 -1
  192. package/dist/src/services/directory.d.ts.map +1 -1
  193. package/dist/src/services/directory.js +3 -2
  194. package/dist/src/services/directory.js.map +1 -1
  195. package/dist/src/services/generator-prompt-seeds.d.ts.map +1 -1
  196. package/dist/src/services/generator-prompt-seeds.js +5 -4
  197. package/dist/src/services/generator-prompt-seeds.js.map +1 -1
  198. package/dist/src/services/message-send.d.ts.map +1 -1
  199. package/dist/src/services/message-send.js +14 -0
  200. package/dist/src/services/message-send.js.map +1 -1
  201. package/dist/src/services/organism-search.d.ts +6 -2
  202. package/dist/src/services/organism-search.d.ts.map +1 -1
  203. package/dist/src/services/organism-search.js +2 -2
  204. package/dist/src/services/organism-search.js.map +1 -1
  205. package/dist/src/services/owner-memory.d.ts +1 -0
  206. package/dist/src/services/owner-memory.d.ts.map +1 -1
  207. package/dist/src/services/owner-memory.js.map +1 -1
  208. package/dist/src/services/owner-session.d.ts +1 -0
  209. package/dist/src/services/owner-session.d.ts.map +1 -1
  210. package/dist/src/services/owner-session.js +10 -2
  211. package/dist/src/services/owner-session.js.map +1 -1
  212. package/dist/src/services/package-seeder.d.ts +22 -0
  213. package/dist/src/services/package-seeder.d.ts.map +1 -0
  214. package/dist/src/services/package-seeder.js +30 -0
  215. package/dist/src/services/package-seeder.js.map +1 -0
  216. package/dist/src/services/presence.d.ts +3 -0
  217. package/dist/src/services/presence.d.ts.map +1 -1
  218. package/dist/src/services/presence.js +10 -0
  219. package/dist/src/services/presence.js.map +1 -1
  220. package/dist/src/services/prompt-defaults.d.ts.map +1 -1
  221. package/dist/src/services/prompt-defaults.js +8 -3
  222. package/dist/src/services/prompt-defaults.js.map +1 -1
  223. package/dist/src/services/scheduler.d.ts +41 -2
  224. package/dist/src/services/scheduler.d.ts.map +1 -1
  225. package/dist/src/services/scheduler.js +429 -26
  226. package/dist/src/services/scheduler.js.map +1 -1
  227. package/dist/src/services/secretary-authoring.d.ts +71 -0
  228. package/dist/src/services/secretary-authoring.d.ts.map +1 -0
  229. package/dist/src/services/secretary-authoring.js +336 -0
  230. package/dist/src/services/secretary-authoring.js.map +1 -0
  231. package/dist/src/services/secretary-clarify.d.ts +57 -0
  232. package/dist/src/services/secretary-clarify.d.ts.map +1 -0
  233. package/dist/src/services/secretary-clarify.js +104 -0
  234. package/dist/src/services/secretary-clarify.js.map +1 -0
  235. package/dist/src/services/secretary-feed.d.ts +11 -0
  236. package/dist/src/services/secretary-feed.d.ts.map +1 -0
  237. package/dist/src/services/secretary-feed.js +28 -0
  238. package/dist/src/services/secretary-feed.js.map +1 -0
  239. package/dist/src/services/secretary-tick.d.ts +243 -3
  240. package/dist/src/services/secretary-tick.d.ts.map +1 -1
  241. package/dist/src/services/secretary-tick.js +273 -3
  242. package/dist/src/services/secretary-tick.js.map +1 -1
  243. package/dist/src/services/specialist-runner.d.ts +36 -0
  244. package/dist/src/services/specialist-runner.d.ts.map +1 -0
  245. package/dist/src/services/specialist-runner.js +91 -0
  246. package/dist/src/services/specialist-runner.js.map +1 -0
  247. package/dist/src/services/specialist.d.ts +9 -0
  248. package/dist/src/services/specialist.d.ts.map +1 -1
  249. package/dist/src/services/specialist.js +42 -0
  250. package/dist/src/services/specialist.js.map +1 -1
  251. package/dist/src/services/structure-overview.d.ts +13 -0
  252. package/dist/src/services/structure-overview.d.ts.map +1 -1
  253. package/dist/src/services/structure-overview.js +34 -11
  254. package/dist/src/services/structure-overview.js.map +1 -1
  255. package/dist/src/services/system-agent-responder.d.ts +36 -0
  256. package/dist/src/services/system-agent-responder.d.ts.map +1 -0
  257. package/dist/src/services/system-agent-responder.js +107 -0
  258. package/dist/src/services/system-agent-responder.js.map +1 -0
  259. package/dist/src/services/system-agent.d.ts +34 -1
  260. package/dist/src/services/system-agent.d.ts.map +1 -1
  261. package/dist/src/services/system-agent.js +73 -0
  262. package/dist/src/services/system-agent.js.map +1 -1
  263. package/dist/src/storage/interface.d.ts +33 -0
  264. package/dist/src/storage/interface.d.ts.map +1 -1
  265. package/dist/src/storage/interface.js.map +1 -1
  266. package/dist/src/storage/providers/mongodb/index.d.ts +37 -0
  267. package/dist/src/storage/providers/mongodb/index.d.ts.map +1 -1
  268. package/dist/src/storage/providers/mongodb/index.js +132 -12
  269. package/dist/src/storage/providers/mongodb/index.js.map +1 -1
  270. package/dist/src/storage/providers/sqlite/index.d.ts +23 -1
  271. package/dist/src/storage/providers/sqlite/index.d.ts.map +1 -1
  272. package/dist/src/storage/providers/sqlite/index.js +60 -8
  273. package/dist/src/storage/providers/sqlite/index.js.map +1 -1
  274. package/dist/src/storage/providers/sqlite/repos/memory.d.ts +29 -1
  275. package/dist/src/storage/providers/sqlite/repos/memory.d.ts.map +1 -1
  276. package/dist/src/storage/providers/sqlite/repos/memory.js +109 -10
  277. package/dist/src/storage/providers/sqlite/repos/memory.js.map +1 -1
  278. package/dist/src/storage/providers/sqlite/schema.d.ts +3 -0
  279. package/dist/src/storage/providers/sqlite/schema.d.ts.map +1 -1
  280. package/dist/src/storage/providers/sqlite/schema.js +64 -9
  281. package/dist/src/storage/providers/sqlite/schema.js.map +1 -1
  282. package/dist/src/storage/repositories/app.repository.d.ts +15 -0
  283. package/dist/src/storage/repositories/app.repository.d.ts.map +1 -1
  284. package/dist/src/storage/repositories/memory.repository.d.ts +41 -1
  285. package/dist/src/storage/repositories/memory.repository.d.ts.map +1 -1
  286. package/dist/src/storage/repositories/organism.repository.d.ts +2 -1
  287. package/dist/src/storage/repositories/organism.repository.d.ts.map +1 -1
  288. package/dist/static/app-catalog.html +469 -122
  289. package/package.json +2 -1
  290. package/prisma/schema.postgres.prisma +10 -0
  291. package/prisma/schema.prisma +12 -0
@@ -86,6 +86,7 @@ import { recordSecurityIncident } from '../services/security-incident.js';
86
86
  import { updateWorkspaceMeta, WorkspaceMetaError } from '../services/workspace-meta.js';
87
87
  import { countWorkspaceInstances, latestWorkspaceEvent, deriveWorkspaceEvents, aggregateParticipants } from '../services/workspace-enrichment.js';
88
88
  import { buildOrganismOverview, buildWorkspaceOverview } from '../services/structure-overview.js';
89
+ import { archiveTarget, unarchiveTarget, isKeyArchived } from '../services/archive.js';
89
90
  import { getOrganismReadme, setOrganismReadme } from '../services/organism-readme.js';
90
91
  import { collectOrganismGraph, collectWorkspaceGraph } from '../services/structure-graph.js';
91
92
  import { updateOrganismStructure } from '../services/structure-snapshot.js';
@@ -193,6 +194,10 @@ export function organismsRouter(config, storage) {
193
194
  visibility: member ? (selfOrOperator ? visibility : 'public') : (visibility || 'public'),
194
195
  page: page ? Number(page) : 1,
195
196
  perPage: per_page ? Number(per_page) : 20,
197
+ // The owner's OWN list includes archived (the client splits them into an "Archived" section);
198
+ // browsing/discovery (anyone else, or no member filter) excludes archived — retired organisms
199
+ // are read-only and not discoverable.
200
+ archived: (member && selfOrOperator) ? 'include' : 'exclude',
196
201
  });
197
202
  // ?include=counts — attach workspace_count per org (distinct ids in the registry across all
198
203
  // members' registry records), so the list view doesn't fan out one discoverWorkspaces per org.
@@ -997,12 +1002,33 @@ export function organismsRouter(config, storage) {
997
1002
  // (No ws → legacy organism-level root, kept only so an un-scoped call still reads something.)
998
1003
  const ws = typeof req.query.ws === 'string' ? req.query.ws : undefined;
999
1004
  const nsRoot = ws ? `organism.${id}.w.${ws}.` : `organism.${id}.`;
1005
+ // Archived content is excluded by default (the AI working set); ?includeArchived=true surfaces it
1006
+ // — the explicit "look in archive" escape hatch. ?archived=only reads ONLY archived content.
1007
+ const archived = req.query.archived === 'only' ? 'only' : (req.query.includeArchived === 'true' ? 'include' : undefined);
1000
1008
  // A workspace is SHARED: authorization is at the workspace level, not per record. If the caller can
1001
1009
  // read the manifest (they created it, are a same-owner agent, or hold a viewer/contributor grant —
1002
1010
  // see authorizeRead/the workspace-role consents), they see ALL of the workspace's content, whoever
1003
1011
  // wrote it — so a contributor's writes are visible to the creator + other members. If not, they see
1004
1012
  // nothing (org membership alone is discovery-only). The manifest is the single gate record.
1005
- const { items } = await storage.listAllMemory({ prefix: nsRoot, limit: 5000 });
1013
+ // For the archived views we must still surface the (active) manifest/readme so the workspace can
1014
+ // render — otherwise `archived=only` would drop the manifest and the whole workspace reads empty.
1015
+ // So: include everything, then filter CONTENT by the requested view using each record's own flag
1016
+ // while always keeping the workspace's own meta.* (manifest/readme). Default (active) keeps the
1017
+ // efficient storage-level exclude.
1018
+ let items;
1019
+ if (archived === 'only' || archived === 'include') {
1020
+ const all = (await storage.listAllMemory({ prefix: nsRoot, limit: 5000, archived: 'include' })).items;
1021
+ // Keep ONLY the manifest + readme (so the workspace shell renders) plus the archived content.
1022
+ // NB: must match the manifest/readme EXACTLY, not a `meta.` prefix — an objectType namespace can
1023
+ // itself start with `meta.` (e.g. `meta.goals`), and a prefix filter would leak ACTIVE content
1024
+ // from those spaces into the archived-only view.
1025
+ items = archived === 'only'
1026
+ ? all.filter(r => r.archived || r.key === `${nsRoot}meta.manifest` || r.key === `${nsRoot}meta.readme`)
1027
+ : all;
1028
+ }
1029
+ else {
1030
+ items = (await storage.listAllMemory({ prefix: nsRoot, limit: 5000 })).items;
1031
+ }
1006
1032
  const manRec = items.find(r => r.key === `${nsRoot}meta.manifest`);
1007
1033
  let canReadWorkspace = false;
1008
1034
  if (manRec) {
@@ -1121,13 +1147,15 @@ export function organismsRouter(config, storage) {
1121
1147
  return;
1122
1148
  }
1123
1149
  const viewerGaii = resolveIdentity(req.auth, config.nodeId);
1124
- const { markdown, workspaces } = await buildOrganismOverview(storage, config, { orgId: id, viewerGaii });
1150
+ const includeArchived = req.query.includeArchived === 'true';
1151
+ const { markdown, workspaces, archivedWorkspaces } = await buildOrganismOverview(storage, config, { orgId: id, viewerGaii, includeArchived });
1125
1152
  if (req.query.format === 'md') {
1126
1153
  res.type('text/markdown').send(markdown);
1127
1154
  return;
1128
1155
  }
1129
- res.json(success(config.nodeId, { markdown, workspaces }, [
1156
+ res.json(success(config.nodeId, { markdown, workspaces, archivedWorkspaces }, [
1130
1157
  { description: 'Drill into one workspace', method: 'GET', url: `/v1/organisms/${id}/workspace/overview?ws=<ws>` },
1158
+ ...(archivedWorkspaces && !includeArchived ? [{ description: 'Include archived workspaces', method: 'GET', url: `/v1/organisms/${id}/overview?includeArchived=true` }] : []),
1131
1159
  ]));
1132
1160
  });
1133
1161
  /* ── GET /v1/organisms/:id/workspace/overview — OKF-style overview of ONE workspace (Markdown) ──
@@ -1295,8 +1323,10 @@ export function organismsRouter(config, storage) {
1295
1323
  return;
1296
1324
  }
1297
1325
  const callerGaii = resolveIdentity(req.auth, config.nodeId);
1298
- const { results, truncated } = await searchOrganismContent(storage, config, organism, callerGaii, q, onlyWs);
1299
- res.json(success(config.nodeId, { query: q, results, total: results.length, truncated }));
1326
+ // Default excludes archived; ?archived=only is "archive search"; ?includeArchived=true searches both.
1327
+ const archived = req.query.archived === 'only' ? 'only' : (req.query.includeArchived === 'true' ? 'include' : undefined);
1328
+ const { results, truncated } = await searchOrganismContent(storage, config, organism, callerGaii, q, onlyWs, { archived });
1329
+ res.json(success(config.nodeId, { query: q, results, total: results.length, truncated, archived: archived ?? 'exclude' }));
1300
1330
  });
1301
1331
  /* ── Comments / threads on workspace records + documents ──
1302
1332
  * A comment targets one workspace object (record or document) by (ws, space, instance_id), can be
@@ -1725,7 +1755,8 @@ export function organismsRouter(config, storage) {
1725
1755
  }
1726
1756
  const callerGaii = resolveIdentity(req.auth, config.nodeId);
1727
1757
  const ownerName = req.auth.owner;
1728
- const { items } = await storage.listAllMemory({ prefix: wsRegPrefix(id), limit: 1000 });
1758
+ // `include` so an archived organism's registry (cascade-archived with it) still lists workspaces.
1759
+ const { items } = await storage.listAllMemory({ prefix: wsRegPrefix(id), limit: 1000, archived: 'include' });
1729
1760
  const seen = new Map();
1730
1761
  for (const rec of items) {
1731
1762
  if (rec.key !== wsRegPrefix(id))
@@ -1740,7 +1771,7 @@ export function organismsRouter(config, storage) {
1740
1771
  access = 'owner';
1741
1772
  else if (await canReadWs(id, w.id, callerGaii))
1742
1773
  access = 'granted';
1743
- seen.set(w.id, { id: w.id, name: w.name ?? w.id, created_by: createdBy, created_at: w.createdAt, access });
1774
+ seen.set(w.id, { id: w.id, name: w.name ?? w.id, created_by: createdBy, created_at: w.createdAt, access, archived: w.archived === true });
1744
1775
  }
1745
1776
  }
1746
1777
  // ?include=enrichment — fold the per-workspace getWorkspace+activity+participants fan-out (3N
@@ -2291,6 +2322,12 @@ export function organismsRouter(config, storage) {
2291
2322
  res.status(400).json(error(config.nodeId, 'INVALID_INPUT', 'ws is required'));
2292
2323
  return;
2293
2324
  }
2325
+ // Archived workspace/organism is read-only — block structure/name/readme edits.
2326
+ const wsGuard = await isKeyArchived(storage, `organism.${id}.w.${ws}.`);
2327
+ if (wsGuard.archived) {
2328
+ res.status(409).json(error(config.nodeId, 'ARCHIVED', `This ${wsGuard.level} is archived (read-only). Unarchive it before editing.`));
2329
+ return;
2330
+ }
2294
2331
  try {
2295
2332
  const result = await updateWorkspaceMeta(storage, config, {
2296
2333
  orgId: id, ws, callerOwner: req.auth.owner,
@@ -2625,6 +2662,63 @@ export function organismsRouter(config, storage) {
2625
2662
  if (ws)
2626
2663
  void updateOrganismStructure(storage, config, id, { event: 'workspace deleted', actor: resolveIdentity(req.auth, config.nodeId) }).catch(() => { });
2627
2664
  });
2665
+ /* ── Archive / Unarchive ──────────────────────────────────────────────────────────────────────
2666
+ * Flag an organism, a workspace, a record-table/document-space, or a single record as read-only +
2667
+ * archived so it drops out of every AI-facing material (overview, workspace read, search) yet stays
2668
+ * findable via archive search and resolvable by key. Cascades down a container with smart restore
2669
+ * (see services/archive.ts). Creator/admin only — archiving is a structural, destructive-adjacent op.
2670
+ * Body: { level: 'organism'|'workspace'|'space'|'record', ws?, namespace?, key? }. */
2671
+ const validateArchiveTarget = (id, body) => {
2672
+ const level = body.level;
2673
+ if (!['organism', 'workspace', 'space', 'record'].includes(level))
2674
+ return { ok: false, msg: 'level must be organism|workspace|space|record' };
2675
+ const ws = typeof body.ws === 'string' ? body.ws : undefined;
2676
+ const namespace = typeof body.namespace === 'string' ? body.namespace : undefined;
2677
+ const key = typeof body.key === 'string' ? body.key : undefined;
2678
+ if ((level === 'workspace' || level === 'space' || level === 'record') && !ws)
2679
+ return { ok: false, msg: 'ws is required for workspace/space/record' };
2680
+ if (level === 'space' && !namespace)
2681
+ return { ok: false, msg: 'namespace is required for space' };
2682
+ if (level === 'record') {
2683
+ if (!key)
2684
+ return { ok: false, msg: 'key is required for record' };
2685
+ if (!key.startsWith(`organism.${id}.w.${ws}.`))
2686
+ return { ok: false, msg: 'key must be inside organism.{id}.w.{ws}.' };
2687
+ }
2688
+ return { ok: true, target: { level, orgId: id, ws, namespace, key } };
2689
+ };
2690
+ const archiveHandler = (mode) => async (req, res) => {
2691
+ const id = req.params.id;
2692
+ const organism = await storage.getOrganism(id);
2693
+ if (!organism) {
2694
+ res.status(404).json(error(config.nodeId, 'NOT_FOUND', 'Organism not found'));
2695
+ return;
2696
+ }
2697
+ const role = await memberRole(req, organism, id);
2698
+ if (role !== 'creator' && role !== 'admin') {
2699
+ res.status(403).json(error(config.nodeId, 'ACCESS_DENIED', `Only the creator or an admin can ${mode} organism content`));
2700
+ return;
2701
+ }
2702
+ const v = validateArchiveTarget(id, (req.body ?? {}));
2703
+ if (!v.ok) {
2704
+ res.status(400).json(error(config.nodeId, 'INVALID_INPUT', v.msg));
2705
+ return;
2706
+ }
2707
+ const actor = resolveIdentity(req.auth, config.nodeId);
2708
+ try {
2709
+ const result = mode === 'archive'
2710
+ ? await archiveTarget(storage, v.target, actor)
2711
+ : await unarchiveTarget(storage, v.target, actor);
2712
+ res.json(success(config.nodeId, { [mode === 'archive' ? 'archived' : 'restored']: result.count, level: result.level, root: result.root }));
2713
+ emitChange('organisms');
2714
+ void updateOrganismStructure(storage, config, id, { event: `${v.target.level} ${mode}d`, actor }).catch(() => { });
2715
+ }
2716
+ catch (e) {
2717
+ res.status(400).json(error(config.nodeId, 'ARCHIVE_FAILED', e.message || `Could not ${mode}`));
2718
+ }
2719
+ };
2720
+ router.post('/v1/organisms/:id/archive', requireAuth(), requireRole('agent'), archiveHandler('archive'));
2721
+ router.post('/v1/organisms/:id/unarchive', requireAuth(), requireRole('agent'), archiveHandler('unarchive'));
2628
2722
  // POST /v1/organisms/:id/approvals — request approval for an action (gate or auto-run).
2629
2723
  router.post('/v1/organisms/:id/approvals', requireAuth(), async (req, res) => {
2630
2724
  const id = req.params.id;
@@ -2713,6 +2807,12 @@ export function organismsRouter(config, storage) {
2713
2807
  res.status(403).json(error(config.nodeId, 'ACCESS_DENIED', 'Admin/creator role required to publish in a meta.* namespace'));
2714
2808
  return;
2715
2809
  }
2810
+ // Archived content is read-only — block publishing into an archived organism/workspace.
2811
+ const pubGuard = await isKeyArchived(storage, wsId ? `organism.${id}.w.${wsId}.` : `organism.${id}.`);
2812
+ if (pubGuard.archived) {
2813
+ res.status(409).json(error(config.nodeId, 'ARCHIVED', `This ${pubGuard.level} is archived (read-only). Unarchive it before publishing.`));
2814
+ return;
2815
+ }
2716
2816
  const publisher = resolveIdentity(req.auth, config.nodeId);
2717
2817
  // Config decides whether publishing needs a review gate. Absent / disabled = publish now.
2718
2818
  const cfg = await readConfig(id);