aimeat 1.20.0 → 1.20.2

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 (48) hide show
  1. package/dist/locales/en.json +42 -1
  2. package/dist/locales/fi.json +42 -1
  3. package/dist/public/css/views/profile.css +81 -5
  4. package/dist/public/css/views/public-workspace-viewer.css +206 -0
  5. package/dist/public/js/services/organisms.js +122 -1
  6. package/dist/public/llms-template.txt +7 -2
  7. package/dist/public/spa.html +2 -0
  8. package/dist/public/views/profile/organisms-tab.js +157 -9
  9. package/dist/public/views/public-workspace-viewer.js +128 -0
  10. package/dist/src/cli/connect/mcp/tools/workspaces.d.ts.map +1 -1
  11. package/dist/src/cli/connect/mcp/tools/workspaces.js +15 -9
  12. package/dist/src/cli/connect/mcp/tools/workspaces.js.map +1 -1
  13. package/dist/src/cli/connect/tool-call.d.ts.map +1 -1
  14. package/dist/src/cli/connect/tool-call.js +10 -6
  15. package/dist/src/cli/connect/tool-call.js.map +1 -1
  16. package/dist/src/generated/api-types.d.ts +204 -0
  17. package/dist/src/generated/api-types.d.ts.map +1 -1
  18. package/dist/src/mcp/catalog/definitions.d.ts.map +1 -1
  19. package/dist/src/mcp/catalog/definitions.js +3 -2
  20. package/dist/src/mcp/catalog/definitions.js.map +1 -1
  21. package/dist/src/mcp/workspaces.d.ts +19 -0
  22. package/dist/src/mcp/workspaces.d.ts.map +1 -1
  23. package/dist/src/mcp/workspaces.js +147 -51
  24. package/dist/src/mcp/workspaces.js.map +1 -1
  25. package/dist/src/middleware/workspace-access.d.ts +5 -0
  26. package/dist/src/middleware/workspace-access.d.ts.map +1 -1
  27. package/dist/src/middleware/workspace-access.js +52 -15
  28. package/dist/src/middleware/workspace-access.js.map +1 -1
  29. package/dist/src/routes/organisms.d.ts +11 -0
  30. package/dist/src/routes/organisms.d.ts.map +1 -1
  31. package/dist/src/routes/organisms.js +357 -31
  32. package/dist/src/routes/organisms.js.map +1 -1
  33. package/dist/src/routes/portal.d.ts.map +1 -1
  34. package/dist/src/routes/portal.js +1 -0
  35. package/dist/src/routes/portal.js.map +1 -1
  36. package/dist/src/services/handbooks/agent.d.ts +3 -1
  37. package/dist/src/services/handbooks/agent.d.ts.map +1 -1
  38. package/dist/src/services/handbooks/agent.js +3 -1
  39. package/dist/src/services/handbooks/agent.js.map +1 -1
  40. package/dist/src/services/handbooks/appdev.d.ts +3 -1
  41. package/dist/src/services/handbooks/appdev.d.ts.map +1 -1
  42. package/dist/src/services/handbooks/appdev.js +19 -0
  43. package/dist/src/services/handbooks/appdev.js.map +1 -1
  44. package/dist/src/services/workspace-meta.d.ts +10 -0
  45. package/dist/src/services/workspace-meta.d.ts.map +1 -1
  46. package/dist/src/services/workspace-meta.js +50 -3
  47. package/dist/src/services/workspace-meta.js.map +1 -1
  48. package/package.json +1 -1
@@ -5523,6 +5523,21 @@
5523
5523
  "hiddenAgent": "An agent whose details you cannot see",
5524
5524
  "otherAgentHint": "Another owner’s agent — you see what it has done here, not its live status",
5525
5525
  "viaAgent": "done via this agent",
5526
+ "manageAccess": "Manage who can work here",
5527
+ "requestedAccess": "requested access",
5528
+ "addAsContributor": "Add as contributor",
5529
+ "addAsViewer": "as viewer",
5530
+ "deny": "Deny",
5531
+ "roleContributorShort": "contributor",
5532
+ "roleViewerShort": "viewer",
5533
+ "makeContributor": "→ can write",
5534
+ "makeViewer": "→ read only",
5535
+ "remove": "Remove",
5536
+ "addMemberPlaceholder": "owner name (or owner@node / agent#owner@node)",
5537
+ "roleContributor": "contributor (read + write)",
5538
+ "roleViewer": "viewer (read only)",
5539
+ "addMember": "Add",
5540
+ "accessHint": "Members can be a different account; their agents inherit the role. Viewers read; contributors read + write.",
5526
5541
  "contributions": "contributions",
5527
5542
  "events": "events",
5528
5543
  "less": "Less",
@@ -5540,8 +5555,12 @@
5540
5555
  "aiPrompt": "AI access prompt:",
5541
5556
  "aiPromptHuman": "For chat",
5542
5557
  "aiPromptAgent": "For coding agent",
5558
+ "contractPrompt": "Create contract agent",
5559
+ "contractPromptHint": "Copy a prompt to build an agent that processes this workspace (reads requests → writes results)",
5560
+ "contractPromptCopied": "Contract-agent prompt copied — paste it to your AI / coding agent.",
5543
5561
  "promptCopied": "Access prompt copied — paste it to your AI.",
5544
- "addSpaceBtn": "Space",
5562
+ "addSpaceBtn": "Document space",
5563
+ "workspaceOrganism": "Organism",
5545
5564
  "addSpaceTitle": "Add a space",
5546
5565
  "addSpaceDesc": "A document space is a free-form wiki (sections + markdown pages). A record space is a schema-locked list (forms). You can remove spaces in Settings.",
5547
5566
  "modeDocument": "Document (wiki)",
@@ -5576,7 +5595,20 @@
5576
5595
  "sourcesSaveError": "Failed to save sources",
5577
5596
  "publishGated": "Sent for review (publish gate is on)",
5578
5597
  "publishGate": "Require review before publishing",
5598
+ "publishGateHint": "When on, an agent’s publish is held for your review instead of going live",
5579
5599
  "gateToggled": "Publish gate updated",
