aimeat 1.20.6 → 1.23.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 (92) hide show
  1. package/dist/.env.example +9 -0
  2. package/dist/locales/en.json +19 -1
  3. package/dist/locales/fi.json +19 -3
  4. package/dist/public/css/views/profile.css +58 -0
  5. package/dist/public/js/services/memory.js +9 -2
  6. package/dist/public/js/services/organisms.js +23 -11
  7. package/dist/public/views/profile/landing-page.js +16 -1
  8. package/dist/public/views/profile/organisms-tab.js +483 -224
  9. package/dist/src/cli/connect/api-client.d.ts +24 -0
  10. package/dist/src/cli/connect/api-client.d.ts.map +1 -1
  11. package/dist/src/cli/connect/api-client.js +29 -33
  12. package/dist/src/cli/connect/api-client.js.map +1 -1
  13. package/dist/src/cli/connect/config.d.ts.map +1 -1
  14. package/dist/src/cli/connect/config.js +4 -1
  15. package/dist/src/cli/connect/config.js.map +1 -1
  16. package/dist/src/cli/connect/mcp/local-server.d.ts +25 -0
  17. package/dist/src/cli/connect/mcp/local-server.d.ts.map +1 -0
  18. package/dist/src/cli/connect/mcp/local-server.js +454 -0
  19. package/dist/src/cli/connect/mcp/local-server.js.map +1 -0
  20. package/dist/src/cli/connect/mcp/poller.d.ts +13 -0
  21. package/dist/src/cli/connect/mcp/poller.d.ts.map +1 -1
  22. package/dist/src/cli/connect/mcp/poller.js +3 -2
  23. package/dist/src/cli/connect/mcp/poller.js.map +1 -1
  24. package/dist/src/cli/connect/mcp/server.d.ts +41 -0
  25. package/dist/src/cli/connect/mcp/server.d.ts.map +1 -1
  26. package/dist/src/cli/connect/mcp/server.js +47 -21
  27. package/dist/src/cli/connect/mcp/server.js.map +1 -1
  28. package/dist/src/cli/connect/mcp/tools/workspaces.d.ts +4 -0
  29. package/dist/src/cli/connect/mcp/tools/workspaces.d.ts.map +1 -1
  30. package/dist/src/cli/connect/mcp/tools/workspaces.js +22 -3
  31. package/dist/src/cli/connect/mcp/tools/workspaces.js.map +1 -1
  32. package/dist/src/cli/connect/tunnel-client.d.ts +109 -0
  33. package/dist/src/cli/connect/tunnel-client.d.ts.map +1 -0
  34. package/dist/src/cli/connect/tunnel-client.js +462 -0
  35. package/dist/src/cli/connect/tunnel-client.js.map +1 -0
  36. package/dist/src/config.d.ts +4 -0
  37. package/dist/src/config.d.ts.map +1 -1
  38. package/dist/src/config.js +9 -0
  39. package/dist/src/config.js.map +1 -1
  40. package/dist/src/generated/api-types.d.ts +139 -0
  41. package/dist/src/generated/api-types.d.ts.map +1 -1
  42. package/dist/src/index.js +72 -7
  43. package/dist/src/index.js.map +1 -1
  44. package/dist/src/mcp/catalog/definitions.js +1 -1
  45. package/dist/src/mcp/catalog/definitions.js.map +1 -1
  46. package/dist/src/mcp/workspaces.d.ts +4 -0
  47. package/dist/src/mcp/workspaces.d.ts.map +1 -1
  48. package/dist/src/mcp/workspaces.js +24 -4
  49. package/dist/src/mcp/workspaces.js.map +1 -1
  50. package/dist/src/models/schemas.d.ts +1 -1
  51. package/dist/src/routes/agent-tasks.d.ts.map +1 -1
  52. package/dist/src/routes/agent-tasks.js +6 -1
  53. package/dist/src/routes/agent-tasks.js.map +1 -1
  54. package/dist/src/routes/connect-tunnel.d.ts +17 -0
  55. package/dist/src/routes/connect-tunnel.d.ts.map +1 -0
  56. package/dist/src/routes/connect-tunnel.js +31 -0
  57. package/dist/src/routes/connect-tunnel.js.map +1 -0
  58. package/dist/src/routes/organisms.d.ts +4 -0
  59. package/dist/src/routes/organisms.d.ts.map +1 -1
  60. package/dist/src/routes/organisms.js +6 -2
  61. package/dist/src/routes/organisms.js.map +1 -1
  62. package/dist/src/server-bootstrap/routes-loader.d.ts.map +1 -1
  63. package/dist/src/server-bootstrap/routes-loader.js +5 -0
  64. package/dist/src/server-bootstrap/routes-loader.js.map +1 -1
  65. package/dist/src/server-bootstrap/service-init.d.ts +2 -0
  66. package/dist/src/server-bootstrap/service-init.d.ts.map +1 -1
  67. package/dist/src/server-bootstrap/service-init.js +11 -0
  68. package/dist/src/server-bootstrap/service-init.js.map +1 -1
  69. package/dist/src/server.d.ts +2 -0
  70. package/dist/src/server.d.ts.map +1 -1
  71. package/dist/src/server.js +1 -0
  72. package/dist/src/server.js.map +1 -1
  73. package/dist/src/services/config-schema.d.ts.map +1 -1
  74. package/dist/src/services/config-schema.js +5 -0
  75. package/dist/src/services/config-schema.js.map +1 -1
  76. package/dist/src/services/connect-tunnel.d.ts +123 -0
  77. package/dist/src/services/connect-tunnel.d.ts.map +1 -0
  78. package/dist/src/services/connect-tunnel.js +403 -0
  79. package/dist/src/services/connect-tunnel.js.map +1 -0
  80. package/dist/src/services/event-bus.d.ts +14 -0
  81. package/dist/src/services/event-bus.d.ts.map +1 -1
  82. package/dist/src/services/event-bus.js +25 -0
  83. package/dist/src/services/event-bus.js.map +1 -1
  84. package/dist/src/services/manifest-schema.d.ts +21 -4
  85. package/dist/src/services/manifest-schema.d.ts.map +1 -1
  86. package/dist/src/services/manifest-schema.js +30 -7
  87. package/dist/src/services/manifest-schema.js.map +1 -1
  88. package/dist/src/services/workspace-meta.d.ts +22 -0
  89. package/dist/src/services/workspace-meta.d.ts.map +1 -1
  90. package/dist/src/services/workspace-meta.js +34 -6
  91. package/dist/src/services/workspace-meta.js.map +1 -1
  92. package/package.json +1 -1
