aimeat 1.19.0 → 1.20.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 +39 -3
- package/dist/.env.example +5 -1
- package/dist/locales/en.json +231 -1
- package/dist/locales/fi.json +233 -1
- package/dist/public/components/Markdown.js +88 -15
- package/dist/public/components/Mermaid.js +59 -0
- package/dist/public/components/NotificationBell.js +94 -0
- package/dist/public/css/theme.css +26 -0
- package/dist/public/css/views/admin.css +16 -0
- package/dist/public/css/views/agents-detail.css +93 -0
- package/dist/public/css/views/profile.css +241 -2
- package/dist/public/js/api.js +11 -5
- package/dist/public/js/services/admin.js +4 -0
- package/dist/public/js/services/agents.js +19 -0
- package/dist/public/js/services/organisms.js +822 -2
- package/dist/public/lib/mermaid/README.md +6 -0
- package/dist/public/lib/mermaid/mermaid.min.js +3405 -0
- package/dist/public/lib/toastui/toastui-editor-all.min.js +24 -0
- package/dist/public/lib/toastui/toastui-editor.min.css +6 -0
- package/dist/public/llms-template.txt +4 -0
- package/dist/public/spa.html +8 -0
- package/dist/public/views/admin/security-tab.js +93 -0
- package/dist/public/views/admin.js +2 -0
- package/dist/public/views/doc-solo.js +102 -0
- package/dist/public/views/profile/agents/agent-card.js +67 -8
- package/dist/public/views/profile/agents/tab-messages.js +51 -7
- package/dist/public/views/profile/agents-tab.js +184 -4
- package/dist/public/views/profile/agents-tasks-subtab.js +11 -1
- package/dist/public/views/profile/generator-dashboard/use-autopilot.js +5 -2
- package/dist/public/views/profile/landing-page.js +12 -4
- package/dist/public/views/profile/organisms-tab.js +1640 -2
- package/dist/public/views/profile/schedule-item.js +15 -1
- package/dist/public/views/profile.js +6 -3
- package/dist/src/cli/connect/mcp/tools/index.d.ts.map +1 -1
- package/dist/src/cli/connect/mcp/tools/index.js +2 -0
- package/dist/src/cli/connect/mcp/tools/index.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 +15 -0
- package/dist/src/cli/connect/mcp/tools/workspaces.d.ts.map +1 -0
- package/dist/src/cli/connect/mcp/tools/workspaces.js +240 -0
- package/dist/src/cli/connect/mcp/tools/workspaces.js.map +1 -0
- package/dist/src/cli/connect/tool-call.d.ts +5 -0
- package/dist/src/cli/connect/tool-call.d.ts.map +1 -1
- package/dist/src/cli/connect/tool-call.js +255 -0
- package/dist/src/cli/connect/tool-call.js.map +1 -1
- package/dist/src/cli/init-wizard.d.ts.map +1 -1
- package/dist/src/cli/init-wizard.js +16 -8
- package/dist/src/cli/init-wizard.js.map +1 -1
- package/dist/src/config.d.ts +1 -1
- package/dist/src/config.d.ts.map +1 -1
- package/dist/src/config.js +4 -1
- package/dist/src/config.js.map +1 -1
- package/dist/src/generated/api-types.d.ts +998 -23
- package/dist/src/generated/api-types.d.ts.map +1 -1
- package/dist/src/generated/prisma-postgres/client.d.ts +1 -0
- package/dist/src/generated/prisma-postgres/client.js +5 -0
- package/dist/src/generated/prisma-postgres/default.d.ts +1 -0
- package/dist/src/generated/prisma-postgres/default.js +5 -0
- package/dist/src/generated/prisma-postgres/edge.d.ts +1 -0
- package/dist/src/generated/prisma-postgres/edge.js +1530 -0
- package/dist/src/generated/prisma-postgres/index-browser.js +1516 -0
- package/dist/src/generated/prisma-postgres/index.d.ts +128983 -0
- package/dist/src/generated/prisma-postgres/index.js +1551 -0
- package/dist/src/generated/prisma-postgres/package.json +183 -0
- package/dist/src/generated/prisma-postgres/query_engine-windows.dll.node +0 -0
- package/dist/src/generated/prisma-postgres/query_engine_bg.js +2 -0
- package/dist/src/generated/prisma-postgres/query_engine_bg.wasm +0 -0
- package/dist/src/generated/prisma-postgres/runtime/edge-esm.js +35 -0
- package/dist/src/generated/prisma-postgres/runtime/edge.js +35 -0
- package/dist/src/generated/prisma-postgres/runtime/index-browser.d.ts +370 -0
- package/dist/src/generated/prisma-postgres/runtime/index-browser.js +17 -0
- package/dist/src/generated/prisma-postgres/runtime/library.d.ts +3982 -0
- package/dist/src/generated/prisma-postgres/runtime/library.js +147 -0
- package/dist/src/generated/prisma-postgres/runtime/react-native.js +84 -0
- package/dist/src/generated/prisma-postgres/runtime/wasm-compiler-edge.js +85 -0
- package/dist/src/generated/prisma-postgres/runtime/wasm-engine-edge.js +38 -0
- package/dist/src/generated/prisma-postgres/schema.prisma +1465 -0
- package/dist/src/generated/prisma-postgres/wasm-edge-light-loader.mjs +5 -0
- package/dist/src/generated/prisma-postgres/wasm-worker-loader.mjs +5 -0
- package/dist/src/generated/prisma-postgres/wasm.d.ts +1 -0
- package/dist/src/generated/prisma-postgres/wasm.js +1537 -0
- package/dist/src/index.js +1 -1
- package/dist/src/mcp/agent-messages.d.ts +3 -0
- package/dist/src/mcp/agent-messages.d.ts.map +1 -1
- package/dist/src/mcp/agent-messages.js +9 -3
- package/dist/src/mcp/agent-messages.js.map +1 -1
- package/dist/src/mcp/annotations.d.ts.map +1 -1
- package/dist/src/mcp/annotations.js +12 -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 +139 -0
- package/dist/src/mcp/catalog/definitions.js.map +1 -1
- package/dist/src/mcp/catalog/surfaces.d.ts.map +1 -1
- package/dist/src/mcp/catalog/surfaces.js +9 -2
- package/dist/src/mcp/catalog/surfaces.js.map +1 -1
- package/dist/src/mcp/index.d.ts.map +1 -1
- package/dist/src/mcp/index.js +2 -0
- package/dist/src/mcp/index.js.map +1 -1
- package/dist/src/mcp/organisms.d.ts +2 -0
- package/dist/src/mcp/organisms.d.ts.map +1 -1
- package/dist/src/mcp/organisms.js +106 -21
- package/dist/src/mcp/organisms.js.map +1 -1
- package/dist/src/mcp/workspaces.d.ts +34 -0
- package/dist/src/mcp/workspaces.d.ts.map +1 -0
- package/dist/src/mcp/workspaces.js +464 -0
- package/dist/src/mcp/workspaces.js.map +1 -0
- package/dist/src/middleware/workspace-access.d.ts +13 -0
- package/dist/src/middleware/workspace-access.d.ts.map +1 -1
- package/dist/src/middleware/workspace-access.js +12 -7
- package/dist/src/middleware/workspace-access.js.map +1 -1
- package/dist/src/models/schemas.d.ts +2 -2
- package/dist/src/routes/admin-prompts.d.ts.map +1 -1
- package/dist/src/routes/admin-prompts.js +4 -1
- package/dist/src/routes/admin-prompts.js.map +1 -1
- package/dist/src/routes/admin-security.d.ts +19 -0
- package/dist/src/routes/admin-security.d.ts.map +1 -0
- package/dist/src/routes/admin-security.js +87 -0
- package/dist/src/routes/admin-security.js.map +1 -0
- package/dist/src/routes/agent-messages.d.ts +3 -0
- package/dist/src/routes/agent-messages.d.ts.map +1 -1
- package/dist/src/routes/agent-messages.js +27 -2
- package/dist/src/routes/agent-messages.js.map +1 -1
- package/dist/src/routes/agent-tasks.d.ts +5 -1
- package/dist/src/routes/agent-tasks.d.ts.map +1 -1
- package/dist/src/routes/agent-tasks.js +43 -3
- package/dist/src/routes/agent-tasks.js.map +1 -1
- package/dist/src/routes/apps.d.ts +13 -0
- package/dist/src/routes/apps.d.ts.map +1 -1
- package/dist/src/routes/apps.js +74 -42
- package/dist/src/routes/apps.js.map +1 -1
- package/dist/src/routes/bootstrap.d.ts.map +1 -1
- package/dist/src/routes/bootstrap.js +1 -0
- package/dist/src/routes/bootstrap.js.map +1 -1
- package/dist/src/routes/extensions.d.ts.map +1 -1
- package/dist/src/routes/extensions.js +5 -1
- package/dist/src/routes/extensions.js.map +1 -1
- package/dist/src/routes/generator-autopilot.d.ts +1 -0
- package/dist/src/routes/generator-autopilot.d.ts.map +1 -1
- package/dist/src/routes/generator-autopilot.js +8 -2
- package/dist/src/routes/generator-autopilot.js.map +1 -1
- package/dist/src/routes/generator.d.ts.map +1 -1
- package/dist/src/routes/generator.js +20 -0
- package/dist/src/routes/generator.js.map +1 -1
- package/dist/src/routes/libs.d.ts +4 -0
- package/dist/src/routes/libs.d.ts.map +1 -1
- package/dist/src/routes/libs.js +134 -5
- package/dist/src/routes/libs.js.map +1 -1
- package/dist/src/routes/memory.d.ts +2 -0
- package/dist/src/routes/memory.d.ts.map +1 -1
- package/dist/src/routes/memory.js +20 -10
- package/dist/src/routes/memory.js.map +1 -1
- package/dist/src/routes/notifications.d.ts +18 -0
- package/dist/src/routes/notifications.d.ts.map +1 -0
- package/dist/src/routes/notifications.js +64 -0
- package/dist/src/routes/notifications.js.map +1 -0
- package/dist/src/routes/organisms.d.ts +29 -0
- package/dist/src/routes/organisms.d.ts.map +1 -1
- package/dist/src/routes/organisms.js +1042 -2
- package/dist/src/routes/organisms.js.map +1 -1
- package/dist/src/routes/schedules.d.ts.map +1 -1
- package/dist/src/routes/schedules.js +10 -2
- package/dist/src/routes/schedules.js.map +1 -1
- package/dist/src/routes/storage-files.d.ts +5 -0
- package/dist/src/routes/storage-files.d.ts.map +1 -1
- package/dist/src/routes/storage-files.js +83 -16
- package/dist/src/routes/storage-files.js.map +1 -1
- package/dist/src/routes/upload.d.ts +3 -0
- package/dist/src/routes/upload.d.ts.map +1 -1
- package/dist/src/routes/upload.js +9 -1
- package/dist/src/routes/upload.js.map +1 -1
- package/dist/src/server-bootstrap/config-init.d.ts.map +1 -1
- package/dist/src/server-bootstrap/config-init.js +1 -0
- package/dist/src/server-bootstrap/config-init.js.map +1 -1
- package/dist/src/server-bootstrap/middleware-guards.d.ts.map +1 -1
- package/dist/src/server-bootstrap/middleware-guards.js +4 -2
- package/dist/src/server-bootstrap/middleware-guards.js.map +1 -1
- package/dist/src/server-bootstrap/routes-loader.d.ts.map +1 -1
- package/dist/src/server-bootstrap/routes-loader.js +4 -0
- package/dist/src/server-bootstrap/routes-loader.js.map +1 -1
- package/dist/src/server-bootstrap/service-init.d.ts +17 -0
- package/dist/src/server-bootstrap/service-init.d.ts.map +1 -1
- package/dist/src/server-bootstrap/service-init.js +26 -0
- package/dist/src/server-bootstrap/service-init.js.map +1 -1
- package/dist/src/services/access-guard.d.ts +52 -0
- package/dist/src/services/access-guard.d.ts.map +1 -0
- package/dist/src/services/access-guard.js +30 -0
- package/dist/src/services/access-guard.js.map +1 -0
- package/dist/src/services/config-schema.js +1 -1
- package/dist/src/services/config-schema.js.map +1 -1
- package/dist/src/services/consent.d.ts.map +1 -1
- package/dist/src/services/consent.js +37 -1
- package/dist/src/services/consent.js.map +1 -1
- package/dist/src/services/gate-expiry.d.ts +25 -0
- package/dist/src/services/gate-expiry.d.ts.map +1 -0
- package/dist/src/services/gate-expiry.js +26 -0
- package/dist/src/services/gate-expiry.js.map +1 -0
- package/dist/src/services/gate-policy.d.ts +50 -0
- package/dist/src/services/gate-policy.d.ts.map +1 -0
- package/dist/src/services/gate-policy.js +82 -0
- package/dist/src/services/gate-policy.js.map +1 -0
- package/dist/src/services/generator-autopilot.d.ts +18 -1
- package/dist/src/services/generator-autopilot.d.ts.map +1 -1
- package/dist/src/services/generator-autopilot.js +94 -154
- package/dist/src/services/generator-autopilot.js.map +1 -1
- package/dist/src/services/handbooks/agent.d.ts +3 -1
- package/dist/src/services/handbooks/agent.d.ts.map +1 -1
- package/dist/src/services/handbooks/agent.js +10 -3
- package/dist/src/services/handbooks/agent.js.map +1 -1
- package/dist/src/services/manifest-schema.d.ts +48 -0
- package/dist/src/services/manifest-schema.d.ts.map +1 -0
- package/dist/src/services/manifest-schema.js +88 -0
- package/dist/src/services/manifest-schema.js.map +1 -0
- package/dist/src/services/notify.d.ts +19 -0
- package/dist/src/services/notify.d.ts.map +1 -0
- package/dist/src/services/notify.js +43 -0
- package/dist/src/services/notify.js.map +1 -0
- package/dist/src/services/organism-export.d.ts +13 -0
- package/dist/src/services/organism-export.d.ts.map +1 -0
- package/dist/src/services/organism-export.js +58 -0
- package/dist/src/services/organism-export.js.map +1 -0
- package/dist/src/services/organism-import.d.ts +16 -0
- package/dist/src/services/organism-import.d.ts.map +1 -0
- package/dist/src/services/organism-import.js +82 -0
- package/dist/src/services/organism-import.js.map +1 -0
- package/dist/src/services/prompt-defaults.d.ts.map +1 -1
- package/dist/src/services/prompt-defaults.js +75 -0
- package/dist/src/services/prompt-defaults.js.map +1 -1
- package/dist/src/services/safe-zip.d.ts +27 -0
- package/dist/src/services/safe-zip.d.ts.map +1 -0
- package/dist/src/services/safe-zip.js +131 -0
- package/dist/src/services/safe-zip.js.map +1 -0
- package/dist/src/services/scheduler.d.ts +19 -1
- package/dist/src/services/scheduler.d.ts.map +1 -1
- package/dist/src/services/scheduler.js +49 -17
- package/dist/src/services/scheduler.js.map +1 -1
- package/dist/src/services/security-incident.d.ts +25 -0
- package/dist/src/services/security-incident.d.ts.map +1 -0
- package/dist/src/services/security-incident.js +49 -0
- package/dist/src/services/security-incident.js.map +1 -0
- package/dist/src/services/skill-bundle/generator.d.ts +2 -0
- package/dist/src/services/skill-bundle/generator.d.ts.map +1 -1
- package/dist/src/services/skill-bundle/generator.js +11 -5
- package/dist/src/services/skill-bundle/generator.js.map +1 -1
- package/dist/src/services/template-bundles.d.ts +37 -0
- package/dist/src/services/template-bundles.d.ts.map +1 -0
- package/dist/src/services/template-bundles.js +130 -0
- package/dist/src/services/template-bundles.js.map +1 -0
- package/dist/src/services/workspace-export.d.ts +63 -0
- package/dist/src/services/workspace-export.d.ts.map +1 -0
- package/dist/src/services/workspace-export.js +145 -0
- package/dist/src/services/workspace-export.js.map +1 -0
- package/dist/src/services/workspace-import.d.ts +44 -0
- package/dist/src/services/workspace-import.d.ts.map +1 -0
- package/dist/src/services/workspace-import.js +120 -0
- package/dist/src/services/workspace-import.js.map +1 -0
- package/dist/src/services/workspace-meta.d.ts +39 -0
- package/dist/src/services/workspace-meta.d.ts.map +1 -0
- package/dist/src/services/workspace-meta.js +95 -0
- package/dist/src/services/workspace-meta.js.map +1 -0
- package/dist/src/storage/interface.d.ts +26 -0
- package/dist/src/storage/interface.d.ts.map +1 -1
- package/dist/src/storage/interface.js.map +1 -1
- package/dist/src/storage/pattern-utils.d.ts +26 -1
- package/dist/src/storage/pattern-utils.d.ts.map +1 -1
- package/dist/src/storage/pattern-utils.js +37 -8
- package/dist/src/storage/pattern-utils.js.map +1 -1
- package/dist/src/storage/providers/mongodb/index.d.ts +50 -7
- package/dist/src/storage/providers/mongodb/index.d.ts.map +1 -1
- package/dist/src/storage/providers/mongodb/index.js +244 -15
- package/dist/src/storage/providers/mongodb/index.js.map +1 -1
- package/dist/src/storage/providers/postgres/index.d.ts +6 -0
- package/dist/src/storage/providers/postgres/index.d.ts.map +1 -0
- package/dist/src/storage/providers/postgres/index.js +33 -0
- package/dist/src/storage/providers/postgres/index.js.map +1 -0
- package/dist/src/storage/providers/sqlite/index.d.ts +11 -1
- package/dist/src/storage/providers/sqlite/index.d.ts.map +1 -1
- package/dist/src/storage/providers/sqlite/index.js +152 -2
- package/dist/src/storage/providers/sqlite/index.js.map +1 -1
- package/dist/src/storage/providers/sqlite/repos/agent-task.d.ts +1 -0
- package/dist/src/storage/providers/sqlite/repos/agent-task.d.ts.map +1 -1
- package/dist/src/storage/providers/sqlite/repos/agent-task.js +5 -1
- package/dist/src/storage/providers/sqlite/repos/agent-task.js.map +1 -1
- package/dist/src/storage/providers/sqlite/repos/storage-file.d.ts.map +1 -1
- package/dist/src/storage/providers/sqlite/repos/storage-file.js +6 -2
- package/dist/src/storage/providers/sqlite/repos/storage-file.js.map +1 -1
- package/dist/src/storage/providers/sqlite/schema.d.ts.map +1 -1
- package/dist/src/storage/providers/sqlite/schema.js +23 -0
- package/dist/src/storage/providers/sqlite/schema.js.map +1 -1
- package/dist/src/storage/repositories/app.repository.d.ts +42 -0
- package/dist/src/storage/repositories/app.repository.d.ts.map +1 -1
- package/dist/src/storage/repositories/organism.repository.d.ts +8 -1
- package/dist/src/storage/repositories/organism.repository.d.ts.map +1 -1
- package/dist/src/storage/storage-factory.d.ts +1 -1
- package/dist/src/storage/storage-factory.d.ts.map +1 -1
- package/dist/src/storage/storage-factory.js +6 -0
- package/dist/src/storage/storage-factory.js.map +1 -1
- package/dist/src/utils/env-config.js +5 -5
- package/dist/src/utils/env-config.js.map +1 -1
- package/dist/src/utils/env-validator.js +6 -6
- package/dist/src/utils/env-validator.js.map +1 -1
- package/dist/src/utils/stable-json.d.ts +22 -0
- package/dist/src/utils/stable-json.d.ts.map +1 -0
- package/dist/src/utils/stable-json.js +36 -0
- package/dist/src/utils/stable-json.js.map +1 -0
- package/dist/static/app-catalog.html +936 -221
- package/package.json +6 -3
- package/prisma/schema.postgres.prisma +1467 -0
- package/prisma/schema.prisma +27 -0
package/dist/locales/fi.json
CHANGED
|
@@ -9,6 +9,10 @@
|
|
|
9
9
|
"profile.scheduler.newSchedule": "Uusi ajastus",
|
|
10
10
|
"profile.scheduler.close": "Sulje",
|
|
11
11
|
"profile.scheduler.triggered": "Ajastuksen suoritus käynnistetty",
|
|
12
|
+
"profile.scheduler.runCreated": "Suoritus aloitettu — uusi tehtävä luotiin",
|
|
13
|
+
"profile.scheduler.runBusy": "Tehtävää ei luotu — edellinen suoritus on yhä käynnissä. Päätä, merkitse epäonnistuneeksi tai poista se, ja suorita uudelleen.",
|
|
14
|
+
"profile.scheduler.runLimited": "Ei suoritettu — tämän ajastuksen suoritusraja (päivittäinen tai maksimi) on saavutettu.",
|
|
15
|
+
"profile.scheduler.runError": "Suoritus epäonnistui",
|
|
12
16
|
"profile.scheduler.cancelled": "Ajastus peruttu",
|
|
13
17
|
"profile.scheduler.created": "Ajastus luotu",
|
|
14
18
|
"profile.scheduler.saving": "Tallennetaan…",
|
|
@@ -107,6 +111,10 @@
|
|
|
107
111
|
"copied": "✓ Kopioitu",
|
|
108
112
|
"error": "Virhe"
|
|
109
113
|
},
|
|
114
|
+
"notif": {
|
|
115
|
+
"title": "Ilmoitukset",
|
|
116
|
+
"empty": "Ei ilmoituksia vielä"
|
|
117
|
+
},
|
|
110
118
|
"nav": {
|
|
111
119
|
"try": "Kokeile",
|
|
112
120
|
"devView": "Kehittäjille",
|
|
@@ -490,12 +498,27 @@
|
|
|
490
498
|
"byTag": "Suodata tagilla:",
|
|
491
499
|
"groupBy": "Ryhmittele:",
|
|
492
500
|
"groupByNone": "Ei ryhmittelyä",
|
|
501
|
+
"groupByCustom": "Omat ryhmät",
|
|
493
502
|
"groupByTag": "Tagin mukaan",
|
|
494
503
|
"groupByMode": "Tilan mukaan",
|
|
495
504
|
"clear": "Tyhjennä",
|
|
496
505
|
"untagged": "Ei tageja",
|
|
497
506
|
"noMatches": "Yksikään agentti ei vastaa nykyistä suodatinta."
|
|
498
507
|
},
|
|
508
|
+
"groups": {
|
|
509
|
+
"addGroup": "Lisää ryhmä",
|
|
510
|
+
"hint": "Raahaa agentti kahvasta ryhmän päälle liittääksesi sen siihen.",
|
|
511
|
+
"ungrouped": "Ryhmittelemättömät",
|
|
512
|
+
"unnamed": "Nimetön ryhmä",
|
|
513
|
+
"namePlaceholder": "Ryhmän nimi",
|
|
514
|
+
"rename": "Nimeä uudelleen napsauttamalla",
|
|
515
|
+
"remove": "Poista ryhmä",
|
|
516
|
+
"toggle": "Pienennä / laajenna",
|
|
517
|
+
"dragHint": "Raahaa ryhmän päälle liittääksesi",
|
|
518
|
+
"emptyDrop": "Raahaa agentteja tähän lisätäksesi ne tähän ryhmään.",
|
|
519
|
+
"confirmRemove": "Poistetaanko ryhmä ”{name}”? Sen agentit siirtyvät Ryhmittelemättömiin — niitä ei poisteta.",
|
|
520
|
+
"saveError": "Ryhmien tallennus epäonnistui."
|
|
521
|
+
},
|
|
499
522
|
"reorderHint": "Raahaa järjestääksesi",
|
|
500
523
|
"solo": {
|
|
501
524
|
"notFound": "Agenttia ei löytynyt.",
|
|
@@ -743,6 +766,9 @@
|
|
|
743
766
|
"online": "online",
|
|
744
767
|
"offline": "offline",
|
|
745
768
|
"threads": "Keskustelut",
|
|
769
|
+
"threadFallback": "Keskustelu",
|
|
770
|
+
"threadsShowMore": "Näytä {count} lisää",
|
|
771
|
+
"threadsShowLess": "Näytä vähemmän",
|
|
746
772
|
"proposedTask": "Ehdotettu tehtävä",
|
|
747
773
|
"createTask": "Luo tämä tehtävä",
|
|
748
774
|
"adjustTask": "Muokkaan ensin",
|
|
@@ -2875,7 +2901,7 @@
|
|
|
2875
2901
|
"baseUrlInvalid": "Pitää alkaa http:// tai https://",
|
|
2876
2902
|
"dbUrl": "MongoDB URL",
|
|
2877
2903
|
"dbUrlHint": "Jätä tyhjäksi muistinsisäiseen tallennukseen (data katoaa uudelleenkäynnistyksessä)",
|
|
2878
|
-
"dbUrlInvalid": "Pitää
|
|
2904
|
+
"dbUrlInvalid": "Pitää olla kelvollinen mongodb:// (tai mongodb+srv://) tai postgresql:// -yhteysosoite",
|
|
2879
2905
|
"adminPassword": "Ylläpitäjän salasana",
|
|
2880
2906
|
"adminPasswordHint": "Salasana operaattorin hallintapaneeliin (vähintään 8 merkkiä)",
|
|
2881
2907
|
"adminPasswordWeak": "Salasanan pitää olla vähintään 8 merkkiä",
|
|
@@ -3018,6 +3044,7 @@
|
|
|
3018
3044
|
"storage_memory": "Muistissa (vain kehitys, data häviää uudelleenkäynnistyksessä)",
|
|
3019
3045
|
"storage_sqlite": "SQLite (henkilökohtainen käyttö, tiedostopohjainen)",
|
|
3020
3046
|
"storage_mongodb": "MongoDB (tuotanto, vaatii erillisen palvelimen)",
|
|
3047
|
+
"storage_postgresql": "PostgreSQL (tuotanto, vaatii erillisen palvelimen)",
|
|
3021
3048
|
"sqlite_path_label": "SQLite-tietokannan polku",
|
|
3022
3049
|
"sqlite_path_hint": "Tietokantatiedoston polku (luodaan automaattisesti)",
|
|
3023
3050
|
"pushEnabled": "Ota käyttöön push-ilmoitukset henkilökohtaisille nodeille?",
|
|
@@ -5434,6 +5461,197 @@
|
|
|
5434
5461
|
},
|
|
5435
5462
|
"organisms": {
|
|
5436
5463
|
"title": "Organismit",
|
|
5464
|
+
"openWorkspace": "Avaa työtila",
|
|
5465
|
+
"backToList": "Kaikki organismit",
|
|
5466
|
+
"noWorkspace": "Tällä organismilla ei ole vielä työtilaa. Luo sellainen seurataksesi tavoitteita, suunnitelmia, tuotoksia ja päätöksiä — versioituna julkaistaessa.",
|
|
5467
|
+
"setupWorkspace": "Luo työtila",
|
|
5468
|
+
"workspaceReady": "Työtila valmis",
|
|
5469
|
+
"setupError": "Työtilan luonti epäonnistui",
|
|
5470
|
+
"addDraft": "Lisää luonnos",
|
|
5471
|
+
"saveDraft": "Tallenna luonnos",
|
|
5472
|
+
"draftSaved": "Luonnos tallennettu",
|
|
5473
|
+
"idOptional": "tunnus (valinnainen)",
|
|
5474
|
+
"draft": "luonnos",
|
|
5475
|
+
"publish": "Julkaise",
|
|
5476
|
+
"published": "Julkaistu",
|
|
5477
|
+
"draftVersion": "Luonnos",
|
|
5478
|
+
"publishedVersion": "Julkaistu",
|
|
5479
|
+
"workspacesDesc": "Tämän organismin työtilat — jokainen on itsenäinen tila omine dokumentteineen, tietueineen ja historioineen.",
|
|
5480
|
+
"newWorkspace": "Uusi työtila",
|
|
5481
|
+
"workspaceName": "Työtilan nimi",
|
|
5482
|
+
"noWorkspaces": "Ei vielä työtiloja — luo ensimmäinen aloittaaksesi.",
|
|
5483
|
+
"deleteWorkspaceConfirm": "Poistetaanko työtila “{name}” ja kaikki sen sisältö? Tätä ei voi perua.",
|
|
5484
|
+
"backToWorkspaces": "Työtilat",
|
|
5485
|
+
"allOrganisms": "Kaikki organismit",
|
|
5486
|
+
"currentWorkspaces": "Tämän organismin workspacet",
|
|
5487
|
+
"import": "Tuo",
|
|
5488
|
+
"importHint": "Palauta workspace .zip-varmuuskopiosta",
|
|
5489
|
+
"export": "Vie varmuuskopio (.zip)",
|
|
5490
|
+
"imported": "Workspace tuotu",
|
|
5491
|
+
"exportOrg": "Vie organismi",
|
|
5492
|
+
"exportOrgHint": "Lataa ZIP-varmuuskopio koko organismista (kaikki workspacet)",
|
|
5493
|
+
"importOrg": "Tuo organismi",
|
|
5494
|
+
"importOrgHint": "Palauta organismi .zip-varmuuskopiosta",
|
|
5495
|
+
"orgImported": "Organismi tuotu",
|
|
5496
|
+
"requestAccess": "Pyydä pääsyä",
|
|
5497
|
+
"accessRequested": "Pääsyä pyydetty — {creator} päättää.",
|
|
5498
|
+
"byCreator": "tekijä {creator}",
|
|
5499
|
+
"yours": "sinun",
|
|
5500
|
+
"requests": "Pääsypyynnöt",
|
|
5501
|
+
"noRequests": "Ei pääsypyyntöjä.",
|
|
5502
|
+
"approve": "Hyväksy",
|
|
5503
|
+
"deny": "Hylkää",
|
|
5504
|
+
"approved": "hyväksytty",
|
|
5505
|
+
"revoke": "Peru",
|
|
5506
|
+
"editFlow": "Miten muokkaus toimii täällä",
|
|
5507
|
+
"activity": "Aktiivisuus",
|
|
5508
|
+
"draftEdit": "Luonnoksen muokkaus",
|
|
5509
|
+
"publishedWord": "Julkaistu",
|
|
5510
|
+
"publishedVerb": "julkaisi",
|
|
5511
|
+
"editedVerb": "muokkasi",
|
|
5512
|
+
"confirmDeleteItem": "Poistetaanko “{name}”? Sen luonnos, julkaistu versio ja koko historia poistetaan. Tätä ei voi perua.",
|
|
5513
|
+
"deletedItem": "Poistettu",
|
|
5514
|
+
"popOut": "Avaa omaan ikkunaan",
|
|
5515
|
+
"docNotFound2": "Dokumenttia ei löytynyt.",
|
|
5516
|
+
"loginToView": "Kirjaudu nähdäksesi tämän dokumentin.",
|
|
5517
|
+
"docRejected": "Dokumentti hylättiin",
|
|
5518
|
+
"participants": "Ketkä työskentelevät täällä",
|
|
5519
|
+
"you": "sinä",
|
|
5520
|
+
"creatorTag": "luoja",
|
|
5521
|
+
"guest": "vieras",
|
|
5522
|
+
"anAgent": "agentti",
|
|
5523
|
+
"hiddenAgent": "Agentti jonka tietoja et näe",
|
|
5524
|
+
"otherAgentHint": "Toisen omistajan agentti — näet mitä se on tehnyt täällä, et sen nykytilaa",
|
|
5525
|
+
"viaAgent": "tehty tämän agentin kautta",
|
|
5526
|
+
"contributions": "kontribuutiota",
|
|
5527
|
+
"events": "tapahtumaa",
|
|
5528
|
+
"less": "Vähemmän",
|
|
5529
|
+
"more": "Enemmän",
|
|
5530
|
+
"mon": "Ma",
|
|
5531
|
+
"wed": "Ke",
|
|
5532
|
+
"fri": "Pe",
|
|
5533
|
+
"docsDraft": "Dokumentit luonnos",
|
|
5534
|
+
"docsPublished": "Dokumentit julkaistu",
|
|
5535
|
+
"recordsDraft": "Tietueet luonnos",
|
|
5536
|
+
"recordsPublished": "Tietueet julkaistu",
|
|
5537
|
+
"overview": "Yleiskuva — ketkä ja mitkä käyttävät tätä organismia",
|
|
5538
|
+
"hide": "Piilota",
|
|
5539
|
+
"show": "Näytä",
|
|
5540
|
+
"aiPrompt": "AI-käyttöohje:",
|
|
5541
|
+
"aiPromptHuman": "Chattiin",
|
|
5542
|
+
"aiPromptAgent": "Koodausagentille",
|
|
5543
|
+
"promptCopied": "Käyttöohje kopioitu — liitä se tekoälyllesi.",
|
|
5544
|
+
"addSpaceBtn": "Tila",
|
|
5545
|
+
"addSpaceTitle": "Lisää tila",
|
|
5546
|
+
"addSpaceDesc": "Dokumenttitila on vapaamuotoinen wiki (osiot + markdown-sivut). Tietuetila on skeemalukittu lista (lomakkeet). Voit poistaa tiloja asetuksissa.",
|
|
5547
|
+
"modeDocument": "Dokumentti (wiki)",
|
|
5548
|
+
"modeRecords": "Tietueet (lomake)",
|
|
5549
|
+
"noFields": "Ei kenttiä",
|
|
5550
|
+
"createdAt": "Luotu",
|
|
5551
|
+
"lastSaved": "Viimeksi tallennettu",
|
|
5552
|
+
"publishedAt": "Julkaistu",
|
|
5553
|
+
"fileVisibility": "Tiedostojen näkyvyys",
|
|
5554
|
+
"fileVisibilityNote": "Yksityiset tiedostot näkyvät vain sinulle — tee niistä julkisia jakaaksesi dokumentin.",
|
|
5555
|
+
"imageVisibility": "Kuvien näkyvyys",
|
|
5556
|
+
"imageVisibilityNote": "Yksityiset kuvat näkyvät vain sinulle — tee niistä julkisia jakaaksesi dokumentin.",
|
|
5557
|
+
"makeAllPublic": "Tee kaikista julkisia",
|
|
5558
|
+
"toggleVisibility": "Vaihda julkinen / yksityinen",
|
|
5559
|
+
"public": "Julkinen",
|
|
5560
|
+
"private": "Yksityinen",
|
|
5561
|
+
"sources": "Lähteet",
|
|
5562
|
+
"addSource": "Lisää lähde",
|
|
5563
|
+
"close": "Sulje",
|
|
5564
|
+
"sourcesDesc": "Viitteet, joita tämä työtila hyödyntää — muisti, tiedostot ja tietopaketit. Vain osoittimia; alkuperäiset pysyvät paikoillaan.",
|
|
5565
|
+
"src_memory": "Muisti",
|
|
5566
|
+
"src_storage": "Tiedostot",
|
|
5567
|
+
"src_knowledge": "Tieto",
|
|
5568
|
+
"mine": "Omat",
|
|
5569
|
+
"searchSources": "Hae…",
|
|
5570
|
+
"search": "Hae",
|
|
5571
|
+
"noResults": "Ei tuloksia",
|
|
5572
|
+
"entries": "merkintää",
|
|
5573
|
+
"attach": "Liitä",
|
|
5574
|
+
"noSources": "Ei vielä lähteitä",
|
|
5575
|
+
"external": "ulkoinen",
|
|
5576
|
+
"sourceAdded": "Lähde lisätty",
|
|
5577
|
+
"sourceExists": "Jo lisätty",
|
|
5578
|
+
"sourcesSaveError": "Lähteiden tallennus epäonnistui",
|
|
5579
|
+
"publishGated": "Lähetetty tarkistettavaksi (julkaisuportti päällä)",
|
|
5580
|
+
"publishGate": "Vaadi tarkistus ennen julkaisua",
|
|
5581
|
+
"gateToggled": "Julkaisuportti päivitetty",
|
|
5582
|
+
"needsDecision": "Vaatii päätöksesi",
|
|
5583
|
+
"approve": "Hyväksy",
|
|
5584
|
+
"reject": "Hylkää",
|
|
5585
|
+
"approved": "Hyväksytty",
|
|
5586
|
+
"rejected": "Hylätty",
|
|
5587
|
+
"decisions": "Viimeisimmät päätökset",
|
|
5588
|
+
"noneYet": "ei vielä mitään",
|
|
5589
|
+
"onePerLine": "yksi per rivi",
|
|
5590
|
+
"docs": "dokumentit",
|
|
5591
|
+
"newPage": "Uusi dokumentti",
|
|
5592
|
+
"edit": "Muokkaa",
|
|
5593
|
+
"pageTitle": "Dokumentin otsikko",
|
|
5594
|
+
"writeMarkdown": "Kirjoita markdownia…",
|
|
5595
|
+
"insertImage": "Lataa kuva tiedostosta",
|
|
5596
|
+
"orPaste": "…tai liitä / vedä kuva editoriin",
|
|
5597
|
+
"saving": "Tallennetaan…",
|
|
5598
|
+
"pageSaved": "Dokumentti tallennettu",
|
|
5599
|
+
"section": "Osio",
|
|
5600
|
+
"sectionName": "Osion nimi",
|
|
5601
|
+
"unsorted": "Lajittelematon",
|
|
5602
|
+
"moveTo": "siirrä…",
|
|
5603
|
+
"newDocHere": "Uusi dokumentti tähän",
|
|
5604
|
+
"addSubsection": "Alaosio",
|
|
5605
|
+
"selectDoc": "Valitse dokumentti tai luo uusi.",
|
|
5606
|
+
"docNotFound": "Ei dokumenttia nimeltä ”{title}”",
|
|
5607
|
+
"rename": "Nimeä uudelleen",
|
|
5608
|
+
"dragHint": "Vedä osioon",
|
|
5609
|
+
"unnamed": "(nimetön)",
|
|
5610
|
+
"removeSection": "Poista osio",
|
|
5611
|
+
"confirmRemoveSection": "Poistetaanko osio ”{name}”? Sen dokumentit siirtyvät Lajittelemattomiin — niitä ei poisteta.",
|
|
5612
|
+
"confirmDeleteWorkspace": "Haluatko varmasti poistaa tämän työtilan? Kaikki sen dokumentit, tietueet ja versiohistoria poistetaan pysyvästi. Tätä ei voi perua.",
|
|
5613
|
+
"spaces": "Tilat",
|
|
5614
|
+
"recordsMode": "tietueet",
|
|
5615
|
+
"remove": "Poista",
|
|
5616
|
+
"spaceName": "Uuden tilan nimi",
|
|
5617
|
+
"docsSpace": "dokumenttitila",
|
|
5618
|
+
"recordsSpace": "tietuetyyppi",
|
|
5619
|
+
"addSpace": "+ Lisää",
|
|
5620
|
+
"spaceAdded": "Tila lisätty",
|
|
5621
|
+
"spaceRemoved": "Tila poistettu",
|
|
5622
|
+
"removeSpace": "Poista tila",
|
|
5623
|
+
"confirmRemoveSpace": "Poistetaanko \"{name}\" tästä työtilasta? Sen data säilyy muistissa (orpona) mutta osio katoaa.",
|
|
5624
|
+
"restructure": "✨ Muokkaa rakennetta / lisää tyyppejä tekoälyllä",
|
|
5625
|
+
"restructureTitle": "Muokkaa rakennetta / lisää tyyppejä tekoälyllä",
|
|
5626
|
+
"restructureDesc": "Kuvaile mitä lisätä tai muuttaa. Olemassa olevat tyypit ja niiden data säilyvät — tekoäly laajentaa nykyistä rakennetta. (Aloita kokonaan alusta poistamalla työtila ensin alta.)",
|
|
5627
|
+
"dangerZone": "Vaaravyöhyke",
|
|
5628
|
+
"deleteWarn": "Työtilan poistaminen poistaa manifestin ja KAIKEN sen datan — luonnokset, julkaistut tietueet, versiohistorian — ja sen skeemat. Organismi säilyy. Tätä ei voi perua.",
|
|
5629
|
+
"deleteConfirmLabel": "Vahvista kirjoittamalla työtilan nimi",
|
|
5630
|
+
"deleteWorkspace": "Poista työtila",
|
|
5631
|
+
"workspaceDeleted": "Työtila poistettu",
|
|
5632
|
+
"settings": "Asetukset",
|
|
5633
|
+
"wsName": "Nimi",
|
|
5634
|
+
"wsSummary": "Kuvaus",
|
|
5635
|
+
"autonomy": "Tekoälyn autonomia (L1 varovainen → L5 vapaa)",
|
|
5636
|
+
"template": "Malli",
|
|
5637
|
+
"settingsSaved": "Asetukset tallennettu",
|
|
5638
|
+
"generateTitle": "Tai luo mukautettu työtila tekoälyllä",
|
|
5639
|
+
"generateDesc": "Kuvaile mihin tämä työtila on tarkoitettu — seuraa, järjestä tai jalosta tietoa, tai hoida kokonainen projektin elinkaari. Tekoäly suunnittelee objektityypit. Käytä OpenRouter-avaintasi yhden klikkauksen luontiin, tai kopioi kehote mihin tahansa AI-keskusteluun (ilmaiseksi) ja liitä tulos takaisin.",
|
|
5640
|
+
"generatePlaceholder": "esim. peliprojektin koko kehityskaari · tekoälyn hallinnan tutkimuksen järjestäminen · tuotespeksien jalostaminen",
|
|
5641
|
+
"generate": "Luo tekoälyllä",
|
|
5642
|
+
"generating": "Luodaan…",
|
|
5643
|
+
"generateError": "Luonti epäonnistui",
|
|
5644
|
+
"noAiKey": "Määritä OpenRouter-avaimesi yllä, tai kopioi kehote omaan AI-keskusteluusi.",
|
|
5645
|
+
"copyPrompt": "Kopioi kehote",
|
|
5646
|
+
"promptCopied": "Kehote kopioitu — liitä se mihin tahansa AI-keskusteluun ja liitä sen palauttama JSON alle.",
|
|
5647
|
+
"pasteHelp": "Ei avainta? Kopioi yllä oleva kehote mihin tahansa AI-keskusteluun ja liitä sen palauttama JSON tähän:",
|
|
5648
|
+
"pastePlaceholder": "Liitä tekoälyn JSON-vastaus tähän",
|
|
5649
|
+
"applyPasted": "Tarkista ja ota käyttöön",
|
|
5650
|
+
"applyError": "Käyttöönotto epäonnistui — tarkista liitetty JSON.",
|
|
5651
|
+
"genFailed": "Luonti epäonnistui — yritä uudelleen",
|
|
5652
|
+
"fixNeeded": "Tämä pitää korjata ennen tallennusta:",
|
|
5653
|
+
"copyFixPrompt": "Kopioi korjauskehote tekoälylle",
|
|
5654
|
+
"fixPromptCopied": "Korjauskehote kopioitu — liitä se takaisin tekoälylle ja liitä korjattu JSON.",
|
|
5437
5655
|
"desc": "Organismit ovat ryhmiä — yhteisöjä, tiimejä, kerhoja tai projekteja. Luo oma tai liity olemassa oleviin jakaaksesi tietoa, koordinoidaksesi työtä ja rakentaaksesi yhdessä.",
|
|
5438
5656
|
"loading": "Ladataan organismeja...",
|
|
5439
5657
|
"empty": "Et kuulu vielä yhteenkään organismiin.",
|
|
@@ -5873,6 +6091,20 @@
|
|
|
5873
6091
|
}
|
|
5874
6092
|
},
|
|
5875
6093
|
"admin": {
|
|
6094
|
+
"security": {
|
|
6095
|
+
"title": "Tietoturva",
|
|
6096
|
+
"desc": "Hylätyt / karanteeniin laitetut lataukset ja muut tietoturvatapahtumat.",
|
|
6097
|
+
"open": "auki",
|
|
6098
|
+
"none": "Ei tietoturvatapahtumia 🎉",
|
|
6099
|
+
"actor": "Kenen puolesta",
|
|
6100
|
+
"source": "Lähde",
|
|
6101
|
+
"resolve": "Merkitse hoidetuksi",
|
|
6102
|
+
"resolved": "Tapahtuma hoidettu",
|
|
6103
|
+
"delete": "Poista",
|
|
6104
|
+
"deleted": "Poistettu",
|
|
6105
|
+
"deleteConfirm": "Poistetaanko tämä tapahtuma ja sen karanteenitiedosto?",
|
|
6106
|
+
"evidence": "Tiedosto"
|
|
6107
|
+
},
|
|
5876
6108
|
"tabs": {
|
|
5877
6109
|
"agentIntegration": "Agenttiintegraatio"
|
|
5878
6110
|
},
|
|
@@ -15,17 +15,31 @@
|
|
|
15
15
|
* @structure
|
|
16
16
|
* - Markdown ({ text }) -> vnode tree wrapped in a div.md-body
|
|
17
17
|
* - sanitizeHref(url) -> safe href or null
|
|
18
|
+
* - sanitizeImgSrc(url) -> safe <img> src or null (also permits blob: object URLs)
|
|
18
19
|
* @usage
|
|
19
20
|
* import { Markdown } from '/components/Markdown.js';
|
|
20
21
|
* html`<${Markdown} text=${someMarkdownString} />`
|
|
21
22
|
* @version-history
|
|
22
23
|
* v1.0.0 -- 2026-05-31 -- Initial creation for the agent README tab
|
|
24
|
+
* v1.1.0 -- 2026-06-08 -- Image src sanitized separately, allowing blob: (auth'd object URLs)
|
|
25
|
+
* so callers can swap a private /v1/storage URL to a fetched blob in the markdown text.
|
|
26
|
+
* v1.2.0 -- 2026-06-08 -- ```mermaid fenced blocks render as diagrams (lazy-loaded Mermaid),
|
|
27
|
+
* so documents (and any Markdown view) can embed charts.
|
|
23
28
|
*/
|
|
24
29
|
import { h } from 'preact';
|
|
30
|
+
import { Mermaid } from './Mermaid.js';
|
|
25
31
|
|
|
26
32
|
// Only these schemes may appear in a rendered link. Everything else (javascript:,
|
|
27
33
|
// data:, vbscript:, file:, etc.) is dropped — the anchor renders without href.
|
|
28
34
|
const SAFE_SCHEME = /^(https?:|mailto:)/i;
|
|
35
|
+
// Image src may additionally be a blob: object URL — a caller resolving a private /v1/storage image
|
|
36
|
+
// to an auth'd `blob:` URL (scripts never execute from an <img src>, and blob: is same-origin).
|
|
37
|
+
const SAFE_IMG_SCHEME = /^(https?:|blob:)/i;
|
|
38
|
+
|
|
39
|
+
// Slug used for heading anchor ids — kept in sync with the [[Doc#Heading]] wiki-link resolver.
|
|
40
|
+
export function slugifyHeading(text) {
|
|
41
|
+
return String(text).toLowerCase().trim().replace(/[`*_~[\]()#]/g, '').replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '');
|
|
42
|
+
}
|
|
29
43
|
|
|
30
44
|
export function sanitizeHref(url) {
|
|
31
45
|
if (typeof url !== 'string') return null;
|
|
@@ -35,9 +49,16 @@ export function sanitizeHref(url) {
|
|
|
35
49
|
return SAFE_SCHEME.test(trimmed) ? trimmed : null;
|
|
36
50
|
}
|
|
37
51
|
|
|
52
|
+
export function sanitizeImgSrc(url) {
|
|
53
|
+
if (typeof url !== 'string') return null;
|
|
54
|
+
const trimmed = url.trim();
|
|
55
|
+
if (!/^[a-z][a-z0-9+.-]*:/i.test(trimmed)) return trimmed; // relative (e.g. /v1/storage/…)
|
|
56
|
+
return SAFE_IMG_SCHEME.test(trimmed) ? trimmed : null;
|
|
57
|
+
}
|
|
58
|
+
|
|
38
59
|
// ── Inline parsing: code, bold, italic, links. Returns an array of vnodes/strings.
|
|
39
60
|
// Order matters: inline code is extracted first so markup inside it is literal.
|
|
40
|
-
function parseInline(text) {
|
|
61
|
+
function parseInline(text, onWikiLink) {
|
|
41
62
|
const out = [];
|
|
42
63
|
let i = 0;
|
|
43
64
|
let buf = '';
|
|
@@ -46,6 +67,36 @@ function parseInline(text) {
|
|
|
46
67
|
while (i < text.length) {
|
|
47
68
|
const c = text[i];
|
|
48
69
|
|
|
70
|
+
// Image  — checked before links so the leading ! is consumed.
|
|
71
|
+
if (c === '!' && text[i + 1] === '[') {
|
|
72
|
+
const close = text.indexOf(']', i + 2);
|
|
73
|
+
if (close > i && text[close + 1] === '(') {
|
|
74
|
+
const paren = text.indexOf(')', close + 2);
|
|
75
|
+
if (paren > close) {
|
|
76
|
+
const alt = text.slice(i + 2, close);
|
|
77
|
+
const src = sanitizeImgSrc(text.slice(close + 2, paren));
|
|
78
|
+
flush();
|
|
79
|
+
if (src) out.push(h('img', { src, alt, class: 'md-img', loading: 'lazy' }));
|
|
80
|
+
i = paren + 1;
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Wiki link [[Document Title]] — resolves to another document when a resolver is supplied.
|
|
87
|
+
if (c === '[' && text[i + 1] === '[') {
|
|
88
|
+
const end = text.indexOf(']]', i + 2);
|
|
89
|
+
if (end > i) {
|
|
90
|
+
flush();
|
|
91
|
+
const title = text.slice(i + 2, end).trim();
|
|
92
|
+
out.push(onWikiLink
|
|
93
|
+
? h('a', { href: '#', class: 'md-wikilink', onClick: (e) => { e.preventDefault(); onWikiLink(title); } }, title.replace('#', ' › '))
|
|
94
|
+
: '[[' + title + ']]');
|
|
95
|
+
i = end + 2;
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
49
100
|
// Inline code `...` — contents are literal (no further parsing).
|
|
50
101
|
if (c === '`') {
|
|
51
102
|
const end = text.indexOf('`', i + 1);
|
|
@@ -69,8 +120,8 @@ function parseInline(text) {
|
|
|
69
120
|
flush();
|
|
70
121
|
out.push(
|
|
71
122
|
href
|
|
72
|
-
? h('a', { href, target: '_blank', rel: 'noopener noreferrer nofollow' }, parseInline(label))
|
|
73
|
-
: h('span', null, parseInline(label)),
|
|
123
|
+
? h('a', { href, target: '_blank', rel: 'noopener noreferrer nofollow' }, parseInline(label, onWikiLink))
|
|
124
|
+
: h('span', null, parseInline(label, onWikiLink)),
|
|
74
125
|
);
|
|
75
126
|
i = paren + 1;
|
|
76
127
|
continue;
|
|
@@ -83,7 +134,7 @@ function parseInline(text) {
|
|
|
83
134
|
const end = text.indexOf('**', i + 2);
|
|
84
135
|
if (end > i) {
|
|
85
136
|
flush();
|
|
86
|
-
out.push(h('strong', null, parseInline(text.slice(i + 2, end))));
|
|
137
|
+
out.push(h('strong', null, parseInline(text.slice(i + 2, end), onWikiLink)));
|
|
87
138
|
i = end + 2;
|
|
88
139
|
continue;
|
|
89
140
|
}
|
|
@@ -94,12 +145,28 @@ function parseInline(text) {
|
|
|
94
145
|
const end = text.indexOf('*', i + 1);
|
|
95
146
|
if (end > i) {
|
|
96
147
|
flush();
|
|
97
|
-
out.push(h('em', null, parseInline(text.slice(i + 1, end))));
|
|
148
|
+
out.push(h('em', null, parseInline(text.slice(i + 1, end), onWikiLink)));
|
|
98
149
|
i = end + 1;
|
|
99
150
|
continue;
|
|
100
151
|
}
|
|
101
152
|
}
|
|
102
153
|
|
|
154
|
+
// Italic _..._ (underscore) — only at word boundaries, so snake_case identifiers stay literal.
|
|
155
|
+
if (c === '_' && (i === 0 || !/\w/.test(text[i - 1])) && text[i + 1] && text[i + 1] !== ' ') {
|
|
156
|
+
let j = i + 1;
|
|
157
|
+
while ((j = text.indexOf('_', j)) >= 0) {
|
|
158
|
+
const after = text[j + 1];
|
|
159
|
+
if (text[j - 1] !== ' ' && (after === undefined || !/\w/.test(after))) break;
|
|
160
|
+
j++;
|
|
161
|
+
}
|
|
162
|
+
if (j >= 0) {
|
|
163
|
+
flush();
|
|
164
|
+
out.push(h('em', null, parseInline(text.slice(i + 1, j), onWikiLink)));
|
|
165
|
+
i = j + 1;
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
103
170
|
buf += c;
|
|
104
171
|
i++;
|
|
105
172
|
}
|
|
@@ -121,7 +188,7 @@ function isTableDivider(line) {
|
|
|
121
188
|
}
|
|
122
189
|
|
|
123
190
|
// ── Block parsing. Walks lines, emits block-level vnodes.
|
|
124
|
-
function parseBlocks(src) {
|
|
191
|
+
function parseBlocks(src, onWikiLink) {
|
|
125
192
|
const lines = src.replace(/\r\n?/g, '\n').split('\n');
|
|
126
193
|
const blocks = [];
|
|
127
194
|
let i = 0;
|
|
@@ -143,7 +210,13 @@ function parseBlocks(src) {
|
|
|
143
210
|
i++;
|
|
144
211
|
}
|
|
145
212
|
i++; // consume closing fence (or EOF)
|
|
146
|
-
|
|
213
|
+
const lang = (fence[2] || '').trim().toLowerCase();
|
|
214
|
+
if (lang === 'mermaid') {
|
|
215
|
+
// ```mermaid → render the diagram (Mermaid lazy-loads its 3MB renderer only when used).
|
|
216
|
+
blocks.push(h(Mermaid, { chart: codeLines.join('\n') }));
|
|
217
|
+
} else {
|
|
218
|
+
blocks.push(h('pre', { class: 'md-pre' }, h('code', { class: 'md-code' }, codeLines.join('\n'))));
|
|
219
|
+
}
|
|
147
220
|
continue;
|
|
148
221
|
}
|
|
149
222
|
|
|
@@ -151,7 +224,7 @@ function parseBlocks(src) {
|
|
|
151
224
|
const heading = line.match(/^(#{1,6})\s+(.*)$/);
|
|
152
225
|
if (heading) {
|
|
153
226
|
const level = heading[1].length;
|
|
154
|
-
blocks.push(h('h' + level,
|
|
227
|
+
blocks.push(h('h' + level, { id: slugifyHeading(heading[2].trim()) }, parseInline(heading[2].trim(), onWikiLink)));
|
|
155
228
|
i++;
|
|
156
229
|
continue;
|
|
157
230
|
}
|
|
@@ -163,7 +236,7 @@ function parseBlocks(src) {
|
|
|
163
236
|
quoted.push(lines[i].replace(/^\s*>\s?/, ''));
|
|
164
237
|
i++;
|
|
165
238
|
}
|
|
166
|
-
blocks.push(h('blockquote', null, parseBlocks(quoted.join('\n'))));
|
|
239
|
+
blocks.push(h('blockquote', null, parseBlocks(quoted.join('\n'), onWikiLink)));
|
|
167
240
|
continue;
|
|
168
241
|
}
|
|
169
242
|
|
|
@@ -177,9 +250,9 @@ function parseBlocks(src) {
|
|
|
177
250
|
i++;
|
|
178
251
|
}
|
|
179
252
|
blocks.push(h('table', null, [
|
|
180
|
-
h('thead', null, h('tr', null, header.map((c, ci) => h('th', { key: ci }, parseInline(c))))),
|
|
253
|
+
h('thead', null, h('tr', null, header.map((c, ci) => h('th', { key: ci }, parseInline(c, onWikiLink))))),
|
|
181
254
|
h('tbody', null, rows.map((r, ri) =>
|
|
182
|
-
h('tr', { key: ri }, r.map((c, ci) => h('td', { key: ci }, parseInline(c)))))),
|
|
255
|
+
h('tr', { key: ri }, r.map((c, ci) => h('td', { key: ci }, parseInline(c, onWikiLink)))))),
|
|
183
256
|
]));
|
|
184
257
|
continue;
|
|
185
258
|
}
|
|
@@ -193,7 +266,7 @@ function parseBlocks(src) {
|
|
|
193
266
|
while (i < lines.length) {
|
|
194
267
|
const m = lines[i].match(ordered ? /^(\s*)(\d+)\.\s+(.*)$/ : /^(\s*)([-*+])\s+(.*)$/);
|
|
195
268
|
if (!m) break;
|
|
196
|
-
items.push(h('li', { key: items.length }, parseInline(m[3])));
|
|
269
|
+
items.push(h('li', { key: items.length }, parseInline(m[3], onWikiLink)));
|
|
197
270
|
i++;
|
|
198
271
|
}
|
|
199
272
|
blocks.push(h(ordered ? 'ol' : 'ul', null, items));
|
|
@@ -215,15 +288,15 @@ function parseBlocks(src) {
|
|
|
215
288
|
i++;
|
|
216
289
|
}
|
|
217
290
|
// Join wrapped lines with a space (standard markdown paragraph behavior).
|
|
218
|
-
blocks.push(h('p', null, parseInline(para.join(' '))));
|
|
291
|
+
blocks.push(h('p', null, parseInline(para.join(' '), onWikiLink)));
|
|
219
292
|
}
|
|
220
293
|
|
|
221
294
|
return blocks;
|
|
222
295
|
}
|
|
223
296
|
|
|
224
|
-
export function Markdown({ text }) {
|
|
297
|
+
export function Markdown({ text, onWikiLink }) {
|
|
225
298
|
const src = typeof text === 'string' ? text : '';
|
|
226
|
-
return h('div', { class: 'md-body' }, parseBlocks(src));
|
|
299
|
+
return h('div', { class: 'md-body' }, parseBlocks(src, onWikiLink));
|
|
227
300
|
}
|
|
228
301
|
|
|
229
302
|
export default Markdown;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Mermaid.js
|
|
3
|
+
* @description Renders a Mermaid diagram from its source text. Lazy-loads the vendored single-file
|
|
4
|
+
* Mermaid build (public/lib/mermaid/, MIT) only when a chart is first shown — it's ~3MB, so it
|
|
5
|
+
* must never be in the initial bundle. securityLevel:'strict' (no click handlers, sanitised). On
|
|
6
|
+
* any load/parse error it falls back to showing the raw source in a <pre> so nothing is lost.
|
|
7
|
+
* @structure Mermaid({ chart }) — chart is the Mermaid source string.
|
|
8
|
+
* @usage import { Mermaid } from '/components/Mermaid.js'; html`<${Mermaid} chart=${src} />`
|
|
9
|
+
* @version-history
|
|
10
|
+
* v1.0.0 — 2026-06-08 — Initial: lazy-loaded vendored Mermaid renderer for organism/workspace charts.
|
|
11
|
+
*/
|
|
12
|
+
import { h } from 'preact';
|
|
13
|
+
import { useEffect, useRef, useState } from 'preact/hooks';
|
|
14
|
+
import htm from 'htm';
|
|
15
|
+
const html = htm.bind(h);
|
|
16
|
+
|
|
17
|
+
let _promise = null;
|
|
18
|
+
let _seq = 0;
|
|
19
|
+
|
|
20
|
+
function loadMermaid() {
|
|
21
|
+
if (typeof window !== 'undefined' && window.mermaid) return Promise.resolve(window.mermaid);
|
|
22
|
+
if (_promise) return _promise;
|
|
23
|
+
_promise = new Promise((resolve, reject) => {
|
|
24
|
+
const s = document.createElement('script');
|
|
25
|
+
s.src = '/lib/mermaid/mermaid.min.js' + (window.__B || '');
|
|
26
|
+
s.onload = () => {
|
|
27
|
+
try {
|
|
28
|
+
window.mermaid.initialize({ startOnLoad: false, securityLevel: 'strict', theme: 'neutral', flowchart: { htmlLabels: false } });
|
|
29
|
+
resolve(window.mermaid);
|
|
30
|
+
} catch (e) { reject(e); }
|
|
31
|
+
};
|
|
32
|
+
s.onerror = () => reject(new Error('failed to load mermaid'));
|
|
33
|
+
document.head.appendChild(s);
|
|
34
|
+
});
|
|
35
|
+
return _promise;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** Mermaid — render a diagram from source text (lazy-loads the renderer). */
|
|
39
|
+
export function Mermaid({ chart }) {
|
|
40
|
+
const ref = useRef(null);
|
|
41
|
+
const [err, setErr] = useState('');
|
|
42
|
+
|
|
43
|
+
useEffect(() => {
|
|
44
|
+
let cancelled = false;
|
|
45
|
+
setErr('');
|
|
46
|
+
if (!chart) return undefined;
|
|
47
|
+
loadMermaid().then(async (m) => {
|
|
48
|
+
if (cancelled || !ref.current) return;
|
|
49
|
+
try {
|
|
50
|
+
const { svg } = await m.render('mmd-' + (_seq++), chart);
|
|
51
|
+
if (!cancelled && ref.current) ref.current.innerHTML = svg;
|
|
52
|
+
} catch (e) { if (!cancelled) setErr((e && e.message) || 'diagram error'); }
|
|
53
|
+
}).catch(() => { if (!cancelled) setErr('renderer'); });
|
|
54
|
+
return () => { cancelled = true; };
|
|
55
|
+
}, [chart]);
|
|
56
|
+
|
|
57
|
+
if (err) return html`<pre class="mmd-fallback">${chart}</pre>`;
|
|
58
|
+
return html`<div class="mmd" ref=${ref}></div>`;
|
|
59
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file NotificationBell.js
|
|
3
|
+
* @description Header notification bell — shows the unread count and a dropdown of the user's
|
|
4
|
+
* in-app notifications (GET /v1/notifications). Opening the dropdown marks them read. Refreshes on
|
|
5
|
+
* the SSE `aimeat-live-update` event and a 45s poll, so a workspace-access approval (or request)
|
|
6
|
+
* surfaces without the user having to guess. Self-contained: reads the JWT from window.AIMEAT.auth.
|
|
7
|
+
* @structure NotificationBell({ t, onNavigate }) — t = i18n fn, onNavigate(path) = SPA navigate.
|
|
8
|
+
* @usage import { NotificationBell } from '/components/NotificationBell.js'; html`<${NotificationBell} t=${t} onNavigate=${navigate} />`
|
|
9
|
+
* @version-history
|
|
10
|
+
* v1.0.0 — 2026-06-08 — Initial: header bell + dropdown + mark-read for the notification inbox.
|
|
11
|
+
*/
|
|
12
|
+
import { h } from 'preact';
|
|
13
|
+
import { useState, useEffect, useRef, useCallback } from 'preact/hooks';
|
|
14
|
+
import htm from 'htm';
|
|
15
|
+
const html = htm.bind(h);
|
|
16
|
+
|
|
17
|
+
const jwt = () => { try { return window.AIMEAT?.auth?.getSession?.()?.jwt || ''; } catch { return ''; } };
|
|
18
|
+
async function api(path, opts = {}) {
|
|
19
|
+
const token = jwt();
|
|
20
|
+
if (!token) return null;
|
|
21
|
+
try {
|
|
22
|
+
const res = await fetch(path, { ...opts, headers: { 'Content-Type': 'application/json', Authorization: 'Bearer ' + token, ...(opts.headers || {}) } });
|
|
23
|
+
return await res.json();
|
|
24
|
+
} catch { return null; }
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function relTime(iso) {
|
|
28
|
+
try {
|
|
29
|
+
const d = new Date(iso), now = new Date(), s = Math.round((now - d) / 1000);
|
|
30
|
+
if (s < 60) return 'just now';
|
|
31
|
+
if (s < 3600) return Math.floor(s / 60) + 'm ago';
|
|
32
|
+
if (s < 86400) return Math.floor(s / 3600) + 'h ago';
|
|
33
|
+
return d.toLocaleDateString();
|
|
34
|
+
} catch { return ''; }
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function NotificationBell({ t, onNavigate }) {
|
|
38
|
+
const tr = (k, fb) => (t ? t(k) : null) || fb;
|
|
39
|
+
const [items, setItems] = useState([]);
|
|
40
|
+
const [unread, setUnread] = useState(0);
|
|
41
|
+
const [open, setOpen] = useState(false);
|
|
42
|
+
const ref = useRef(null);
|
|
43
|
+
|
|
44
|
+
const load = useCallback(async () => {
|
|
45
|
+
const r = await api('/v1/notifications');
|
|
46
|
+
if (r && r.data) { setItems(r.data.notifications || []); setUnread(r.data.unread || 0); }
|
|
47
|
+
}, []);
|
|
48
|
+
|
|
49
|
+
useEffect(() => {
|
|
50
|
+
load();
|
|
51
|
+
const onUpd = () => load();
|
|
52
|
+
window.addEventListener('aimeat-live-update', onUpd);
|
|
53
|
+
const iv = setInterval(load, 45000);
|
|
54
|
+
return () => { window.removeEventListener('aimeat-live-update', onUpd); clearInterval(iv); };
|
|
55
|
+
}, [load]);
|
|
56
|
+
|
|
57
|
+
// Close the dropdown on an outside click.
|
|
58
|
+
useEffect(() => {
|
|
59
|
+
if (!open) return undefined;
|
|
60
|
+
const onDoc = (e) => { if (ref.current && !ref.current.contains(e.target)) setOpen(false); };
|
|
61
|
+
document.addEventListener('mousedown', onDoc);
|
|
62
|
+
return () => document.removeEventListener('mousedown', onDoc);
|
|
63
|
+
}, [open]);
|
|
64
|
+
|
|
65
|
+
const toggle = async () => {
|
|
66
|
+
const next = !open;
|
|
67
|
+
setOpen(next);
|
|
68
|
+
if (next && unread > 0) {
|
|
69
|
+
setUnread(0);
|
|
70
|
+
setItems(its => its.map(n => ({ ...n, read: true })));
|
|
71
|
+
await api('/v1/notifications/read', { method: 'POST', body: JSON.stringify({ all: true }) });
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
const clickNotif = (n) => { setOpen(false); if (n.link && onNavigate) onNavigate(n.link); };
|
|
75
|
+
|
|
76
|
+
return html`
|
|
77
|
+
<div class="notif-bell" ref=${ref}>
|
|
78
|
+
<button class="notif-bell-btn" aria-label=${tr('notif.title', 'Notifications')} title=${tr('notif.title', 'Notifications')} onClick=${toggle}>
|
|
79
|
+
${'🔔'}${unread > 0 ? html`<span class="notif-badge">${unread > 99 ? '99+' : unread}</span>` : null}
|
|
80
|
+
</button>
|
|
81
|
+
${open ? html`
|
|
82
|
+
<div class="notif-dropdown">
|
|
83
|
+
<div class="notif-dropdown-head">${tr('notif.title', 'Notifications')}</div>
|
|
84
|
+
${items.length === 0
|
|
85
|
+
? html`<div class="notif-empty">${tr('notif.empty', 'No notifications yet')}</div>`
|
|
86
|
+
: items.map(n => html`
|
|
87
|
+
<button class="notif-item ${n.read ? '' : 'unread'}" key=${n.id} onClick=${() => clickNotif(n)}>
|
|
88
|
+
<div class="notif-item-title">${n.title}</div>
|
|
89
|
+
${n.body ? html`<div class="notif-item-body">${n.body}</div>` : null}
|
|
90
|
+
<div class="notif-item-time">${relTime(n.createdAt)}</div>
|
|
91
|
+
</button>`)}
|
|
92
|
+
</div>` : null}
|
|
93
|
+
</div>`;
|
|
94
|
+
}
|