5600
+ "share": "Share",
5601
+ "shareHint": "Publish document pages to a public, no-login link",
5602
+ "sharePublicTitle": "Public sharing",
5603
+ "sharePublicDesc": "Make published document-space pages readable by anyone with the link — no login required. Drafts are never shared.",
5604
+ "noDocSpaces": "This workspace has no document spaces to share.",
5605
+ "noPublishedDocs": "No published documents yet — publish a page to share it.",
5606
+ "openLink": "open ↗",
5607
+ "openPublicViewer": "Open public viewer",
5608
+ "copyLink": "Copy link",
5609
+ "linkCopied": "Link copied",
5610
+ "copyFailed": "Copy failed",
5611
+ "shareFailed": "Failed to update sharing",
5580
5612
  "needsDecision": "Needs your decision",
5581
5613
  "approve": "Approve",
5582
5614
  "reject": "Reject",
@@ -6192,5 +6224,14 @@
6192
6224
  "exportJson": "Export JSON",
6193
6225
  "copyMarkdown": "Copy as Markdown",
6194
6226
  "copied": "Copied!"
6227
+ },
6228
+ "pwv": {
6229
+ "loading": "Loading…",
6230
+ "sharedDocuments": "Shared documents",
6231
+ "publicBadge": "Public document",
6232
+ "print": "Print / Save as PDF",
6233
+ "selectDocument": "Select a document.",
6234
+ "unavailableTitle": "Nothing to show here",
6235
+ "unavailableDesc": "This workspace has no publicly shared documents, or the link is incomplete."
6195
6236
  }
6196
6237
  }
@@ -5523,6 +5523,21 @@
5523
5523
  "hiddenAgent": "Agentti jonka tietoja et näe",
5524
5524
  "otherAgentHint": "Toisen omistajan agentti — näet mitä se on tehnyt täällä, et sen nykytilaa",
5525
5525
  "viaAgent": "tehty tämän agentin kautta",
5526
+ "manageAccess": "Hallitse ketkä työskentelevät täällä",
5527
+ "requestedAccess": "pyysi pääsyä",
5528
+ "addAsContributor": "Lisää kirjoittajaksi",
5529
+ "addAsViewer": "lukijaksi",
5530
+ "deny": "Hylkää",
5531
+ "roleContributorShort": "kirjoittaja",
5532
+ "roleViewerShort": "lukija",
5533
+ "makeContributor": "→ saa kirjoittaa",
5534
+ "makeViewer": "→ vain luku",
5535
+ "remove": "Poista",
5536
+ "addMemberPlaceholder": "omistajan nimi (tai owner@node / agent#owner@node)",
5537
+ "roleContributor": "kirjoittaja (luku + kirjoitus)",
5538
+ "roleViewer": "lukija (vain luku)",
5539
+ "addMember": "Lisää",
5540
+ "accessHint": "Jäsen voi olla eri tili; sen agentit perivät roolin. Lukijat lukevat; kirjoittajat lukevat + kirjoittavat.",
5526
5541
  "contributions": "kontribuutiota",
5527
5542
  "events": "tapahtumaa",
5528
5543
  "less": "Vähemmän",
@@ -5540,8 +5555,12 @@
5540
5555
  "aiPrompt": "AI-käyttöohje:",
5541
5556
  "aiPromptHuman": "Chattiin",
5542
5557
  "aiPromptAgent": "Koodausagentille",
5558
+ "contractPrompt": "Luo contract-agentti",
5559
+ "contractPromptHint": "Kopioi kehote agentin rakentamiseksi joka prosessoi tätä workspacea (lukee pyynnöt → kirjoittaa tulokset)",
5560
+ "contractPromptCopied": "Contract-agentti-kehote kopioitu — liitä se tekoälyllesi / koodausagentille.",
5543
5561
  "promptCopied": "Käyttöohje kopioitu — liitä se tekoälyllesi.",
5544
- "addSpaceBtn": "Tila",
5562
+ "addSpaceBtn": "Dokumenttitila",
5563
+ "workspaceOrganism": "Organismi",
5545
5564
  "addSpaceTitle": "Lisää tila",
5546
5565
  "addSpaceDesc": "Dokumenttitila on vapaamuotoinen wiki (osiot + markdown-sivut). Tietuetila on skeemalukittu lista (lomakkeet). Voit poistaa tiloja asetuksissa.",
5547
5566
  "modeDocument": "Dokumentti (wiki)",
@@ -5578,7 +5597,20 @@
5578
5597
  "sourcesSaveError": "Lähteiden tallennus epäonnistui",
5579
5598
  "publishGated": "Lähetetty tarkistettavaksi (julkaisuportti päällä)",
5580
5599
  "publishGate": "Vaadi tarkistus ennen julkaisua",
5600
+ "publishGateHint": "Päällä ollessaan agentin julkaisu jää tarkistettavaksesi sen sijaan että menisi suoraan liveksi",
5581
5601
  "gateToggled": "Julkaisuportti päivitetty",
5602
+ "share": "Jaa",
5603
+ "shareHint": "Julkaise dokumenttisivuja julkiseen linkkiin ilman kirjautumista",
5604
+ "sharePublicTitle": "Julkinen jako",
5605
+ "sharePublicDesc": "Tee julkaistut dokumenttisivut luettaviksi kenelle tahansa linkin kautta — ilman kirjautumista. Luonnoksia ei koskaan jaeta.",
5606
+ "noDocSpaces": "Tässä työtilassa ei ole jaettavia dokumenttitiloja.",
5607
+ "noPublishedDocs": "Ei julkaistuja dokumentteja vielä — julkaise sivu jakaaksesi sen.",
5608
+ "openLink": "avaa ↗",
5609
+ "openPublicViewer": "Avaa julkinen näkymä",
5610
+ "copyLink": "Kopioi linkki",
5611
+ "linkCopied": "Linkki kopioitu",
5612
+ "copyFailed": "Kopiointi epäonnistui",
5613
+ "shareFailed": "Jaon päivitys epäonnistui",
5582
5614
  "needsDecision": "Vaatii päätöksesi",
5583
5615
  "approve": "Hyväksy",
5584
5616
  "reject": "Hylkää",
@@ -6194,5 +6226,14 @@
6194
6226
  "exportJson": "Vie JSON",
6195
6227
  "copyMarkdown": "Kopioi Markdownina",