package/dist/.env.example CHANGED
@@ -168,6 +168,15 @@ AIMEAT_PORT=40050
168
168
  # AIMEAT_PERSONAL_HEARTBEAT_MS=30000
169
169
  # AIMEAT_PERSONAL_OFFLINE_MS=300000
170
170
 
171
+ # ── Connector Forward Tunnel ─────────────────────────────────
172
+ # One persistent WS per agent identity at /v1/connect/tunnel: carries forward
173
+ # API calls (agent→server) + realtime reverse delivery (server→agent push).
174
+ # OPT-IN — off by default until the Node connector client (Phase 3) ships.
175
+ # AIMEAT_CONNECT_TUNNEL_ENABLED=false
176
+ # AIMEAT_CONNECT_TUNNEL_HEARTBEAT_MS=30000
177
+ # AIMEAT_CONNECT_TUNNEL_OFFLINE_MS=90000
178
+ # AIMEAT_CONNECT_TUNNEL_REQUEST_TIMEOUT_MS=30000
179
+
171
180
  # ── Email / SMTP (Phase 1.1) ────────────────────────────────
172
181
  # AIMEAT_SMTP_HOST="smtp.example.com"
173
182
  # AIMEAT_SMTP_PORT=587
@@ -5463,7 +5463,6 @@
5463
5463
  },
