aimeat 1.30.2 → 1.32.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.
- package/dist/locales/en.json +246 -1
- package/dist/locales/fi.json +246 -1
- package/dist/public/components/InboxLink.js +29 -0
- package/dist/public/components/offer-card-view.js +87 -0
- package/dist/public/css/views/companies.css +65 -0
- package/dist/public/css/views/inbox.css +153 -1
- package/dist/public/css/views/members.css +33 -0
- package/dist/public/css/views/my-company.css +315 -0
- package/dist/public/css/views/profile.css +22 -0
- package/dist/public/js/services/messages.js +21 -3
- package/dist/public/js/services/notebook.js +16 -6
- package/dist/public/llms-template.txt +7 -0
- package/dist/public/spa.html +14 -0
- package/dist/public/views/companies.js +190 -0
- package/dist/public/views/members.js +42 -0
- package/dist/public/views/my-company.js +664 -0
- package/dist/public/views/portfolio-themes.js +77 -0
- package/dist/public/views/profile/agents-tab.js +4 -1
- package/dist/public/views/profile/discover-tab.js +118 -0
- package/dist/public/views/profile/inbox-tab.js +663 -16
- package/dist/public/views/profile/landing-page.js +2 -1
- package/dist/public/views/profile/notebook-card.js +11 -3
- package/dist/public/views/profile/offers-tab.js +5 -24
- package/dist/public/views/profile/organisms/home.js +5 -3
- package/dist/public/views/profile/organisms/mindmap.js +14 -3
- package/dist/public/views/profile/organisms/workspace.js +5 -2
- package/dist/public/views/profile/organisms-tab.js +12 -4
- package/dist/public/views/profile.js +2 -0
- package/dist/src/cli/connect/mcp/tools/core.d.ts.map +1 -1
- package/dist/src/cli/connect/mcp/tools/core.js +34 -0
- package/dist/src/cli/connect/mcp/tools/core.js.map +1 -1
- package/dist/src/cli/connect/mcp/tools/dm-messages.d.ts +1 -0
- package/dist/src/cli/connect/mcp/tools/dm-messages.d.ts.map +1 -1
- package/dist/src/cli/connect/mcp/tools/dm-messages.js +23 -0
- package/dist/src/cli/connect/mcp/tools/dm-messages.js.map +1 -1
- package/dist/src/cli/connect/mcp/tools/organisms.d.ts.map +1 -1
- package/dist/src/cli/connect/mcp/tools/organisms.js +31 -0
- package/dist/src/cli/connect/mcp/tools/organisms.js.map +1 -1
- package/dist/src/cli/connect/mcp/tools/workspaces.d.ts.map +1 -1
- package/dist/src/cli/connect/mcp/tools/workspaces.js +4 -0
- package/dist/src/cli/connect/mcp/tools/workspaces.js.map +1 -1
- package/dist/src/generated/api-types.d.ts +249 -0
- package/dist/src/generated/api-types.d.ts.map +1 -1
- package/dist/src/generated/prisma-postgres/edge.js +6 -3
- package/dist/src/generated/prisma-postgres/index-browser.js +3 -0
- package/dist/src/generated/prisma-postgres/index.d.ts +112 -1
- package/dist/src/generated/prisma-postgres/index.js +6 -3
- package/dist/src/generated/prisma-postgres/package.json +1 -1
- package/dist/src/generated/prisma-postgres/schema.prisma +4 -0
- package/dist/src/generated/prisma-postgres/wasm.js +6 -3
- package/dist/src/mcp/annotations.d.ts.map +1 -1
- package/dist/src/mcp/annotations.js +2 -0
- package/dist/src/mcp/annotations.js.map +1 -1
- package/dist/src/mcp/catalog/definitions.d.ts.map +1 -1
- package/dist/src/mcp/catalog/definitions.js +33 -1
- package/dist/src/mcp/catalog/definitions.js.map +1 -1
- package/dist/src/mcp/catalog/scopes.d.ts.map +1 -1
- package/dist/src/mcp/catalog/scopes.js +1 -0
- package/dist/src/mcp/catalog/scopes.js.map +1 -1
- package/dist/src/mcp/catalog/surfaces.d.ts.map +1 -1
- package/dist/src/mcp/catalog/surfaces.js +7 -4
- package/dist/src/mcp/catalog/surfaces.js.map +1 -1
- package/dist/src/mcp/core.d.ts.map +1 -1
- package/dist/src/mcp/core.js +49 -0
- package/dist/src/mcp/core.js.map +1 -1
- package/dist/src/mcp/dm-messages.d.ts +2 -0
- package/dist/src/mcp/dm-messages.d.ts.map +1 -1
- package/dist/src/mcp/dm-messages.js +45 -1
- package/dist/src/mcp/dm-messages.js.map +1 -1
- package/dist/src/models/message-schemas.d.ts +140 -2
- package/dist/src/models/message-schemas.d.ts.map +1 -1
- package/dist/src/models/message-schemas.js +60 -3
- package/dist/src/models/message-schemas.js.map +1 -1
- package/dist/src/routes/bootstrap.d.ts.map +1 -1
- package/dist/src/routes/bootstrap.js +3 -0
- package/dist/src/routes/bootstrap.js.map +1 -1
- package/dist/src/routes/discover.d.ts +22 -0
- package/dist/src/routes/discover.d.ts.map +1 -0
- package/dist/src/routes/discover.js +123 -0
- package/dist/src/routes/discover.js.map +1 -0
- package/dist/src/routes/federation-sync.d.ts.map +1 -1
- package/dist/src/routes/federation-sync.js +69 -2
- package/dist/src/routes/federation-sync.js.map +1 -1
- package/dist/src/routes/messages.d.ts.map +1 -1
- package/dist/src/routes/messages.js +102 -3
- package/dist/src/routes/messages.js.map +1 -1
- package/dist/src/routes/organisms.d.ts +3 -0
- package/dist/src/routes/organisms.d.ts.map +1 -1
- package/dist/src/routes/organisms.js +11 -32
- package/dist/src/routes/organisms.js.map +1 -1
- package/dist/src/routes/portal.d.ts.map +1 -1
- package/dist/src/routes/portal.js +3 -0
- package/dist/src/routes/portal.js.map +1 -1
- package/dist/src/routes/portfolio.d.ts.map +1 -1
- package/dist/src/routes/portfolio.js +30 -0
- package/dist/src/routes/portfolio.js.map +1 -1
- package/dist/src/server-bootstrap/routes-loader.d.ts.map +1 -1
- package/dist/src/server-bootstrap/routes-loader.js +2 -0
- package/dist/src/server-bootstrap/routes-loader.js.map +1 -1
- package/dist/src/services/connect-tunnel.d.ts +3 -0
- package/dist/src/services/connect-tunnel.d.ts.map +1 -1
- package/dist/src/services/connect-tunnel.js +6 -0
- package/dist/src/services/connect-tunnel.js.map +1 -1
- package/dist/src/services/discovery/__tests__/discovery.test.d.ts +2 -0
- package/dist/src/services/discovery/__tests__/discovery.test.d.ts.map +1 -0
- package/dist/src/services/discovery/__tests__/discovery.test.js +178 -0
- package/dist/src/services/discovery/__tests__/discovery.test.js.map +1 -0
- package/dist/src/services/discovery/classify.d.ts +36 -0
- package/dist/src/services/discovery/classify.d.ts.map +1 -0
- package/dist/src/services/discovery/classify.js +61 -0
- package/dist/src/services/discovery/classify.js.map +1 -0
- package/dist/src/services/discovery/facets.d.ts +21 -0
- package/dist/src/services/discovery/facets.d.ts.map +1 -0
- package/dist/src/services/discovery/facets.js +0 -0
- package/dist/src/services/discovery/facets.js.map +1 -0
- package/dist/src/services/discovery/index.d.ts +22 -0
- package/dist/src/services/discovery/index.d.ts.map +1 -0
- package/dist/src/services/discovery/index.js +22 -0
- package/dist/src/services/discovery/index.js.map +1 -0
- package/dist/src/services/discovery/normalize.d.ts +25 -0
- package/dist/src/services/discovery/normalize.d.ts.map +1 -0
- package/dist/src/services/discovery/normalize.js +108 -0
- package/dist/src/services/discovery/normalize.js.map +1 -0
- package/dist/src/services/discovery/registry.d.ts +30 -0
- package/dist/src/services/discovery/registry.d.ts.map +1 -0
- package/dist/src/services/discovery/registry.js +31 -0
- package/dist/src/services/discovery/registry.js.map +1 -0
- package/dist/src/services/discovery/run.d.ts +23 -0
- package/dist/src/services/discovery/run.d.ts.map +1 -0
- package/dist/src/services/discovery/run.js +20 -0
- package/dist/src/services/discovery/run.js.map +1 -0
- package/dist/src/services/discovery/setup.d.ts +16 -0
- package/dist/src/services/discovery/setup.d.ts.map +1 -0
- package/dist/src/services/discovery/setup.js +12 -0
- package/dist/src/services/discovery/setup.js.map +1 -0
- package/dist/src/services/discovery/sources/memory-source.d.ts +24 -0
- package/dist/src/services/discovery/sources/memory-source.d.ts.map +1 -0
- package/dist/src/services/discovery/sources/memory-source.js +183 -0
- package/dist/src/services/discovery/sources/memory-source.js.map +1 -0
- package/dist/src/services/discovery/sources/table-sources.d.ts +27 -0
- package/dist/src/services/discovery/sources/table-sources.d.ts.map +1 -0
- package/dist/src/services/discovery/sources/table-sources.js +128 -0
- package/dist/src/services/discovery/sources/table-sources.js.map +1 -0
- package/dist/src/services/discovery/types.d.ts +117 -0
- package/dist/src/services/discovery/types.d.ts.map +1 -0
- package/dist/src/services/discovery/types.js +19 -0
- package/dist/src/services/discovery/types.js.map +1 -0
- package/dist/src/services/handbooks/agent.d.ts +1 -1
- package/dist/src/services/handbooks/agent.d.ts.map +1 -1
- package/dist/src/services/handbooks/agent.js +9 -3
- package/dist/src/services/handbooks/agent.js.map +1 -1
- package/dist/src/services/message-broadcast.d.ts +49 -0
- package/dist/src/services/message-broadcast.d.ts.map +1 -0
- package/dist/src/services/message-broadcast.js +116 -0
- package/dist/src/services/message-broadcast.js.map +1 -0
- package/dist/src/services/message-delivery.d.ts.map +1 -1
- package/dist/src/services/message-delivery.js +3 -0
- package/dist/src/services/message-delivery.js.map +1 -1
- package/dist/src/services/message-send.d.ts +9 -1
- package/dist/src/services/message-send.d.ts.map +1 -1
- package/dist/src/services/message-send.js +11 -5
- package/dist/src/services/message-send.js.map +1 -1
- package/dist/src/services/presence.d.ts +8 -0
- package/dist/src/services/presence.d.ts.map +1 -1
- package/dist/src/services/presence.js +38 -0
- package/dist/src/services/presence.js.map +1 -1
- package/dist/src/services/workspace-enrichment.d.ts +15 -5
- package/dist/src/services/workspace-enrichment.d.ts.map +1 -1
- package/dist/src/services/workspace-enrichment.js +52 -14
- package/dist/src/services/workspace-enrichment.js.map +1 -1
- package/dist/src/storage/interface.d.ts +49 -0
- package/dist/src/storage/interface.d.ts.map +1 -1
- package/dist/src/storage/providers/mongodb/index.d.ts +1 -0
- package/dist/src/storage/providers/mongodb/index.d.ts.map +1 -1
- package/dist/src/storage/providers/mongodb/index.js +16 -0
- package/dist/src/storage/providers/mongodb/index.js.map +1 -1
- package/dist/src/storage/providers/sqlite/index.d.ts +1 -0
- package/dist/src/storage/providers/sqlite/index.d.ts.map +1 -1
- package/dist/src/storage/providers/sqlite/index.js +3 -0
- package/dist/src/storage/providers/sqlite/index.js.map +1 -1
- package/dist/src/storage/providers/sqlite/repos/direct-message.d.ts +3 -0
- package/dist/src/storage/providers/sqlite/repos/direct-message.d.ts.map +1 -1
- package/dist/src/storage/providers/sqlite/repos/direct-message.js +15 -2
- package/dist/src/storage/providers/sqlite/repos/direct-message.js.map +1 -1
- package/dist/src/storage/providers/sqlite/schema.d.ts.map +1 -1
- package/dist/src/storage/providers/sqlite/schema.js +10 -0
- package/dist/src/storage/providers/sqlite/schema.js.map +1 -1
- package/dist/src/storage/repositories/direct-message.repository.d.ts +3 -0
- package/dist/src/storage/repositories/direct-message.repository.d.ts.map +1 -1
- package/package.json +1 -1
- package/prisma/schema.postgres.prisma +4 -0
- package/prisma/schema.prisma +4 -0
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* @structure
|
|
10
10
|
* - classifyNote(text) — POST /v1/librarian/classify
|
|
11
11
|
* - distributeNote(text) — POST /v1/librarian/distribute (split into placed chunks)
|
|
12
|
-
* - materializeDocument(plan) — resolve/create org → ws → document space →
|
|
12
|
+
* - materializeDocument(plan) — resolve/create org → ws → document space → draft→publish doc → drop source
|
|
13
13
|
* - distributeChunks(chunks, sourceKey, onProgress) — materialize each chunk to its home
|
|
14
14
|
* - getNotebookSettings/saveNotebookSettings — the per-owner trust toggles (notebook.settings)
|
|
15
15
|
* @version-history
|
|
@@ -18,10 +18,13 @@
|
|
|
18
18
|
* v1.2.0 — 2026-06-21 — (reverted) materializeRecord/patchRecord removed — the Tracked Response flow
|
|
19
19
|
* now writes records through the proper workspace draft→publish path (services/organisms.js), not a
|
|
20
20
|
* raw memory write, so records land in the right namespace/owner and show up with activity.
|
|
21
|
+
* v1.3.0 — 2026-06-23 — materializeDocument now writes via writeDraft + publishDraft (was a raw
|
|
22
|
+
* `.latest` memory write) so notebook documents get version history and appear in the workspace
|
|
23
|
+
* activity log/heatmap — the document-path counterpart to the v1.2.0 record fix.
|
|
21
24
|
*/
|
|
22
25
|
import { api, apiPost } from '/js/api.js';
|
|
23
26
|
import { createMemory, getMemory, deleteMemory } from '/js/services/memory.js';
|
|
24
|
-
import { createOrganism, saveManifest, listWorkspaces, saveWorkspaceRegistry, wsRoot } from '/js/services/organisms.js';
|
|
27
|
+
import { createOrganism, saveManifest, listWorkspaces, saveWorkspaceRegistry, wsRoot, writeDraft, publishDraft } from '/js/services/organisms.js';
|
|
25
28
|
|
|
26
29
|
const DOC_SPACE = 'pages';
|
|
27
30
|
|
|
@@ -162,11 +165,18 @@ export async function materializeDocument(plan) {
|
|
|
162
165
|
}
|
|
163
166
|
}
|
|
164
167
|
|
|
165
|
-
// 4. Write the document.
|
|
168
|
+
// 4. Write the document through the proper workspace draft→publish path (NOT a raw `.latest` write).
|
|
169
|
+
// A raw write to `…{space}.{docId}.latest` lands the content but produces no version history and
|
|
170
|
+
// no activity event (the feed is derived from `.draft`/`.version.N` keys), so notebook documents
|
|
171
|
+
// used to be invisible in the workspace activity log / heatmap. Going through writeDraft +
|
|
172
|
+
// publishDraft mints `.version.1` + `.latest` and shows up like every other published object —
|
|
173
|
+
// matching the Tracked-Response record path migrated in v1.2.0.
|
|
166
174
|
const docId = rid('doc-');
|
|
167
|
-
const
|
|
168
|
-
const
|
|
169
|
-
if (
|
|
175
|
+
const docValue = { id: docId, title: plan.title, markdown: plan.markdown };
|
|
176
|
+
const draftResp = await writeDraft(organismId, workspaceId, space, docId, docValue);
|
|
177
|
+
if (draftResp?.ok === false) throw new Error(draftResp.error?.message || 'Could not write document');
|
|
178
|
+
const pubResp = await publishDraft(organismId, workspaceId, space, docId);
|
|
179
|
+
if (pubResp?.ok === false) throw new Error(pubResp.error?.message || 'Could not publish document');
|
|
170
180
|
|
|
171
181
|
// 5. Drop the source inbox note (it has been filed).
|
|
172
182
|
if (plan.sourceKey) await deleteMemory(plan.sourceKey).catch(() => {});
|
|
@@ -285,6 +285,7 @@ entry: index.html
|
|
|
285
285
|
|
|
286
286
|
### Other options (not app building)
|
|
287
287
|
|
|
288
|
+
- **Discover everything from one place:** `GET /v1/discover` — the master directory. One faceted query across all domains (capabilities, workflows, knowledge, decisions, companies+offerings, apps, documents, memory). `?mode=map` (or `/v1/discover/facets`) returns counts by type/tag so you can see what exists before pulling content; `scope=own|public|shared`. MCP: `aimeat_discover`.
|
|
288
289
|
- Browse this node: `GET /v1/catalogue`, `GET /v1/apps`, `GET /v1/stats`
|
|
289
290
|
- Connect as AI agent: see "Connecting: Device Authorization" section below
|
|
290
291
|
- Anonymous quick test: `POST /v1/auth/anonymous`
|
|
@@ -1668,6 +1669,12 @@ Discover actions, agents, and boards available on this node.
|
|
|
1668
1669
|
|
|
1669
1670
|
#### Endpoints
|
|
1670
1671
|
|
|
1672
|
+
GET {{BASE_URL}}/v1/discover — Master directory: unified cross-domain discovery (start here)
|
|
1673
|
+
Query: ?mode=find&scope=own|public|shared&q=text&type=capability,knowledge&tags=finance&segment=research&page=1&per_page=20
|
|
1674
|
+
→ 200: { "ok": true, "data": { "entries": [{ "type": "capability", "segment": "manual", "id": "...", "title": "...", "description": "...", "tags": [...], "visibility": "public", "owner": "alice@node", "updatedAt": "...", "href": "/v1/..." }], "total": 42, "scope": "own", "facets": { "types": [...], "segments": [...], "tags": [...] } } }
|
|
1675
|
+
GET {{BASE_URL}}/v1/discover/facets — Map mode: counts by type/segment/tag only (cheap "what exists?" probe), same filters + scope
|
|
1676
|
+
→ 200: { "ok": true, "data": { "scope": "public", "total": 42, "types": [{ "value": "knowledge", "count": 18 }], "segments": [...], "tags": [...] } }
|
|
1677
|
+
|
|
1671
1678
|
GET {{BASE_URL}}/v1/catalogue — Full catalogue listing
|
|
1672
1679
|
Query: ?search=translate&category=language&page=1&per_page=20&include_federated=true
|
|
1673
1680
|
→ 200: { "ok": true, "data": { "actions": [{ "id": "...", "display_name": "...", "description": "...", "provider_gaii": "...", "category": "...", "pricing": { "base_morsels": 5 }, "tags": [...] }], "total": 42 } }
|
package/dist/public/spa.html
CHANGED
|
@@ -86,10 +86,13 @@
|
|
|
86
86
|
<link rel="stylesheet" href="/css/views/aimeat-os.css">
|
|
87
87
|
<link rel="stylesheet" href="/css/views/openclaw.css">
|
|
88
88
|
<link rel="stylesheet" href="/css/views/portfolio.css">
|
|
89
|
+
<link rel="stylesheet" href="/css/views/members.css">
|
|
89
90
|
<link rel="stylesheet" href="/css/views/inbox.css">
|
|
90
91
|
<link rel="stylesheet" href="/css/components/tags.css">
|
|
91
92
|
<link rel="stylesheet" href="/css/components/image-deliverable.css">
|
|
92
93
|
<link rel="stylesheet" href="/css/views/help.css">
|
|
94
|
+
<link rel="stylesheet" href="/css/views/my-company.css">
|
|
95
|
+
<link rel="stylesheet" href="/css/views/companies.css">
|
|
93
96
|
<link rel="stylesheet" href="/css/views/capabilities.css">
|
|
94
97
|
<link rel="stylesheet" href="/css/views/agents-detail.css">
|
|
95
98
|
<link rel="stylesheet" href="/css/views/scheduler.css">
|
|
@@ -187,8 +190,10 @@
|
|
|
187
190
|
"/components/Modal.js": "/components/Modal.js",
|
|
188
191
|
"/components/useViewCSS.js": "/components/useViewCSS.js",
|
|
189
192
|
"/components/Markdown.js": "/components/Markdown.js",
|
|
193
|
+
"/components/InboxLink.js": "/components/InboxLink.js",
|
|
190
194
|
"/components/JsonView.js": "/components/JsonView.js",
|
|
191
195
|
"/components/ImageDeliverable.js": "/components/ImageDeliverable.js",
|
|
196
|
+
"/components/offer-card-view.js": "/components/offer-card-view.js",
|
|
192
197
|
"/components/Mermaid.js": "/components/Mermaid.js",
|
|
193
198
|
"/components/NotificationBell.js": "/components/NotificationBell.js",
|
|
194
199
|
"/components/CopyButton.js": "/components/CopyButton.js",
|
|
@@ -224,6 +229,7 @@
|
|
|
224
229
|
"/js/services/admin-agent-integration.js": "/js/services/admin-agent-integration.js",
|
|
225
230
|
"/js/services/schedules.js": "/js/services/schedules.js",
|
|
226
231
|
"/js/services/workflows.js": "/js/services/workflows.js",
|
|
232
|
+
"/views/portfolio-themes.js": "/views/portfolio-themes.js",
|
|
227
233
|
"/views/profile/shared.js": "/views/profile/shared.js",
|
|
228
234
|
"/views/profile/generator-settings.js": "/views/profile/generator-settings.js",
|
|
229
235
|
"/views/profile/organisms/helpers.js": "/views/profile/organisms/helpers.js",
|
|
@@ -338,6 +344,8 @@
|
|
|
338
344
|
'/v1/how-it-works': () => import('/views/how-it-works.js' + B),
|
|
339
345
|
'/v1/business': () => import('/views/business.js' + B),
|
|
340
346
|
'/v1/profile': () => import('/views/profile.js' + B),
|
|
347
|
+
'/v1/my-company': () => import('/views/my-company.js' + B),
|
|
348
|
+
'/v1/companies': () => import('/views/companies.js' + B),
|
|
341
349
|
'/v1/app-grant': () => import('/views/app-grant.js' + B),
|
|
342
350
|
'/v1/guides': () => import('/views/guides.js' + B),
|
|
343
351
|
'/v1/hobbies': () => import('/views/hobbies.js' + B),
|
|
@@ -346,6 +354,7 @@
|
|
|
346
354
|
'/v1/openclaw': () => import('/views/openclaw.js' + B),
|
|
347
355
|
'/v1/classic': () => import('/views/portal-classic.js' + B),
|
|
348
356
|
'/v1/portfolio': () => import('/views/portfolio.js' + B),
|
|
357
|
+
'/v1/members': () => import('/views/members.js' + B),
|
|
349
358
|
'/v1/admin': () => import('/views/admin.js' + B),
|
|
350
359
|
'/v1/help': () => import('/views/help.js' + B),
|
|
351
360
|
'/v1/publicknowledgeviewer': () => import('/views/public-knowledge-viewer.js' + B),
|
|
@@ -508,6 +517,8 @@
|
|
|
508
517
|
{ id: 'try', path: '/v1/portal', key: 'nav.try' },
|
|
509
518
|
{ id: 'howItWorks', path: '/v1/how-it-works', key: 'nav.howItWorks', fallback: 'How it works' },
|
|
510
519
|
{ id: 'business', path: '/v1/business', key: 'nav.business', fallback: 'For your business' },
|
|
520
|
+
{ id: 'companies', path: '/v1/companies', key: 'nav.companies', fallback: 'Companies' },
|
|
521
|
+
{ id: 'members', path: '/v1/members', key: 'nav.members', fallback: 'Members' },
|
|
511
522
|
{ id: 'devView', path: '/v1/portal?view=dev', key: 'nav.devView', matchActive: false },
|
|
512
523
|
{ id: 'help', path: '/v1/help', key: 'nav.help' },
|
|
513
524
|
];
|
|
@@ -610,6 +621,9 @@
|
|
|
610
621
|
<a href="/v1/profile" class="profile-link visible ${currentPath === '/v1/profile' ? 'active' : ''}" onClick=${(e) => { handleNav(e, '/v1/profile'); setMenuOpen(false); }}>
|
|
611
622
|
${t('nav.profile')}
|
|
612
623
|
</a>
|
|
624
|
+
<a href="/v1/my-company" class="${currentPath === '/v1/my-company' ? 'active' : ''}" onClick=${(e) => { handleNav(e, '/v1/my-company'); setMenuOpen(false); }}>
|
|
625
|
+
${t('nav.myCompany')}
|
|
626
|
+
</a>
|
|
613
627
|
${session.roles && session.roles.includes('operator') && html`
|
|
614
628
|
<a href="/v1/admin" class="${currentPath === '/v1/admin' ? 'active' : ''}" onClick=${(e) => { handleNav(e, '/v1/admin'); setMenuOpen(false); }}>
|
|
615
629
|
${t('nav.admin')}
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file companies.js
|
|
3
|
+
* @description Public company directory + public company page (the Enterprise discovery surface).
|
|
4
|
+
* Anyone (even anonymous) can browse every company on the node (GET /v1/orgs/directory), open one
|
|
5
|
+
* to see its public profile (name, Y-tunnus, description) and catalogue (GET
|
|
6
|
+
* /v1/orgs/:owner/:slug/offerings — the SAME offer cards as profile>offers), and order an offering
|
|
7
|
+
* (POST .../use — ordering requires login). Backend stays protocol-only; the EE module provides the
|
|
8
|
+
* org APIs (a Community node returns ENTERPRISE_REQUIRED).
|
|
9
|
+
* @structure CompaniesView · directory list · PublicOfferingCard (order box, reuses OfferCardView)
|
|
10
|
+
* @usage routed at /v1/companies; deep-link a company via ?c=owner/slug.
|
|
11
|
+
* @version-history
|
|
12
|
+
* v0.1.0 — 2026-06-23 — initial: directory + public company page + order
|
|
13
|
+
*/
|
|
14
|
+
import { h } from 'preact';
|
|
15
|
+
import { useState, useEffect } from 'preact/hooks';
|
|
16
|
+
import htm from 'htm';
|
|
17
|
+
import { t } from '/js/i18n.js';
|
|
18
|
+
import { apiGet, apiPost } from '/js/api.js';
|
|
19
|
+
import { DeliverableBody } from '/components/ImageDeliverable.js';
|
|
20
|
+
import { OfferCardView } from '/components/offer-card-view.js';
|
|
21
|
+
|
|
22
|
+
const html = htm.bind(h);
|
|
23
|
+
|
|
24
|
+
const isLoggedIn = () => !!(typeof window !== 'undefined' && window.AIMEAT?.auth?.getSession?.());
|
|
25
|
+
|
|
26
|
+
/** One orderable offering on the public company page (same card as profile>offers + an order box). */
|
|
27
|
+
function PublicOfferingCard({ o, owner, slug }) {
|
|
28
|
+
const offer = o.offer;
|
|
29
|
+
const [input, setInput] = useState('');
|
|
30
|
+
const [busy, setBusy] = useState(false);
|
|
31
|
+
const [result, setResult] = useState(null);
|
|
32
|
+
const [err, setErr] = useState('');
|
|
33
|
+
const loggedIn = isLoggedIn();
|
|
34
|
+
|
|
35
|
+
async function order() {
|
|
36
|
+
setBusy(true); setErr(''); setResult(null);
|
|
37
|
+
try {
|
|
38
|
+
const res = await apiPost(`/v1/orgs/${encodeURIComponent(owner)}/${encodeURIComponent(slug)}/use`,
|
|
39
|
+
{ agentName: o.agentName, offerId: o.offerId, input: input.trim() || undefined });
|
|
40
|
+
setResult(res.data); setInput('');
|
|
41
|
+
} catch (e) { setErr(e.message || 'Order failed'); }
|
|
42
|
+
finally { setBusy(false); }
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const actions = html`
|
|
46
|
+
<div class="cm-not-callable">${o.callable ? t('companies.callable') : t('companies.viaInbox')}</div>
|
|
47
|
+
${loggedIn
|
|
48
|
+
? html`
|
|
49
|
+
<textarea class="input-field input-sm of-input" rows="2" value=${input}
|
|
50
|
+
placeholder=${t('companies.usePlaceholder')} onInput=${(e) => setInput(e.target.value)}></textarea>
|
|
51
|
+
<div class="flex-row-wrap">
|
|
52
|
+
<button class="btn-primary btn-sm" disabled=${busy} onClick=${order}>
|
|
53
|
+
${t('companies.order')}${offer.price?.morsels ? ` · ${offer.price.morsels} ${t('companies.morsels')}` : ''}
|
|
54
|
+
</button>
|
|
55
|
+
</div>`
|
|
56
|
+
: html`<a class="btn-outline btn-sm" href="/v1/profile">${t('companies.loginToOrder')}</a>`}
|
|
57
|
+
${err && html`<p class="cm-error">${err}</p>`}
|
|
58
|
+
${result && html`
|
|
59
|
+
<div class="cm-result">
|
|
60
|
+
${result.kind === 'result'
|
|
61
|
+
? html`<div class="cm-result-msg">${t('companies.orderResult')}</div><${DeliverableBody} value=${result.result} alt=${offer.title} format=${offer.deliverable?.format} />`
|
|
62
|
+
: html`<div class="cm-result-msg">${t('companies.orderTask').replace('{agent}', o.agentName)}</div>`}
|
|
63
|
+
${result.receipt?.charged > 0 && html`<div class="cm-receipt">${t('companies.charged').replace('{n}', result.receipt.charged)}</div>`}
|
|
64
|
+
</div>`}
|
|
65
|
+
`;
|
|
66
|
+
return html`<li class="cm-cat-item"><${OfferCardView} entry=${{ agent: o.agentName, online: o.online }} offer=${offer} actions=${actions} /></li>`;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** One purchase receipt in the buyer's "My orders" panel. */
|
|
70
|
+
function ReceiptRow({ o }) {
|
|
71
|
+
const statusKey = o.kind === 'result' ? 'stInstant' : ({ queued: 'stQueued', active: 'stActive', done: 'stDone', failed: 'stFailed' }[o.status] || 'stQueued');
|
|
72
|
+
return html`
|
|
73
|
+
<li class="cm-receipt-row">
|
|
74
|
+
<div class="cm-receipt-top">
|
|
75
|
+
<span class="cm-receipt-title">${o.offerTitle}</span>
|
|
76
|
+
<span class="cm-receipt-amt">${o.charged > 0 ? `${o.charged} ${t('companies.morsels')}` : t('companies.free')}</span>
|
|
77
|
+
</div>
|
|
78
|
+
<div class="cm-receipt-meta">
|
|
79
|
+
<span>${t('companies.fromCompany')}: ${o.orgSlug}</span>
|
|
80
|
+
<span>🤖 ${o.agentName}</span>
|
|
81
|
+
<span>${t('companies.' + statusKey)}</span>
|
|
82
|
+
<span class="cm-mini">${new Date(o.createdAt).toLocaleString()}</span>
|
|
83
|
+
</div>
|
|
84
|
+
${o.trackingCode && html`<div class="cm-mini cm-receipt-code">🧾 ${o.trackingCode}</div>`}
|
|
85
|
+
</li>`;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export default function CompaniesView() {
|
|
89
|
+
const [companies, setCompanies] = useState(null);
|
|
90
|
+
const [selected, setSelected] = useState(null); // { owner, slug }
|
|
91
|
+
const [profile, setProfile] = useState(null); // { org, offerings }
|
|
92
|
+
const [myOrders, setMyOrders] = useState(null);
|
|
93
|
+
const [showOrders, setShowOrders] = useState(false);
|
|
94
|
+
const [err, setErr] = useState('');
|
|
95
|
+
const loggedIn = isLoggedIn();
|
|
96
|
+
|
|
97
|
+
async function loadMyOrders() {
|
|
98
|
+
try { const r = await apiGet('/v1/orders'); setMyOrders(r.data?.orders ?? []); }
|
|
99
|
+
catch { setMyOrders([]); }
|
|
100
|
+
}
|
|
101
|
+
function toggleOrders() { const n = !showOrders; setShowOrders(n); if (n) loadMyOrders(); }
|
|
102
|
+
|
|
103
|
+
async function loadDirectory() {
|
|
104
|
+
try { const r = await apiGet('/v1/orgs/directory'); setCompanies(r.data?.companies ?? []); }
|
|
105
|
+
catch (e) {
|
|
106
|
+
if (e.code === 'ENTERPRISE_REQUIRED') setCompanies('enterprise');
|
|
107
|
+
else { setErr(e.message || 'Failed to load'); setCompanies([]); }
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
useEffect(() => { loadDirectory(); }, []);
|
|
111
|
+
|
|
112
|
+
async function openCompany(owner, slug) {
|
|
113
|
+
setSelected({ owner, slug }); setProfile(null); setErr('');
|
|
114
|
+
try { history.replaceState(null, '', `/v1/companies?c=${encodeURIComponent(owner)}/${encodeURIComponent(slug)}`); } catch { /* ignore */ }
|
|
115
|
+
try {
|
|
116
|
+
const r = await apiGet(`/v1/orgs/${encodeURIComponent(owner)}/${encodeURIComponent(slug)}/offerings`);
|
|
117
|
+
setProfile(r.data ?? null);
|
|
118
|
+
} catch (e) { setErr(e.message || ''); }
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Deep-link: once the directory is loaded, open ?c=owner/slug if present.
|
|
122
|
+
useEffect(() => {
|
|
123
|
+
if (Array.isArray(companies) && !selected) {
|
|
124
|
+
const c = new URLSearchParams(location.search).get('c');
|
|
125
|
+
if (c && c.includes('/')) { const [o, s] = c.split('/'); openCompany(o, s); }
|
|
126
|
+
}
|
|
127
|
+
}, [companies]);
|
|
128
|
+
|
|
129
|
+
if (companies === null) return html`<div class="cm-container"><div class="cm-center"><div class="spinner"></div></div></div>`;
|
|
130
|
+
if (companies === 'enterprise') return html`<div class="cm-container"><div class="cm-card"><h1 class="cm-title">${t('companies.title')}</h1><p class="cm-desc">${t('companies.enterpriseRequired')}</p></div></div>`;
|
|
131
|
+
|
|
132
|
+
return html`
|
|
133
|
+
<div class="cm-container">
|
|
134
|
+
<header class="cm-header">
|
|
135
|
+
<div class="cm-header-row">
|
|
136
|
+
<h1 class="cm-title">${t('companies.title')}</h1>
|
|
137
|
+
${loggedIn && html`<button class="btn-outline btn-sm" onClick=${toggleOrders}>${showOrders ? t('companies.done') : t('companies.myOrders')}</button>`}
|
|
138
|
+
</div>
|
|
139
|
+
<p class="cm-desc">${t('companies.desc')}</p>
|
|
140
|
+
</header>
|
|
141
|
+
${err && html`<p class="cm-error">${err}</p>`}
|
|
142
|
+
|
|
143
|
+
${showOrders && html`
|
|
144
|
+
<div class="cm-col cm-orders-panel">
|
|
145
|
+
<h2 class="cm-col-title">${t('companies.myOrders')}</h2>
|
|
146
|
+
${myOrders === null ? html`<div class="cm-center"><div class="spinner"></div></div>`
|
|
147
|
+
: (myOrders.length === 0 ? html`<p class="cm-empty">${t('companies.noMyOrders')}</p>`
|
|
148
|
+
: html`<ul class="cm-receipt-list">${myOrders.map(o => html`<${ReceiptRow} key=${o.id} o=${o} />`)}</ul>`)}
|
|
149
|
+
</div>`}
|
|
150
|
+
<div class="cm-grid">
|
|
151
|
+
<aside class="cm-col">
|
|
152
|
+
<h2 class="cm-col-title">${t('companies.directory')} (${companies.length})</h2>
|
|
153
|
+
${companies.length === 0 && html`<p class="cm-empty">${t('companies.none')}</p>`}
|
|
154
|
+
<ul class="cm-dir-list">
|
|
155
|
+
${companies.map(c => html`<li key=${c.goii}>
|
|
156
|
+
<button class="cm-dir-item ${selected?.slug === c.slug && selected?.owner === c.creatorOwner ? 'active' : ''}" onClick=${() => openCompany(c.creatorOwner, c.slug)}>
|
|
157
|
+
${c.logo && html`<img class="cm-dir-logo" src=${c.logo} alt=${c.name} />`}
|
|
158
|
+
<div class="cm-dir-text">
|
|
159
|
+
<span class="cm-dir-name">${c.name}</span>
|
|
160
|
+
<span class="cm-dir-meta">${c.businessId ? html`<span class="cm-tag">Y ${c.businessId}</span>` : ''}${c.offerings} ${t('companies.offeringsShort')}</span>
|
|
161
|
+
</div>
|
|
162
|
+
</button></li>`)}
|
|
163
|
+
</ul>
|
|
164
|
+
</aside>
|
|
165
|
+
<section class="cm-col">
|
|
166
|
+
${!selected && html`<p class="cm-empty">${t('companies.selectHint')}</p>`}
|
|
167
|
+
${selected && !profile && html`<div class="cm-center"><div class="spinner"></div></div>`}
|
|
168
|
+
${profile && html`
|
|
169
|
+
<div class="cm-profile-head">
|
|
170
|
+
<div class="cm-profile-id">
|
|
171
|
+
${profile.org?.logo && html`<img class="cm-profile-logo" src=${profile.org.logo} alt=${profile.org?.name} />`}
|
|
172
|
+
<div>
|
|
173
|
+
<h2 class="cm-col-title">${profile.org?.name}</h2>
|
|
174
|
+
${profile.org?.businessId && html`<span class="cm-mini">${t('companies.businessId')}: ${profile.org.businessId}</span>`}
|
|
175
|
+
</div>
|
|
176
|
+
</div>
|
|
177
|
+
${profile.org?.description && html`<p class="cm-profile-desc">${profile.org.description}</p>`}
|
|
178
|
+
${profile.org?.portfolio?.enabled && profile.org.portfolio.publicUrl && html`
|
|
179
|
+
<a class="btn-outline btn-sm cm-pf-link" href=${profile.org.portfolio.publicUrl} target="_blank">${t('companies.viewPortfolio')}</a>`}
|
|
180
|
+
</div>
|
|
181
|
+
<h3 class="cm-form-title">${t('companies.catalogue')}</h3>
|
|
182
|
+
${(profile.offerings ?? []).length === 0 && html`<p class="cm-empty">${t('companies.noOfferings')}</p>`}
|
|
183
|
+
<ul class="cm-cat-list">
|
|
184
|
+
${(profile.offerings ?? []).map(o => html`<${PublicOfferingCard} key=${o.agentName + '/' + o.offerId} o=${o} owner=${selected.owner} slug=${selected.slug} />`)}
|
|
185
|
+
</ul>
|
|
186
|
+
`}
|
|
187
|
+
</section>
|
|
188
|
+
</div>
|
|
189
|
+
</div>`;
|
|
190
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file members.js
|
|
3
|
+
* @description Node members showcase — registered owners who have PUBLISHED a portfolio. A public grid
|
|
4
|
+
* (avatar + name + bio) that links each member to their portfolio (/v1/portfolio/<username>). Data from
|
|
5
|
+
* GET /v1/portfolio/members. "Discover the people on this node."
|
|
6
|
+
* @structure MembersView (default) — fetch + grid.
|
|
7
|
+
* @usage routed at /v1/members by spa.html.
|
|
8
|
+
* @version-history
|
|
9
|
+
* v1.0.0 — 2026-06-23 — Initial node member showcase (published-portfolio owners).
|
|
10
|
+
*/
|
|
11
|
+
import { h } from 'preact';
|
|
12
|
+
import htm from 'htm';
|
|
13
|
+
const html = htm.bind(h);
|
|
14
|
+
import { useState, useEffect } from 'preact/hooks';
|
|
15
|
+
import { t } from '/js/i18n.js';
|
|
16
|
+
import { apiGet } from '/js/api.js';
|
|
17
|
+
import { escHtml } from '/js/utils.js';
|
|
18
|
+
import { useViewCSS } from '/components/useViewCSS.js';
|
|
19
|
+
|
|
20
|
+
export default function MembersView() {
|
|
21
|
+
useViewCSS('/css/views/members.css');
|
|
22
|
+
const [members, setMembers] = useState(null);
|
|
23
|
+
useEffect(() => {
|
|
24
|
+
apiGet('/v1/portfolio/members').then(r => setMembers(r?.data?.members || [])).catch(() => setMembers([]));
|
|
25
|
+
}, []);
|
|
26
|
+
|
|
27
|
+
return html`
|
|
28
|
+
<div class="mbr">
|
|
29
|
+
<h1 class="mbr-title">${t('members.title')}</h1>
|
|
30
|
+
<p class="mbr-desc">${t('members.desc')}</p>
|
|
31
|
+
${members === null ? html`<div class="mbr-empty">…</div>`
|
|
32
|
+
: members.length === 0 ? html`<div class="mbr-empty">${t('members.empty')}</div>`
|
|
33
|
+
: html`<div class="mbr-grid">
|
|
34
|
+
${members.map(m => html`
|
|
35
|
+
<a class="mbr-card" key=${m.username} href=${`/v1/portfolio/${encodeURIComponent(m.username)}`}>
|
|
36
|
+
<div class="mbr-avatar">${(m.avatar && String(m.avatar).length <= 4) ? m.avatar : '👤'}</div>
|
|
37
|
+
<div class="mbr-name">${escHtml(m.display_name || m.username)}</div>
|
|
38
|
+
${m.bio ? html`<div class="mbr-bio">${escHtml(m.bio)}</div>` : null}
|
|
39
|
+
</a>`)}
|
|
40
|
+
</div>`}
|
|
41
|
+
</div>`;
|
|
42
|
+
}
|