6196
6228
  "copied": "Kopioitu!"
6229
+ },
6230
+ "pwv": {
6231
+ "loading": "Ladataan…",
6232
+ "sharedDocuments": "Jaetut dokumentit",
6233
+ "publicBadge": "Julkinen dokumentti",
6234
+ "print": "Tulosta / Tallenna PDF:nä",
6235
+ "selectDocument": "Valitse dokumentti.",
6236
+ "unavailableTitle": "Ei näytettävää",
6237
+ "unavailableDesc": "Tällä työtilalla ei ole julkisesti jaettuja dokumentteja, tai linkki on puutteellinen."
6197
6238
  }
6198
6239
  }
@@ -53,6 +53,17 @@
53
53
  * var(--success,#22c55e)/var(--danger,#ef4444). Appearance unchanged (values
54
54
  * resolve identically; swatches deliberately do not flip in dark). Shared shape
55
55
  * was already factored onto .badge-label — kept as-is.
56
+ * v1.12.0 — 2026-06-09 — Workspace header restyle (pj-): breadcrumb (.pj-ws-crumbs)
57
+ * keeps the parent organism visible; inline title+badge (.pj-ws-titlerow); the
58
+ * action row became a tinted .pj-toolbar with consistent buttons (card fill +
59
+ * shadow so they stop blending into the page), .pj-toolbar-sep separators, and the
60
+ * review gate pushed apart (margin-left:auto). .pj-section-head no longer
61
+ * space-betweens — add-actions cluster next to their title and lift off the panel;
62
+ * the .pj-doc-tag kind chip got an accent-tinted fill so it stops blending in.
63
+ * v1.13.0 — 2026-06-09 — Record-item readability: draft rows get a --warn rail +
64
+ * bordered/bolder DRAFT chip and the inline Edit button gets the card-fill
65
+ * treatment (both were nearly invisible). Expanded fields (.pj-rec-fields .kv-row)
66
+ * gain a dotted leader between label and value so each value maps to its key.
56
67
  */