5464
5464
  "organisms": {
5465
5465
  "title": "Organisms",
5466
- "openWorkspace": "Open workspace",
5467
5466
  "backToList": "All organisms",
5468
5467
  "noWorkspace": "This organism has no workspace yet. Set one up to track goals, plans, deliverables and decisions — versioned on publish.",
5469
5468
  "setupWorkspace": "Set up workspace",
@@ -5674,6 +5673,8 @@
5674
5673
  "rejected": "Rejected",
5675
5674
  "decisions": "Recent decisions",
5676
5675
  "noneYet": "none yet",
5676
+ "spaceTasksBacked": "This space points at the task system — its items are tasks, not workspace records. Manage them in the Tasks views.",
5677
+ "spaceBackingUnsupported": "This space's backing is not supported, so its content is not shown here. Edit the workspace (manifest) and set this space's backing to \"memory\" to restore it — files and knowledge packages attach via Sources or document images instead.",
5677
5678
  "onePerLine": "one per line",
5678
5679
  "docs": "docs",
5679
5680
  "newPage": "New document",
@@ -5712,6 +5713,23 @@
5712
5713
  "restructure": "✨ Restructure / add types with AI",
5713
5714
  "restructureTitle": "Restructure / add types with AI",
5714
5715
  "restructureDesc": "Describe what to add or change. Existing types and their data are kept — the AI extends the current structure. (To start completely fresh, delete the workspace below first.)",
5716
+ "open": "Open",
5717
+ "sortTitle": "Sort",
5718
+ "sortCustom": "My order",
5719
+ "sortName": "Name A–Z",
5720
+ "sortNewest": "Newest first",
5721
+ "reorderHint": "Drag rows to reorder — the order is saved to your profile.",
5722
+ "moreActions": "More actions",
5723
+ "policyLabel": "Join policy",
5724
+ "tabWorkspaces": "Workspaces",
5725
+ "tabMembers": "Members",
5726
+ "tabAgents": "Agents",
5727
+ "tabBoard": "Board",
5728
+ "openBoardsTab": "Open in Boards",
5729
+ "boardDesc": "This organism has a discussion board. Open it in the Boards view.",
5730
+ "noBoard": "This organism has no board.",
5731
+ "copyId": "Copy ID",
5732
+ "copied": "Copied!",
5715
5733
  "dangerZone": "Danger zone",
5716
5734
  "deleteWarn": "Deleting the workspace removes the manifest and ALL its data — drafts, published records, version history — and its schemas. The organism stays. This cannot be undone.",
5717
5735
  "deleteConfirmLabel": "Type the workspace name to confirm",
@@ -5463,7 +5463,6 @@
5463
5463
  },
