aimeat 1.33.2 → 1.35.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/locales/en.json +437 -15
- package/dist/locales/fi.json +437 -15
- package/dist/public/cortex-bundled/aimeat-charts.js +3 -3
- package/dist/public/cortex-bundled/aimeat-charts.yaml +3 -3
- package/dist/public/cortex-bundled/aimeat-i18n.js +123 -0
- package/dist/public/cortex-bundled/aimeat-i18n.yaml +64 -0
- package/dist/public/css/views/landing.css +2 -0
- package/dist/public/css/views/secretary.css +464 -2
- package/dist/public/js/i18n.js +9 -0
- package/dist/public/js/services/apps.js +4 -2
- package/dist/public/js/services/memory.js +9 -3
- package/dist/public/js/services/offers.js +1 -1
- package/dist/public/js/services/organisms.js +49 -17
- package/dist/public/js/services/secretary-helpers.js +266 -17
- package/dist/public/js/services/secretary-policy.js +28 -2
- package/dist/public/js/services/secretary-rules.js +70 -0
- package/dist/public/js/theme.js +20 -0
- package/dist/public/lib/VENDORED-STYLING.md +31 -0
- package/dist/public/lib/aimeat-daisyui-bridge.css +48 -0
- package/dist/public/lib/chartjs@4.js +14 -0
- package/dist/public/lib/daisyui@5.css +7 -0
- package/dist/public/lib/tailwindcss@4.js +8 -0
- package/dist/public/llms-template.txt +9 -6
- package/dist/public/showroom.html +104 -0
- package/dist/public/showroom.js +247 -0
- package/dist/public/spa.html +18 -16
- package/dist/public/views/aimeat-os.js +3 -2
- package/dist/public/views/landing.js +50 -6
- package/dist/public/views/profile/agents/agent-card.js +13 -4
- package/dist/public/views/profile/agents/state-detector.js +6 -0
- package/dist/public/views/profile/agents/tab-integration.js +11 -2
- package/dist/public/views/profile/apps-tab.js +46 -0
- package/dist/public/views/profile/extensions-tab.js +4 -0
- package/dist/public/views/profile/inbox-tab.js +1 -1
- package/dist/public/views/profile/landing-page.js +8 -3
- package/dist/public/views/profile/memory-tab.js +37 -6
- package/dist/public/views/profile/organisms/home.js +32 -0
- package/dist/public/views/profile/organisms/workspace-list.js +36 -5
- package/dist/public/views/profile/organisms/workspace.js +29 -4
- package/dist/public/views/profile/organisms-tab.js +61 -8
- package/dist/public/views/secretary/calendar.js +327 -0
- package/dist/public/views/secretary/cards-reach.js +16 -17
- package/dist/public/views/secretary/cards.js +217 -79
- package/dist/public/views/secretary/dashboard.js +617 -0
- package/dist/public/views/secretary/quality.js +156 -0
- package/dist/public/views/secretary/use-autonomy.js +17 -2
- package/dist/public/views/secretary/use-freshness.js +50 -0
- package/dist/public/views/secretary/use-intake.js +23 -4
- package/dist/public/views/secretary/use-layout.js +122 -0
- package/dist/public/views/secretary/use-quick-actions.js +98 -0
- package/dist/public/views/secretary/use-specialists.js +103 -0
- package/dist/public/views/secretary/use-triggers.js +159 -0
- package/dist/public/views/secretary/use-whats-next.js +340 -0
- package/dist/public/views/secretary/workflow-design.js +112 -0
- package/dist/public/views/secretary.js +836 -44
- package/dist/scripts/check-no-max-tokens.d.ts +2 -0
- package/dist/scripts/check-no-max-tokens.d.ts.map +1 -0
- package/dist/scripts/check-no-max-tokens.js +71 -0
- package/dist/scripts/check-no-max-tokens.js.map +1 -0
- package/dist/src/cli/connect/mcp/tools/organisms.d.ts +2 -0
- package/dist/src/cli/connect/mcp/tools/organisms.d.ts.map +1 -1
- package/dist/src/cli/connect/mcp/tools/organisms.js +9 -1
- package/dist/src/cli/connect/mcp/tools/organisms.js.map +1 -1
- package/dist/src/cli/connect/onboarding-prompt.d.ts +3 -0
- package/dist/src/cli/connect/onboarding-prompt.d.ts.map +1 -1
- package/dist/src/cli/connect/onboarding-prompt.js +10 -3
- package/dist/src/cli/connect/onboarding-prompt.js.map +1 -1
- package/dist/src/data/aimeat-iam-package.d.ts +25 -0
- package/dist/src/data/aimeat-iam-package.d.ts.map +1 -0
- package/dist/src/data/aimeat-iam-package.js +312 -0
- package/dist/src/data/aimeat-iam-package.js.map +1 -0
- package/dist/src/data/aimeat-marketplace-package.d.ts +25 -0
- package/dist/src/data/aimeat-marketplace-package.d.ts.map +1 -0
- package/dist/src/data/aimeat-marketplace-package.js +231 -0
- package/dist/src/data/aimeat-marketplace-package.js.map +1 -0
- package/dist/src/data/app-templates.d.ts +48 -0
- package/dist/src/data/app-templates.d.ts.map +1 -0
- package/dist/src/data/app-templates.js +856 -0
- package/dist/src/data/app-templates.js.map +1 -0
- package/dist/src/data/example-packages.d.ts.map +1 -1
- package/dist/src/data/example-packages.js +3 -1
- package/dist/src/data/example-packages.js.map +1 -1
- package/dist/src/generated/api-types.d.ts +689 -7
- package/dist/src/generated/api-types.d.ts.map +1 -1
- package/dist/src/generated/prisma-postgres/edge.js +10 -3
- package/dist/src/generated/prisma-postgres/index-browser.js +7 -0
- package/dist/src/generated/prisma-postgres/index.d.ts +205 -2
- package/dist/src/generated/prisma-postgres/index.js +10 -3
- package/dist/src/generated/prisma-postgres/package.json +1 -1
- package/dist/src/generated/prisma-postgres/schema.prisma +23 -13
- package/dist/src/generated/prisma-postgres/wasm.js +10 -3
- package/dist/src/mcp/agent-onboarding.d.ts +4 -0
- package/dist/src/mcp/agent-onboarding.d.ts.map +1 -1
- package/dist/src/mcp/agent-onboarding.js +28 -2
- package/dist/src/mcp/agent-onboarding.js.map +1 -1
- package/dist/src/mcp/annotations.d.ts.map +1 -1
- package/dist/src/mcp/annotations.js +1 -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 +16 -1
- package/dist/src/mcp/catalog/definitions.js.map +1 -1
- package/dist/src/mcp/catalog/surfaces.js +3 -3
- package/dist/src/mcp/catalog/surfaces.js.map +1 -1
- package/dist/src/mcp/index.d.ts +3 -0
- package/dist/src/mcp/index.d.ts.map +1 -1
- package/dist/src/mcp/index.js +11 -0
- package/dist/src/mcp/index.js.map +1 -1
- package/dist/src/mcp/organisms.d.ts.map +1 -1
- package/dist/src/mcp/organisms.js +48 -8
- package/dist/src/mcp/organisms.js.map +1 -1
- package/dist/src/mcp/workspaces.d.ts.map +1 -1
- package/dist/src/mcp/workspaces.js +6 -4
- package/dist/src/mcp/workspaces.js.map +1 -1
- package/dist/src/models/agent-onboarding-schemas.d.ts +47 -0
- package/dist/src/models/agent-onboarding-schemas.d.ts.map +1 -1
- package/dist/src/models/agent-onboarding-schemas.js +117 -0
- package/dist/src/models/agent-onboarding-schemas.js.map +1 -1
- package/dist/src/models/offer-schemas.d.ts +8 -8
- package/dist/src/routes/agent-onboarding.d.ts +5 -0
- package/dist/src/routes/agent-onboarding.d.ts.map +1 -1
- package/dist/src/routes/agent-onboarding.js +21 -2
- package/dist/src/routes/agent-onboarding.js.map +1 -1
- package/dist/src/routes/ai.d.ts +8 -4
- package/dist/src/routes/ai.d.ts.map +1 -1
- package/dist/src/routes/ai.js +38 -14
- package/dist/src/routes/ai.js.map +1 -1
- package/dist/src/routes/app-grants.d.ts +2 -0
- package/dist/src/routes/app-grants.d.ts.map +1 -1
- package/dist/src/routes/app-grants.js +7 -1
- package/dist/src/routes/app-grants.js.map +1 -1
- package/dist/src/routes/app-templates.d.ts +16 -0
- package/dist/src/routes/app-templates.d.ts.map +1 -0
- package/dist/src/routes/app-templates.js +40 -0
- package/dist/src/routes/app-templates.js.map +1 -0
- package/dist/src/routes/apps.d.ts.map +1 -1
- package/dist/src/routes/apps.js +55 -5
- package/dist/src/routes/apps.js.map +1 -1
- package/dist/src/routes/auth.d.ts +3 -0
- package/dist/src/routes/auth.d.ts.map +1 -1
- package/dist/src/routes/auth.js +9 -4
- package/dist/src/routes/auth.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/generator.d.ts.map +1 -1
- package/dist/src/routes/generator.js +3 -2
- package/dist/src/routes/generator.js.map +1 -1
- package/dist/src/routes/lib-ai.d.ts +0 -1
- package/dist/src/routes/lib-ai.d.ts.map +1 -1
- package/dist/src/routes/lib-ai.js +13 -6
- package/dist/src/routes/lib-ai.js.map +1 -1
- package/dist/src/routes/lib-header.d.ts +2 -0
- package/dist/src/routes/lib-header.d.ts.map +1 -1
- package/dist/src/routes/lib-header.js +7 -16
- package/dist/src/routes/lib-header.js.map +1 -1
- package/dist/src/routes/lib-markdown.d.ts +18 -0
- package/dist/src/routes/lib-markdown.d.ts.map +1 -0
- package/dist/src/routes/lib-markdown.js +236 -0
- package/dist/src/routes/lib-markdown.js.map +1 -0
- package/dist/src/routes/libs.d.ts +22 -0
- package/dist/src/routes/libs.d.ts.map +1 -1
- package/dist/src/routes/libs.js +133 -10
- package/dist/src/routes/libs.js.map +1 -1
- package/dist/src/routes/memory.d.ts.map +1 -1
- package/dist/src/routes/memory.js +21 -2
- package/dist/src/routes/memory.js.map +1 -1
- package/dist/src/routes/openrouter.d.ts +4 -0
- package/dist/src/routes/openrouter.d.ts.map +1 -1
- package/dist/src/routes/openrouter.js +17 -0
- package/dist/src/routes/openrouter.js.map +1 -1
- package/dist/src/routes/organisms.d.ts.map +1 -1
- package/dist/src/routes/organisms.js +107 -7
- package/dist/src/routes/organisms.js.map +1 -1
- package/dist/src/routes/portal.d.ts +9 -0
- package/dist/src/routes/portal.d.ts.map +1 -1
- package/dist/src/routes/portal.js +1 -1
- package/dist/src/routes/portal.js.map +1 -1
- package/dist/src/routes/public-stats.d.ts +3 -0
- package/dist/src/routes/public-stats.d.ts.map +1 -1
- package/dist/src/routes/public-stats.js +9 -2
- package/dist/src/routes/public-stats.js.map +1 -1
- package/dist/src/routes/secretary.d.ts +34 -0
- package/dist/src/routes/secretary.d.ts.map +1 -0
- package/dist/src/routes/secretary.js +311 -0
- package/dist/src/routes/secretary.js.map +1 -0
- package/dist/src/routes/specialists.d.ts.map +1 -1
- package/dist/src/routes/specialists.js +21 -0
- package/dist/src/routes/specialists.js.map +1 -1
- package/dist/src/routes/subdomains.js +1 -1
- package/dist/src/routes/subdomains.js.map +1 -1
- package/dist/src/routes/workflows.d.ts +9 -3
- package/dist/src/routes/workflows.d.ts.map +1 -1
- package/dist/src/routes/workflows.js +9 -3
- package/dist/src/routes/workflows.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.map +1 -1
- package/dist/src/server-bootstrap/service-init.js +7 -0
- package/dist/src/server-bootstrap/service-init.js.map +1 -1
- package/dist/src/server-bootstrap/static-files.d.ts +4 -0
- package/dist/src/server-bootstrap/static-files.d.ts.map +1 -1
- package/dist/src/server-bootstrap/static-files.js +18 -0
- package/dist/src/server-bootstrap/static-files.js.map +1 -1
- package/dist/src/services/archive.d.ts +74 -0
- package/dist/src/services/archive.d.ts.map +1 -0
- package/dist/src/services/archive.js +132 -0
- package/dist/src/services/archive.js.map +1 -0
- package/dist/src/services/cortex-seeder.d.ts +4 -1
- package/dist/src/services/cortex-seeder.d.ts.map +1 -1
- package/dist/src/services/cortex-seeder.js +25 -6
- package/dist/src/services/cortex-seeder.js.map +1 -1
- package/dist/src/services/directory.d.ts.map +1 -1
- package/dist/src/services/directory.js +3 -2
- package/dist/src/services/directory.js.map +1 -1
- package/dist/src/services/generator-prompt-seeds.d.ts.map +1 -1
- package/dist/src/services/generator-prompt-seeds.js +5 -4
- package/dist/src/services/generator-prompt-seeds.js.map +1 -1
- package/dist/src/services/message-send.d.ts.map +1 -1
- package/dist/src/services/message-send.js +14 -0
- package/dist/src/services/message-send.js.map +1 -1
- package/dist/src/services/onboarding-guide.d.ts +53 -0
- package/dist/src/services/onboarding-guide.d.ts.map +1 -0
- package/dist/src/services/onboarding-guide.js +81 -0
- package/dist/src/services/onboarding-guide.js.map +1 -0
- package/dist/src/services/organism-search.d.ts +6 -2
- package/dist/src/services/organism-search.d.ts.map +1 -1
- package/dist/src/services/organism-search.js +2 -2
- package/dist/src/services/organism-search.js.map +1 -1
- package/dist/src/services/owner-memory.d.ts +1 -0
- package/dist/src/services/owner-memory.d.ts.map +1 -1
- package/dist/src/services/owner-memory.js.map +1 -1
- package/dist/src/services/owner-session.d.ts +1 -0
- package/dist/src/services/owner-session.d.ts.map +1 -1
- package/dist/src/services/owner-session.js +10 -2
- package/dist/src/services/owner-session.js.map +1 -1
- package/dist/src/services/package-seeder.d.ts +22 -0
- package/dist/src/services/package-seeder.d.ts.map +1 -0
- package/dist/src/services/package-seeder.js +30 -0
- package/dist/src/services/package-seeder.js.map +1 -0
- package/dist/src/services/presence.d.ts +3 -0
- package/dist/src/services/presence.d.ts.map +1 -1
- package/dist/src/services/presence.js +10 -0
- package/dist/src/services/presence.js.map +1 -1
- package/dist/src/services/prompt-defaults.d.ts.map +1 -1
- package/dist/src/services/prompt-defaults.js +8 -3
- package/dist/src/services/prompt-defaults.js.map +1 -1
- package/dist/src/services/scheduler.d.ts +50 -2
- package/dist/src/services/scheduler.d.ts.map +1 -1
- package/dist/src/services/scheduler.js +454 -26
- package/dist/src/services/scheduler.js.map +1 -1
- package/dist/src/services/secretary-authoring.d.ts +71 -0
- package/dist/src/services/secretary-authoring.d.ts.map +1 -0
- package/dist/src/services/secretary-authoring.js +336 -0
- package/dist/src/services/secretary-authoring.js.map +1 -0
- package/dist/src/services/secretary-clarify.d.ts +57 -0
- package/dist/src/services/secretary-clarify.d.ts.map +1 -0
- package/dist/src/services/secretary-clarify.js +104 -0
- package/dist/src/services/secretary-clarify.js.map +1 -0
- package/dist/src/services/secretary-feed.d.ts +11 -0
- package/dist/src/services/secretary-feed.d.ts.map +1 -0
- package/dist/src/services/secretary-feed.js +28 -0
- package/dist/src/services/secretary-feed.js.map +1 -0
- package/dist/src/services/secretary-tick.d.ts +243 -3
- package/dist/src/services/secretary-tick.d.ts.map +1 -1
- package/dist/src/services/secretary-tick.js +273 -3
- package/dist/src/services/secretary-tick.js.map +1 -1
- package/dist/src/services/secretary-workbrief.d.ts +144 -0
- package/dist/src/services/secretary-workbrief.d.ts.map +1 -0
- package/dist/src/services/secretary-workbrief.js +315 -0
- package/dist/src/services/secretary-workbrief.js.map +1 -0
- package/dist/src/services/secretary-worktier.d.ts +118 -0
- package/dist/src/services/secretary-worktier.d.ts.map +1 -0
- package/dist/src/services/secretary-worktier.js +157 -0
- package/dist/src/services/secretary-worktier.js.map +1 -0
- package/dist/src/services/skill-bundle/generator.d.ts +3 -0
- package/dist/src/services/skill-bundle/generator.d.ts.map +1 -1
- package/dist/src/services/skill-bundle/generator.js +19 -0
- package/dist/src/services/skill-bundle/generator.js.map +1 -1
- package/dist/src/services/specialist-runner.d.ts +36 -0
- package/dist/src/services/specialist-runner.d.ts.map +1 -0
- package/dist/src/services/specialist-runner.js +91 -0
- package/dist/src/services/specialist-runner.js.map +1 -0
- package/dist/src/services/specialist.d.ts +9 -0
- package/dist/src/services/specialist.d.ts.map +1 -1
- package/dist/src/services/specialist.js +42 -0
- package/dist/src/services/specialist.js.map +1 -1
- package/dist/src/services/structure-overview.d.ts +13 -0
- package/dist/src/services/structure-overview.d.ts.map +1 -1
- package/dist/src/services/structure-overview.js +34 -11
- package/dist/src/services/structure-overview.js.map +1 -1
- package/dist/src/services/system-agent-responder.d.ts +36 -0
- package/dist/src/services/system-agent-responder.d.ts.map +1 -0
- package/dist/src/services/system-agent-responder.js +107 -0
- package/dist/src/services/system-agent-responder.js.map +1 -0
- package/dist/src/services/system-agent.d.ts +34 -1
- package/dist/src/services/system-agent.d.ts.map +1 -1
- package/dist/src/services/system-agent.js +73 -0
- package/dist/src/services/system-agent.js.map +1 -1
- package/dist/src/storage/interface.d.ts +33 -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 +37 -0
- package/dist/src/storage/providers/mongodb/index.d.ts.map +1 -1
- package/dist/src/storage/providers/mongodb/index.js +132 -12
- package/dist/src/storage/providers/mongodb/index.js.map +1 -1
- package/dist/src/storage/providers/sqlite/index.d.ts +23 -1
- package/dist/src/storage/providers/sqlite/index.d.ts.map +1 -1
- package/dist/src/storage/providers/sqlite/index.js +60 -8
- package/dist/src/storage/providers/sqlite/index.js.map +1 -1
- package/dist/src/storage/providers/sqlite/repos/memory.d.ts +29 -1
- package/dist/src/storage/providers/sqlite/repos/memory.d.ts.map +1 -1
- package/dist/src/storage/providers/sqlite/repos/memory.js +109 -10
- package/dist/src/storage/providers/sqlite/repos/memory.js.map +1 -1
- package/dist/src/storage/providers/sqlite/schema.d.ts +3 -0
- package/dist/src/storage/providers/sqlite/schema.d.ts.map +1 -1
- package/dist/src/storage/providers/sqlite/schema.js +64 -9
- package/dist/src/storage/providers/sqlite/schema.js.map +1 -1
- package/dist/src/storage/repositories/app.repository.d.ts +15 -0
- package/dist/src/storage/repositories/app.repository.d.ts.map +1 -1
- package/dist/src/storage/repositories/memory.repository.d.ts +41 -1
- package/dist/src/storage/repositories/memory.repository.d.ts.map +1 -1
- package/dist/src/storage/repositories/organism.repository.d.ts +2 -1
- package/dist/src/storage/repositories/organism.repository.d.ts.map +1 -1
- package/dist/static/app-catalog.html +469 -122
- package/package.json +2 -1
- package/prisma/schema.postgres.prisma +10 -0
- package/prisma/schema.prisma +12 -0
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
* @description Agent card component with collapsed/expanded states,
|
|
4
4
|
* Two-Zone Header (identity + state-dependent status), and tab bar.
|
|
5
5
|
* @version-history
|
|
6
|
+
* v1.18.0 -- 2026-06-30 -- Onboarding step labels use tOr() so a missing agentOnboarding.steps.*
|
|
7
|
+
* key falls back to the server-provided step.title instead of rendering the raw key.
|
|
6
8
|
* v1.17.0 -- 2026-06-24 -- Secretary P5 (S-A): render a "Specialist · <role>" badge for agents tagged
|
|
7
9
|
* system:specialist, so the new specialist agent type is recognizable in the Agents tab.
|
|
8
10
|
* v1.16.0 -- 2026-06-21 -- Unseen-change badges are now has-unseen DOTS (no count) — the
|
|
@@ -59,7 +61,7 @@
|
|
|
59
61
|
import { h } from 'preact';
|
|
60
62
|
import { useState, useEffect, useCallback, useRef } from 'preact/hooks';
|
|
61
63
|
import htm from 'htm';
|
|
62
|
-
import { t } from '/js/i18n.js';
|
|
64
|
+
import { t, tOr } from '/js/i18n.js';
|
|
63
65
|
import { apiGet, apiPatch } from '/js/api.js';
|
|
64
66
|
import { timeAgo } from '/js/utils.js';
|
|
65
67
|
import { detectAgentState, getDefaultTab, getStateColor } from './state-detector.js';
|
|
@@ -402,6 +404,10 @@ function renderPlatformBadge(onboarding) {
|
|
|
402
404
|
const READINESS_RANKS = { none: 0, basic: 1, standard: 2, advanced: 3, full: 4 };
|
|
403
405
|
|
|
404
406
|
function renderReadinessBadge(state, onboarding) {
|
|
407
|
+
if (state === 'system') {
|
|
408
|
+
// Internal (auto-provisioned) agent — no device-auth onboarding / readiness.
|
|
409
|
+
return html`<span class="pf-agd-badge pf-agd-badge--readiness-none">${t('profile.agents.detail.state.internal')}</span>`;
|
|
410
|
+
}
|
|
405
411
|
if (state === 'new') {
|
|
406
412
|
return html`<span class="pf-agd-badge pf-agd-badge--readiness-none">--</span>`;
|
|
407
413
|
}
|
|
@@ -433,7 +439,7 @@ function renderCollapsedStats(state, agent, onboarding) {
|
|
|
433
439
|
return html`${agent.last_seen ? `${t('profile.agents.detail.lastSeen')}: ${timeAgo(agent.last_seen)}` : ''} | ${t('profile.agents.detail.state.newSummary')}`;
|
|
434
440
|
case 'onboarding': {
|
|
435
441
|
const nextStep = onboarding?.steps?.find(s => s.status === 'pending');
|
|
436
|
-
return html`${agent.last_seen ? `${t('profile.agents.detail.lastSeen')}: ${timeAgo(agent.last_seen)}` : ''} ${nextStep ? `| ${t('profile.agents.detail.state.next')}: ${
|
|
442
|
+
return html`${agent.last_seen ? `${t('profile.agents.detail.lastSeen')}: ${timeAgo(agent.last_seen)}` : ''} ${nextStep ? `| ${t('profile.agents.detail.state.next')}: ${tOr('agentOnboarding.steps.' + nextStep.id, nextStep.title || nextStep.id)}` : ''}`;
|
|
437
443
|
}
|
|
438
444
|
case 'problem':
|
|
439
445
|
return html`${t('profile.agents.detail.state.problemSummary')} | ${agent.last_seen ? `${t('profile.agents.detail.lastSeen')}: ${timeAgo(agent.last_seen)}` : ''}`;
|
|
@@ -454,6 +460,9 @@ function renderCollapsedStats(state, agent, onboarding) {
|
|
|
454
460
|
|
|
455
461
|
function renderZone2(state, agent, onboarding, setActiveTab, showToast) {
|
|
456
462
|
switch (state) {
|
|
463
|
+
case 'system':
|
|
464
|
+
// Internal agents (Secretary / company Secretary / specialists) skip the Hello Integration banner.
|
|
465
|
+
return null;
|
|
457
466
|
case 'new':
|
|
458
467
|
return html`
|
|
459
468
|
<div class="pf-agd-zone2 pf-agd-zone2--new">
|
|
@@ -476,7 +485,7 @@ function renderZone2(state, agent, onboarding, setActiveTab, showToast) {
|
|
|
476
485
|
<div class="pf-agd-zone2 pf-agd-zone2--onboarding">
|
|
477
486
|
<div class="pf-agd-zone2-title">
|
|
478
487
|
${t('profile.agents.detail.zone2.onboardingTitle')}: ${passed} / ${total}
|
|
479
|
-
${nextStep ? html`<span class="pf-agd-zone2-desc"> ${t('profile.agents.detail.state.next')}: ${
|
|
488
|
+
${nextStep ? html`<span class="pf-agd-zone2-desc"> ${t('profile.agents.detail.state.next')}: ${tOr('agentOnboarding.steps.' + nextStep.id, nextStep.title || nextStep.id)}</span>` : ''}
|
|
480
489
|
</div>
|
|
481
490
|
<div class="pf-agd-progress-bar">
|
|
482
491
|
<div class="pf-agd-progress-fill" style="width: ${pct}%"></div>
|
|
@@ -484,7 +493,7 @@ function renderZone2(state, agent, onboarding, setActiveTab, showToast) {
|
|
|
484
493
|
<div class="pf-agd-step-pills">
|
|
485
494
|
${steps.map(s => html`
|
|
486
495
|
<span key=${s.id} class="pf-agd-step-pill pf-agd-step-pill--${s.status}">
|
|
487
|
-
${s.status === 'passed' ? '✓' : '○'} ${
|
|
496
|
+
${s.status === 'passed' ? '✓' : '○'} ${tOr('agentOnboarding.steps.' + s.id, s.title || s.id)}
|
|
488
497
|
</span>
|
|
489
498
|
`)}
|
|
490
499
|
</div>
|
|
@@ -16,6 +16,10 @@
|
|
|
16
16
|
* Checked in priority order: new > onboarding > problem > idle > production.
|
|
17
17
|
*/
|
|
18
18
|
export function detectAgentState(agent, onboarding) {
|
|
19
|
+
// System agents (Secretary, company Secretary, specialists) are auto-provisioned and never run the
|
|
20
|
+
// device-auth "Hello Integration" onboarding — so they must never show the 0/11 "onboarding not
|
|
21
|
+
// started" state. Any `system:*` tag marks an internal agent.
|
|
22
|
+
if ((agent.tags || []).some((tag) => typeof tag === 'string' && tag.startsWith('system:'))) return 'system';
|
|
19
23
|
if (!onboarding || onboarding.status === 'pending' || onboarding.status === 'not_started') return 'new';
|
|
20
24
|
if (onboarding.status === 'in_progress') return 'onboarding';
|
|
21
25
|
|
|
@@ -34,6 +38,7 @@ export function getDefaultTab(state) {
|
|
|
34
38
|
case 'new': return 'integration';
|
|
35
39
|
case 'onboarding': return 'integration';
|
|
36
40
|
case 'problem': return 'integration';
|
|
41
|
+
case 'system': return 'directives'; // internal agents: brain, not onboarding
|
|
37
42
|
case 'idle': return 'tasks';
|
|
38
43
|
case 'production': return 'tasks';
|
|
39
44
|
default: return 'tasks';
|
|
@@ -45,6 +50,7 @@ export function getStateColor(state) {
|
|
|
45
50
|
case 'new': return 'var(--warning)';
|
|
46
51
|
case 'onboarding': return 'var(--warning)';
|
|
47
52
|
case 'problem': return 'var(--danger)';
|
|
53
|
+
case 'system': return 'var(--success)';
|
|
48
54
|
case 'idle': return 'var(--text-muted)';
|
|
49
55
|
case 'production': return 'var(--success)';
|
|
50
56
|
default: return 'var(--text-muted)';
|
|
@@ -4,6 +4,9 @@
|
|
|
4
4
|
* during onboarding or production status (connection, platform, readiness,
|
|
5
5
|
* identity, delivery log) after completion.
|
|
6
6
|
* @version-history
|
|
7
|
+
* v1.8.0 -- 2026-06-30 -- Onboarding checklist step labels use tOr() so a missing
|
|
8
|
+
* agentOnboarding.steps.* key falls back to the server-provided step.title (which carries
|
|
9
|
+
* the howTo-enriched onboarding payload) instead of rendering the raw i18n key.
|
|
7
10
|
* v1.7.0 -- 2026-06-10 -- Webhook fields (URL, fail count, Test/Edit) hidden while delivery
|
|
8
11
|
* is polling; a "+ Set up webhook" reveal opens the URL form for switching methods.
|
|
9
12
|
* v1.6.0 -- 2026-06-02 -- Component unification (#1): the 3 copy buttons (agent prompt,
|
|
@@ -29,7 +32,7 @@ import { h } from 'preact';
|
|
|
29
32
|
import { useState, useEffect, useRef } from 'preact/hooks';
|
|
30
33
|
import htm from 'htm';
|
|
31
34
|
import { onLiveUpdate } from '/lib/live-updates.js';
|
|
32
|
-
import { t } from '/js/i18n.js';
|
|
35
|
+
import { t, tOr } from '/js/i18n.js';
|
|
33
36
|
import { timeAgo } from '/js/utils.js';
|
|
34
37
|
import { CopyButton } from '/components/CopyButton.js';
|
|
35
38
|
import { detectAgentState } from './state-detector.js';
|
|
@@ -187,6 +190,12 @@ curl -H "Authorization: Bearer <jwt>" -o skill-bundle.zip "${skillBundleUrl}" &&
|
|
|
187
190
|
return html`<div class="pf-agd-empty">${t('profile.loading')}</div>`;
|
|
188
191
|
}
|
|
189
192
|
|
|
193
|
+
// System agents (Secretary / company Secretary / specialists) are auto-provisioned and never run the
|
|
194
|
+
// device-auth "Hello Integration" onboarding — show a short note instead of the 0/11 checklist.
|
|
195
|
+
if (state === 'system') {
|
|
196
|
+
return html`<div class="pf-agd-empty">${t('profile.agents.detail.internalAgentNote')}</div>`;
|
|
197
|
+
}
|
|
198
|
+
|
|
190
199
|
const isOnboarding = state === 'new' || state === 'onboarding';
|
|
191
200
|
|
|
192
201
|
if (isOnboarding) {
|
|
@@ -235,7 +244,7 @@ function renderOnboardingView(onboarding, agentName, handleRerun, rerunning, cur
|
|
|
235
244
|
<span class="pf-agd-step-icon">
|
|
236
245
|
${step.status === 'passed' ? '✓' : step.status === 'failed' ? '✗' : '○'}
|
|
237
246
|
</span>
|
|
238
|
-
<span class="pf-agd-step-name">${i + 1}. ${
|
|
247
|
+
<span class="pf-agd-step-name">${i + 1}. ${tOr('agentOnboarding.steps.' + step.id, step.title || step.id)}</span>
|
|
239
248
|
<span class="pf-agd-step-detail">
|
|
240
249
|
${step.validatedAt ? timeAgo(step.validatedAt) : ''}
|
|
241
250
|
${step.validationDetail ? ` -- ${step.validationDetail}` : ''}
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
* @file apps-tab.js
|
|
3
3
|
* @description Profile tab for HTML app management — upload, gallery, access code editing.
|
|
4
4
|
* @version-history
|
|
5
|
+
* v1.4.0 — 2026-06-26 — Add "Edit details" (rename + edit description) to My Apps — updates the
|
|
6
|
+
* display name in place without re-publishing; the app link (owner/filename) stays the same.
|
|
5
7
|
* v1.3.0 — 2026-06-24 — Show a "moderated by operator: hidden" badge + hint (with reason) on My Apps
|
|
6
8
|
* when an operator has hidden the app; the owner sees it but cannot lift it.
|
|
7
9
|
* v1.2.0 — 2026-06-20 — Add Park/Unpark control + Parked badge/hint to My Apps (hide an app
|
|
@@ -30,6 +32,9 @@ export default function AppsTab({ session, showToast, onStats }) {
|
|
|
30
32
|
const [showAppUpload, setShowAppUpload] = useState(false);
|
|
31
33
|
const [editingApp, setEditingApp] = useState(null);
|
|
32
34
|
const [editCode, setEditCode] = useState('');
|
|
35
|
+
const [editingMeta, setEditingMeta] = useState(null);
|
|
36
|
+
const [editName, setEditName] = useState('');
|
|
37
|
+
const [editDesc, setEditDesc] = useState('');
|
|
33
38
|
|
|
34
39
|
useEffect(() => {
|
|
35
40
|
if (session) loadData();
|
|
@@ -78,6 +83,33 @@ export default function AppsTab({ session, showToast, onStats }) {
|
|
|
78
83
|
setEditCode('');
|
|
79
84
|
}
|
|
80
85
|
|
|
86
|
+
function startEditMeta(app) {
|
|
87
|
+
setEditingMeta(app.filename);
|
|
88
|
+
setEditName(app.manifest?.name || String(app.filename || app.name || '').replace(/\.html?$/i, ''));
|
|
89
|
+
setEditDesc(app.manifest?.description || '');
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function cancelEditMeta() {
|
|
93
|
+
setEditingMeta(null);
|
|
94
|
+
setEditName('');
|
|
95
|
+
setEditDesc('');
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
async function handleSaveMeta(filename) {
|
|
99
|
+
const name = editName.trim();
|
|
100
|
+
const description = editDesc.trim();
|
|
101
|
+
if (!name) { showToast(t('profile.apps.nameRequired') || 'Name cannot be empty', true); return; }
|
|
102
|
+
if (!description) { showToast(t('profile.apps.descRequired') || 'Description cannot be empty', true); return; }
|
|
103
|
+
const resp = await patchApp(filename, { name, description });
|
|
104
|
+
if (resp.ok !== false) {
|
|
105
|
+
showToast(t('profile.apps.detailsUpdated') || 'App details updated');
|
|
106
|
+
cancelEditMeta();
|
|
107
|
+
loadData();
|
|
108
|
+
} else {
|
|
109
|
+
showToast(resp?.error?.message || t('profile.apps.updateFailed') || 'Update failed', true);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
81
113
|
async function handleTogglePark(app) {
|
|
82
114
|
const next = !app.parked;
|
|
83
115
|
const resp = await patchApp(app.filename || app.name, { parked: next });
|
|
@@ -158,10 +190,24 @@ export default function AppsTab({ session, showToast, onStats }) {
|
|
|
158
190
|
data: { owner: a.owner || session.owner, filename: a.filename || a.name } });
|
|
159
191
|
window.open(`/v1/apps/${encodeURIComponent(a.owner || session.owner)}/${encodeURIComponent(a.filename || a.name)}?mode=inline`, '_blank');
|
|
160
192
|
}}>${t('profile.apps.launch') || 'Launch'}</button>
|
|
193
|
+
<button class="btn-sm" onClick=${() => startEditMeta(a)}>${t('profile.apps.editDetails') || 'Edit Details'}</button>
|
|
161
194
|
<button class="btn-sm" onClick=${() => startEdit(a)}>${t('profile.apps.editAccess') || 'Edit Access Code'}</button>
|
|
162
195
|
<button class=${a.parked ? 'btn-success btn-sm' : 'btn-outline btn-sm'} onClick=${() => handleTogglePark(a)}>${a.parked ? (t('profile.apps.unpark') || 'Unpark') : (t('profile.apps.park') || 'Park')}</button>
|
|
163
196
|
<button class="btn-danger-solid btn-sm" onClick=${() => handleDelete(a.filename || a.name)}>${t('profile.apps.deleteBtn') || 'Delete'}</button>
|
|
164
197
|
</div>
|
|
198
|
+
${editingMeta === a.filename ? html`
|
|
199
|
+
<div class="pf-edit-panel">
|
|
200
|
+
<label class="text-meta mb-half">${t('profile.apps.nameLabel') || 'App Name'}</label>
|
|
201
|
+
<input class="input-field pf-flex-fill mb-half" maxLength="120" placeholder=${t('profile.apps.namePlaceholder') || 'Display name'} value=${editName} onInput=${e => setEditName(e.target.value)} />
|
|
202
|
+
<label class="text-meta mb-half">${t('profile.apps.descLabel') || 'Description'}</label>
|
|
203
|
+
<textarea class="input-field pf-flex-fill mb-half" rows="2" maxLength="2000" placeholder=${t('profile.apps.descPlaceholder') || 'What does this app do?'} value=${editDesc} onInput=${e => setEditDesc(e.target.value)}></textarea>
|
|
204
|
+
<div class="text-meta-sm mb-half">${t('profile.apps.renameHint') || 'The app link stays the same — only the displayed name and description change.'}</div>
|
|
205
|
+
<div class="flex-row">
|
|
206
|
+
<button class="btn-primary btn-sm" onClick=${() => handleSaveMeta(a.filename)}>${t('profile.apps.save') || 'Save'}</button>
|
|
207
|
+
<button class="btn-outline btn-sm" onClick=${cancelEditMeta}>${t('profile.cancel') || 'Cancel'}</button>
|
|
208
|
+
</div>
|
|
209
|
+
</div>
|
|
210
|
+
` : ''}
|
|
165
211
|
${editingApp === a.filename ? html`
|
|
166
212
|
<div class="pf-edit-panel">
|
|
167
213
|
<label class="text-meta mb-half">${t('profile.apps.accessCodeLabel') || 'Access Code'}</label>
|
|
@@ -961,11 +961,13 @@ export default function ExtensionsTab({ session, showToast }) {
|
|
|
961
961
|
<div class="ext-grid">
|
|
962
962
|
${nodeExts.map(ext => {
|
|
963
963
|
const types = ext.component_types || [];
|
|
964
|
+
const isLib = types.includes('lib') && !types.some(ct => ['schema','action','board-template','ontology','seed-data'].includes(ct));
|
|
964
965
|
return html`
|
|
965
966
|
<div class="ext-card" onClick=${() => loadDetail(ext.name)}>
|
|
966
967
|
<div class="ext-card-header">
|
|
967
968
|
<span class="ext-card-name">${ext.name}</span>
|
|
968
969
|
<span class="ext-card-version">v${ext.version || '?'}</span>
|
|
970
|
+
<span class="badge ${isLib ? 'badge-info' : 'badge-dim'}">${isLib ? t('profile.extensions.libraryBadge') : t('profile.extensions.serviceBadge')}</span>
|
|
969
971
|
<span class="ext-visibility-badge public">${'\u{1F310}'}</span>
|
|
970
972
|
</div>
|
|
971
973
|
<div class="ext-card-desc">${ext.description || ''}</div>
|
|
@@ -985,6 +987,7 @@ export default function ExtensionsTab({ session, showToast }) {
|
|
|
985
987
|
<div class="ext-grid">
|
|
986
988
|
${myExts.map(ext => {
|
|
987
989
|
const types = ext.component_types || [];
|
|
990
|
+
const isLib = types.includes('lib') && !types.some(ct => ['schema','action','board-template','ontology','seed-data'].includes(ct));
|
|
988
991
|
const isActive = ext.status === 'active';
|
|
989
992
|
const vis = ext.visibility || 'private';
|
|
990
993
|
return html`
|
|
@@ -992,6 +995,7 @@ export default function ExtensionsTab({ session, showToast }) {
|
|
|
992
995
|
<div class="ext-card-header">
|
|
993
996
|
<span class="ext-card-name">${ext.name}</span>
|
|
994
997
|
<span class="ext-card-version">v${ext.version || '?'}</span>
|
|
998
|
+
<span class="badge ${isLib ? 'badge-info' : 'badge-dim'}">${isLib ? t('profile.extensions.libraryBadge') : t('profile.extensions.serviceBadge')}</span>
|
|
995
999
|
<span class="ext-visibility-badge ${vis}">${vis === 'public' ? '\u{1F310}' : '\u{1F512}'}</span>
|
|
996
1000
|
</div>
|
|
997
1001
|
<div class="ext-card-desc">${ext.description || ''}</div>
|
|
@@ -164,7 +164,7 @@ function groupConversations(conversations) {
|
|
|
164
164
|
}
|
|
165
165
|
|
|
166
166
|
function Avatar({ seed, size = 36 }) {
|
|
167
|
-
const svg = minidenticon(seed
|
|
167
|
+
const svg = minidenticon(typeof seed === 'string' && seed ? seed : 'user');
|
|
168
168
|
return html`<span class="inbox-avatar" style=${`width:${size}px;height:${size}px`}
|
|
169
169
|
dangerouslySetInnerHTML=${{ __html: svg }}></span>`;
|
|
170
170
|
}
|
|
@@ -230,7 +230,12 @@ function EditProfileModal({ session, onClose, onSaved, onChangePassword }) {
|
|
|
230
230
|
const resp = await updateProfile(fields);
|
|
231
231
|
if (resp && resp.data) {
|
|
232
232
|
if (session && typeof fields.display_name === 'string') {
|
|
233
|
-
|
|
233
|
+
// Persist + re-render the golden login pill live (so it shows the new name now).
|
|
234
|
+
if (window.AIMEAT?.auth?.updateSessionMeta) {
|
|
235
|
+
window.AIMEAT.auth.updateSessionMeta({ displayName: fields.display_name });
|
|
236
|
+
} else {
|
|
237
|
+
session.displayName = fields.display_name;
|
|
238
|
+
}
|
|
234
239
|
}
|
|
235
240
|
onSaved?.();
|
|
236
241
|
} else {
|
|
@@ -732,7 +737,7 @@ function ProfileCard({ tier, stats, session, onEditProfile, switchTab }) {
|
|
|
732
737
|
const NODE_URL = getNodeUrl();
|
|
733
738
|
const isNew = tier === 'new';
|
|
734
739
|
const isExperienced = tier === 'experienced';
|
|
735
|
-
const avatarSvg = minidenticon(session.owner
|
|
740
|
+
const avatarSvg = minidenticon(typeof session.owner === 'string' && session.owner ? session.owner : 'user');
|
|
736
741
|
|
|
737
742
|
// Stats are NAVIGATION, not decoration \u2014 each one opens its own section.
|
|
738
743
|
const stat = (icon, val, labelKey, tabId, green) => html`
|
|
@@ -1184,7 +1189,7 @@ export default function LandingPage({ tier, stats, session, navigate, showToast,
|
|
|
1184
1189
|
|
|
1185
1190
|
<aside class="pf-sidebar">
|
|
1186
1191
|
<div class="pf-side-identity">
|
|
1187
|
-
<div class="pf-side-avatar" dangerouslySetInnerHTML=${{ __html: minidenticon(owner
|
|
1192
|
+
<div class="pf-side-avatar" dangerouslySetInnerHTML=${{ __html: minidenticon(typeof owner === 'string' && owner ? owner : 'user') }}></div>
|
|
1188
1193
|
<div class="pf-side-id-name">${session.displayName || owner}</div>
|
|
1189
1194
|
</div>
|
|
1190
1195
|
|
|
@@ -41,6 +41,12 @@
|
|
|
41
41
|
* v2.3.1 — 2026-06-22 — Toolbar layout: data tools (Load all / Export / Import) grouped in their
|
|
42
42
|
* own bordered .mem-tools-section up top; content-search + filter on one row; sort + "New memory"
|
|
43
43
|
* moved to a bottom bar (New-memory pushed right).
|
|
44
|
+
* v2.4.0 — 2026-06-26 — Per-row "Copy URL" button in Files actions (canonical <CopyButton>) so a
|
|
45
|
+
* single file's URL can be grabbed for embedding without copying all URLs at once. Both the
|
|
46
|
+
* per-row and the bulk "Copy URLs" buttons now emit the PUBLIC no-auth URL
|
|
47
|
+
* (/v1/pub/:owner/:key, served when visibility==='public') instead of the authenticated,
|
|
48
|
+
* owner-scoped /v1/memory/files/:key — so a public file's link actually loads in a browser /
|
|
49
|
+
* <img>. Requires owner_gaii from the files list (added to GET /v1/memory/files).
|
|
44
50
|
*/
|
|
45
51
|
import { h } from 'preact';
|
|
46
52
|
import { useState, useEffect, useRef } from 'preact/hooks';
|
|
@@ -88,6 +94,7 @@ export default function MemoryTab({ session, showToast, onStats }) {
|
|
|
88
94
|
const [mainTab, setMainTab] = useState('own'); // 'own' | 'discover' | 'remote'
|
|
89
95
|
const [browseMode, setBrowseMode] = useState(null); // 'home' | 'remote' | 'discover' | null
|
|
90
96
|
const [filterText, setFilterText] = useState('');
|
|
97
|
+
const [memArchived, setMemArchived] = useState(false); // false = active working set, true = archived-only view
|
|
91
98
|
const [orgNames, setOrgNames] = useState({}); // organism uuid → display name
|
|
92
99
|
const [collapsedGroups, setCollapsedGroups] = useState(() => {
|
|
93
100
|
try { return new Set(JSON.parse(sessionStorage.getItem('aimeat.mem.groups.collapsed') || '[]')); } catch { return new Set(); }
|
|
@@ -145,7 +152,7 @@ export default function MemoryTab({ session, showToast, onStats }) {
|
|
|
145
152
|
|
|
146
153
|
useEffect(() => {
|
|
147
154
|
if (session) { loadMemories(); }
|
|
148
|
-
}, [selectedAgent]);
|
|
155
|
+
}, [selectedAgent, memArchived]);
|
|
149
156
|
|
|
150
157
|
async function loadFedConsents() {
|
|
151
158
|
try {
|
|
@@ -231,16 +238,18 @@ export default function MemoryTab({ session, showToast, onStats }) {
|
|
|
231
238
|
async function loadMemories() {
|
|
232
239
|
try {
|
|
233
240
|
const agentGaii = selectedAgent || undefined;
|
|
241
|
+
const memOpts = memArchived ? { archived: 'only' } : undefined;
|
|
234
242
|
if (fullLoaded) {
|
|
235
|
-
const list = await memoryService.listMemories(agentGaii);
|
|
243
|
+
const list = await memoryService.listMemories(agentGaii, memOpts);
|
|
236
244
|
setMemories(Array.isArray(list) ? list : []);
|
|
237
|
-
|
|
245
|
+
// Don't report the archived-only count as the headline memory stat (it's a filtered view).
|
|
246
|
+
if (!memArchived) onStats?.({ memory: Array.isArray(list) ? list.length : 0 });
|
|
238
247
|
} else {
|
|
239
|
-
const { items, quota } = await memoryService.listMemoriesMeta(agentGaii);
|
|
248
|
+
const { items, quota } = await memoryService.listMemoriesMeta(agentGaii, memOpts);
|
|
240
249
|
setMemories(items);
|
|
241
250
|
setMemQuota(quota);
|
|
242
251
|
setValueCache({});
|
|
243
|
-
onStats?.({ memory: items.length });
|
|
252
|
+
if (!memArchived) onStats?.({ memory: items.length });
|
|
244
253
|
}
|
|
245
254
|
} catch { setMemories([]); }
|
|
246
255
|
}
|
|
@@ -830,6 +839,10 @@ export default function MemoryTab({ session, showToast, onStats }) {
|
|
|
830
839
|
value=${filterText} onInput=${e => setFilterText(e.target.value)} />
|
|
831
840
|
${filterText && html`<button class="btn-ghost btn-sm" onClick=${() => setFilterText('')}>✕</button>`}
|
|
832
841
|
</div>
|
|
842
|
+
<div class="search-bar">
|
|
843
|
+
<button class="btn-sm ${!memArchived ? 'btn-primary' : 'btn-outline'}" onClick=${() => setMemArchived(false)}>${t('profile.memory.viewActive') || 'Active'}</button>
|
|
844
|
+
<button class="btn-sm ${memArchived ? 'btn-primary' : 'btn-outline'}" onClick=${() => setMemArchived(true)}>${'🗄️ '}${t('profile.memory.viewArchived') || 'Archived'}</button>
|
|
845
|
+
</div>
|
|
833
846
|
</div>
|
|
834
847
|
<div class="action-bar mem-bottom-bar">
|
|
835
848
|
<div class="mem-sort-bar">
|
|
@@ -917,7 +930,19 @@ export default function MemoryTab({ session, showToast, onStats }) {
|
|
|
917
930
|
});
|
|
918
931
|
};
|
|
919
932
|
|
|
920
|
-
|
|
933
|
+
// Public, no-auth file URL (mirrors memory's /v1/memory/:gaii/:key public read):
|
|
934
|
+
// GET /v1/pub/:owner/:key serves the bytes when visibility==='public', so the copied
|
|
935
|
+
// link is embeddable anywhere (<img src>, another site, a chat). Keeps slashes in keys
|
|
936
|
+
// literal for the wildcard route; only encodes per-segment. Falls back to the legacy
|
|
937
|
+
// authenticated URL if the list response predates owner_gaii (server needs a restart).
|
|
938
|
+
const fileUrl = (f) => {
|
|
939
|
+
const owner = f.owner_gaii;
|
|
940
|
+
const keyPath = String(f.key || f.name).split('/').map(encodeURIComponent).join('/');
|
|
941
|
+
return owner
|
|
942
|
+
? `${NODE_URL}/v1/pub/${encodeURIComponent(owner)}/${keyPath}`
|
|
943
|
+
: `${NODE_URL}/v1/memory/files/${encodeURIComponent(f.key || f.name)}`;
|
|
944
|
+
};
|
|
945
|
+
const fileUrls = filtered.map(fileUrl).join('\n');
|
|
921
946
|
|
|
922
947
|
return html`
|
|
923
948
|
<div class="action-bar">
|
|
@@ -965,6 +990,12 @@ export default function MemoryTab({ session, showToast, onStats }) {
|
|
|
965
990
|
`}
|
|
966
991
|
</div>
|
|
967
992
|
<div class="file-actions">
|
|
993
|
+
<${CopyButton}
|
|
994
|
+
text=${fileUrl(f)}
|
|
995
|
+
label=${`\u{1F517} ${t('profile.files.copyUrl') || 'Copy URL'}`}
|
|
996
|
+
title=${t('profile.files.copyUrl') || 'Copy URL'}
|
|
997
|
+
className="btn-outline btn-sm"
|
|
998
|
+
onCopied=${() => showToast(t('profile.files.urlCopied') || 'URL copied to clipboard')} />
|
|
968
999
|
<button class="btn-outline btn-sm" onClick=${() => handleDownloadFile(fKey)}>${t('profile.files.download')}</button>
|
|
969
1000
|
<button class="btn-danger-solid btn-sm" onClick=${() => handleDeleteFile(fKey)}>${t('profile.files.delete')}</button>
|
|
970
1001
|
</div>
|
|
@@ -194,6 +194,25 @@ export function OrganismHome({ org, ghii, showToast, initialSettings, onOpenWs,
|
|
|
194
194
|
} catch { showToast(t('organisms.deleteError') || 'Failed to delete'); }
|
|
195
195
|
}, { danger: true, title: t('organisms.deleteOrganismTitle') || 'Delete this organism' });
|
|
196
196
|
};
|
|
197
|
+
// Archive / unarchive the whole organism (creator/admin) — read-only + hidden from AI materials,
|
|
198
|
+
// cascades to its workspaces, fully reversible (smart restore). Unlike delete, nothing is destroyed.
|
|
199
|
+
const doArchive = (archived) => {
|
|
200
|
+
confirm(
|
|
201
|
+
(archived
|
|
202
|
+
? (t('organisms.confirmArchive') || 'Archive “{name}”? It becomes read-only and is hidden from AI operations until you unarchive it. Its workspaces are archived too.')
|
|
203
|
+
: (t('organisms.confirmUnarchive') || 'Unarchive “{name}”? It and the workspaces archived with it become active again.')
|
|
204
|
+
).replace('{name}', org.name || org.id),
|
|
205
|
+
async () => {
|
|
206
|
+
try {
|
|
207
|
+
if (archived) await orgService.archiveContent(org.id, { level: 'organism' });
|
|
208
|
+
else await orgService.unarchiveContent(org.id, { level: 'organism' });
|
|
209
|
+
showToast(archived ? (t('organisms.organismArchived') || 'Organism archived') : (t('organisms.organismUnarchived') || 'Organism restored'));
|
|
210
|
+
onChanged?.();
|
|
211
|
+
} catch (e) { showToast((e && e.message) || 'Failed'); }
|
|
212
|
+
},
|
|
213
|
+
{ title: archived ? (t('organisms.archive') || 'Archive') : (t('organisms.unarchive') || 'Unarchive') },
|
|
214
|
+
);
|
|
215
|
+
};
|
|
197
216
|
|
|
198
217
|
const extraAdmins = (org.admins || []).filter(a => a !== org.creatorGhii);
|
|
199
218
|
const visHint = t(`organisms.visHint.${form.visibility}`);
|
|
@@ -254,6 +273,19 @@ export function OrganismHome({ org, ghii, showToast, initialSettings, onOpenWs,
|
|
|
254
273
|
` : null}
|
|
255
274
|
</div>
|
|
256
275
|
|
|
276
|
+
${canEdit ? html`
|
|
277
|
+
<div class="pj-danger-box">
|
|
278
|
+
<div class="pj-danger-row">
|
|
279
|
+
<div class="pj-danger-text">
|
|
280
|
+
<div class="pj-danger-title">${org.archived ? (t('organisms.unarchiveOrganismTitle') || 'Unarchive this organism') : (t('organisms.archiveOrganismTitle') || 'Archive this organism')}</div>
|
|
281
|
+
<div class="pj-danger-sub">${org.archived
|
|
282
|
+
? (t('organisms.unarchiveOrganismSub') || 'Make it active again. Workspaces archived together with it are restored.')
|
|
283
|
+
: (t('organisms.archiveOrganismSub') || 'Make it read-only and hide it (and its workspaces) from AI operations. Reversible — nothing is deleted.')}</div>
|
|
284
|
+
</div>
|
|
285
|
+
<button class="btn-outline btn-sm" onClick=${() => doArchive(!org.archived)}>${org.archived ? `♻️ ${t('organisms.unarchive') || 'Unarchive'}` : `🗄️ ${t('organisms.archive') || 'Archive'}`}</button>
|
|
286
|
+
</div>
|
|
287
|
+
</div>` : null}
|
|
288
|
+
|
|
257
289
|
${(isCreator || isMember) ? html`
|
|
258
290
|
<div class="pj-danger pj-danger-box">
|
|
259
291
|
${isCreator ? html`
|
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
* v1.1.0 — 2026-06-22 — Kill the per-workspace fetch storm: one discoverWorkspaces({include:'enrichment'})
|
|
14
14
|
* replaces the 1 + 3N (getWorkspace+activity+participants) fan-out; pending-review counts come inline;
|
|
15
15
|
* the 'organisms' live refresh is debounced (1.5s) so an agent-driven event burst is one reload.
|
|
16
|
+
* v1.2.0 — 2026-06-26 — Archive/unarchive a workspace (creator/admin) via the kebab menu + an
|
|
17
|
+
* "archived" badge; archived workspaces are read-only and hidden from AI materials.
|
|
16
18
|
*/
|
|
17
19
|
import { h } from 'preact';
|
|
18
20
|
import { useState, useEffect, useCallback, useRef } from 'preact/hooks';
|
|
@@ -45,6 +47,7 @@ export function WorkspaceList({ org, showToast, onOpen, onCount }) {
|
|
|
45
47
|
const [openReqWs, setOpenReqWs] = useState(null); // which owned workspace's request-inbox is open
|
|
46
48
|
const [reqInbox, setReqInbox] = useState([]); // access requests for openReqWs
|
|
47
49
|
const [openPeopleWs, setOpenPeopleWs] = useState(null); // which workspace's inline participants list is open
|
|
50
|
+
const [archivedOpen, setArchivedOpen] = useState(false); // collapsible "Archived workspaces" section
|
|
48
51
|
const [wsStats, setWsStats] = useState({}); // wsId → { recs, docs, lastEv, hasManifest }
|
|
49
52
|
const [apprByWs, setApprByWs] = useState({}); // wsId → pending review count
|
|
50
53
|
|
|
@@ -142,6 +145,19 @@ export function WorkspaceList({ org, showToast, onOpen, onCount }) {
|
|
|
142
145
|
);
|
|
143
146
|
};
|
|
144
147
|
|
|
148
|
+
// Archive / unarchive a whole workspace (creator/admin). Archived workspaces become read-only and
|
|
149
|
+
// drop out of AI materials (overview/read/search) but stay searchable in the archive + restorable.
|
|
150
|
+
const setArchived = async (w, archived) => {
|
|
151
|
+
setBusy(true);
|
|
152
|
+
try {
|
|
153
|
+
const target = { level: 'workspace', ws: w.id };
|
|
154
|
+
if (archived) await orgService.archiveContent(orgId, target); else await orgService.unarchiveContent(orgId, target);
|
|
155
|
+
await load();
|
|
156
|
+
showToast(archived ? (t('organisms.workspaceArchived') || 'Workspace archived') : (t('organisms.workspaceUnarchived') || 'Workspace restored'));
|
|
157
|
+
} catch (e) { showToast((e && e.message) || 'Failed'); }
|
|
158
|
+
finally { setBusy(false); }
|
|
159
|
+
};
|
|
160
|
+
|
|
145
161
|
// ── Export (download ZIP backup) + Import (upload a ZIP as a new workspace) ──
|
|
146
162
|
const jwt = () => { try { return window.AIMEAT?.auth?.getSession?.()?.jwt || ''; } catch { return ''; } };
|
|
147
163
|
const fileRef = useRef(null);
|
|
@@ -207,14 +223,16 @@ export function WorkspaceList({ org, showToast, onOpen, onCount }) {
|
|
|
207
223
|
|
|
208
224
|
${list === null ? html`<${Spinner} />`
|
|
209
225
|
: list.length === 0 ? html`<${EmptyState} icon="🗂️" text=${t('organisms.noWorkspaces') || 'No workspaces yet — create one to get started.'} />`
|
|
210
|
-
:
|
|
211
|
-
|
|
212
|
-
${list.map(w => {
|
|
226
|
+
: (() => {
|
|
227
|
+
const renderWsRow = (w) => {
|
|
213
228
|
const locked = w.access === 'none';
|
|
214
229
|
const reviews = apprByWs[w.id] || 0;
|
|
215
230
|
const menuItems = w.access === 'owner' ? [
|
|
216
231
|
{ label: t('organisms.requests') || 'Access requests', icon: '👥', onClick: () => toggleInbox(w) },
|
|
217
232
|
{ label: t('organisms.export') || 'Export backup (.zip)', icon: '⬇', onClick: () => doExport(w) },
|
|
233
|
+
w.archived
|
|
234
|
+
? { label: t('organisms.unarchive') || 'Unarchive', icon: '♻️', onClick: () => setArchived(w, false) }
|
|
235
|
+
: { label: t('organisms.archive') || 'Archive', icon: '🗄️', onClick: () => setArchived(w, true) },
|
|
218
236
|
{ label: t('organisms.delete') || 'Delete', danger: true, onClick: () => remove(w.id, w.name || w.id) },
|
|
219
237
|
] : [];
|
|
220
238
|
return html`
|
|
@@ -226,6 +244,7 @@ export function WorkspaceList({ org, showToast, onOpen, onCount }) {
|
|
|
226
244
|
<div class="pj-org-titlerow">
|
|
227
245
|
${locked ? html`<span class="pj-org-lock">${'🔒'}</span>` : null}
|
|
228
246
|
<span class="pj-org-name">${(w.name || w.id)}</span>
|
|
247
|
+
${w.archived ? html`<span class="pj-tab-pill" title=${t('organisms.archivedHint') || 'Archived — read-only, hidden from AI operations'}>${'🗄️ '}${t('organisms.archived') || 'archived'}</span>` : null}
|
|
229
248
|
${reviews > 0 ? html`<span class="pj-tab-pill">${'📨 '}${(t('organisms.toReview') || '{n} to review').replace('{n}', String(reviews))}</span>` : null}
|
|
230
249
|
</div>
|
|
231
250
|
<div class="pj-org-desc">${locked
|
|
@@ -265,8 +284,20 @@ export function WorkspaceList({ org, showToast, onOpen, onCount }) {
|
|
|
265
284
|
</div>`)}
|
|
266
285
|
</div>` : null}
|
|
267
286
|
</div>`;
|
|
268
|
-
}
|
|
269
|
-
|
|
287
|
+
};
|
|
288
|
+
// Active workspaces in the main list; archived ones collapse into a section below (restorable).
|
|
289
|
+
const active = list.filter(w => !w.archived);
|
|
290
|
+
const archived = list.filter(w => w.archived);
|
|
291
|
+
return html`
|
|
292
|
+
<div class="pj-org-list">${active.map(renderWsRow)}</div>
|
|
293
|
+
${archived.length > 0 ? html`
|
|
294
|
+
<button class="pj-struct-toggle section-title-spaced" aria-expanded=${archivedOpen} onClick=${() => setArchivedOpen(o => !o)}>
|
|
295
|
+
<span class="pj-struct-caret">${archivedOpen ? '▾' : '▸'}</span>
|
|
296
|
+
<span>${'🗄️ '}${(t('organisms.archivedWorkspacesSection') || 'Archived workspaces ({n})').replace('{n}', String(archived.length))}</span>
|
|
297
|
+
</button>
|
|
298
|
+
${archivedOpen ? html`<div class="pj-org-list">${archived.map(renderWsRow)}</div>` : null}` : null}
|
|
299
|
+
`;
|
|
300
|
+
})()}
|
|
270
301
|
|
|
271
302
|
${overview && showOverview ? html`
|
|
272
303
|
<div class="pj-chart">
|
|
@@ -151,6 +151,7 @@ export function Workspace({ org, wsId, showToast, onBack, onBackToList, initialS
|
|
|
151
151
|
const [editingSec, setEditingSec] = useState(null); // section id currently being renamed inline
|
|
152
152
|
const draggedDoc = useRef(null); // { type, id } of the doc being dragged
|
|
153
153
|
const [showRegenerate, setShowRegenerate] = useState(false);
|
|
154
|
+
const [showArchived, setShowArchived] = useState(false); // false = active records, true = archived-only view
|
|
154
155
|
const [delConfirm, setDelConfirm] = useState(''); // typed-name confirmation for delete
|
|
155
156
|
const [newSpaceName, setNewSpaceName] = useState('');
|
|
156
157
|
const [addingInitial, setAddingInitial] = useState(null); // record being edited (null = new draft)
|
|
@@ -196,7 +197,8 @@ export function Workspace({ org, wsId, showToast, onBack, onBackToList, initialS
|
|
|
196
197
|
}, [seen, wsEvents]);
|
|
197
198
|
|
|
198
199
|
const load = useCallback(async () => {
|
|
199
|
-
|
|
200
|
+
// In the archived view, request ONLY archived content (read-only); otherwise the normal active set.
|
|
201
|
+
const w = await orgService.getWorkspace(orgId, wsId, showArchived ? { archived: 'only' } : undefined).catch(() => null);
|
|
200
202
|
if (w && w.manifest) {
|
|
201
203
|
const [ap, cfg, secs, act, cols] = await Promise.all([
|
|
202
204
|
orgService.listApprovals(orgId, 'pending').catch(() => []),
|
|
@@ -209,7 +211,7 @@ export function Workspace({ org, wsId, showToast, onBack, onBackToList, initialS
|
|
|
209
211
|
setWsEvents(act?.events || []); setColorsByType(cols);
|
|
210
212
|
}
|
|
211
213
|
setWs(w && w.manifest ? w : null);
|
|
212
|
-
}, [orgId, wsId]);
|
|
214
|
+
}, [orgId, wsId, showArchived]);
|
|
213
215
|
|
|
214
216
|
useEffect(() => { load(); }, [load]);
|
|
215
217
|
|
|
@@ -575,6 +577,20 @@ export function Workspace({ org, wsId, showToast, onBack, onBackToList, initialS
|
|
|
575
577
|
finally { setBusy(false); }
|
|
576
578
|
}, [orgId, wsId, showToast, load]);
|
|
577
579
|
|
|
580
|
+
// Archive / unarchive ONE record or document instance (read-only + hidden from AI; restorable). The
|
|
581
|
+
// record level archives the whole instance subtree (bare + .draft/.latest/.version.*) by its base key.
|
|
582
|
+
const setRecordArchived = useCallback(async (ot, instanceId, archived) => {
|
|
583
|
+
setBusy(true);
|
|
584
|
+
try {
|
|
585
|
+
const key = `organism.${orgId}.w.${wsId}.${ot.namespace}.${instanceId}`;
|
|
586
|
+
if (archived) await orgService.archiveContent(orgId, { level: 'record', ws: wsId, key });
|
|
587
|
+
else await orgService.unarchiveContent(orgId, { level: 'record', ws: wsId, key });
|
|
588
|
+
showToast(archived ? (t('organisms.recordArchived') || 'Archived') : (t('organisms.recordUnarchived') || 'Restored'));
|
|
589
|
+
await load();
|
|
590
|
+
} catch (e) { showToast((e && e.message) || 'Failed'); }
|
|
591
|
+
finally { setBusy(false); }
|
|
592
|
+
}, [orgId, wsId, showToast, load]);
|
|
593
|
+
|
|
578
594
|
const resolve = useCallback(async (aid, decision) => {
|
|
579
595
|
setBusy(true);
|
|
580
596
|
try { await orgService.resolveApproval(orgId, aid, decision); showToast(decision === 'approve' ? (t('organisms.approved') || 'Approved') : (t('organisms.rejected') || 'Rejected')); await load(); }
|
|
@@ -918,6 +934,9 @@ export function Workspace({ org, wsId, showToast, onBack, onBackToList, initialS
|
|
|
918
934
|
<button class="pj-doc-link" onClick=${() => setActiveDoc({ type: ot.name, mode: 'view', page: d })}>
|
|
919
935
|
${d._draft ? html`<span class="badge badge-warn pj-mini">${t('organisms.draft') || 'draft'}</span> ` : ''}${d.title || d.id}
|
|
920
936
|
</button>
|
|
937
|
+
${showArchived
|
|
938
|
+
? html`<button class="pj-icon-btn" title=${t('organisms.unarchive') || 'Unarchive'} disabled=${busy} onClick=${() => setRecordArchived(ot, d.id, false)}>♻️</button>`
|
|
939
|
+
: html`<button class="pj-icon-btn" title=${t('organisms.archive') || 'Archive'} disabled=${busy} onClick=${() => setRecordArchived(ot, d.id, true)}>🗄️</button>`}
|
|
921
940
|
<button class="pj-icon-btn pj-doc-del" title=${t('organisms.delete') || 'Delete'} disabled=${busy} onClick=${() => removeObject(ot.namespace, d.id, d.title || d.id)}>🗑</button>
|
|
922
941
|
</div>`;
|
|
923
942
|
|
|
@@ -1051,8 +1070,11 @@ export function Workspace({ org, wsId, showToast, onBack, onBackToList, initialS
|
|
|
1051
1070
|
<${ColorPicker} value=${itemColor(ot.name, o.id)} onPick=${(c) => setItemColor(ot.name, o.id, c)} />
|
|
1052
1071
|
<button class="pj-rec-title" onClick=${() => toggleExpand(ot, o.id)}>${String(o[PRIMARY_FIELD[ot.name] || 'title'] || o.summary || o.id || '')}</button>
|
|
1053
1072
|
${o.status ? html`<span class="badge badge-info">${(o.status)}</span>` : null}
|
|
1054
|
-
${!draftsFor(ot.name).some(dr => dr.id === o.id) ? html`
|
|
1073
|
+
${!showArchived && !draftsFor(ot.name).some(dr => dr.id === o.id) ? html`
|
|
1055
1074
|
<button class="btn-ghost btn-sm" title=${t('organisms.reopenEditHint') || 'Reopen for editing — creates an editable draft from the published version'} disabled=${busy} onClick=${() => reopen(ot, o.id)}>${t('organisms.edit') || 'Edit'}</button>` : null}
|
|
1075
|
+
${showArchived
|
|
1076
|
+
? html`<button class="btn-ghost btn-sm" title=${t('organisms.unarchive') || 'Unarchive'} disabled=${busy} onClick=${() => setRecordArchived(ot, o.id, false)}>${'♻️ '}${t('organisms.unarchive') || 'Unarchive'}</button>`
|
|
1077
|
+
: html`<button class="pj-icon-btn" title=${t('organisms.archive') || 'Archive'} disabled=${busy} onClick=${() => setRecordArchived(ot, o.id, true)}>🗄️</button>`}
|
|
1056
1078
|
<button class="pj-icon-btn" title=${t('organisms.delete') || 'Delete'} disabled=${busy} onClick=${() => removeObject(ot.namespace, o.id, String(o[PRIMARY_FIELD[ot.name] || 'title'] || o.id))}>🗑</button>
|
|
1057
1079
|
</div>
|
|
1058
1080
|
${expandedRec[ot.name + ':' + o.id] ? html`<div class="pj-rec-fields">${recordFields(ot, o)}</div><${WorkspaceComments} orgId=${orgId} ws=${wsId} space=${ot.name} instanceId=${o.id} showToast=${showToast} batched=${true} initialComments=${commentsByKey[cKey(wsId, ot.name, o.id)]} onReload=${reloadComments} />` : null}
|
|
@@ -1364,8 +1386,11 @@ export function Workspace({ org, wsId, showToast, onBack, onBackToList, initialS
|
|
|
1364
1386
|
${back}
|
|
1365
1387
|
<div class="pj-ws-titlerow">
|
|
1366
1388
|
<span class="section-title pj-ws-title">${(ws.manifest?.name || org.name || 'Workspace')}</span>
|
|
1367
|
-
|
|
1389
|
+
${showArchived
|
|
1390
|
+
? html`<span class="pj-tab-pill" title=${t('organisms.archivedViewHint') || 'Showing archived (read-only) records — restore one with ♻️'}>${'🗄️ '}${t('organisms.archivedView') || 'Archived view'}</span>`
|
|
1391
|
+
: html`<span class="badge badge-success">${(ws.manifest?.status || 'active')}</span>`}
|
|
1368
1392
|
<span class="pj-ws-head-actions">
|
|
1393
|
+
<button class="btn-outline btn-sm ${showArchived ? 'pj-org-btn-active' : ''}" title=${t('organisms.toggleArchivedHint') || 'View/hide archived records'} onClick=${() => setShowArchived(s => !s)}>${showArchived ? `↩ ${t('organisms.viewActive') || 'Active'}` : `🗄️ ${t('organisms.viewArchived') || 'Archived'}`}</button>
|
|
1369
1394
|
<${KebabMenu} label=${t('organisms.forAgentsHint') || 'Copy a ready prompt that teaches an AI to use this workspace'}
|
|
1370
1395
|
btnClass="btn-outline btn-sm" trigger=${'🤖 ' + (t('organisms.agentAccess') || 'Agent access') + ' ▾'} items=${agentMenuItems} />
|
|
1371
1396
|
<button class="btn-outline btn-sm ${showSettings ? 'pj-org-btn-active' : ''}" onClick=${() => guardWsDirty(() => setShowSettings(s => !s))}>${'⚙ '}${t('organisms.settings') || 'Settings'}</button>
|