57
68
  .pf-hero{background:var(--pf-hero-gradient);border-bottom:1px solid var(--border,#E5E7EB)}
58
69
  .pf-hero-inner{max-width:1000px;margin:0 auto;padding:2rem 1.5rem 0}
@@ -2018,24 +2029,62 @@
2018
2029
 
2019
2030
  /* ── Projects tab (pj-) ── */
2020
2031
  .pj-ws { display: flex; flex-direction: column; gap: 0.5rem; }
2021
- .pj-gate { margin: 0.25rem 0 0.5rem; }
2032
+
2033
+ /* Workspace breadcrumb — keeps the parent organism visible so you always know
2034
+ which organism this workspace belongs to. */
2035
+ .pj-ws-crumbs { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; margin-bottom: 0.2rem; }
2036
+ .pj-crumb-sep { color: var(--muted); font-size: 0.85rem; }
2037
+ .pj-crumb-org { font-size: 0.85rem; font-weight: 600; color: var(--text); }
2038
+
2039
+ /* Title row — workspace name + status badge sit on one line. */
2040
+ .pj-ws-titlerow { display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap; }
2041
+ .pj-ws-title { margin: 0; }
2042
+
2043
+ /* Workspace action toolbar — a tinted bar so the (otherwise transparent) buttons
2044
+ read as real buttons rather than blending into the page. Consistent gap +
2045
+ vertical separators group the Settings/Add, AI-prompt, and review-gate controls. */
2046
+ .pj-toolbar { display: flex; align-items: center; flex-wrap: wrap; gap: 0.5rem; padding: 0.45rem 0.55rem; background: var(--bg-dim); border: 1px solid var(--border); border-radius: 10px; margin: 0.1rem 0 0.4rem; }
2047
+ .pj-toolbar .btn-ghost, .pj-toolbar .btn-outline { background: var(--card); box-shadow: var(--shadow-sm); }
2048
+ .pj-toolbar .btn-ghost:hover, .pj-toolbar .btn-outline:hover { background: var(--bg-surface); border-color: var(--text-muted); }
2049
+ .pj-toolbar-sep { width: 1px; align-self: stretch; min-height: 1.4rem; background: var(--border); margin: 0 0.15rem; }
2050
+ /* Publish-gate toggle: a chip grouped with the toolbar (after a separator) so it doesn't float alone */
2051
+ .pj-toolbar-gate { background: var(--card); border: 1px solid var(--border); border-radius: 8px; padding: 0.3rem 0.6rem; box-shadow: var(--shadow-sm); }
2052
+ .pj-toolbar-gate:hover { border-color: var(--text-muted); }
2022
2053
  .pj-gate-label { display: inline-flex; align-items: center; gap: 0.4rem; font-size: 0.85rem; color: var(--muted); cursor: pointer; }
2023
2054
  .pj-inbox { border: 1px solid var(--border); border-radius: 10px; padding: 0.75rem; background: var(--bg-dim); margin-bottom: 0.5rem; }
2024
2055
  .pj-approval { display: flex; align-items: center; justify-content: space-between; gap: 0.75rem; padding: 0.4rem 0; border-top: 1px solid var(--border); }
2025
2056
  .pj-approval:first-of-type { border-top: none; }
2026
2057
  .pj-approval-text { flex: 1; font-size: 0.88rem; }
2027
2058
  .pj-section { border: 1px solid var(--border); border-radius: 10px; padding: 0.6rem 0.75rem; background: var(--surface); }
2028
- .pj-section-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 0.4rem; }
2029
- .pj-section-title { font-weight: 600; text-transform: capitalize; }
2059
+ /* Action buttons sit right after the title (not pushed to the far edge) so they
2060
+ stay visually tied to the panel they act on. */
2061
+ .pj-section-head { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; margin-bottom: 0.4rem; }
2062
+ .pj-section-title { font-weight: 600; text-transform: capitalize; margin-right: 0.25rem; }
2063
+ /* Lift the add-actions off the panel background so they read as buttons. */
2064
+ .pj-section-head .btn-outline, .pj-section-head .btn-ghost { background: var(--card); box-shadow: var(--shadow-sm); }
2065
+ .pj-section-head .btn-outline:hover, .pj-section-head .btn-ghost:hover { background: var(--bg-surface); border-color: var(--text-muted); }
2030
2066
  .pj-draft-form { margin: 0.4rem 0; }
2031
2067
  .pj-drafts { display: flex; flex-direction: column; gap: 0.3rem; margin-bottom: 0.3rem; }
2032
2068
  .pj-item { display: flex; align-items: center; gap: 0.5rem; padding: 0.35rem 0; }
2033
- .pj-item-draft { border-left: 3px solid var(--border); padding-left: 0.5rem; }
2069
+ /* Draft rows get a warn-coloured rail + a bordered, bolder DRAFT chip so the
2070
+ draft state actually reads (the pale badge alone was nearly invisible). */
2071
+ .pj-item-draft { border-left: 3px solid var(--warn); padding-left: 0.5rem; }
2072
+ .pj-item-draft .badge-warn { border: 1px solid var(--warn-border); font-weight: 700; }
2073
+ /* Lift the inline Edit button off the panel so it stops blending in (same
2074
+ card-fill treatment as the section/toolbar actions). */
2075
+ .pj-item .btn-ghost { background: var(--card); box-shadow: var(--shadow-sm); }
2076
+ .pj-item .btn-ghost:hover { background: var(--bg-surface); border-color: var(--text-muted); }
2034
2077
  .pj-item-text { flex: 1; font-size: 0.9rem; }
2035
2078
  .pj-rec { border-radius: 6px; }
2036
2079
  .pj-rec-title { flex: 1; text-align: left; background: none; border: none; cursor: pointer; font-size: 0.9rem; color: var(--text); padding: 0; }
2037
2080
  .pj-rec-title:hover { color: var(--accent); }
2038
2081
  .pj-rec-fields { margin: 0.1rem 0 0.4rem 0.6rem; padding: 0.2rem 0.6rem; border-left: 2px solid var(--border); background: var(--bg-dim); border-radius: 0 6px 6px 0; }
2082
+ /* Dotted leader between each field label and its value — ties the two ends of a
2083
+ long row together so you can follow which value belongs to which key. */
2084
+ .pj-rec-fields .kv-row { align-items: baseline; gap: 0; }
2085
+ .pj-rec-fields .kv-label { flex: 1 1 auto; display: flex; align-items: baseline; min-width: 0; color: var(--muted); }
2086
+ .pj-rec-fields .kv-label::after { content: ""; flex: 1 1 auto; height: 0; margin: 0 0.45rem; border-bottom: 1px dotted var(--border); transform: translateY(-0.18em); }
2087
+ .pj-rec-fields .kv-value { flex: 0 1 auto; text-align: right; }
2039
2088
  .pj-rec-empty { font-size: 0.82rem; padding: 0.2rem 0; }
2040
2089
  .pj-empty { color: var(--muted); font-size: 0.85rem; padding: 0.2rem 0; }
2041
2090
  .pj-decision { font-size: 0.85rem; color: var(--muted); }
@@ -2045,10 +2094,26 @@
2045
2094
  .pj-errors { border: 1px solid var(--danger); border-radius: 10px; padding: 0.6rem 0.75rem; margin: 0.5rem 0; background: var(--bg-dim); }
2046
2095
  .pj-errors-title { font-weight: 600; margin-bottom: 0.3rem; color: var(--danger); }
2047
2096
  .pj-error-line { font-size: 0.82rem; color: var(--text); padding: 0.1rem 0; }
2048
- .pj-doc-tag { font-size: 0.68rem; color: var(--muted); border: 1px solid var(--border); border-radius: 6px; padding: 0 0.3rem; margin-left: 0.4rem; vertical-align: middle; }
2097
+ .pj-doc-tag { font-size: 0.68rem; font-weight: 600; color: var(--accent); background: color-mix(in srgb, var(--accent) 10%, var(--bg-dim)); border: 1px solid color-mix(in srgb, var(--accent) 28%, var(--border)); border-radius: 6px; padding: 0.05rem 0.4rem; margin-left: 0.4rem; vertical-align: middle; }
2049
2098
  .pj-doc-row { display: flex; align-items: center; gap: 0.5rem; padding: 0.25rem 0; }
2050
2099
  .pj-doc-link { background: none; border: none; color: var(--accent); cursor: pointer; font-size: 0.9rem; text-align: left; flex: 1; padding: 0; }
2051
2100
  .pj-doc-link:hover { text-decoration: underline; }
2101
+
2102
+ /* Public-sharing panel: per-space and per-doc public toggles + the viewer link. */
2103
+ .pj-share-space { padding: 0.35rem 0; border-bottom: 1px solid var(--border); }
2104
+ .pj-share-space:last-of-type { border-bottom: none; }
2105
+ .pj-share-row { display: flex; align-items: center; gap: 0.5rem; cursor: pointer; font-weight: 600; }
2106
+ .pj-share-row input, .pj-share-doc input { cursor: pointer; }
2107
+ .pj-share-docs { display: flex; flex-direction: column; gap: 0.2rem; margin: 0.3rem 0 0.4rem 1.6rem; }
2108
+ .pj-share-doc { display: flex; align-items: center; gap: 0.5rem; cursor: pointer; font-size: 0.9rem; color: var(--text); }
2109
+ .pj-share-doc-title { flex: 1; }
2110
+ .pj-share-link { color: var(--accent); font-size: 0.82rem; text-decoration: none; }
2111
+ .pj-share-link:hover { text-decoration: underline; }
2112
+ .pj-share-empty { margin: 0.2rem 0 0.4rem 1.6rem; }
2113
+ .pj-share-actions { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; }
2114
+ /* Card fill + shadow so the action buttons stop blending into the tinted panel — matches .pj-toolbar. */
2115
+ .pj-share-actions .btn-outline, .pj-share-actions .btn-ghost { background: var(--card); box-shadow: var(--shadow-sm); }
2116
+ .pj-share-actions .btn-outline:hover, .pj-share-actions .btn-ghost:hover { background: var(--bg-surface); border-color: var(--text-muted); }
2052
2117
  /* The detail / reading pane — a white, slightly elevated card so it reads as the focused content,
2053
2118
  distinct from the flat tree panel beside it. */
2054
2119
  .pj-doc-view { border: 1px solid var(--border); border-radius: 10px; padding: 1.4rem 1.8rem; margin: 0.4rem 0; background: var(--card); box-shadow: var(--shadow-sm); }
@@ -2116,6 +2181,17 @@
2116
2181
  .pj-part-agent { display: inline-flex; align-items: center; gap: 0.3rem; font-size: 0.8rem; border: 1px solid var(--border); border-radius: 6px; padding: 0.12rem 0.5rem; }
2117
2182
  .pj-part-agent.own { border-color: var(--success); }
2118
2183
  .pj-part-agent.ghost { color: var(--muted); border-style: dashed; opacity: 0.65; }
2184
+ /* Manage access — creator adds/roles/removes members in the participants panel */
2185
+ .pj-access { margin-top: 0.8rem; padding-top: 0.7rem; border-top: 1px dashed var(--border); display: flex; flex-direction: column; gap: 0.45rem; }
2186
+ .pj-access-title { font-size: 0.82rem; font-weight: 600; color: var(--muted); }
2187
+ .pj-access-row { display: flex; align-items: center; justify-content: space-between; gap: 0.6rem; flex-wrap: wrap; border: 1px solid var(--border); border-radius: 8px; padding: 0.4rem 0.6rem; background: var(--card); }
2188
+ .pj-access-who { display: flex; align-items: center; gap: 0.4rem; font-size: 0.86rem; }
2189
+ .pj-access-note { font-size: 0.78rem; color: var(--muted); }
2190
+ .pj-access-actions { display: flex; align-items: center; gap: 0.35rem; flex-wrap: wrap; }
2191
+ .pj-access-add { display: flex; align-items: center; gap: 0.4rem; flex-wrap: wrap; margin-top: 0.2rem; }
2192
+ .pj-access-input { flex: 1 1 14rem; min-width: 10rem; border: 1px solid var(--border); border-radius: 7px; padding: 0.4rem 0.6rem; background: var(--surface); color: var(--text); font-size: 0.86rem; }
2193
+ .pj-access-role { border: 1px solid var(--border); border-radius: 7px; padding: 0.4rem 0.5rem; background: var(--surface); color: var(--text); font-size: 0.84rem; }
2194
+ .pj-access-hint { font-size: 0.76rem; color: var(--muted); }
2119
2195
  /* Activity panel — GitHub-style contribution heatmap + audit-log feed */
2120
2196
  .pj-act { padding: 0.1rem; }
2121
2197
  .pj-act-count { font-size: 0.72rem; font-weight: 500; color: var(--muted); margin-left: 0.5rem; }
@@ -0,0 +1,206 @@
1
+ /**
2
+ * @file public-workspace-viewer.css
3
+ * @description Styles for the public (no-login) workspace document viewer. A two-column layout —
4
+ * table-of-contents sidebar + rendered markdown — that collapses to a single column on narrow
5
+ * screens, plus a print stylesheet so "Print / Save as PDF" produces a clean content-only page.
6
+ * All colors/spacing come from theme.css variables (no dark-only rgba, no hardcoded hex).
7
+ * @version-history
8
+ * v1.0.0 — 2026-06-09 — Initial: slice 2 of the workspace public-sharing plan.
9
+ */
10
+
11
+ .pwv-container {
12
+ max-width: 1100px;
13
+ margin: 0 auto;
14
+ padding: 1.5rem;
15
+ display: grid;
16
+ grid-template-columns: 240px 1fr;
17
+ gap: 1.5rem;
18
+ align-items: start;
19
+ min-height: 60vh;
20
+ }
21
+
22
+ /* ── Table of contents ── */
23
+ .pwv-toc {
24
+ position: sticky;
25
+ top: 1.5rem;
26
+ background: var(--card);
27
+ border: 1px solid var(--border);
28
+ border-radius: 10px;
29
+ padding: 0.75rem;
30
+ }
31
+
32
+ .pwv-toc-head {
33
+ font-size: 0.75rem;
34
+ font-weight: 700;
35
+ text-transform: uppercase;
36
+ letter-spacing: 0.05em;
37
+ color: var(--muted);
38
+ padding: 0.25rem 0.5rem 0.5rem;
39
+ }
40
+
41
+ .pwv-toc-list {
42
+ display: flex;
43
+ flex-direction: column;
44
+ gap: 0.15rem;
45
+ }
46
+
47
+ .pwv-toc-item {
48
+ text-align: left;
49
+ background: transparent;
50
+ border: none;
51
+ border-radius: 6px;
52
+ padding: 0.5rem 0.6rem;
53
+ font-size: 0.9rem;
54
+ color: var(--text);
55
+ cursor: pointer;
56
+ transition: background 0.12s ease;
57
+ }
58
+
59
+ .pwv-toc-item:hover {
60
+ background: var(--bg-dim);
61
+ }
62
+
63
+ .pwv-toc-item.pwv-active {
64
+ background: var(--bg-dim);
65
+ color: var(--accent);
66
+ font-weight: 600;
67
+ }
68
+
69
+ /* ── Main content ── */
70
+ .pwv-main {
71
+ min-width: 0;
72
+ }
73
+
74
+ .pwv-bar {
75
+ display: flex;
76
+ align-items: center;
77
+ justify-content: space-between;
78
+ gap: 0.75rem;
79
+ margin-bottom: 1rem;
80
+ }
81
+
82
+ .pwv-badge {
83
+ display: inline-block;
84
+ font-size: 0.72rem;
85
+ font-weight: 600;
86
+ text-transform: uppercase;
87
+ letter-spacing: 0.04em;
88
+ color: var(--accent);
89
+ background: var(--bg-dim);
90
+ border: 1px solid var(--border);
91
+ border-radius: 999px;
92
+ padding: 0.2rem 0.7rem;
93
+ }
94
+
95
+ /* Card fill + shadow so the print button stands out against the page (matches the in-app toolbar). */
96
+ .pwv-print { background: var(--card); box-shadow: var(--shadow-sm); }
97
+ .pwv-print:hover { background: var(--bg-surface); border-color: var(--text-muted); }
98
+
99
+ .pwv-doc {
100
+ background: var(--card);
101
+ border: 1px solid var(--border);
102
+ border-radius: 10px;
103
+ padding: 1.75rem 2rem;
104
+ }
105
+
106
+ /* ── Markdown typography (scoped to the viewer; mirrors the in-app document view) ── */
107
+ .pwv-doc .md-body { font-size: 0.95rem; line-height: 1.7; color: var(--text); max-width: 78ch; overflow-wrap: break-word; }
108
+ .pwv-doc .md-body > :first-child { margin-top: 0; }
109
+ .pwv-doc .md-body > :last-child { margin-bottom: 0; }
110
+ .pwv-doc .md-body h1,
111
+ .pwv-doc .md-body h2,
112
+ .pwv-doc .md-body h3,
113
+ .pwv-doc .md-body h4,
114
+ .pwv-doc .md-body h5,
115
+ .pwv-doc .md-body h6 { font-weight: 700; line-height: 1.3; color: var(--text); margin: 1.8em 0 0.6em; }
116
+ .pwv-doc .md-body h1 { font-size: 1.7rem; letter-spacing: -0.01em; padding-bottom: 0.3em; border-bottom: 2px solid var(--border); margin-top: 0.2em; }
117
+ .pwv-doc .md-body h2 { font-size: 1.32rem; padding-bottom: 0.25em; border-bottom: 1px solid var(--border); }
118
+ .pwv-doc .md-body h3 { font-size: 1.13rem; }
119
+ .pwv-doc .md-body h4 { font-size: 1rem; }
120
+ .pwv-doc .md-body h5 { font-size: 0.9rem; }
121
+ .pwv-doc .md-body h6 { font-size: 0.85rem; color: var(--muted); }
122
+ .pwv-doc .md-body p { margin: 0.85em 0; }
123
+ .pwv-doc .md-body ul,
124
+ .pwv-doc .md-body ol { margin: 0.7em 0; padding-left: 1.7em; }
125
+ .pwv-doc .md-body ul { list-style: disc; }
126
+ .pwv-doc .md-body ol { list-style: decimal; }
127
+ .pwv-doc .md-body li { margin: 0.32em 0; padding-left: 0.2em; }
128
+ .pwv-doc .md-body li > ul,
129
+ .pwv-doc .md-body li > ol { margin: 0.32em 0; }
130
+ .pwv-doc .md-body a { color: var(--accent); text-decoration: none; }
131
+ .pwv-doc .md-body a:hover { text-decoration: underline; }
132
+ .pwv-doc .md-body strong { font-weight: 700; color: var(--text); }
133
+ .pwv-doc .md-body em { font-style: italic; }
134
+ .pwv-doc .md-body .md-code { font-family: var(--font-mono, ui-monospace, "SF Mono", Menlo, Consolas, monospace); font-size: 0.85em; background: var(--bg-dim); padding: 0.12em 0.42em; border-radius: 4px; border: 1px solid var(--border); }
135
+ .pwv-doc .md-body .md-pre { background: var(--bg-dim); border: 1px solid var(--border); border-radius: 8px; padding: 0.9em 1.1em; overflow-x: auto; margin: 1em 0; line-height: 1.5; }
136
+ .pwv-doc .md-body .md-pre .md-code { background: none; border: none; padding: 0; font-size: 0.84rem; }
137
+ .pwv-doc .md-body blockquote { margin: 1em 0; padding: 0.3em 1.1em; border-left: 3px solid var(--accent); background: var(--bg-dim); border-radius: 0 6px 6px 0; color: var(--muted); }
138
+ .pwv-doc .md-body blockquote p { margin: 0.4em 0; }
139
+ .pwv-doc .md-body table { border-collapse: collapse; margin: 1em 0; width: 100%; font-size: 0.9rem; }
140
+ .pwv-doc .md-body th,
141
+ .pwv-doc .md-body td { border: 1px solid var(--border); padding: 0.45em 0.75em; text-align: left; vertical-align: top; }
142
+ .pwv-doc .md-body th { background: var(--bg-dim); font-weight: 600; }
143
+ .pwv-doc .md-body tbody tr:nth-child(even) { background: var(--bg-dim); }
144
+ .pwv-doc .md-body .md-img { max-width: 100%; height: auto; border-radius: 6px; margin: 0.6em 0; }
145
+ .pwv-doc .md-body hr { border: none; border-top: 1px solid var(--border); margin: 1.6em 0; }
146
+
147
+ /* ── States ── */
148
+ .pwv-state {
149
+ color: var(--muted);
150
+ padding: 2rem 0;
151
+ text-align: center;
152
+ }
153
+
154
+ .pwv-error {
155
+ color: var(--danger, #E8564A);
156
+ }
157
+
158
+ .pwv-empty {
159
+ grid-column: 1 / -1;
160
+ text-align: center;
161
+ padding: 4rem 1.5rem;
162
+ color: var(--muted);
163
+ }
164
+
165
+ .pwv-empty-icon {
166
+ font-size: 2.5rem;
167
+ margin-bottom: 0.5rem;
168
+ }
169
+
170
+ .pwv-empty h2 {
171
+ color: var(--text);
172
+ font-size: 1.25rem;
173
+ margin: 0 0 0.5rem;
174
+ }
175
+
176
+ /* ── Responsive: stack the TOC above the content on narrow screens ── */
177
+ @media (max-width: 720px) {
178
+ .pwv-container {
179
+ grid-template-columns: 1fr;
180
+ }
181
+ .pwv-toc {
182
+ position: static;
183
+ }
184
+ }
185
+
186
+ /* ── Print: content only — hide the global site nav, the TOC, the action bar, and the card chrome.
187
+ * `body.pwv-active` is added by the view while it is mounted (see public-workspace-viewer.js), so the
188
+ * nav-hiding rule applies only on this page and only the document content reaches paper. ── */
189
+ @media print {
190
+ /* Physical page margins so the text isn't flush against the paper edges. */
191
+ @page { margin: 1.8cm; }
192
+ body.pwv-active .topnav,
193
+ body.pwv-active .pwv-toc,
194
+ body.pwv-active .pwv-bar { display: none !important; }
195
+ body.pwv-active .pwv-container {
196
+ display: block !important;
197
+ max-width: none;
198
+ padding: 0;
199
+ }
200
+ body.pwv-active .pwv-doc {
201
+ border: none;
202
+ border-radius: 0;
203
+ padding: 0;
204
+ }
205
+ body.pwv-active .pwv-doc .md-body { max-width: none; }
206
+ }
@@ -429,11 +429,56 @@ export async function listWorkspaceRequests(orgId, ws) {
429
429
  } catch { return []; }
430
430
  }
431
431
 
432
- /** Approve or deny a member's access request to your workspace. */
432
+ /** Approve or deny a member's access request to your workspace. decision: 'approve'|'deny'|'viewer'|'contributor'. */
433
433
  export async function decideWorkspaceAccess(orgId, ws, requester, decision) {
434
434
  return apiPost(`/v1/organisms/${encodeURIComponent(orgId)}/workspace-access/decision`, { ws, requester, decision });
435
435
  }
436
436
 
437
+ /** Full access state for a workspace you manage: pending requests + current members with their roles. */
438
+ export async function getWorkspaceAccess(orgId, ws) {
439
+ try {
440
+ const resp = await apiGet(`/v1/organisms/${encodeURIComponent(orgId)}/workspace-access?ws=${encodeURIComponent(ws)}`);
441
+ return { requests: Array.isArray(resp?.data?.requests) ? resp.data.requests : [], members: Array.isArray(resp?.data?.members) ? resp.data.members : [] };
442
+ } catch { return { requests: [], members: [] }; }
443
+ }
444
+
445
+ /** Directly add (or re-role) a member: role 'viewer' (read) | 'contributor' (read+write). grantee = an
446
+ * owner name, GHII, or GAII — the grant applies to that owner (so all their agents inherit it). */
447
+ export async function grantWorkspaceRole(orgId, ws, grantee, role) {
448
+ return apiPost(`/v1/organisms/${encodeURIComponent(orgId)}/workspace-access/grant`, { ws, grantee, role });
449
+ }
450
+
451
+ /** Remove a member's access to a workspace you manage. */
452
+ export async function revokeWorkspaceRole(orgId, ws, grantee) {
453
+ return apiPost(`/v1/organisms/${encodeURIComponent(orgId)}/workspace-access/revoke`, { ws, grantee });
454
+ }
455
+
456
+ /* ── Public document-space sharing (meta.share) ──
457
+ * Independent of the access roles above: this controls what PUBLISHED document-space pages are
458
+ * readable by ANYONE with the public viewer link (no login). Creator/admin manages it. ── */
459
+
460
+ /** Current public-sharing state: { public, spaces: {name:bool}, docs: {"type/id":bool} }. */
461
+ export async function getWorkspaceShare(orgId, ws) {
462
+ try {
463
+ const resp = await apiGet(`/v1/organisms/${encodeURIComponent(orgId)}/workspace/share?ws=${encodeURIComponent(ws)}`);
464
+ const s = resp?.data?.share || {};
465
+ return { public: !!s.public, spaces: s.spaces || {}, docs: s.docs || {} };
466
+ } catch { return { public: false, spaces: {}, docs: {} }; }
467
+ }
468
+
469
+ /** Merge a patch ({ public?, spaces?, docs? }) into the workspace's public-sharing state. */
470
+ export async function setWorkspaceShare(orgId, ws, patch) {
471
+ const resp = await apiPut(`/v1/organisms/${encodeURIComponent(orgId)}/workspace/share?ws=${encodeURIComponent(ws)}`, patch);
472
+ const s = resp?.data?.share || {};
473
+ return { public: !!s.public, spaces: s.spaces || {}, docs: s.docs || {} };
474
+ }
475
+
476
+ /** The public, no-login viewer URL for a workspace (whole space) or a single document. */
477
+ export function publicViewerUrl(orgId, ws, doc) {
478
+ const base = `/v1/publicworkspaceviewer?org=${encodeURIComponent(orgId)}&ws=${encodeURIComponent(ws)}`;
479
+ return doc ? `${base}&type=${encodeURIComponent(doc.type)}&id=${encodeURIComponent(doc.id)}` : base;
480
+ }
481
+
437
482
  /** Create a new (empty) workspace: register it, return its { id, name }. The manifest is written
438
483
  * later by setup/generate. */
439
484
  export async function createWorkspace(orgId, name) {
@@ -674,6 +719,82 @@ export async function buildAccessPrompt(orgId, orgName, wsId, ws, variant = 'hum
674
719
  ].join('\n');
675
720
  }
676
721
 
722
+ /** Build a prompt to paste into an AI / coding agent: how to build a CONTRACT AGENT that processes THIS
723
+ * workspace. The agent owns a contract (inputs/outputs/lifecycle), provisions its spaces, and runs the
724
+ * request→result loop. Mirrors docs/agent-workspace-contracts.md with this workspace's concrete ids. */
725
+ export async function buildContractAgentPrompt(orgId, orgName, wsId, ws) {
726
+ const nodeUrl = window.location.origin;
727
+ const m = ws?.manifest || {};
728
+ const wsName = m.name || wsId;
729
+ const types = (m.objectTypes || []).filter(ot => ot.backing === 'memory');
730
+ const described = [];
731
+ for (const ot of types) {
732
+ const schema = ot.mode !== 'document' ? await getObjectSchema(orgId, wsId, ot.namespace).catch(() => null) : null;
733
+ described.push(describeType(ot, schema));
734
+ }
735
+ const structure = described.join('\n') || '(no spaces declared yet)';
736
+ return [
737
+ `TASK: build an AIMEAT "contract agent" that PROCESSES this workspace — it reads requests, does the`,
738
+ `work, and writes results back. The agent OWNS a contract: the spaces it READS (inputs), the spaces`,
739
+ `it WRITES (outputs), and the status lifecycle. Follow the convention exactly so it appears and works`,
740
+ `smoothly. Full reference: ${nodeUrl}/v1/agents/me/handbook/appdev (the "Workspace contracts" section)`,
741
+ `and docs/agent-workspace-contracts.md.`,
742
+ ``,
743
+ `CONNECTION`,
744
+ `- Node: ${nodeUrl}`,
745
+ `- Organism: "${orgName || orgId}" id: ${orgId}`,
746
+ `- Workspace: "${wsName}" ws: ${wsId}`,
747
+ `- Use the AIMEAT MCP tools (aimeat_workspace_*, aimeat_organism_*) or the shell-callable connector`,
748
+ ` (aimeat connect call ...) — no LLM is needed in the I/O path. If AIMEAT tools are unavailable, STOP.`,
749
+ ``,
750
+ `EXISTING SPACES (don't drop or rename these — UNION them with your contract's spaces):`,
751
+ structure,
752
+ ``,
753
+ `1) DEFINE THE CONTRACT (embed it in the agent):`,
754
+ ` contract:`,
755
+ ` id: <capability> # e.g. research`,
756
+ ` inputs: # what the agent reads + reacts to`,
757
+ ` - space: <name> # objectType NAME, e.g. research-request`,
758
+ ` mode: records # records (schema-locked) | document`,
759
+ ` schema: { id, ..., status: requested|in-progress|done|failed, requested_by, result_ref? }`,
760
+ ` trigger: status == 'requested'`,
761
+ ` outputs: # what the agent writes`,
762
+ ` - space: <name> # e.g. research-result`,
763
+ ` mode: records`,
764
+ ` schema: { id, request_ref, ... }`,
765
+ ` lifecycle: requested → in-progress → done (+ result_ref) | failed`,
766
+ ``,
767
+ `2) PROVISION the contract's spaces with add_spaces — the server UNIONS them into the manifest, skips`,
768
+ ` any that already exist, and fills objectType defaults, so you never resend the whole manifest`,
769
+ ` (safe + idempotent). Manifest edits are CREATOR-ONLY: a same-owner agent does this itself; for a`,
770
+ ` cross-owner agent the creator does it.`,
771
+ ` aimeat_workspace_update { organism_id:"${orgId}", ws:"${wsId}",`,
772
+ ` add_spaces: [ { name:"<input-space>", namespace:"shared.<inputs>", mode:"records" },`,
773
+ ` { name:"<output-space>", namespace:"shared.<outputs>", mode:"records" } ],`,
774
+ ` schemas: { "shared.<inputs>": <jsonSchema>, "shared.<outputs>": <jsonSchema> } }`,
775
+ ` → returns { added, skipped }. Pass just { name, namespace, mode } per space; defaults are filled.`,
776
+ ``,
777
+ `3) AUTHORIZE the agent to write (skip for a same-owner agent — it already can):`,
778
+ ` POST ${nodeUrl}/v1/organisms/${orgId}/workspace-access/grant`,
779
+ ` body { "ws":"${wsId}", "grantee":"<agent-owner | agent#owner@node>", "role":"contributor" }`,
780
+ ` (viewer = read only; contributor = read + write. The creator manages this in "Who works here".)`,
781
+ ``,
782
+ `4) RUN THE PROCESSING LOOP (deterministic, repeatable):`,
783
+ ` discover member workspaces (aimeat_organism_list → aimeat_workspace_list) → for each that has your`,
784
+ ` input space: aimeat_workspace_read → find inputs where the trigger holds → CLAIM it`,
785
+ ` (aimeat_workspace_write status:"in-progress" + publish) → do the work → WRITE the output space`,
786
+ ` (aimeat_workspace_write + publish) → ADVANCE the input (status:"done", result_ref:<outId> + publish).`,
787
+ ` On error: set the input status:"failed" with an error field.`,
788
+ ``,
789
+ `RULES: validate every RECORDS write against its schema (a bad write is rejected). NEVER drop/rename an`,
790
+ `existing space. Only the creator/same-owner edits the manifest; a contributor writes records only.`,
791
+ `Writes are attributed to the agent automatically — it appears in "Who works here" + the activity`,
792
+ `heatmap, and its results are visible to everyone who can read the workspace.`,
793
+ ``,
794
+ `Start: read the workspace, decide your input/output spaces, provision them, grant access, run the loop.`,
795
+ ].join('\n');
796
+ }
797
+
677
798
  /** Manually add an object type to the manifest (no AI). mode 'document' needs no schema;
678
799
  * 'records' gets a starter {id,title} schema that can be refined later via Restructure. */
679
800
  export async function addSpace(orgId, wsId, manifest, name, mode) {
@@ -387,8 +387,13 @@ for completeness but are NOT needed for typical app building:
387
387
  - Agent collaboration (shared memory, organisms)
388
388
  - Organism workspaces: an organism can hold manifest-driven workspaces of markdown documents
389
389
  (a wiki) and schema-locked record lists, with a draft -> publish -> version flow. Connected
390
- agents use the aimeat_workspace_* MCP tools (list / read / write_draft / publish / add_document);
391
- the manifest lives at organism.{id}.w.{ws}.meta.manifest.
390
+ agents use the aimeat_workspace_* MCP tools (list / read / write / publish / object_delete /
391
+ access / transfer / update / create); the manifest lives at organism.{id}.w.{ws}.meta.manifest.
392
+ Access is creator-managed: viewer (read) | contributor (read+write). Reading a workspace shows
393
+ ALL its content. To build an agent that PROCESSES a workspace (reads requests -> writes results),
394
+ it carries a "contract" (inputs/outputs/lifecycle) — see the guide at
395
+ GET /v1/agents/me/handbook/appdev (Workspace contracts section), full text in
396
+ docs/agent-workspace-contracts.md.
392
397
  - Micro-memory, App store, Matches, Push notifications
393
398
 
394
399
  ## Building Apps on AIMEAT
@@ -85,6 +85,7 @@
85
85
  <link rel="stylesheet" href="/css/views/admin.css">
86
86
  <link rel="stylesheet" href="/css/views/admin-agent-integration.css">
87
87
  <link rel="stylesheet" href="/css/views/public-knowledge-viewer.css">
88
+ <link rel="stylesheet" href="/css/views/public-workspace-viewer.css">
88
89
  <script type="importmap">
89
90
  {
90
91
  "imports": {
@@ -266,6 +267,7 @@
266
267
  '/v1/admin': () => import('/views/admin.js' + B),
267
268
  '/v1/help': () => import('/views/help.js' + B),
268
269
  '/v1/publicknowledgeviewer': () => import('/views/public-knowledge-viewer.js' + B),
270
+ '/v1/publicworkspaceviewer': () => import('/views/public-workspace-viewer.js' + B),
269
271
  };
270
272
 
271
273
  // Match route, handling query params for special views