5464
5464
  "organisms": {
5465
5465
  "title": "Organismit",
5466
- "openWorkspace": "Avaa työtila",
5467
5466
  "backToList": "Kaikki organismit",
5468
5467
  "noWorkspace": "Tällä organismilla ei ole vielä työtilaa. Luo sellainen seurataksesi tavoitteita, suunnitelmia, tuotoksia ja päätöksiä — versioituna julkaistaessa.",
5469
5468
  "setupWorkspace": "Luo työtila",
@@ -5629,8 +5628,6 @@
5629
5628
  "publishedAt": "Julkaistu",
5630
5629
  "fileVisibility": "Tiedostojen näkyvyys",
5631
5630
  "fileVisibilityNote": "Yksityiset tiedostot näkyvät vain sinulle — tee niistä julkisia jakaaksesi dokumentin.",
5632
- "imageVisibility": "Kuvien näkyvyys",
5633
- "imageVisibilityNote": "Yksityiset kuvat näkyvät vain sinulle — tee niistä julkisia jakaaksesi dokumentin.",
5634
5631
  "makeAllPublic": "Tee kaikista julkisia",
5635
5632
  "toggleVisibility": "Vaihda julkinen / yksityinen",
5636
5633
  "public": "Julkinen",
@@ -5676,6 +5673,8 @@
5676
5673
  "rejected": "Hylätty",
5677
5674
  "decisions": "Viimeisimmät päätökset",
5678
5675
  "noneYet": "ei vielä mitään",
5676
+ "spaceTasksBacked": "Tämä tila osoittaa tehtäväjärjestelmään — sen sisältö on tehtäviä, ei työtilan tietueita. Hallitse niitä Tehtävät-näkymissä.",
5677
+ "spaceBackingUnsupported": "Tämän tilan backing-arvoa ei tueta, joten sen sisältöä ei näytetä tässä. Muokkaa työtilaa (manifestia) ja vaihda tilan backing-arvoksi \"memory\" palauttaaksesi sen — tiedostot ja tietopaketit liitetään Lähteiden tai dokumenttien kuvien kautta.",
5679
5678
  "onePerLine": "yksi per rivi",
5680
5679
  "docs": "dokumentit",
5681
5680
  "newPage": "Uusi dokumentti",
@@ -5714,6 +5713,23 @@
5714
5713
  "restructure": "✨ Muokkaa rakennetta / lisää tyyppejä tekoälyllä",
5715
5714
  "restructureTitle": "Muokkaa rakennetta / lisää tyyppejä tekoälyllä",
5716
5715
  "restructureDesc": "Kuvaile mitä lisätä tai muuttaa. Olemassa olevat tyypit ja niiden data säilyvät — tekoäly laajentaa nykyistä rakennetta. (Aloita kokonaan alusta poistamalla työtila ensin alta.)",
5716
+ "open": "Avaa",
5717
+ "sortTitle": "Järjestä",
5718
+ "sortCustom": "Oma järjestys",
5719
+ "sortName": "Nimi A–Ö",
5720
+ "sortNewest": "Uusin ensin",
5721
+ "reorderHint": "Raahaa rivejä järjestääksesi — järjestys tallentuu profiiliisi.",
5722
+ "moreActions": "Lisätoiminnot",
5723
+ "policyLabel": "Liittymiskäytäntö",
5724
+ "tabWorkspaces": "Työtilat",
5725
+ "tabMembers": "Jäsenet",
5726
+ "tabAgents": "Agentit",
5727
+ "tabBoard": "Taulu",
5728
+ "openBoardsTab": "Avaa Taulut-näkymässä",
5729
+ "boardDesc": "Tällä organismilla on keskustelutaulu. Avaa se Taulut-näkymässä.",
5730
+ "noBoard": "Tällä organismilla ei ole taulua.",
5731
+ "copyId": "Kopioi ID",
5732
+ "copied": "Kopioitu!",
5717
5733
  "dangerZone": "Vaaravyöhyke",
5718
5734
  "deleteWarn": "Työtilan poistaminen poistaa manifestin ja KAIKEN sen datan — luonnokset, julkaistut tietueet, versiohistorian — ja sen skeemat. Organismi säilyy. Tätä ei voi perua.",
5719
5735
  "deleteConfirmLabel": "Vahvista kirjoittamalla työtilan nimi",
@@ -4,6 +4,9 @@
4
4
  * wallet, memory, agents, extensions, packages, knowledge, generator, and
5
5
  * edit panels. Consumes theme.css tokens so it flips with dark/light mode.
6
6
  * @version-history
7
+ * v1.12.0 — 2026-06-10 — Organisms list renew, phase 1: compact .pj-org-row list
8
+ * (avatar, one-line meta, kebab menu, drag-over state), .pj-menu dropdown,
9
+ * organism home page (.pj-org-home-head, underline .pj-org-tabs, breadcrumb).
7
10
  * v1.11.0 — 2026-06-08 — Full-bleed dashboard shell: drop the 1000px cap on the
8
11
  * .pf wrapper so the sidebar+content fill the viewport like the admin dashboard
9
12
  * (tab content was squeezed to ~760px). Sidebar stays left-anchored; .pf-content
@@ -2063,6 +2066,9 @@
2063
2066
  /* Lift the add-actions off the panel background so they read as buttons. */
2064
2067
  .pj-section-head .btn-outline, .pj-section-head .btn-ghost { background: var(--card); box-shadow: var(--shadow-sm); }
2065
2068
  .pj-section-head .btn-outline:hover, .pj-section-head .btn-ghost:hover { background: var(--bg-surface); border-color: var(--text-muted); }
2069
+ /* A declared space whose data does not live in workspace records (backing 'tasks', or a legacy
2070
+ unsupported backing) — shown as a notice instead of silently dropped from the view. */
2071
+ .pj-space-notice { font-size: 0.88rem; color: var(--muted); padding: 0.2rem 0 0.3rem; }
2066
2072
  .pj-draft-form { margin: 0.4rem 0; }
2067
2073
  .pj-drafts { display: flex; flex-direction: column; gap: 0.3rem; margin-bottom: 0.3rem; }
2068
2074
  .pj-item { display: flex; align-items: center; gap: 0.5rem; padding: 0.35rem 0; }
@@ -2324,3 +2330,55 @@
2324
2330
  .md-wikilink:hover { border-bottom-style: solid; }
2325
2331
  .md-img { max-width: 100%; height: auto; border-radius: 6px; }
2326
2332
  @media (max-width: 640px) { .pj-docspace { flex-direction: column; } .pj-doc-index { flex: none; width: 100%; } }
2333
+
2334
+ /* ───────────────── Organisms list renew (phase 1) ─────────────────
2335
+ * Compact list rows + kebab menu + organism home page. All colors via theme tokens. */
2336
+
2337
+ /* Topbar action cluster (sort select + Import + Create) */
2338
+ .pj-org-topbar-actions { display: flex; align-items: center; gap: 0.4rem; flex-wrap: wrap; }
2339
+ .pj-org-sort { width: auto; }
2340
+
2341
+ /* Compact rows */
2342
+ .pj-org-list { display: flex; flex-direction: column; gap: 0.5rem; margin-bottom: 0.75rem; }
2343
+ .pj-org-row { display: flex; align-items: center; flex-wrap: wrap; gap: 0.65rem; border: 1px solid var(--border); border-radius: 10px; background: var(--card); padding: 0.5rem 0.65rem; box-shadow: var(--shadow-sm); }
2344
+ .pj-org-row[draggable="true"] { cursor: grab; }
2345
+ .pj-org-row.pj-org-drag-over { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent); }
2346
+ .pj-org-avatar { width: 36px; height: 36px; border-radius: 9px; display: flex; align-items: center; justify-content: center; font-weight: 700; font-size: 0.85rem; background: var(--bg-dim); color: var(--text-dim); border: 1px solid var(--border); flex: none; user-select: none; }
2347
+ .pj-org-avatar-lg { width: 46px; height: 46px; font-size: 1.05rem; border-radius: 11px; }
2348
+ .pj-org-main { flex: 1; min-width: 220px; cursor: pointer; }
2349
+ .pj-org-titlerow { display: flex; align-items: center; gap: 0.4rem; flex-wrap: wrap; min-width: 0; }
2350
+ .pj-org-name { font-weight: 600; font-size: 0.95rem; color: var(--text); }
2351
+ .pj-org-lock { font-size: 0.75rem; }
2352
+ .pj-org-desc { font-size: 0.78rem; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 48ch; }
2353
+ .pj-org-stats { display: flex; align-items: center; gap: 0.8rem; font-size: 0.78rem; color: var(--muted); flex: none; }
2354
+ .pj-org-stat { display: inline-flex; align-items: center; gap: 0.25rem; white-space: nowrap; }
2355
+ .pj-org-openbtn { flex: none; white-space: nowrap; }
2356
+ .pj-org-detail { flex-basis: 100%; border-top: 1px solid var(--border); margin-top: 0.35rem; padding-top: 0.5rem; cursor: default; }
2357
+ .pj-org-hint { font-size: 0.74rem; color: var(--muted); margin: -0.35rem 0 0.75rem; }
2358
+
2359
+ /* Kebab ("…") menu */
2360
+ .pj-menu { position: relative; flex: none; }
2361
+ .pj-menu-btn { font-size: 1.05rem; padding: 0.2rem 0.35rem; border-radius: 6px; }
2362
+ .pj-menu-btn:hover { background: var(--bg-surface); }
2363
+ .pj-menu-pop { position: absolute; right: 0; top: calc(100% + 4px); background: var(--card); border: 1px solid var(--border); border-radius: 8px; box-shadow: var(--shadow-md); display: flex; flex-direction: column; min-width: 170px; z-index: 30; padding: 0.25rem; }
2364
+ .pj-menu-item { text-align: left; background: none; border: none; padding: 0.45rem 0.6rem; font-size: 0.83rem; color: var(--text); cursor: pointer; border-radius: 6px; white-space: nowrap; }
2365
+ .pj-menu-item:hover { background: var(--bg-surface); }
2366
+ .pj-menu-item-danger { color: var(--danger-fg); }
2367
+
2368
+ /* Organism home page */
2369
+ .pj-org-breadcrumb { font-size: 0.8rem; color: var(--muted); margin-bottom: 0.6rem; display: flex; align-items: center; gap: 0.35rem; }
2370
+ .pj-org-crumb-link { background: none; border: none; padding: 0; font-size: inherit; color: var(--accent); cursor: pointer; }
2371
+ .pj-org-crumb-link:hover { text-decoration: underline; }
2372
+ .pj-org-home-head { display: flex; align-items: flex-start; gap: 0.75rem; flex-wrap: wrap; margin-bottom: 0.5rem; }
2373
+ .pj-org-home-title { flex: 1; min-width: 220px; }
2374
+ .pj-org-home-name { font-weight: 700; font-size: 1.25rem; color: var(--text); }
2375
+ .pj-org-home-desc { margin-top: 0.15rem; }
2376
+ .pj-org-home-actions { display: flex; gap: 0.4rem; flex: none; align-items: flex-start; }
2377
+ .pj-org-btn-active { border-color: var(--accent); color: var(--accent); }
2378
+ .pj-org-settings { margin-bottom: 0.75rem; }
2379
+ .pj-org-tabs { display: flex; gap: 1.1rem; border-bottom: 1px solid var(--border); margin: 0.6rem 0 1rem; flex-wrap: wrap; }
2380
+ .pj-org-tab { background: none; border: none; padding: 0.45rem 0.1rem; font-size: 0.88rem; color: var(--text-dim); cursor: pointer; border-bottom: 2px solid transparent; margin-bottom: -1px; }
2381
+ .pj-org-tab:hover { color: var(--text); }
2382
+ .pj-org-tab.active { color: var(--text); border-bottom-color: var(--accent); font-weight: 600; }
2383
+ .pj-org-tab-count { color: var(--muted); font-size: 0.75rem; margin-left: 0.3rem; }
2384
+ .pj-org-boardrow { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; }
@@ -1,6 +1,8 @@
1
1
  /**
2
- * AIMEAT Memory Service
3
- * Key-value memory CRUD, search, file management.
2
+ * @file memory.js
3
+ * @description AIMEAT Memory Service — key-value memory CRUD, search, file management.
4
+ * @version-history
5
+ * v1.1.0 — 2026-06-10 — Add getMemory(key) single-entry read (GET /v1/memory/:key).
4
6
  */
