aimeat 1.25.0 → 1.26.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/README.md +8 -1
- package/dist/locales/en.json +144 -0
- package/dist/locales/fi.json +144 -0
- package/dist/public/components/ImageDeliverable.js +2 -1
- package/dist/public/components/Modal.js +3 -2
- package/dist/public/components/NotificationBell.js +2 -1
- package/dist/public/components/PresenceDot.js +53 -0
- package/dist/public/css/components/markdown.css +67 -0
- package/dist/public/css/theme.css +30 -0
- package/dist/public/css/views/notebook.css +195 -0
- package/dist/public/css/views/profile.css +15 -0
- package/dist/public/js/api.js +5 -3
- package/dist/public/js/components/auth-image.js +3 -2
- package/dist/public/js/components/tag-cloud.js +1 -1
- package/dist/public/js/components/tag-editor.js +1 -1
- package/dist/public/js/hooks.js +1 -2
- package/dist/public/js/presence-store.js +97 -0
- package/dist/public/js/services/admin.js +14 -5
- package/dist/public/js/services/boards.js +1 -1
- package/dist/public/js/services/ecosystem.js +1 -1
- package/dist/public/js/services/foundry-prompts-base.js +2 -2
- package/dist/public/js/services/foundry-smoke.js +2 -1
- package/dist/public/js/services/foundry-validate.js +6 -8
- package/dist/public/js/services/foundry.js +4 -3
- package/dist/public/js/services/generator-prompts-base.js +2 -2
- package/dist/public/js/services/generator-smoke.js +2 -1
- package/dist/public/js/services/generator-validate.js +5 -7
- package/dist/public/js/services/generator.js +2 -1
- package/dist/public/js/services/memory.js +13 -0
- package/dist/public/js/services/messages.js +2 -1
- package/dist/public/js/services/notebook.js +124 -0
- package/dist/public/js/services/packages.js +3 -2
- package/dist/public/js/services/presence.js +35 -0
- package/dist/public/js/style-testbed.js +6 -5
- package/dist/public/lib/minidenticons.min.js +1 -0
- package/dist/public/lib/yaml.mjs +1 -0
- package/dist/public/spa.html +90 -8
- package/dist/public/types/aimeat-globals.d.ts +52 -0
- package/dist/public/types/vendored-libs.d.ts +56 -0
- package/dist/public/views/_template.js +3 -1
- package/dist/public/views/admin/agent-integration-tab.js +4 -3
- package/dist/public/views/admin/agents-tab.js +3 -2
- package/dist/public/views/admin/config-tab.js +4 -3
- package/dist/public/views/admin/economy-tab.js +4 -3
- package/dist/public/views/admin/federation-tab.js +138 -1
- package/dist/public/views/admin/maintenance-tab.js +1 -1
- package/dist/public/views/admin/messages-tab.js +115 -0
- package/dist/public/views/admin/overview-tab.js +4 -3
- package/dist/public/views/admin/portal-tab.js +90 -2
- package/dist/public/views/admin/push-tab.js +8 -6
- package/dist/public/views/admin/security-tab.js +7 -7
- package/dist/public/views/admin.js +29 -9
- package/dist/public/views/doc-solo.js +3 -1
- package/dist/public/views/guides.js +8 -4
- package/dist/public/views/hobbies.js +4 -2
- package/dist/public/views/marketplace.js +10 -9
- package/dist/public/views/openclaw.js +1 -1
- package/dist/public/views/portal-dev.js +5 -2
- package/dist/public/views/portal.js +3 -2
- package/dist/public/views/profile/agents/shared-board.js +4 -2
- package/dist/public/views/profile/agents/tab-messages.js +13 -11
- package/dist/public/views/profile/agents-messages-subtab.js +2 -1
- package/dist/public/views/profile/apps-tab.js +2 -1
- package/dist/public/views/profile/boards-tab.js +3 -2
- package/dist/public/views/profile/calibrator-batch.js +3 -2
- package/dist/public/views/profile/data-wallet-tab.js +2 -1
- package/dist/public/views/profile/extensions-tab.js +4 -3
- package/dist/public/views/profile/federation-tab.js +4 -0
- package/dist/public/views/profile/foundry-dashboard/use-autopilot.js +3 -2
- package/dist/public/views/profile/foundry-detail.js +1 -1
- package/dist/public/views/profile/generator-detail.js +1 -1
- package/dist/public/views/profile/inbox-tab.js +7 -3
- package/dist/public/views/profile/inline-panels.js +3 -1
- package/dist/public/views/profile/knowledge-tab.js +2 -1
- package/dist/public/views/profile/landing-page.js +88 -0
- package/dist/public/views/profile/memory-tab.js +6 -5
- package/dist/public/views/profile/notebook-tab.js +500 -0
- package/dist/public/views/profile/organisms/activity-panel.js +135 -0
- package/dist/public/views/profile/organisms/agents.js +141 -0
- package/dist/public/views/profile/organisms/document.js +274 -0
- package/dist/public/views/profile/organisms/helpers.js +61 -0
- package/dist/public/views/profile/organisms/home.js +315 -0
- package/dist/public/views/profile/organisms/members.js +220 -0
- package/dist/public/views/profile/organisms/panels.js +173 -0
- package/dist/public/views/profile/organisms/participants-panel.js +160 -0
- package/dist/public/views/profile/organisms/schema-form.js +127 -0
- package/dist/public/views/profile/organisms/sources-panel.js +164 -0
- package/dist/public/views/profile/organisms/widgets.js +58 -0
- package/dist/public/views/profile/organisms/workspace-comments.js +99 -0
- package/dist/public/views/profile/organisms/workspace-list.js +268 -0
- package/dist/public/views/profile/organisms/workspace.js +1272 -0
- package/dist/public/views/profile/organisms-tab.js +456 -3819
- package/dist/public/views/profile/shared.js +64 -2
- package/dist/public/views/profile/workflows-form.js +1 -1
- package/dist/public/views/profile.js +16 -14
- package/dist/public/views/public-knowledge-viewer.js +3 -2
- package/dist/public/views/public-workspace-viewer.js +2 -1
- package/dist/scripts/check-importmap.d.ts +2 -0
- package/dist/scripts/check-importmap.d.ts.map +1 -0
- package/dist/scripts/check-importmap.js +102 -0
- package/dist/scripts/check-importmap.js.map +1 -0
- package/dist/src/cli/scaffold.d.ts +26 -3
- package/dist/src/cli/scaffold.d.ts.map +1 -1
- package/dist/src/cli/scaffold.js +33 -3
- package/dist/src/cli/scaffold.js.map +1 -1
- package/dist/src/config.d.ts +10 -0
- package/dist/src/config.d.ts.map +1 -1
- package/dist/src/config.js +5 -0
- package/dist/src/config.js.map +1 -1
- package/dist/src/generated/api-types.d.ts +927 -11
- package/dist/src/generated/api-types.d.ts.map +1 -1
- package/dist/src/generated/prisma-postgres/edge.js +32 -6
- package/dist/src/generated/prisma-postgres/index-browser.js +29 -3
- package/dist/src/generated/prisma-postgres/index.d.ts +1970 -160
- package/dist/src/generated/prisma-postgres/index.js +32 -6
- package/dist/src/generated/prisma-postgres/package.json +1 -1
- package/dist/src/generated/prisma-postgres/schema.prisma +45 -12
- package/dist/src/generated/prisma-postgres/wasm.js +32 -6
- package/dist/src/index.js +36 -4
- package/dist/src/index.js.map +1 -1
- package/dist/src/routes/admin-monitoring.d.ts.map +1 -1
- package/dist/src/routes/admin-monitoring.js +8 -0
- package/dist/src/routes/admin-monitoring.js.map +1 -1
- package/dist/src/routes/federation-peer.d.ts.map +1 -1
- package/dist/src/routes/federation-peer.js +327 -43
- package/dist/src/routes/federation-peer.js.map +1 -1
- package/dist/src/routes/federation-sync.d.ts +2 -0
- package/dist/src/routes/federation-sync.d.ts.map +1 -1
- package/dist/src/routes/federation-sync.js +20 -1
- package/dist/src/routes/federation-sync.js.map +1 -1
- package/dist/src/routes/librarian.d.ts +18 -0
- package/dist/src/routes/librarian.d.ts.map +1 -0
- package/dist/src/routes/librarian.js +88 -0
- package/dist/src/routes/librarian.js.map +1 -0
- package/dist/src/routes/messages.d.ts.map +1 -1
- package/dist/src/routes/messages.js +2 -1
- package/dist/src/routes/messages.js.map +1 -1
- package/dist/src/routes/portal.d.ts.map +1 -1
- package/dist/src/routes/portal.js +9 -1
- package/dist/src/routes/portal.js.map +1 -1
- package/dist/src/routes/presence.d.ts +23 -0
- package/dist/src/routes/presence.d.ts.map +1 -0
- package/dist/src/routes/presence.js +88 -0
- package/dist/src/routes/presence.js.map +1 -0
- package/dist/src/routes/site.d.ts +12 -0
- package/dist/src/routes/site.d.ts.map +1 -1
- package/dist/src/routes/site.js +45 -1
- package/dist/src/routes/site.js.map +1 -1
- package/dist/src/routes/sse.d.ts +2 -0
- package/dist/src/routes/sse.d.ts.map +1 -1
- package/dist/src/routes/sse.js +9 -0
- package/dist/src/routes/sse.js.map +1 -1
- package/dist/src/routes/wellknown.d.ts.map +1 -1
- package/dist/src/routes/wellknown.js +5 -0
- package/dist/src/routes/wellknown.js.map +1 -1
- package/dist/src/routes/work.d.ts.map +1 -1
- package/dist/src/routes/work.js +6 -0
- package/dist/src/routes/work.js.map +1 -1
- package/dist/src/server-bootstrap/routes-loader.d.ts.map +1 -1
- package/dist/src/server-bootstrap/routes-loader.js +13 -0
- package/dist/src/server-bootstrap/routes-loader.js.map +1 -1
- package/dist/src/server-bootstrap/service-init.d.ts.map +1 -1
- package/dist/src/server-bootstrap/service-init.js +34 -0
- package/dist/src/server-bootstrap/service-init.js.map +1 -1
- package/dist/src/services/config-schema.d.ts.map +1 -1
- package/dist/src/services/config-schema.js +2 -0
- package/dist/src/services/config-schema.js.map +1 -1
- package/dist/src/services/federation-availability.d.ts +28 -0
- package/dist/src/services/federation-availability.d.ts.map +1 -0
- package/dist/src/services/federation-availability.js +58 -0
- package/dist/src/services/federation-availability.js.map +1 -0
- package/dist/src/services/federation-book.d.ts +70 -0
- package/dist/src/services/federation-book.d.ts.map +1 -0
- package/dist/src/services/federation-book.js +198 -0
- package/dist/src/services/federation-book.js.map +1 -0
- package/dist/src/services/federation-tiers.d.ts +45 -0
- package/dist/src/services/federation-tiers.d.ts.map +1 -0
- package/dist/src/services/federation-tiers.js +58 -0
- package/dist/src/services/federation-tiers.js.map +1 -0
- package/dist/src/services/federation.d.ts +15 -0
- package/dist/src/services/federation.d.ts.map +1 -1
- package/dist/src/services/federation.js +12 -0
- package/dist/src/services/federation.js.map +1 -1
- package/dist/src/services/librarian.d.ts +62 -0
- package/dist/src/services/librarian.d.ts.map +1 -0
- package/dist/src/services/librarian.js +135 -0
- package/dist/src/services/librarian.js.map +1 -0
- package/dist/src/services/message-delivery.d.ts +3 -1
- package/dist/src/services/message-delivery.d.ts.map +1 -1
- package/dist/src/services/message-delivery.js +23 -2
- package/dist/src/services/message-delivery.js.map +1 -1
- package/dist/src/services/network-policy.d.ts +88 -0
- package/dist/src/services/network-policy.d.ts.map +1 -0
- package/dist/src/services/network-policy.js +154 -0
- package/dist/src/services/network-policy.js.map +1 -0
- package/dist/src/services/notebook-classify-prompt.d.ts +15 -0
- package/dist/src/services/notebook-classify-prompt.d.ts.map +1 -0
- package/dist/src/services/notebook-classify-prompt.js +39 -0
- package/dist/src/services/notebook-classify-prompt.js.map +1 -0
- package/dist/src/services/notebook-classify.d.ts +80 -0
- package/dist/src/services/notebook-classify.d.ts.map +1 -0
- package/dist/src/services/notebook-classify.js +150 -0
- package/dist/src/services/notebook-classify.js.map +1 -0
- package/dist/src/services/presence.d.ts +108 -0
- package/dist/src/services/presence.d.ts.map +1 -0
- package/dist/src/services/presence.js +304 -0
- package/dist/src/services/presence.js.map +1 -0
- package/dist/src/services/prompt-defaults.d.ts.map +1 -1
- package/dist/src/services/prompt-defaults.js +13 -0
- package/dist/src/services/prompt-defaults.js.map +1 -1
- package/dist/src/services/site.d.ts +20 -0
- package/dist/src/services/site.d.ts.map +1 -1
- package/dist/src/services/site.js +70 -0
- package/dist/src/services/site.js.map +1 -1
- package/dist/src/storage/interface.d.ts +48 -0
- package/dist/src/storage/interface.d.ts.map +1 -1
- package/dist/src/storage/interface.js.map +1 -1
- package/dist/src/storage/providers/mongodb/index.d.ts +11 -1
- package/dist/src/storage/providers/mongodb/index.d.ts.map +1 -1
- package/dist/src/storage/providers/mongodb/index.js +128 -2
- package/dist/src/storage/providers/mongodb/index.js.map +1 -1
- package/dist/src/storage/providers/sqlite/index.d.ts +7 -1
- package/dist/src/storage/providers/sqlite/index.d.ts.map +1 -1
- package/dist/src/storage/providers/sqlite/index.js +27 -2
- package/dist/src/storage/providers/sqlite/index.js.map +1 -1
- package/dist/src/storage/providers/sqlite/repos/direct-message.d.ts +5 -1
- package/dist/src/storage/providers/sqlite/repos/direct-message.d.ts.map +1 -1
- package/dist/src/storage/providers/sqlite/repos/direct-message.js +48 -0
- package/dist/src/storage/providers/sqlite/repos/direct-message.js.map +1 -1
- package/dist/src/storage/providers/sqlite/repos/memory.d.ts +2 -0
- package/dist/src/storage/providers/sqlite/repos/memory.d.ts.map +1 -1
- package/dist/src/storage/providers/sqlite/repos/memory.js +55 -0
- package/dist/src/storage/providers/sqlite/repos/memory.js.map +1 -1
- package/dist/src/storage/providers/sqlite/schema.d.ts.map +1 -1
- package/dist/src/storage/providers/sqlite/schema.js +61 -0
- package/dist/src/storage/providers/sqlite/schema.js.map +1 -1
- package/dist/src/storage/repositories/direct-message.repository.d.ts +5 -1
- package/dist/src/storage/repositories/direct-message.repository.d.ts.map +1 -1
- package/dist/src/storage/repositories/memory.repository.d.ts +25 -0
- package/dist/src/storage/repositories/memory.repository.d.ts.map +1 -1
- package/dist/src/utils/node-descriptor.d.ts +34 -0
- package/dist/src/utils/node-descriptor.d.ts.map +1 -0
- package/dist/src/utils/node-descriptor.js +42 -0
- package/dist/src/utils/node-descriptor.js.map +1 -0
- package/dist/src/utils/version.d.ts +3 -0
- package/dist/src/utils/version.d.ts.map +1 -0
- package/dist/src/utils/version.js +40 -0
- package/dist/src/utils/version.js.map +1 -0
- package/dist/static/app-catalog.html +643 -4
- package/package.json +5 -2
- package/prisma/schema.postgres.prisma +51 -18
- package/prisma/schema.prisma +29 -0
|
@@ -28,6 +28,19 @@ export async function searchMemory(query, agentGaii) {
|
|
|
28
28
|
return Array.isArray(list) ? list : [];
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
/**
|
|
32
|
+
* Librarian full-text search across all of the caller's content (GET /v1/librarian/search).
|
|
33
|
+
* Returns the ranked hits array (each: { key, title, snippet, score, organismId, workspaceId, ... }).
|
|
34
|
+
*/
|
|
35
|
+
export async function librarianSearch(query, limit, scope) {
|
|
36
|
+
let url = `/v1/librarian/search?q=${encodeURIComponent(query)}`;
|
|
37
|
+
if (limit) url += `&limit=${encodeURIComponent(limit)}`;
|
|
38
|
+
if (scope) url += `&scope=${encodeURIComponent(scope)}`;
|
|
39
|
+
const data = await apiGet(url);
|
|
40
|
+
const hits = data?.data?.hits || [];
|
|
41
|
+
return Array.isArray(hits) ? hits : [];
|
|
42
|
+
}
|
|
43
|
+
|
|
31
44
|
/**
|
|
32
45
|
* Create a new memory entry.
|
|
33
46
|
* @param {string} [agentGaii] Owner-session only — store the entry under one of
|
|
@@ -9,13 +9,14 @@
|
|
|
9
9
|
* @usage import * as messages from '/js/services/messages.js';
|
|
10
10
|
* @version-history
|
|
11
11
|
* v1.0.0 -- 2026-06-16 -- Initial creation for user-to-user messaging (layer 5: Inbox tab).
|
|
12
|
+
* v1.0.1 -- 2026-06-19 -- JSDoc type annotations for frontend type-checking
|
|
12
13
|
*/
|
|
13
14
|
import { api, apiGet } from '/js/api.js';
|
|
14
15
|
|
|
15
16
|
const enc = encodeURIComponent;
|
|
16
17
|
|
|
17
18
|
/** Send a direct message. `attachments` is an array of descriptors (storage_key, mime, size, kind, inline, id). */
|
|
18
|
-
export async function send({ to, body, attachments, replyTo }) {
|
|
19
|
+
export async function send({ to, body, attachments, replyTo } = /** @type {{ to?: any, body?: any, attachments?: any, replyTo?: any }} */ ({})) {
|
|
19
20
|
return api('/v1/messages', {
|
|
20
21
|
method: 'POST',
|
|
21
22
|
body: JSON.stringify({ to, body, attachments, reply_to: replyTo }),
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file notebook.js
|
|
3
|
+
* @description Notebook slice B client service. classifyNote() asks the backend AI classifier where a
|
|
4
|
+
* note belongs; materializeDocument() then ORCHESTRATES the placement over the existing generic
|
|
5
|
+
* memory/organism APIs (no-SSR — the client composes create-organism / create-workspace /
|
|
6
|
+
* write-document; there is no per-feature backend write route). Supports an existing target, a new
|
|
7
|
+
* workspace in an existing organism, or a brand-new organism+workspace, always materializing the
|
|
8
|
+
* note as a workspace DOCUMENT.
|
|
9
|
+
* @structure
|
|
10
|
+
* - classifyNote(text) — POST /v1/librarian/classify
|
|
11
|
+
* - materializeDocument(plan) — resolve/create org → ws → document space → write doc → drop source
|
|
12
|
+
* @version-history
|
|
13
|
+
* v1.0.0 — 2026-06-19 — Initial: classify + materialize-document orchestration (slice B).
|
|
14
|
+
*/
|
|
15
|
+
import { api, apiPost } from '/js/api.js';
|
|
16
|
+
import { createMemory, getMemory, deleteMemory } from '/js/services/memory.js';
|
|
17
|
+
import { createOrganism, saveManifest, listWorkspaces, saveWorkspaceRegistry, wsRoot } from '/js/services/organisms.js';
|
|
18
|
+
|
|
19
|
+
const DOC_SPACE = 'pages';
|
|
20
|
+
|
|
21
|
+
function rid(prefix) {
|
|
22
|
+
const r = (typeof crypto !== 'undefined' && crypto.randomUUID) ? crypto.randomUUID().slice(0, 8) : Math.random().toString(36).slice(2, 10);
|
|
23
|
+
return prefix + r;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** Ask the backend AI classifier where a note belongs. Returns the ClassifyResult envelope's data.
|
|
27
|
+
* This is a slow AI call — give it the full AI timeout (30 min) and DO NOT retry, otherwise the
|
|
28
|
+
* default 30s client timeout aborts a model that is still thinking and re-fires the request. */
|
|
29
|
+
export async function classifyNote(text) {
|
|
30
|
+
const resp = await api('/v1/librarian/classify', {
|
|
31
|
+
method: 'POST',
|
|
32
|
+
body: JSON.stringify({ text }),
|
|
33
|
+
timeoutMs: 1_800_000,
|
|
34
|
+
retries: 0,
|
|
35
|
+
});
|
|
36
|
+
if (resp?.ok === false) throw new Error(resp.error?.message || 'Classify failed');
|
|
37
|
+
return resp?.data || null;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** A document-space objectType for a memory-backed workspace. */
|
|
41
|
+
function docSpaceObjectType() {
|
|
42
|
+
return { name: 'Pages', namespace: DOC_SPACE, schemaRef: 'schema:document@1', mode: 'document', backing: 'memory', writeRole: 'member', cardinality: 'many', versioned: true };
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function newWorkspaceManifest(orgId, name) {
|
|
46
|
+
return { manifestVersion: '1.0', id: orgId, name: name || 'Notebook', kind: 'project', status: 'active', objectTypes: [docSpaceObjectType()] };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** Read a workspace manifest (raw value), or null if it has none / is unreadable. */
|
|
50
|
+
async function readManifest(orgId, wsId) {
|
|
51
|
+
try {
|
|
52
|
+
const r = await getMemory(`${wsRoot(orgId, wsId)}.meta.manifest`);
|
|
53
|
+
return r?.data?.value || null;
|
|
54
|
+
} catch { return null; }
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Materialize a note into a workspace document.
|
|
59
|
+
* @param {object} plan
|
|
60
|
+
* @param {string|null} plan.organismId Existing organism id, or null to create one.
|
|
61
|
+
* @param {string} [plan.organismName] Name for a new organism (when organismId is null).
|
|
62
|
+
* @param {string|null} plan.workspaceId Existing workspace id, or null to create one.
|
|
63
|
+
* @param {string} [plan.workspaceName] Name for a new workspace (when workspaceId is null).
|
|
64
|
+
* @param {string|null} plan.space Existing document-space namespace, or null to use/create the default.
|
|
65
|
+
* @param {string} plan.title
|
|
66
|
+
* @param {string} plan.markdown
|
|
67
|
+
* @param {string} [plan.sourceKey] Inbox note key to delete once filed.
|
|
68
|
+
* @returns {Promise<{organismId:string, workspaceId:string, space:string, docId:string}>}
|
|
69
|
+
*/
|
|
70
|
+
export async function materializeDocument(plan) {
|
|
71
|
+
let { organismId, workspaceId, space } = plan;
|
|
72
|
+
|
|
73
|
+
// 1. Organism — create if needed.
|
|
74
|
+
if (!organismId) {
|
|
75
|
+
const resp = await createOrganism({
|
|
76
|
+
name: (plan.organismName || 'Notebook').trim(),
|
|
77
|
+
description: 'Created from the notebook',
|
|
78
|
+
type: 'project',
|
|
79
|
+
join_policy: 'approval_required',
|
|
80
|
+
visibility: 'private',
|
|
81
|
+
});
|
|
82
|
+
if (resp?.ok === false) throw new Error(resp.error?.message || 'Could not create organism');
|
|
83
|
+
organismId = resp?.data?.organism?.id;
|
|
84
|
+
if (!organismId) throw new Error('Organism creation returned no id');
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// 2. Workspace — create if needed (registry + manifest with a document space).
|
|
88
|
+
if (!workspaceId) {
|
|
89
|
+
workspaceId = rid('ws-');
|
|
90
|
+
const manifest = newWorkspaceManifest(organismId, plan.workspaceName);
|
|
91
|
+
await saveManifest(organismId, workspaceId, manifest);
|
|
92
|
+
await apiPost('/v1/memory', { key: `${wsRoot(organismId, workspaceId)}.meta.readme`, value: `# ${manifest.name}\n\nCreated from the notebook.`, visibility: 'private' });
|
|
93
|
+
const existing = await listWorkspaces(organismId);
|
|
94
|
+
await saveWorkspaceRegistry(organismId, [...existing, { id: workspaceId, name: manifest.name, createdAt: new Date().toISOString() }]);
|
|
95
|
+
space = DOC_SPACE;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// 3. Document space — ensure one exists on the chosen workspace.
|
|
99
|
+
if (!space) {
|
|
100
|
+
const manifest = await readManifest(organismId, workspaceId);
|
|
101
|
+
const existingDoc = (manifest?.objectTypes || []).find(ot => (ot.mode === 'document') || (!ot.mode && ot.kind === 'document'));
|
|
102
|
+
if (existingDoc?.namespace) {
|
|
103
|
+
space = existingDoc.namespace;
|
|
104
|
+
} else if (manifest) {
|
|
105
|
+
// Best-effort: add a default document space to the manifest so the doc renders.
|
|
106
|
+
const updated = { ...manifest, objectTypes: [...(manifest.objectTypes || []), docSpaceObjectType()] };
|
|
107
|
+
await saveManifest(organismId, workspaceId, updated).catch(() => {});
|
|
108
|
+
space = DOC_SPACE;
|
|
109
|
+
} else {
|
|
110
|
+
space = DOC_SPACE;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// 4. Write the document.
|
|
115
|
+
const docId = rid('doc-');
|
|
116
|
+
const key = `${wsRoot(organismId, workspaceId)}.${space}.${docId}.latest`;
|
|
117
|
+
const resp = await createMemory(key, { id: docId, title: plan.title, markdown: plan.markdown }, 'private');
|
|
118
|
+
if (resp?.ok === false) throw new Error(resp.error?.message || 'Could not write document');
|
|
119
|
+
|
|
120
|
+
// 5. Drop the source inbox note (it has been filed).
|
|
121
|
+
if (plan.sourceKey) await deleteMemory(plan.sourceKey).catch(() => {});
|
|
122
|
+
|
|
123
|
+
return { organismId, workspaceId, space, docId };
|
|
124
|
+
}
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
* v1.0.0 — 2026-03-15 — initial implementation (Phase 6)
|
|
17
17
|
* v1.1.0 — 2026-03-20 — add exportPackageZip, importPackageZip, proposeAsTemplate
|
|
18
18
|
* v1.2.0 — 2026-03-20 — add syncFederationTemplates, listFederationTemplates
|
|
19
|
+
* v1.2.1 — 2026-06-19 — JSDoc type annotations for frontend type-checking
|
|
19
20
|
*/
|
|
20
21
|
import { apiGet, apiPost, apiPatch, apiDelete } from '/js/api.js';
|
|
21
22
|
|
|
@@ -54,7 +55,7 @@ export const toggleFeatured = (id, featured) => apiPatch(`/v1/templates/${enc(id
|
|
|
54
55
|
// ── ZIP Import/Export ──
|
|
55
56
|
export async function exportPackageZip(groupId) {
|
|
56
57
|
const session = window.AIMEAT?.auth?.getSession?.();
|
|
57
|
-
const headers = {};
|
|
58
|
+
const headers = /** @type {Record<string,string>} */ ({});
|
|
58
59
|
if (session?.jwt) headers['Authorization'] = `Bearer ${session.jwt}`;
|
|
59
60
|
const res = await fetch(`/v1/packages/${enc(groupId)}/export`, { headers });
|
|
60
61
|
if (!res.ok) throw new Error(`Export failed: ${res.status}`);
|
|
@@ -65,7 +66,7 @@ export async function importPackageZip(file) {
|
|
|
65
66
|
const session = window.AIMEAT?.auth?.getSession?.();
|
|
66
67
|
const formData = new FormData();
|
|
67
68
|
formData.append('file', file);
|
|
68
|
-
const headers = {};
|
|
69
|
+
const headers = /** @type {Record<string,string>} */ ({});
|
|
69
70
|
if (session?.jwt) headers['Authorization'] = `Bearer ${session.jwt}`;
|
|
70
71
|
const res = await fetch('/v1/packages/import', {
|
|
71
72
|
method: 'POST',
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file presence.js
|
|
3
|
+
* @description AIMEAT Presence Service — thin API layer over /v1/presence/*. Read
|
|
4
|
+
* your own config + status, update it, and read viewer-scoped status for one or
|
|
5
|
+
* many identities. List/dot rendering should go through /js/presence-store.js
|
|
6
|
+
* (cache + batch coalescing) rather than calling getPresence per row.
|
|
7
|
+
* @structure getMyPresence / setMyPresence / getPresence / getPresenceBatch
|
|
8
|
+
* @usage import { getPresenceBatch } from '/js/services/presence.js';
|
|
9
|
+
* @version-history
|
|
10
|
+
* v1.0.0 — 2026-06-19 — Initial presence service.
|
|
11
|
+
*/
|
|
12
|
+
import { apiGet, apiPut } from '/js/api.js';
|
|
13
|
+
|
|
14
|
+
/** Read the caller's own presence config + computed status. Returns the envelope. */
|
|
15
|
+
export async function getMyPresence() {
|
|
16
|
+
return apiGet('/v1/presence/me');
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** Update the caller's presence config (partial: { mode, status, visibility }). */
|
|
20
|
+
export async function setMyPresence(config) {
|
|
21
|
+
return apiPut('/v1/presence/me', config);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** Viewer-scoped status of a single identity. Returns the envelope ({ data: { ghii, status, since } }). */
|
|
25
|
+
export async function getPresence(ghii) {
|
|
26
|
+
return apiGet(`/v1/presence/${encodeURIComponent(ghii)}`);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** Batch viewer-scoped status. Returns a map of ghii → { status, since }. */
|
|
30
|
+
export async function getPresenceBatch(ghiis) {
|
|
31
|
+
const ids = (ghiis || []).map(encodeURIComponent).join(',');
|
|
32
|
+
if (!ids) return {};
|
|
33
|
+
const r = await apiGet(`/v1/presence?ids=${ids}`);
|
|
34
|
+
return r?.data?.presence || {};
|
|
35
|
+
}
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* (no inline handlers) to satisfy the static-asset CSP (script-src 'self').
|
|
8
8
|
* @version-history
|
|
9
9
|
* v1.0.0 — 2026-06-02 — Initial testbed behavior
|
|
10
|
+
* v1.0.1 — 2026-06-19 — JSDoc type annotations for frontend type-checking
|
|
10
11
|
*/
|
|
11
12
|
(function () {
|
|
12
13
|
'use strict';
|
|
@@ -95,7 +96,7 @@
|
|
|
95
96
|
const sel = variant.querySelector('.stb-decide');
|
|
96
97
|
if (!sel) return; // canonical reference — no decision
|
|
97
98
|
total += 1;
|
|
98
|
-
const val = sel.value;
|
|
99
|
+
const val = /** @type {HTMLInputElement} */ (sel).value;
|
|
99
100
|
if (val !== '') decided += 1;
|
|
100
101
|
sel.classList.toggle('stb-chosen', val !== '');
|
|
101
102
|
const clone = variant.getAttribute('data-clone') || '';
|
|
@@ -104,7 +105,7 @@
|
|
|
104
105
|
rows.push(' [' + pad(LABEL[val] || val, 18) + '] ' + pad(clone, 46) + ' ' + sitesStr);
|
|
105
106
|
});
|
|
106
107
|
const note = fam.querySelector('.stb-note');
|
|
107
|
-
const noteVal = note && note.value.trim();
|
|
108
|
+
const noteVal = note && /** @type {HTMLInputElement} */ (note).value.trim();
|
|
108
109
|
|
|
109
110
|
lines.push('## ' + famName);
|
|
110
111
|
rows.forEach((r) => lines.push(r));
|
|
@@ -113,7 +114,7 @@
|
|
|
113
114
|
});
|
|
114
115
|
|
|
115
116
|
const out = document.getElementById('stb-output');
|
|
116
|
-
if (out) out.value = lines.join('\n');
|
|
117
|
+
if (out) /** @type {HTMLInputElement} */ (out).value = lines.join('\n');
|
|
117
118
|
const count = document.getElementById('stb-count');
|
|
118
119
|
if (count) count.textContent = '(' + decided + '/' + total + ' clones decided)';
|
|
119
120
|
}
|
|
@@ -140,9 +141,9 @@
|
|
|
140
141
|
setTimeout(() => { btn.classList.remove('stb-copied'); btn.textContent = prev; }, 1500);
|
|
141
142
|
};
|
|
142
143
|
if (navigator.clipboard && navigator.clipboard.writeText) {
|
|
143
|
-
navigator.clipboard.writeText(out.value).then(done, () => { out.select(); document.execCommand('copy'); done(); });
|
|
144
|
+
navigator.clipboard.writeText(/** @type {HTMLInputElement} */ (out).value).then(done, () => { /** @type {HTMLInputElement} */ (out).select(); document.execCommand('copy'); done(); });
|
|
144
145
|
} else {
|
|
145
|
-
out.select();
|
|
146
|
+
/** @type {HTMLInputElement} */ (out).select();
|
|
146
147
|
document.execCommand('copy');
|
|
147
148
|
done();
|
|
148
149
|
}
|
|
@@ -1 +1,2 @@
|
|
|
1
|
+
// @ts-nocheck — vendored minified third-party bundle; not type-checked by tsconfig.frontend.json
|
|
1
2
|
const t=5;function e(e){return e.split("").reduce(((e,n)=>(e^n.charCodeAt(0))*-t),t)>>>2}export function minidenticon(t="",n=95,i=45,s=e){const o=s(t),c=o%9*40;return[...Array(t?25:0)].reduce(((t,e,n)=>o&1<<n%15?t+`<rect x="${n>14?7-~~(n/5):~~(n/5)}" y="${n%5}" width="1" height="1"/>`:t),`<svg viewBox="-1.5 -1.5 8 8" xmlns="http://www.w3.org/2000/svg" fill="hsl(${c} ${n}% ${i}%)">`)+"</svg>"}export const minidenticonSvg=globalThis.customElements?.get("minidenticon-svg")?null:globalThis.customElements?.define("minidenticon-svg",class t extends HTMLElement{static observedAttributes=["username","saturation","lightness"];static#t={};#e=!1;connectedCallback(){this.#n(),this.#e=!0}attributeChangedCallback(){this.#e&&this.#n()}#n(){const e=t.observedAttributes.map((t=>this.getAttribute(t)||void 0)),n=e.join(",");this.innerHTML=t.#t[n]??=minidenticon(...e)}});
|
package/dist/public/lib/yaml.mjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// @ts-nocheck — vendored minified third-party bundle; not type-checked by tsconfig.frontend.json
|
|
1
2
|
/* esm.sh - yaml@2.8.2 */
|
|
2
3
|
var un=Object.defineProperty;var ps=(s,e)=>{for(var t in e)un(s,t,{get:e[t],enumerable:!0})};var us={};ps(us,{Alias:()=>ee,CST:()=>ls,Composer:()=>be,Document:()=>se,Lexer:()=>Be,LineCounter:()=>De,Pair:()=>v,Parser:()=>we,Scalar:()=>y,Schema:()=>ve,YAMLError:()=>_e,YAMLMap:()=>$,YAMLParseError:()=>F,YAMLSeq:()=>B,YAMLWarning:()=>Pe,isAlias:()=>x,isCollection:()=>L,isDocument:()=>R,isMap:()=>U,isNode:()=>I,isPair:()=>T,isScalar:()=>E,isSeq:()=>V,parse:()=>cn,parseAllDocuments:()=>ln,parseDocument:()=>fs,stringify:()=>fn,visit:()=>Q,visitAsync:()=>je});var tt=Symbol.for("yaml.alias"),st=Symbol.for("yaml.document"),Y=Symbol.for("yaml.map"),jt=Symbol.for("yaml.pair"),q=Symbol.for("yaml.scalar"),re=Symbol.for("yaml.seq"),K=Symbol.for("yaml.node.type"),x=s=>!!s&&typeof s=="object"&&s[K]===tt,R=s=>!!s&&typeof s=="object"&&s[K]===st,U=s=>!!s&&typeof s=="object"&&s[K]===Y,T=s=>!!s&&typeof s=="object"&&s[K]===jt,E=s=>!!s&&typeof s=="object"&&s[K]===q,V=s=>!!s&&typeof s=="object"&&s[K]===re;function L(s){if(s&&typeof s=="object")switch(s[K]){case Y:case re:return!0}return!1}function I(s){if(s&&typeof s=="object")switch(s[K]){case tt:case Y:case q:case re:return!0}return!1}var nt=s=>(E(s)||L(s))&&!!s.anchor;var j=Symbol("break visit"),ms=Symbol("skip children"),z=Symbol("remove node");function Q(s,e){let t=ds(e);R(s)?ke(null,s.contents,t,Object.freeze([s]))===z&&(s.contents=null):ke(null,s,t,Object.freeze([]))}Q.BREAK=j;Q.SKIP=ms;Q.REMOVE=z;function ke(s,e,t,n){let i=gs(s,e,t,n);if(I(i)||T(i))return ys(s,n,i),ke(s,i,t,n);if(typeof i!="symbol"){if(L(e)){n=Object.freeze(n.concat(e));for(let r=0;r<e.items.length;++r){let o=ke(r,e.items[r],t,n);if(typeof o=="number")r=o-1;else{if(o===j)return j;o===z&&(e.items.splice(r,1),r-=1)}}}else if(T(e)){n=Object.freeze(n.concat(e));let r=ke("key",e.key,t,n);if(r===j)return j;r===z&&(e.key=null);let o=ke("value",e.value,t,n);if(o===j)return j;o===z&&(e.value=null)}}return i}async function je(s,e){let t=ds(e);R(s)?await Ne(null,s.contents,t,Object.freeze([s]))===z&&(s.contents=null):await Ne(null,s,t,Object.freeze([]))}je.BREAK=j;je.SKIP=ms;je.REMOVE=z;async function Ne(s,e,t,n){let i=await gs(s,e,t,n);if(I(i)||T(i))return ys(s,n,i),Ne(s,i,t,n);if(typeof i!="symbol"){if(L(e)){n=Object.freeze(n.concat(e));for(let r=0;r<e.items.length;++r){let o=await Ne(r,e.items[r],t,n);if(typeof o=="number")r=o-1;else{if(o===j)return j;o===z&&(e.items.splice(r,1),r-=1)}}}else if(T(e)){n=Object.freeze(n.concat(e));let r=await Ne("key",e.key,t,n);if(r===j)return j;r===z&&(e.key=null);let o=await Ne("value",e.value,t,n);if(o===j)return j;o===z&&(e.value=null)}}return i}function ds(s){return typeof s=="object"&&(s.Collection||s.Node||s.Value)?Object.assign({Alias:s.Node,Map:s.Node,Scalar:s.Node,Seq:s.Node},s.Value&&{Map:s.Value,Scalar:s.Value,Seq:s.Value},s.Collection&&{Map:s.Collection,Seq:s.Collection},s):s}function gs(s,e,t,n){if(typeof t=="function")return t(s,e,n);if(U(e))return t.Map?.(s,e,n);if(V(e))return t.Seq?.(s,e,n);if(T(e))return t.Pair?.(s,e,n);if(E(e))return t.Scalar?.(s,e,n);if(x(e))return t.Alias?.(s,e,n)}function ys(s,e,t){let n=e[e.length-1];if(L(n))n.items[s]=t;else if(T(n))s==="key"?n.key=t:n.value=t;else if(R(n))n.contents=t;else{let i=x(n)?"alias":"scalar";throw new Error(`Cannot replace node with ${i} parent`)}}var hn={"!":"%21",",":"%2C","[":"%5B","]":"%5D","{":"%7B","}":"%7D"},pn=s=>s.replace(/[!,[\]{}]/g,e=>hn[e]),Z=class s{constructor(e,t){this.docStart=null,this.docEnd=!1,this.yaml=Object.assign({},s.defaultYaml,e),this.tags=Object.assign({},s.defaultTags,t)}clone(){let e=new s(this.yaml,this.tags);return e.docStart=this.docStart,e}atDocument(){let e=new s(this.yaml,this.tags);switch(this.yaml.version){case"1.1":this.atNextDocument=!0;break;case"1.2":this.atNextDocument=!1,this.yaml={explicit:s.defaultYaml.explicit,version:"1.2"},this.tags=Object.assign({},s.defaultTags);break}return e}add(e,t){this.atNextDocument&&(this.yaml={explicit:s.defaultYaml.explicit,version:"1.1"},this.tags=Object.assign({},s.defaultTags),this.atNextDocument=!1);let n=e.trim().split(/[ \t]+/),i=n.shift();switch(i){case"%TAG":{if(n.length!==2&&(t(0,"%TAG directive should contain exactly two parts"),n.length<2))return!1;let[r,o]=n;return this.tags[r]=o,!0}case"%YAML":{if(this.yaml.explicit=!0,n.length!==1)return t(0,"%YAML directive should contain exactly one part"),!1;let[r]=n;if(r==="1.1"||r==="1.2")return this.yaml.version=r,!0;{let o=/^\d+\.\d+$/.test(r);return t(6,`Unsupported YAML version ${r}`,o),!1}}default:return t(0,`Unknown directive ${i}`,!0),!1}}tagName(e,t){if(e==="!")return"!";if(e[0]!=="!")return t(`Not a valid tag: ${e}`),null;if(e[1]==="<"){let o=e.slice(2,-1);return o==="!"||o==="!!"?(t(`Verbatim tags aren't resolved, so ${e} is invalid.`),null):(e[e.length-1]!==">"&&t("Verbatim tags must end with a >"),o)}let[,n,i]=e.match(/^(.*!)([^!]*)$/s);i||t(`The ${e} tag has no suffix`);let r=this.tags[n];if(r)try{return r+decodeURIComponent(i)}catch(o){return t(String(o)),null}return n==="!"?e:(t(`Could not resolve tag: ${e}`),null)}tagString(e){for(let[t,n]of Object.entries(this.tags))if(e.startsWith(n))return t+pn(e.substring(n.length));return e[0]==="!"?e:`!<${e}>`}toString(e){let t=this.yaml.explicit?[`%YAML ${this.yaml.version||"1.2"}`]:[],n=Object.entries(this.tags),i;if(e&&n.length>0&&I(e.contents)){let r={};Q(e.contents,(o,a)=>{I(a)&&a.tag&&(r[a.tag]=!0)}),i=Object.keys(r)}else i=[];for(let[r,o]of n)r==="!!"&&o==="tag:yaml.org,2002:"||(!e||i.some(a=>a.startsWith(o)))&&t.push(`%TAG ${r} ${o}`);return t.join(`
|
|
3
4
|
`)}};Z.defaultYaml={explicit:!1,version:"1.2"};Z.defaultTags={"!!":"tag:yaml.org,2002:"};function it(s){if(/[\x00-\x19\s,[\]{}]/.test(s)){let t=`Anchor must not contain whitespace or control characters: ${JSON.stringify(s)}`;throw new Error(t)}return!0}function qt(s){let e=new Set;return Q(s,{Value(t,n){n.anchor&&e.add(n.anchor)}}),e}function xt(s,e){for(let t=1;;++t){let n=`${s}${t}`;if(!e.has(n))return n}}function bs(s,e){let t=[],n=new Map,i=null;return{onAnchor:r=>{t.push(r),i??(i=qt(s));let o=xt(e,i);return i.add(o),o},setAnchors:()=>{for(let r of t){let o=n.get(r);if(typeof o=="object"&&o.anchor&&(E(o.node)||L(o.node)))o.node.anchor=o.anchor;else{let a=new Error("Failed to resolve repeated object (this should not happen)");throw a.source=r,a}}},sourceObjects:n}}function fe(s,e,t,n){if(n&&typeof n=="object")if(Array.isArray(n))for(let i=0,r=n.length;i<r;++i){let o=n[i],a=fe(s,n,String(i),o);a===void 0?delete n[i]:a!==o&&(n[i]=a)}else if(n instanceof Map)for(let i of Array.from(n.keys())){let r=n.get(i),o=fe(s,n,i,r);o===void 0?n.delete(i):o!==r&&n.set(i,o)}else if(n instanceof Set)for(let i of Array.from(n)){let r=fe(s,n,i,i);r===void 0?n.delete(i):r!==i&&(n.delete(i),n.add(r))}else for(let[i,r]of Object.entries(n)){let o=fe(s,n,i,r);o===void 0?delete n[i]:o!==r&&(n[i]=o)}return s.call(e,t,n)}function M(s,e,t){if(Array.isArray(s))return s.map((n,i)=>M(n,String(i),t));if(s&&typeof s.toJSON=="function"){if(!t||!nt(s))return s.toJSON(e,t);let n={aliasCount:0,count:1,res:void 0};t.anchors.set(s,n),t.onCreate=r=>{n.res=r,delete t.onCreate};let i=s.toJSON(e,t);return t.onCreate&&t.onCreate(i),i}return typeof s=="bigint"&&!t?.keep?Number(s):s}var ue=class{constructor(e){Object.defineProperty(this,K,{value:e})}clone(){let e=Object.create(Object.getPrototypeOf(this),Object.getOwnPropertyDescriptors(this));return this.range&&(e.range=this.range.slice()),e}toJS(e,{mapAsMap:t,maxAliasCount:n,onAnchor:i,reviver:r}={}){if(!R(e))throw new TypeError("A document argument is required");let o={anchors:new Map,doc:e,keep:!0,mapAsMap:t===!0,mapKeyWarned:!1,maxAliasCount:typeof n=="number"?n:100},a=M(this,"",o);if(typeof i=="function")for(let{count:l,res:c}of o.anchors.values())i(c,l);return typeof r=="function"?fe(r,{"":a},"",a):a}};var ee=class extends ue{constructor(e){super(tt),this.source=e,Object.defineProperty(this,"tag",{set(){throw new Error("Alias nodes cannot have tags")}})}resolve(e,t){let n;t?.aliasResolveCache?n=t.aliasResolveCache:(n=[],Q(e,{Node:(r,o)=>{(x(o)||nt(o))&&n.push(o)}}),t&&(t.aliasResolveCache=n));let i;for(let r of n){if(r===this)break;r.anchor===this.source&&(i=r)}return i}toJSON(e,t){if(!t)return{source:this.source};let{anchors:n,doc:i,maxAliasCount:r}=t,o=this.resolve(i,t);if(!o){let l=`Unresolved alias (the anchor must be set before the alias): ${this.source}`;throw new ReferenceError(l)}let a=n.get(o);if(a||(M(o,null,t),a=n.get(o)),a?.res===void 0){let l="This should not happen: Alias anchor was not resolved?";throw new ReferenceError(l)}if(r>=0&&(a.count+=1,a.aliasCount===0&&(a.aliasCount=rt(i,o,n)),a.count*a.aliasCount>r)){let l="Excessive alias count indicates a resource exhaustion attack";throw new ReferenceError(l)}return a.res}toString(e,t,n){let i=`*${this.source}`;if(e){if(it(this.source),e.options.verifyAliasOrder&&!e.anchors.has(this.source)){let r=`Unresolved alias (the anchor must be set before the alias): ${this.source}`;throw new Error(r)}if(e.implicitKey)return`${i} `}return i}};function rt(s,e,t){if(x(e)){let n=e.resolve(s),i=t&&n&&t.get(n);return i?i.count*i.aliasCount:0}else if(L(e)){let n=0;for(let i of e.items){let r=rt(s,i,t);r>n&&(n=r)}return n}else if(T(e)){let n=rt(s,e.key,t),i=rt(s,e.value,t);return Math.max(n,i)}return 1}var ot=s=>!s||typeof s!="function"&&typeof s!="object",y=class extends ue{constructor(e){super(q),this.value=e}toJSON(e,t){return t?.keep?this.value:M(this.value,e,t)}toString(){return String(this.value)}};y.BLOCK_FOLDED="BLOCK_FOLDED";y.BLOCK_LITERAL="BLOCK_LITERAL";y.PLAIN="PLAIN";y.QUOTE_DOUBLE="QUOTE_DOUBLE";y.QUOTE_SINGLE="QUOTE_SINGLE";var mn="tag:yaml.org,2002:";function dn(s,e,t){if(e){let n=t.filter(r=>r.tag===e),i=n.find(r=>!r.format)??n[0];if(!i)throw new Error(`Tag ${e} not found`);return i}return t.find(n=>n.identify?.(s)&&!n.format)}function oe(s,e,t){if(R(s)&&(s=s.contents),I(s))return s;if(T(s)){let f=t.schema[Y].createNode?.(t.schema,null,t);return f.items.push(s),f}(s instanceof String||s instanceof Number||s instanceof Boolean||typeof BigInt<"u"&&s instanceof BigInt)&&(s=s.valueOf());let{aliasDuplicateObjects:n,onAnchor:i,onTagObj:r,schema:o,sourceObjects:a}=t,l;if(n&&s&&typeof s=="object"){if(l=a.get(s),l)return l.anchor??(l.anchor=i(s)),new ee(l.anchor);l={anchor:null,node:null},a.set(s,l)}e?.startsWith("!!")&&(e=mn+e.slice(2));let c=dn(s,e,o.tags);if(!c){if(s&&typeof s.toJSON=="function"&&(s=s.toJSON()),!s||typeof s!="object"){let f=new y(s);return l&&(l.node=f),f}c=s instanceof Map?o[Y]:Symbol.iterator in Object(s)?o[re]:o[Y]}r&&(r(c),delete t.onTagObj);let p=c?.createNode?c.createNode(t.schema,s,t):typeof c?.nodeClass?.from=="function"?c.nodeClass.from(t.schema,s,t):new y(s);return e?p.tag=e:c.default||(p.tag=c.tag),l&&(l.node=p),p}function qe(s,e,t){let n=t;for(let i=e.length-1;i>=0;--i){let r=e[i];if(typeof r=="number"&&Number.isInteger(r)&&r>=0){let o=[];o[r]=n,n=o}else n=new Map([[r,n]])}return oe(n,void 0,{aliasDuplicateObjects:!1,keepUndefined:!1,onAnchor:()=>{throw new Error("This should not happen, please report a bug.")},schema:s,sourceObjects:new Map})}var Ae=s=>s==null||typeof s=="object"&&!!s[Symbol.iterator]().next().done,Oe=class extends ue{constructor(e,t){super(e),Object.defineProperty(this,"schema",{value:t,configurable:!0,enumerable:!1,writable:!0})}clone(e){let t=Object.create(Object.getPrototypeOf(this),Object.getOwnPropertyDescriptors(this));return e&&(t.schema=e),t.items=t.items.map(n=>I(n)||T(n)?n.clone(e):n),this.range&&(t.range=this.range.slice()),t}addIn(e,t){if(Ae(e))this.add(t);else{let[n,...i]=e,r=this.get(n,!0);if(L(r))r.addIn(i,t);else if(r===void 0&&this.schema)this.set(n,qe(this.schema,i,t));else throw new Error(`Expected YAML collection at ${n}. Remaining path: ${i}`)}}deleteIn(e){let[t,...n]=e;if(n.length===0)return this.delete(t);let i=this.get(t,!0);if(L(i))return i.deleteIn(n);throw new Error(`Expected YAML collection at ${t}. Remaining path: ${n}`)}getIn(e,t){let[n,...i]=e,r=this.get(n,!0);return i.length===0?!t&&E(r)?r.value:r:L(r)?r.getIn(i,t):void 0}hasAllNullValues(e){return this.items.every(t=>{if(!T(t))return!1;let n=t.value;return n==null||e&&E(n)&&n.value==null&&!n.commentBefore&&!n.comment&&!n.tag})}hasIn(e){let[t,...n]=e;if(n.length===0)return this.has(t);let i=this.get(t,!0);return L(i)?i.hasIn(n):!1}setIn(e,t){let[n,...i]=e;if(i.length===0)this.set(n,t);else{let r=this.get(n,!0);if(L(r))r.setIn(i,t);else if(r===void 0&&this.schema)this.set(n,qe(this.schema,i,t));else throw new Error(`Expected YAML collection at ${n}. Remaining path: ${i}`)}}};var ws=s=>s.replace(/^(?!$)(?: $)?/gm,"#");function J(s,e){return/^\n+$/.test(s)?s.substring(1):e?s.replace(/^(?! *$)/gm,e):s}var te=(s,e,t)=>s.endsWith(`
|
package/dist/public/spa.html
CHANGED
|
@@ -64,6 +64,9 @@
|
|
|
64
64
|
</script>
|
|
65
65
|
<link href="https://fonts.googleapis.com/css2?family=DM+Sans:ital,opsz,wght@0,9..40,300;0,9..40,400;0,9..40,500;0,9..40,600;0,9..40,700;0,9..40,800&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
|
|
66
66
|
<link rel="stylesheet" href="/css/theme.css">
|
|
67
|
+
<!-- Canonical styles for the shared <Markdown> component — load before views so it styles
|
|
68
|
+
rendered markdown everywhere the component is used (no per-view re-definition). -->
|
|
69
|
+
<link rel="stylesheet" href="/css/components/markdown.css">
|
|
67
70
|
<!-- View CSS preloaded so they are ready before any view renders (prevents FOUC) -->
|
|
68
71
|
<!-- hrefs are stamped with ?v=BUILD_ID at serve time by portal.ts serveSpa() -->
|
|
69
72
|
<link rel="stylesheet" href="/css/views/portal.css">
|
|
@@ -71,6 +74,7 @@
|
|
|
71
74
|
<link rel="stylesheet" href="/css/views/portal-classic.css">
|
|
72
75
|
<link rel="stylesheet" href="/css/views/portal-dev.css">
|
|
73
76
|
<link rel="stylesheet" href="/css/views/profile.css">
|
|
77
|
+
<link rel="stylesheet" href="/css/views/notebook.css">
|
|
74
78
|
<link rel="stylesheet" href="/css/views/offers.css">
|
|
75
79
|
<link rel="stylesheet" href="/css/views/foundry.css">
|
|
76
80
|
<link rel="stylesheet" href="/css/views/calibrator.css">
|
|
@@ -157,6 +161,7 @@
|
|
|
157
161
|
"/js/services/foundry-probe-reconcile.js": "/js/services/foundry-probe-reconcile.js",
|
|
158
162
|
"/js/services/knowledge.js": "/js/services/knowledge.js",
|
|
159
163
|
"/js/services/memory.js": "/js/services/memory.js",
|
|
164
|
+
"/js/services/notebook.js": "/js/services/notebook.js",
|
|
160
165
|
"/js/services/nodes.js": "/js/services/nodes.js",
|
|
161
166
|
"/js/services/organisms.js": "/js/services/organisms.js",
|
|
162
167
|
"/js/services/offers.js": "/js/services/offers.js",
|
|
@@ -167,6 +172,8 @@
|
|
|
167
172
|
"/js/services/wallet.js": "/js/services/wallet.js",
|
|
168
173
|
"/js/services/work.js": "/js/services/work.js",
|
|
169
174
|
"/js/services/messages.js": "/js/services/messages.js",
|
|
175
|
+
"/js/services/presence.js": "/js/services/presence.js",
|
|
176
|
+
"/js/presence-store.js": "/js/presence-store.js",
|
|
170
177
|
"/js/components/auth-image.js": "/js/components/auth-image.js",
|
|
171
178
|
"/js/components/tag-cloud.js": "/js/components/tag-cloud.js",
|
|
172
179
|
"/js/components/tag-editor.js": "/js/components/tag-editor.js",
|
|
@@ -184,6 +191,7 @@
|
|
|
184
191
|
"/components/ToggleSwitch.js": "/components/ToggleSwitch.js",
|
|
185
192
|
"/components/Card.js": "/components/Card.js",
|
|
186
193
|
"/components/StatusDot.js": "/components/StatusDot.js",
|
|
194
|
+
"/components/PresenceDot.js": "/components/PresenceDot.js",
|
|
187
195
|
"/components/TagList.js": "/components/TagList.js",
|
|
188
196
|
"/components/Pagination.js": "/components/Pagination.js",
|
|
189
197
|
"/components/KeyValueRow.js": "/components/KeyValueRow.js",
|
|
@@ -208,7 +216,23 @@
|
|
|
208
216
|
"/js/services/agent-integration.js": "/js/services/agent-integration.js",
|
|
209
217
|
"/js/services/admin-agent-integration.js": "/js/services/admin-agent-integration.js",
|
|
210
218
|
"/js/services/schedules.js": "/js/services/schedules.js",
|
|
211
|
-
"/js/services/workflows.js": "/js/services/workflows.js"
|
|
219
|
+
"/js/services/workflows.js": "/js/services/workflows.js",
|
|
220
|
+
"/views/profile/shared.js": "/views/profile/shared.js",
|
|
221
|
+
"/views/profile/generator-settings.js": "/views/profile/generator-settings.js",
|
|
222
|
+
"/views/profile/organisms/helpers.js": "/views/profile/organisms/helpers.js",
|
|
223
|
+
"/views/profile/organisms/widgets.js": "/views/profile/organisms/widgets.js",
|
|
224
|
+
"/views/profile/organisms/panels.js": "/views/profile/organisms/panels.js",
|
|
225
|
+
"/views/profile/organisms/agents.js": "/views/profile/organisms/agents.js",
|
|
226
|
+
"/views/profile/organisms/members.js": "/views/profile/organisms/members.js",
|
|
227
|
+
"/views/profile/organisms/home.js": "/views/profile/organisms/home.js",
|
|
228
|
+
"/views/profile/organisms/workspace-list.js": "/views/profile/organisms/workspace-list.js",
|
|
229
|
+
"/views/profile/organisms/workspace.js": "/views/profile/organisms/workspace.js",
|
|
230
|
+
"/views/profile/organisms/activity-panel.js": "/views/profile/organisms/activity-panel.js",
|
|
231
|
+
"/views/profile/organisms/participants-panel.js": "/views/profile/organisms/participants-panel.js",
|
|
232
|
+
"/views/profile/organisms/workspace-comments.js": "/views/profile/organisms/workspace-comments.js",
|
|
233
|
+
"/views/profile/organisms/sources-panel.js": "/views/profile/organisms/sources-panel.js",
|
|
234
|
+
"/views/profile/organisms/schema-form.js": "/views/profile/organisms/schema-form.js",
|
|
235
|
+
"/views/profile/organisms/document.js": "/views/profile/organisms/document.js"
|
|
212
236
|
}
|
|
213
237
|
}
|
|
214
238
|
</script>
|
|
@@ -223,6 +247,28 @@
|
|
|
223
247
|
<!-- App root (Preact mounts here) -->
|
|
224
248
|
<div id="app"></div>
|
|
225
249
|
|
|
250
|
+
<!-- SSO handoff: the desktop app already holds an authenticated owner JWT (from its inline
|
|
251
|
+
sign-in). It opens the portal with #handoff=<base64({owner,jwt})> so the browser is logged
|
|
252
|
+
in WITHOUT a second sign-in. Runs synchronously before the app reads the session. -->
|
|
253
|
+
<script>
|
|
254
|
+
(function () {
|
|
255
|
+
try {
|
|
256
|
+
var m = location.hash.match(/[#&]handoff=([^&]+)/);
|
|
257
|
+
if (!m) return;
|
|
258
|
+
var s = JSON.parse(atob(decodeURIComponent(m[1])));
|
|
259
|
+
if (s && s.jwt && s.owner) {
|
|
260
|
+
var node = '';
|
|
261
|
+
try { node = (JSON.parse(atob(s.jwt.split('.')[1].replace(/-/g, '+').replace(/_/g, '/'))) || {}).node || ''; } catch (e) {}
|
|
262
|
+
localStorage.setItem('aimeat_session', JSON.stringify({
|
|
263
|
+
owner: s.owner, jwt: s.jwt, ghii: node ? (s.owner + '@' + node) : null, gaii: null,
|
|
264
|
+
}));
|
|
265
|
+
}
|
|
266
|
+
// Strip the token from the URL so it is not bookmarked or left in history.
|
|
267
|
+
history.replaceState(null, '', location.pathname + location.search);
|
|
268
|
+
} catch (e) { /* ignore a malformed handoff */ }
|
|
269
|
+
})();
|
|
270
|
+
</script>
|
|
271
|
+
|
|
226
272
|
<script type="module">
|
|
227
273
|
import { h, render, Component } from 'preact';
|
|
228
274
|
import { useState, useEffect, useCallback } from 'preact/hooks';
|
|
@@ -430,10 +476,24 @@
|
|
|
430
476
|
}
|
|
431
477
|
|
|
432
478
|
// ── Header Component ──
|
|
479
|
+
// Built-in public links. Operators can show/hide and reorder these via the admin
|
|
480
|
+
// Portal tab (persisted at /v1/site/header-nav). Auth/role-gated links (Apps, Profile,
|
|
481
|
+
// Admin) are NOT in this list — they stay forced by the session/role checks below.
|
|
482
|
+
const PUBLIC_NAV_LINKS = [
|
|
483
|
+
{ id: 'try', path: '/v1/portal', key: 'nav.try' },
|
|
484
|
+
{ id: 'howItWorks', path: '/v1/how-it-works', key: 'nav.howItWorks', fallback: 'How it works' },
|
|
485
|
+
{ id: 'business', path: '/v1/business', key: 'nav.business', fallback: 'For your business' },
|
|
486
|
+
{ id: 'devView', path: '/v1/portal?view=dev', key: 'nav.devView', matchActive: false },
|
|
487
|
+
{ id: 'help', path: '/v1/help', key: 'nav.help' },
|
|
488
|
+
];
|
|
489
|
+
|
|
433
490
|
function Header({ navigate, locale }) {
|
|
434
491
|
const [session, setSession] = useState(null);
|
|
435
492
|
const [morsels, setMorsels] = useState(null);
|
|
436
493
|
const [menuOpen, setMenuOpen] = useState(false);
|
|
494
|
+
// Header nav config: { order, hidden }. Defaults to all visible in declared order
|
|
495
|
+
// until the public /v1/site/header-nav fetch resolves (no flash of empty nav).
|
|
496
|
+
const [navConfig, setNavConfig] = useState({ order: PUBLIC_NAV_LINKS.map(l => l.id), hidden: [] });
|
|
437
497
|
|
|
438
498
|
// Check auth state
|
|
439
499
|
useEffect(() => {
|
|
@@ -451,6 +511,21 @@
|
|
|
451
511
|
return () => window.removeEventListener('aimeat-auth-change', checkAuth);
|
|
452
512
|
}, []);
|
|
453
513
|
|
|
514
|
+
// Load operator-configured header nav (public endpoint, no auth needed).
|
|
515
|
+
useEffect(() => {
|
|
516
|
+
let cancelled = false;
|
|
517
|
+
fetch('/v1/site/header-nav')
|
|
518
|
+
.then(r => r.json())
|
|
519
|
+
.then(d => {
|
|
520
|
+
if (cancelled || !d?.ok || !d.data) return;
|
|
521
|
+
const order = Array.isArray(d.data.order) ? d.data.order : PUBLIC_NAV_LINKS.map(l => l.id);
|
|
522
|
+
const hidden = Array.isArray(d.data.hidden) ? d.data.hidden : [];
|
|
523
|
+
setNavConfig({ order, hidden });
|
|
524
|
+
})
|
|
525
|
+
.catch(e => console.warn('Header nav fetch failed:', e.message));
|
|
526
|
+
return () => { cancelled = true; };
|
|
527
|
+
}, []);
|
|
528
|
+
|
|
454
529
|
// Fetch morsels when session is available
|
|
455
530
|
useEffect(() => {
|
|
456
531
|
if (!session) { setMorsels(null); return; }
|
|
@@ -477,6 +552,13 @@
|
|
|
477
552
|
|
|
478
553
|
const currentPath = location.pathname;
|
|
479
554
|
|
|
555
|
+
// Resolve the public links to render: config order, minus hidden, by declared id.
|
|
556
|
+
const linkById = Object.fromEntries(PUBLIC_NAV_LINKS.map(l => [l.id, l]));
|
|
557
|
+
const hiddenSet = new Set(navConfig.hidden);
|
|
558
|
+
const visibleLinks = navConfig.order
|
|
559
|
+
.map(id => linkById[id])
|
|
560
|
+
.filter(l => l && !hiddenSet.has(l.id));
|
|
561
|
+
|
|
480
562
|
return html`
|
|
481
563
|
<nav class="topnav">
|
|
482
564
|
<div style="display:flex;align-items:center;gap:20px">
|
|
@@ -490,14 +572,14 @@
|
|
|
490
572
|
<button class="topnav-burger" aria-label="Menu" aria-expanded=${menuOpen ? 'true' : 'false'}
|
|
491
573
|
onClick=${() => setMenuOpen(o => !o)}>☰</button>
|
|
492
574
|
<div class="topnav-menu ${menuOpen ? 'open' : ''}">
|
|
493
|
-
<!--
|
|
494
|
-
|
|
575
|
+
<!-- Public links are operator-configurable (visibility + order) via the admin
|
|
576
|
+
Portal tab. "Try it" leads to the landing's path cards + app gallery.
|
|
495
577
|
Classic stays reachable deeper (landing card B "Start building"). -->
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
578
|
+
${visibleLinks.map(link => html`
|
|
579
|
+
<a href="${link.path}" key=${link.id}
|
|
580
|
+
onClick=${(e) => { handleNav(e, link.path); setMenuOpen(false); }}
|
|
581
|
+
class="${link.matchActive !== false && currentPath === link.path ? 'active' : ''}">${t(link.key) || link.fallback || link.key}</a>
|
|
582
|
+
`)}
|
|
501
583
|
${session && html`
|
|
502
584
|
<a href="/app-catalog.html" target="_blank" onClick=${() => setMenuOpen(false)} class="${currentPath === '/app-catalog.html' ? 'active' : ''}">${t('nav.apps') || 'Apps'}</a>
|
|
503
585
|
<a href="/v1/profile" class="profile-link visible ${currentPath === '/v1/profile' ? 'active' : ''}" onClick=${(e) => { handleNav(e, '/v1/profile'); setMenuOpen(false); }}>
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file aimeat-globals.d.ts
|
|
3
|
+
* @description Ambient type declarations for the no-build frontend. Covers browser globals that
|
|
4
|
+
* arrive via <script> tags or build-time injection (not ES-module imports), plus the
|
|
5
|
+
* conventional fields the api.js fetch wrapper attaches to thrown Errors. This lets
|
|
6
|
+
* `tsc --noEmit` (checkJs) type-check public/ without these surfacing as "cannot find name"
|
|
7
|
+
* or "property does not exist" noise. It declares no runtime — types only.
|
|
8
|
+
* @usage Picked up automatically by tsconfig.frontend.json via its d.ts include glob.
|
|
9
|
+
* @version-history
|
|
10
|
+
* v1.0.0 — 2026-06-19 — Initial ambient declarations for frontend type-checking
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
export {};
|
|
14
|
+
|
|
15
|
+
declare global {
|
|
16
|
+
/** The window.AIMEAT SDK (auth, data, ai, …) — loaded by aimeat-auth.js before the SPA. */
|
|
17
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
18
|
+
const AIMEAT: any;
|
|
19
|
+
/** Chart.js — loaded via a <script> tag on admin pages. */
|
|
20
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
21
|
+
const Chart: any;
|
|
22
|
+
/** Build-time version string injected for cache-busting (see i18n.js). */
|
|
23
|
+
const __APP_VERSION__: string;
|
|
24
|
+
|
|
25
|
+
interface Window {
|
|
26
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
27
|
+
AIMEAT: any;
|
|
28
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
29
|
+
Chart: any;
|
|
30
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
31
|
+
mermaid: any;
|
|
32
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
33
|
+
toastui: any;
|
|
34
|
+
showToast?: (message: string, isError?: boolean) => void;
|
|
35
|
+
/** Preact bundle marker set by the vendored preact build. */
|
|
36
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
37
|
+
__B?: any;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* The api.js fetch wrapper attaches these fields to thrown Errors so callers can branch
|
|
42
|
+
* on the server error envelope (see public/js/api.js). Declared here so `err.code` /
|
|
43
|
+
* `err.status` / `err.response` type-check at every catch site.
|
|
44
|
+
*/
|
|
45
|
+
interface Error {
|
|
46
|
+
code?: string;
|
|
47
|
+
status?: number;
|
|
48
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
49
|
+
response?: any;
|
|
50
|
+
source?: string;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file vendored-libs.d.ts
|
|
3
|
+
* @description Type stubs for the vendored, minified ESM libraries the frontend imports by bare
|
|
4
|
+
* specifier (preact, preact/hooks, htm). The browser resolves these via the importmap to
|
|
5
|
+
* public/lib/*.mjs at runtime; this stub exists only so `tsc --noEmit` (checkJs) resolves the
|
|
6
|
+
* imports without trying to type-check minified third-party bundles. Exports are intentionally
|
|
7
|
+
* loose (`any`) — htm template rendering is untyped regardless, so precise framework types add
|
|
8
|
+
* little here. tsconfig.frontend.json maps the bare specifiers to this file via "paths".
|
|
9
|
+
* @version-history
|
|
10
|
+
* v1.0.0 — 2026-06-19 — Initial stubs for preact / preact/hooks / htm
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
14
|
+
|
|
15
|
+
declare module 'preact' {
|
|
16
|
+
export const h: any;
|
|
17
|
+
export const Fragment: any;
|
|
18
|
+
export const render: any;
|
|
19
|
+
export const hydrate: any;
|
|
20
|
+
export const cloneElement: any;
|
|
21
|
+
export const createContext: any;
|
|
22
|
+
export const createRef: any;
|
|
23
|
+
export const isValidElement: any;
|
|
24
|
+
export const toChildArray: any;
|
|
25
|
+
export const options: any;
|
|
26
|
+
export class Component {
|
|
27
|
+
constructor(props?: any, context?: any);
|
|
28
|
+
setState(state?: any, callback?: () => void): void;
|
|
29
|
+
forceUpdate(callback?: () => void): void;
|
|
30
|
+
render(props?: any, state?: any, context?: any): any;
|
|
31
|
+
props: any;
|
|
32
|
+
state: any;
|
|
33
|
+
context: any;
|
|
34
|
+
base?: any;
|
|
35
|
+
}
|
|
36
|
+
const preact: any;
|
|
37
|
+
export default preact;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
declare module 'preact/hooks' {
|
|
41
|
+
export const useState: any;
|
|
42
|
+
export const useEffect: any;
|
|
43
|
+
export const useLayoutEffect: any;
|
|
44
|
+
export const useRef: any;
|
|
45
|
+
export const useCallback: any;
|
|
46
|
+
export const useMemo: any;
|
|
47
|
+
export const useReducer: any;
|
|
48
|
+
export const useContext: any;
|
|
49
|
+
export const useErrorBoundary: any;
|
|
50
|
+
export const useId: any;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
declare module 'htm' {
|
|
54
|
+
const htm: any;
|
|
55
|
+
export default htm;
|
|
56
|
+
}
|
|
@@ -13,8 +13,10 @@
|
|
|
13
13
|
* 6. Create public/css/views/myview.css for view-specific styles
|
|
14
14
|
* ─────────────────────────────────────────────────────────────────────────────
|
|
15
15
|
*/
|
|
16
|
-
import {
|
|
16
|
+
import { h } from 'preact';
|
|
17
|
+
import htm from 'htm';
|
|
17
18
|
import { useState, useEffect } from 'preact/hooks';
|
|
19
|
+
const html = htm.bind(h);
|
|
18
20
|
import { t } from '/js/i18n.js';
|
|
19
21
|
import { escHtml } from '/js/utils.js';
|
|
20
22
|
import { apiGet, apiPost } from '/js/api.js';
|
|
@@ -70,7 +70,7 @@ export default function AgentIntegrationTab({ data, session }) {
|
|
|
70
70
|
|
|
71
71
|
return html`
|
|
72
72
|
<div>
|
|
73
|
-
|
|
73
|
+
<${PlatformRegistry} platforms=${platforms} totalAgents=${totalAgents} session=${session} loadData=${loadData} />
|
|
74
74
|
${renderOnboardingOverview(onboarding, readiness, session, loadData)}
|
|
75
75
|
${renderSkillBundles(bundles, handleRegenerate, regenerating, session)}
|
|
76
76
|
${renderBundleTemplates()}
|
|
@@ -78,8 +78,9 @@ export default function AgentIntegrationTab({ data, session }) {
|
|
|
78
78
|
`;
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
-
/* ── M8: Merged Platform column (name + ID as secondary text) ──
|
|
82
|
-
|
|
81
|
+
/* ── M8: Merged Platform column (name + ID as secondary text) ──
|
|
82
|
+
A real component (not a render-helper) so its useState obeys the Rules of Hooks. */
|
|
83
|
+
function PlatformRegistry({ platforms, totalAgents, session, loadData }) {
|
|
83
84
|
const [showForm, setShowForm] = useState(false);
|
|
84
85
|
|
|
85
86
|
return html`
|