5
7
  import { api, apiGet, apiPost, apiDelete } from '/js/api.js';
6
8
 
@@ -12,6 +14,11 @@ export async function listMemories(agentGaii) {
12
14
  return Array.isArray(list) ? list : [];
13
15
  }
14
16
 
17
+ /** Read a single memory entry. Returns the envelope ({ data: { key, value, version, ... } }); throws/404s if missing. */
18
+ export async function getMemory(key) {
19
+ return apiGet(`/v1/memory/${encodeURIComponent(key)}`);
20
+ }
21
+
15
22
  /** Search memory by query string. Returns array. Optional agentGaii. */
16
23
  export async function searchMemory(query, agentGaii) {
17
24
  let url = `/v1/memory/search?q=${encodeURIComponent(query)}`;
@@ -6,6 +6,16 @@
6
6
  */
7
7
  import { api, apiGet, apiPost, apiPut, apiPatch, apiDelete } from '/js/api.js';
8
8
 
9
+ /** Does this space's data live in workspace memory keys (records/documents the workspace view can
10
+ * show)? Missing backing counts as memory. Mirrors the server's isMemoryBackedSpace — THE one
11
+ * frontend predicate; hand-rolled per-view variants of this check are how published content once
12
+ * went invisible. backing:'tasks' points at the task system; other values are legacy/unsupported. */
13
+ export const isMemorySpace = (ot) => !ot?.backing || ot.backing === 'memory';
14
+
15
+ /** Is this space a document space? Old manifests declared kind:'document' without a mode — honour
16
+ * the intent (mirrors the server's normalizeObjectTypes inference). */
17
+ export const isDocSpace = (ot) => ot?.mode === 'document' || (!ot?.mode && ot?.kind === 'document');
18
+
9
19
  /** List organisms. */
10
20
  export async function listOrganisms(opts = {}) {
11
21
  const params = new URLSearchParams();
@@ -342,7 +352,9 @@ export function validateGenerated(generated) {
342
352
  if (!['active', 'paused', 'done', 'archived'].includes(m.status)) errors.push('manifest.status must be one of: active, paused, done, archived');
343
353
  const ots = Array.isArray(m.objectTypes) ? m.objectTypes : [];
344
354
  if (ots.length === 0) errors.push('manifest.objectTypes must have at least one entry');
345
- const backings = ['memory', 'tasks', 'storage', 'knowledge'];
355
+ // 'storage'/'knowledge' are NOT valid backings: files and knowledge packages attach via workspace
356
+ // Sources or document images, never as a backed space (the server gate rejects them too).
357
+ const backings = ['memory', 'tasks'];
346
358
  const roles = ['owner', 'admin', 'member'];
347
359
  for (const ot of ots) {
348
360
  const n = (ot && ot.name) || '(unnamed)';
@@ -595,8 +607,8 @@ export async function buildOrganismOverviewMermaid(orgId) {
595
607
  for (const w of wsList) {
596
608
  const ws = await getWorkspace(orgId, w.id).catch(() => null);
597
609
  const sources = await getWorkspaceSources(orgId, w.id).catch(() => []);
598
- const types = (ws?.manifest?.objectTypes || []).filter(o => o.backing === 'memory')
599
- .map(o => `${o.name} (${o.mode === 'document' ? 'doc' : 'rec'})`);
610
+ const types = (ws?.manifest?.objectTypes || []).filter(isMemorySpace)
611
+ .map(o => `${o.name} (${isDocSpace(o) ? 'doc' : 'rec'})`);
600
612
  const knowledge = sources.filter(s => s.type === 'knowledge').map(s => s.label || s.packageId);
601
613
  wsData.push({ name: w.name || w.id, types, knowledge });
602
614
  }
@@ -653,9 +665,9 @@ export async function buildOrganismOverviewMermaid(orgId) {
653
665
  /** Chart 2 — the edit→publish lifecycle this workspace's manifest defines (deterministic). Records
654
666
  * are schema-validated; the publish gate + the manifest's policy.alwaysGate add a review step. */
655
667
  export function buildEditFlowMermaid(manifest, gateOn) {
656
- const types = (manifest?.objectTypes || []).filter(o => o.backing === 'memory');
657
- const recTypes = types.filter(o => o.mode !== 'document').map(o => o.name);
658
- const docTypes = types.filter(o => o.mode === 'document').map(o => o.name);
668
+ const types = (manifest?.objectTypes || []).filter(isMemorySpace);
669
+ const recTypes = types.filter(o => !isDocSpace(o)).map(o => o.name);
670
+ const docTypes = types.filter(isDocSpace).map(o => o.name);
659
671
  const alwaysGate = (manifest?.policy && manifest.policy.alwaysGate) || [];
660
672
 
661
673
  const L = ['flowchart LR'];
@@ -684,7 +696,7 @@ export function buildEditFlowMermaid(manifest, gateOn) {
684
696
 
685
697
  /** Format one objectType's full schema for the prompt's STRUCTURE block. */
686
698
  function describeType(ot, schema) {
687
- if (ot.mode === 'document') {
699
+ if (isDocSpace(ot)) {
688
700
  return `• ${ot.name} (document) — namespace "${ot.namespace}". Free-form markdown pages { id, title, markdown }, organised into sections (read organism.{id}.w.{ws}.meta.sections.${ot.name}).`;
689
701
  }
690
702
  const props = (schema && schema.properties) || {};
@@ -705,11 +717,11 @@ export async function buildAccessPrompt(orgId, orgName, wsId, ws, variant = 'hum
705
717
  const nodeUrl = window.location.origin;
706
718
  const m = ws?.manifest || {};
707
719
  const wsName = m.name || wsId;
708
- const types = (m.objectTypes || []).filter(ot => ot.backing === 'memory');
720
+ const types = (m.objectTypes || []).filter(isMemorySpace);
709
721
  const described = [];
710
722
  for (const ot of types) {
711
723
  // records is the default mode (mode may be undefined) — fetch the schema unless it's a document.
712
- const schema = ot.mode !== 'document' ? await getObjectSchema(orgId, wsId, ot.namespace).catch(() => null) : null;
724
+ const schema = !isDocSpace(ot) ? await getObjectSchema(orgId, wsId, ot.namespace).catch(() => null) : null;
713
725
  described.push(describeType(ot, schema));
714
726
  }
715
727
  const structure = described.join('\n') || '(no spaces declared yet)';
@@ -802,10 +814,10 @@ export async function buildContractAgentPrompt(orgId, orgName, wsId, ws) {
802
814
  const nodeUrl = window.location.origin;
803
815
  const m = ws?.manifest || {};
804
816
  const wsName = m.name || wsId;
805
- const types = (m.objectTypes || []).filter(ot => ot.backing === 'memory');
817
+ const types = (m.objectTypes || []).filter(isMemorySpace);
806
818
  const described = [];
807
819
  for (const ot of types) {
808
- const schema = ot.mode !== 'document' ? await getObjectSchema(orgId, wsId, ot.namespace).catch(() => null) : null;
820
+ const schema = !isDocSpace(ot) ? await getObjectSchema(orgId, wsId, ot.namespace).catch(() => null) : null;
809
821
  described.push(describeType(ot, schema));
810
822
  }
811
823
  const structure = described.join('\n') || '(no spaces declared yet)';
@@ -15,6 +15,10 @@
15
15
  * AppStrip — home/section sub-components
16
16
  * - LandingPage — main orchestrator (default export)
17
17
  * @version-history
18
+ * v2.3.0 — 2026-06-10 — Drop the "← Home" button from the content header (visual noise,
19
+ * duplicated the sidebar's 🏠 Home item); the header keeps the current-tab label.
20
+ * v2.2.0 — 2026-06-10 — Listen for the `aimeat-open-tab` CustomEvent so tab components can
21
+ * navigate to another profile tab (first user: organism home's Board tab → Boards view).
18
22
  * v2.1.0 — 2026-06-09 — Remembered open view (openView) now persists in
19
23
  * sessionStorage instead of localStorage, so it is per browser TAB: with
20
24
  * multiple profile tabs open, an F5 restores that tab's own view rather than
@@ -619,6 +623,18 @@ export default function LandingPage({ tier, stats, session, navigate, showToast,
619
623
  setOpenView(null);
620
624
  }, []);
621
625
 
626
+ /* Cross-tab navigation: any tab component can dispatch
627
+ * `new CustomEvent('aimeat-open-tab', { detail: { tabId } })` to open another
628
+ * profile tab inline (e.g. an organism's Board tab → the Boards view). */
629
+ useEffect(() => {
630
+ const handler = (e) => {
631
+ const tabId = e.detail?.tabId;
632
+ if (tabId) open(tabId, e.detail?.slot || 'main');
633
+ };
634
+ window.addEventListener('aimeat-open-tab', handler);
635
+ return () => window.removeEventListener('aimeat-open-tab', handler);
636
+ }, [open]);
637
+
622
638
  /* Render inline view if it matches the given slot */
623
639
  const viewAt = (slot) => {
624
640
  if (!openView || openView.slot !== slot) return null;
@@ -683,7 +699,6 @@ export default function LandingPage({ tier, stats, session, navigate, showToast,
683
699
  <main class="pf-content">
684
700
  ${openView ? html`
685
701
  <div class="pf-content-head">
686
- <button class="pf-back-btn" onClick=${close}>← ${t('profile.landing.home')}</button>
687
702
  <span class="pf-back-current">${getTabLabel(openView.tabId)}</span>
688
703
  </div>
689
704
  <div class="pf-content-body">${renderTab(openView.tabId)}</div>