aimeat 1.23.2 → 1.24.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 +580 -21
- package/dist/locales/fi.json +592 -33
- package/dist/public/components/ContactCard.js +28 -0
- package/dist/public/css/views/admin.css +12 -0
- package/dist/public/css/views/agents-detail.css +62 -10
- package/dist/public/css/views/landing.css +87 -0
- package/dist/public/css/views/offers.css +96 -0
- package/dist/public/css/views/portfolio.css +18 -0
- package/dist/public/css/views/profile.css +153 -8
- package/dist/public/css/views/start.css +96 -0
- package/dist/public/css/views/workflows.css +111 -0
- package/dist/public/img/business-hero.png +0 -0
- package/dist/public/img/toimitus.png +0 -0
- package/dist/public/js/components/tag-cloud.js +46 -31
- package/dist/public/js/components/tag-editor.js +2 -2
- package/dist/public/js/recents.js +40 -0
- package/dist/public/js/services/admin.js +6 -0
- package/dist/public/js/services/agents.js +34 -0
- package/dist/public/js/services/offers.js +152 -0
- package/dist/public/js/services/packages.js +1 -0
- package/dist/public/js/services/workflows.js +57 -0
- package/dist/public/llms-template.txt +7 -0
- package/dist/public/spa.html +35 -3
- package/dist/public/views/admin/subdomains-tab.js +182 -0
- package/dist/public/views/admin.js +2 -0
- package/dist/public/views/business.js +119 -0
- package/dist/public/views/how-it-works.js +159 -0
- package/dist/public/views/landing.js +235 -0
- package/dist/public/views/portfolio.js +120 -23
- package/dist/public/views/pricing.js +75 -0
- package/dist/public/views/profile/access-tab.js +124 -51
- package/dist/public/views/profile/agents/agent-card.js +68 -37
- package/dist/public/views/profile/agents/shared-board.js +56 -22
- package/dist/public/views/profile/agents/tab-activity.js +24 -12
- package/dist/public/views/profile/agents/tab-agent-config.js +31 -1
- package/dist/public/views/profile/agents/tab-data-access.js +9 -13
- package/dist/public/views/profile/agents/tab-integration.js +27 -1
- package/dist/public/views/profile/agents/tab-messages.js +6 -11
- package/dist/public/views/profile/agents/tab-quality.js +45 -5
- package/dist/public/views/profile/agents-tab.js +41 -6
- package/dist/public/views/profile/apps-tab.js +7 -1
- package/dist/public/views/profile/knowledge-tab.js +4 -1
- package/dist/public/views/profile/landing-page.js +428 -123
- package/dist/public/views/profile/memory-tab.js +409 -211
- package/dist/public/views/profile/nodes-tab.js +18 -3
- package/dist/public/views/profile/offers-tab.js +310 -0
- package/dist/public/views/profile/organisms-tab.js +289 -28
- package/dist/public/views/profile/packages-tab.js +152 -16
- package/dist/public/views/profile/portfolio-tab.js +98 -31
- package/dist/public/views/profile/workflows-form.js +220 -0
- package/dist/public/views/profile/workflows-tab.js +244 -0
- package/dist/public/views/profile.js +4 -0
- package/dist/public/views/start-flows.js +281 -0
- package/dist/public/views/start.js +258 -0
- 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/workflows.d.ts +12 -0
- package/dist/src/cli/connect/mcp/tools/workflows.d.ts.map +1 -0
- package/dist/src/cli/connect/mcp/tools/workflows.js +37 -0
- package/dist/src/cli/connect/mcp/tools/workflows.js.map +1 -0
- package/dist/src/cli/connect/tool-call.d.ts.map +1 -1
- package/dist/src/cli/connect/tool-call.js +37 -0
- package/dist/src/cli/connect/tool-call.js.map +1 -1
- package/dist/src/generated/api-types.d.ts +1474 -66
- package/dist/src/generated/api-types.d.ts.map +1 -1
- package/dist/src/generated/prisma-postgres/edge.js +15 -3
- package/dist/src/generated/prisma-postgres/index-browser.js +12 -0
- package/dist/src/generated/prisma-postgres/index.d.ts +1476 -160
- package/dist/src/generated/prisma-postgres/index.js +15 -3
- package/dist/src/generated/prisma-postgres/package.json +1 -1
- package/dist/src/generated/prisma-postgres/schema.prisma +11 -0
- package/dist/src/generated/prisma-postgres/wasm.js +15 -3
- package/dist/src/mcp/annotations.d.ts.map +1 -1
- package/dist/src/mcp/annotations.js +3 -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 +27 -0
- package/dist/src/mcp/catalog/definitions.js.map +1 -1
- package/dist/src/mcp/catalog/scopes.d.ts.map +1 -1
- package/dist/src/mcp/catalog/scopes.js +5 -1
- package/dist/src/mcp/catalog/scopes.js.map +1 -1
- package/dist/src/mcp/catalog/surfaces.d.ts.map +1 -1
- package/dist/src/mcp/catalog/surfaces.js +1 -0
- 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/workflows.d.ts +18 -0
- package/dist/src/mcp/workflows.d.ts.map +1 -0
- package/dist/src/mcp/workflows.js +68 -0
- package/dist/src/mcp/workflows.js.map +1 -0
- package/dist/src/middleware/subdomain.d.ts +28 -0
- package/dist/src/middleware/subdomain.d.ts.map +1 -0
- package/dist/src/middleware/subdomain.js +32 -0
- package/dist/src/middleware/subdomain.js.map +1 -0
- package/dist/src/models/offer-schemas.d.ts +236 -0
- package/dist/src/models/offer-schemas.d.ts.map +1 -0
- package/dist/src/models/offer-schemas.js +112 -0
- package/dist/src/models/offer-schemas.js.map +1 -0
- package/dist/src/models/workflow-schemas.d.ts +220 -0
- package/dist/src/models/workflow-schemas.d.ts.map +1 -0
- package/dist/src/models/workflow-schemas.js +102 -0
- package/dist/src/models/workflow-schemas.js.map +1 -0
- package/dist/src/routes/agent-tasks.d.ts.map +1 -1
- package/dist/src/routes/agent-tasks.js +49 -0
- package/dist/src/routes/agent-tasks.js.map +1 -1
- package/dist/src/routes/agents.d.ts.map +1 -1
- package/dist/src/routes/agents.js +146 -1
- package/dist/src/routes/agents.js.map +1 -1
- package/dist/src/routes/apps-backup.d.ts +20 -0
- package/dist/src/routes/apps-backup.d.ts.map +1 -0
- package/dist/src/routes/apps-backup.js +165 -0
- package/dist/src/routes/apps-backup.js.map +1 -0
- package/dist/src/routes/ghii.d.ts.map +1 -1
- package/dist/src/routes/ghii.js +4 -0
- package/dist/src/routes/ghii.js.map +1 -1
- package/dist/src/routes/instances.d.ts +2 -1
- package/dist/src/routes/instances.d.ts.map +1 -1
- package/dist/src/routes/instances.js +59 -1
- package/dist/src/routes/instances.js.map +1 -1
- package/dist/src/routes/memory.d.ts.map +1 -1
- package/dist/src/routes/memory.js +5 -0
- package/dist/src/routes/memory.js.map +1 -1
- package/dist/src/routes/packages.d.ts.map +1 -1
- package/dist/src/routes/packages.js +32 -0
- package/dist/src/routes/packages.js.map +1 -1
- package/dist/src/routes/permissions.d.ts +12 -0
- package/dist/src/routes/permissions.d.ts.map +1 -1
- package/dist/src/routes/permissions.js +35 -3
- package/dist/src/routes/permissions.js.map +1 -1
- package/dist/src/routes/portal.d.ts +3 -0
- package/dist/src/routes/portal.d.ts.map +1 -1
- package/dist/src/routes/portal.js +12 -0
- package/dist/src/routes/portal.js.map +1 -1
- package/dist/src/routes/public-stats.d.ts +15 -0
- package/dist/src/routes/public-stats.d.ts.map +1 -0
- package/dist/src/routes/public-stats.js +90 -0
- package/dist/src/routes/public-stats.js.map +1 -0
- package/dist/src/routes/sse.d.ts +7 -2
- package/dist/src/routes/sse.d.ts.map +1 -1
- package/dist/src/routes/sse.js +35 -5
- package/dist/src/routes/sse.js.map +1 -1
- package/dist/src/routes/stats.d.ts.map +1 -1
- package/dist/src/routes/stats.js +13 -0
- package/dist/src/routes/stats.js.map +1 -1
- package/dist/src/routes/subdomains.d.ts +33 -0
- package/dist/src/routes/subdomains.d.ts.map +1 -0
- package/dist/src/routes/subdomains.js +208 -0
- package/dist/src/routes/subdomains.js.map +1 -0
- package/dist/src/routes/workflows.d.ts +30 -0
- package/dist/src/routes/workflows.d.ts.map +1 -0
- package/dist/src/routes/workflows.js +178 -0
- package/dist/src/routes/workflows.js.map +1 -0
- package/dist/src/server-bootstrap/routes-loader.d.ts +2 -0
- package/dist/src/server-bootstrap/routes-loader.d.ts.map +1 -1
- package/dist/src/server-bootstrap/routes-loader.js +19 -2
- package/dist/src/server-bootstrap/routes-loader.js.map +1 -1
- package/dist/src/server-bootstrap/service-init.d.ts +2 -0
- package/dist/src/server-bootstrap/service-init.d.ts.map +1 -1
- package/dist/src/server-bootstrap/service-init.js +6 -0
- package/dist/src/server-bootstrap/service-init.js.map +1 -1
- package/dist/src/server.d.ts.map +1 -1
- package/dist/src/server.js +5 -0
- package/dist/src/server.js.map +1 -1
- package/dist/src/services/apps-backup-export.d.ts +22 -0
- package/dist/src/services/apps-backup-export.d.ts.map +1 -0
- package/dist/src/services/apps-backup-export.js +136 -0
- package/dist/src/services/apps-backup-export.js.map +1 -0
- package/dist/src/services/apps-backup-import.d.ts +120 -0
- package/dist/src/services/apps-backup-import.d.ts.map +1 -0
- package/dist/src/services/apps-backup-import.js +259 -0
- package/dist/src/services/apps-backup-import.js.map +1 -0
- package/dist/src/services/component-registrar.d.ts +17 -0
- package/dist/src/services/component-registrar.d.ts.map +1 -1
- package/dist/src/services/component-registrar.js +63 -5
- package/dist/src/services/component-registrar.js.map +1 -1
- package/dist/src/services/handbooks/agent.d.ts +1 -1
- package/dist/src/services/handbooks/agent.d.ts.map +1 -1
- package/dist/src/services/handbooks/agent.js +10 -0
- package/dist/src/services/handbooks/agent.js.map +1 -1
- package/dist/src/services/handbooks/appdev.d.ts +1 -1
- package/dist/src/services/handbooks/appdev.d.ts.map +1 -1
- package/dist/src/services/handbooks/appdev.js +5 -2
- package/dist/src/services/handbooks/appdev.js.map +1 -1
- package/dist/src/services/scheduler.d.ts +6 -0
- package/dist/src/services/scheduler.d.ts.map +1 -1
- package/dist/src/services/scheduler.js +22 -0
- package/dist/src/services/scheduler.js.map +1 -1
- package/dist/src/services/schema-validator.d.ts +9 -0
- package/dist/src/services/schema-validator.d.ts.map +1 -1
- package/dist/src/services/schema-validator.js +16 -0
- package/dist/src/services/schema-validator.js.map +1 -1
- package/dist/src/services/workflow/engine.d.ts +84 -0
- package/dist/src/services/workflow/engine.d.ts.map +1 -0
- package/dist/src/services/workflow/engine.js +545 -0
- package/dist/src/services/workflow/engine.js.map +1 -0
- package/dist/src/services/workflow/eval-context.d.ts +23 -0
- package/dist/src/services/workflow/eval-context.d.ts.map +1 -0
- package/dist/src/services/workflow/eval-context.js +52 -0
- package/dist/src/services/workflow/eval-context.js.map +1 -0
- package/dist/src/services/workflow/lifecycle.d.ts +38 -0
- package/dist/src/services/workflow/lifecycle.d.ts.map +1 -0
- package/dist/src/services/workflow/lifecycle.js +99 -0
- package/dist/src/services/workflow/lifecycle.js.map +1 -0
- package/dist/src/services/workflow/signal-eval.d.ts +70 -0
- package/dist/src/services/workflow/signal-eval.d.ts.map +1 -0
- package/dist/src/services/workflow/signal-eval.js +174 -0
- package/dist/src/services/workflow/signal-eval.js.map +1 -0
- package/dist/src/services/workflow/store.d.ts +89 -0
- package/dist/src/services/workflow/store.d.ts.map +1 -0
- package/dist/src/services/workflow/store.js +284 -0
- package/dist/src/services/workflow/store.js.map +1 -0
- package/dist/src/storage/interface.d.ts +13 -3
- 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 +10 -1
- package/dist/src/storage/providers/mongodb/index.d.ts.map +1 -1
- package/dist/src/storage/providers/mongodb/index.js +76 -0
- package/dist/src/storage/providers/mongodb/index.js.map +1 -1
- package/dist/src/storage/providers/sqlite/index.d.ts +8 -1
- package/dist/src/storage/providers/sqlite/index.d.ts.map +1 -1
- package/dist/src/storage/providers/sqlite/index.js +61 -0
- package/dist/src/storage/providers/sqlite/index.js.map +1 -1
- package/dist/src/storage/providers/sqlite/schema.d.ts.map +1 -1
- package/dist/src/storage/providers/sqlite/schema.js +11 -0
- package/dist/src/storage/providers/sqlite/schema.js.map +1 -1
- package/dist/src/storage/repositories/index.d.ts +1 -0
- package/dist/src/storage/repositories/index.d.ts.map +1 -1
- package/dist/src/storage/repositories/package.repository.d.ts +2 -0
- package/dist/src/storage/repositories/package.repository.d.ts.map +1 -1
- package/dist/src/storage/repositories/subdomain-site.repository.d.ts +19 -0
- package/dist/src/storage/repositories/subdomain-site.repository.d.ts.map +1 -0
- package/dist/src/storage/repositories/subdomain-site.repository.js +2 -0
- package/dist/src/storage/repositories/subdomain-site.repository.js.map +1 -0
- package/dist/static/app-catalog.html +1139 -28
- package/package.json +1 -1
- package/prisma/schema.postgres.prisma +11 -0
- package/prisma/schema.prisma +11 -0
|
@@ -1,31 +1,58 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @file shared-board.js
|
|
3
|
-
* @description Shared Agent Board
|
|
4
|
-
*
|
|
3
|
+
* @description Shared Agent Board ("radiator") — fleet state at a glance. Mini-cards per agent
|
|
4
|
+
* (name + status color + ONE essential figure), a status legend that doubles as filter pills,
|
|
5
|
+
* and issue-first sorting so a problem never drowns among healthy agents. Clicking a card
|
|
6
|
+
* expands the same agent in the management list below.
|
|
5
7
|
* @version-history
|
|
8
|
+
* v2.0.0 -- 2026-06-10 -- Glance optimization round: status legend = clickable filter pills
|
|
9
|
+
* (online/quiet/onboarding/issue) with counts; sort issues first, then onboarding, then the
|
|
10
|
+
* rest; cards slimmed to name + one figure (no "--" filler rows, tags line dropped — tags
|
|
11
|
+
* live in the list's filter bar and the shared-tags summary).
|
|
6
12
|
* v1.1.0 -- 2026-05-24 -- Fix: board card name colored by state, fix locale prefix
|
|
7
13
|
* v1.0.0 -- 2026-05-24 -- Initial creation for Agent Detail Tab-View
|
|
8
14
|
*/
|
|
9
15
|
|
|
10
16
|
import { h } from 'preact';
|
|
11
|
-
import { useMemo } from 'preact/hooks';
|
|
17
|
+
import { useMemo, useState } from 'preact/hooks';
|
|
12
18
|
import htm from 'htm';
|
|
13
19
|
import { t } from '/js/i18n.js';
|
|
14
20
|
import { detectAgentState, getStateColor } from './state-detector.js';
|
|
15
21
|
|
|
16
22
|
const html = htm.bind(h);
|
|
17
23
|
|
|
24
|
+
// Detailed states collapse into four glanceable buckets for the legend/filter.
|
|
25
|
+
const BUCKET_OF = { production: 'online', idle: 'quiet', new: 'onboarding', onboarding: 'onboarding', problem: 'issue' };
|
|
26
|
+
const BUCKET_RANK = { issue: 0, onboarding: 1, online: 2, quiet: 3 };
|
|
27
|
+
const BUCKETS = [
|
|
28
|
+
{ id: 'online', color: 'var(--success)', key: 'profile.agents.board.online' },
|
|
29
|
+
{ id: 'quiet', color: 'var(--text-muted)', key: 'profile.agents.board.quiet' },
|
|
30
|
+
{ id: 'onboarding', color: 'var(--warning)', key: 'profile.agents.board.onboarding' },
|
|
31
|
+
{ id: 'issue', color: 'var(--danger)', key: 'profile.agents.board.issue' },
|
|
32
|
+
];
|
|
33
|
+
|
|
18
34
|
export default function SharedBoard({ agents, onboardings, onAgentClick }) {
|
|
35
|
+
const [bucketFilter, setBucketFilter] = useState(null);
|
|
19
36
|
if (!agents || agents.length === 0) return null;
|
|
20
37
|
|
|
21
38
|
const agentStates = useMemo(() => {
|
|
22
|
-
|
|
23
|
-
agent,
|
|
24
|
-
state:
|
|
25
|
-
|
|
26
|
-
|
|
39
|
+
const rows = agents.map(agent => {
|
|
40
|
+
const state = detectAgentState(agent, onboardings?.[agent.name]);
|
|
41
|
+
return { agent, state, bucket: BUCKET_OF[state] || 'quiet', onboarding: onboardings?.[agent.name] };
|
|
42
|
+
});
|
|
43
|
+
// Problems first, onboarding second, then the rest — an issue must not drown.
|
|
44
|
+
rows.sort((a, b) => (BUCKET_RANK[a.bucket] ?? 9) - (BUCKET_RANK[b.bucket] ?? 9));
|
|
45
|
+
return rows;
|
|
27
46
|
}, [agents, onboardings]);
|
|
28
47
|
|
|
48
|
+
const counts = useMemo(() => {
|
|
49
|
+
const c = { online: 0, quiet: 0, onboarding: 0, issue: 0 };
|
|
50
|
+
for (const r of agentStates) c[r.bucket]++;
|
|
51
|
+
return c;
|
|
52
|
+
}, [agentStates]);
|
|
53
|
+
|
|
54
|
+
const shown = bucketFilter ? agentStates.filter(r => r.bucket === bucketFilter) : agentStates;
|
|
55
|
+
|
|
29
56
|
const allTags = useMemo(() => {
|
|
30
57
|
const tagCounts = {};
|
|
31
58
|
for (const { agent } of agentStates) {
|
|
@@ -38,8 +65,19 @@ export default function SharedBoard({ agents, onboardings, onAgentClick }) {
|
|
|
38
65
|
|
|
39
66
|
return html`
|
|
40
67
|
<div class="pf-agd-board">
|
|
68
|
+
<div class="pf-agd-board-legend">
|
|
69
|
+
${BUCKETS.map(b => html`
|
|
70
|
+
<button key=${b.id}
|
|
71
|
+
class="pf-agd-legend-pill ${bucketFilter === b.id ? 'pf-agd-legend-pill--active' : ''}"
|
|
72
|
+
disabled=${counts[b.id] === 0 && bucketFilter !== b.id}
|
|
73
|
+
onClick=${() => setBucketFilter(f => (f === b.id ? null : b.id))}>
|
|
74
|
+
<span class="pf-agd-legend-dot" style="background: ${b.color}"></span>
|
|
75
|
+
${t(b.key)} <span class="pf-agd-legend-count">${counts[b.id]}</span>
|
|
76
|
+
</button>
|
|
77
|
+
`)}
|
|
78
|
+
</div>
|
|
41
79
|
<div class="pf-agd-board-grid">
|
|
42
|
-
${
|
|
80
|
+
${shown.map(({ agent, state, onboarding }) => html`
|
|
43
81
|
<div
|
|
44
82
|
key=${agent.name}
|
|
45
83
|
class="pf-agd-board-card"
|
|
@@ -48,12 +86,7 @@ export default function SharedBoard({ agents, onboardings, onAgentClick }) {
|
|
|
48
86
|
>
|
|
49
87
|
<div class="pf-agd-board-card-name" style="color: ${getStateColor(state)}">${agent.display_name || agent.name}</div>
|
|
50
88
|
<div class="pf-agd-board-card-activity">
|
|
51
|
-
${
|
|
52
|
-
</div>
|
|
53
|
-
<div class="pf-agd-board-card-tags">
|
|
54
|
-
${(agent.tags ?? []).length > 0
|
|
55
|
-
? (agent.tags ?? []).join(', ')
|
|
56
|
-
: '--'}
|
|
89
|
+
${glanceFigure(state, agent, onboarding)}
|
|
57
90
|
</div>
|
|
58
91
|
</div>
|
|
59
92
|
`)}
|
|
@@ -69,22 +102,23 @@ export default function SharedBoard({ agents, onboardings, onAgentClick }) {
|
|
|
69
102
|
`;
|
|
70
103
|
}
|
|
71
104
|
|
|
72
|
-
|
|
105
|
+
// ONE essential figure per card — the radiator's job is fleet state at a glance,
|
|
106
|
+
// not prose. Onboarding → progress, problem → short word, otherwise last-seen age.
|
|
107
|
+
function glanceFigure(state, agent, onboarding) {
|
|
73
108
|
switch (state) {
|
|
74
109
|
case 'new':
|
|
75
|
-
return t('profile.agents.
|
|
110
|
+
return t('profile.agents.board.newShort');
|
|
76
111
|
case 'onboarding': {
|
|
77
112
|
const passed = onboarding?.steps?.filter(s => s.status === 'passed').length ?? 0;
|
|
78
113
|
const total = onboarding?.steps?.length ?? 11;
|
|
79
|
-
return `${
|
|
114
|
+
return `${passed}/${total}`;
|
|
80
115
|
}
|
|
81
116
|
case 'problem':
|
|
82
|
-
return t('profile.agents.
|
|
117
|
+
return t('profile.agents.board.issueShort');
|
|
83
118
|
case 'production':
|
|
119
|
+
case 'idle':
|
|
84
120
|
default:
|
|
85
|
-
return agent.last_seen
|
|
86
|
-
? `${t('profile.agents.detail.lastSeen')}: ${formatTimeAgo(agent.last_seen)}`
|
|
87
|
-
: t('profile.agents.detail.state.idle');
|
|
121
|
+
return agent.last_seen ? formatTimeAgo(agent.last_seen) : t('profile.agents.detail.state.idle');
|
|
88
122
|
}
|
|
89
123
|
}
|
|
90
124
|
|
|
@@ -3,6 +3,10 @@
|
|
|
3
3
|
* @description Enhanced Activity tab with governance filter and category badges.
|
|
4
4
|
* Wraps the existing activity subtab with additional filter pills.
|
|
5
5
|
* @version-history
|
|
6
|
+
* v1.6.0 -- 2026-06-10 -- Event log strictly newest-first (pages interleaved lifecycle events);
|
|
7
|
+
* "Tokens used (30d)" shows "—/not reported" when telemetry isn't wired (0 claimed no usage);
|
|
8
|
+
* delivery health shows a neutral "Delivery: polling" line when neither MCP nor webhook is
|
|
9
|
+
* configured (polling is a working method, not two missing ones).
|
|
6
10
|
* v1.5.0 -- 2026-05-28 -- Fix governance card: telemetry response field is `events` (not `entries`), and per-event tokens live in e.data.tokens_used / e.data.tokens_in+out
|
|
7
11
|
* v1.4.0 -- 2026-05-24 -- Audit fix: two-line event layout with secondary detail row
|
|
8
12
|
* v1.3.0 -- 2026-05-24 -- Wire up MCP status in delivery health from agent data
|
|
@@ -135,7 +139,12 @@ export default function TabActivity({ agent, agentName, session, showToast }) {
|
|
|
135
139
|
return html`<div class="pf-agd-empty">${t('profile.loading')}</div>`;
|
|
136
140
|
}
|
|
137
141
|
|
|
138
|
-
|
|
142
|
+
// Strict newest-first ordering — the backend pages can interleave lifecycle events
|
|
143
|
+
// (completed before progress, timestamps jumping 05:25 → 05:28 → 05:25 otherwise).
|
|
144
|
+
const sorted = [...events].sort((a, b) => String(b.timestamp || '').localeCompare(String(a.timestamp || '')));
|
|
145
|
+
const filtered = filter === 'all' ? sorted : sorted.filter(ev => eventCategory(ev) === filter);
|
|
146
|
+
// Telemetry not wired ≠ zero consumption — don't let "0" claim there was none.
|
|
147
|
+
const telemetryConnected = (governance?.telemetryCount || 0) > 0 || (stats?.tokensUsed30d || 0) > 0;
|
|
139
148
|
|
|
140
149
|
return html`
|
|
141
150
|
<div>
|
|
@@ -147,8 +156,8 @@ export default function TabActivity({ agent, agentName, session, showToast }) {
|
|
|
147
156
|
<div class="stat-card-label">${t('profile.agents.activity.tasksCompleted')}</div>
|
|
148
157
|
</div>
|
|
149
158
|
<div class="stat-card">
|
|
150
|
-
<div class="stat-card-value">${stats.tokensUsed30d ?? 0}</div>
|
|
151
|
-
<div class="stat-card-label">${t('profile.agents.activity.tokensUsed')}</div>
|
|
159
|
+
<div class="stat-card-value">${telemetryConnected ? (stats.tokensUsed30d ?? 0) : '—'}</div>
|
|
160
|
+
<div class="stat-card-label">${t('profile.agents.activity.tokensUsed')}${telemetryConnected ? '' : ` (${t('profile.agents.detail.activity.notReported') || 'not reported'})`}</div>
|
|
152
161
|
</div>
|
|
153
162
|
<div class="stat-card">
|
|
154
163
|
<div class="stat-card-value">${stats.successRate != null ? `${Math.round(stats.successRate)}%` : '-'}</div>
|
|
@@ -184,15 +193,18 @@ export default function TabActivity({ agent, agentName, session, showToast }) {
|
|
|
184
193
|
<div class="pf-agd-governance-delivery">
|
|
185
194
|
<span class="pf-agd-governance-label">${t('profile.agents.detail.activity.governance.deliveryHealth')}</span>
|
|
186
195
|
<span class="pf-agd-governance-value">
|
|
187
|
-
${governance.mcpActive
|
|
188
|
-
? html`<span class="pf-agd-status-dot pf-agd-status-dot--active"></span> ${t('profile.agents.detail.activity.
|
|
189
|
-
: html
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
+
${(!governance.mcpActive && !governance.webhookEnabled)
|
|
197
|
+
? html`<span class="pf-agd-status-dot ${agent?.last_seen && (Date.now() - new Date(agent.last_seen).getTime() < 24 * 3600 * 1000) ? 'pf-agd-status-dot--active' : 'pf-agd-status-dot--inactive'}"></span> ${t('profile.agents.detail.activity.deliveryPollingLine') || 'Delivery: polling'}`
|
|
198
|
+
: html`
|
|
199
|
+
${governance.mcpActive
|
|
200
|
+
? html`<span class="pf-agd-status-dot pf-agd-status-dot--active"></span> ${t('profile.agents.detail.activity.governance.mcpLabel')}: ${t('profile.agents.detail.activity.governance.connected')}`
|
|
201
|
+
: html`<span class="pf-agd-status-dot pf-agd-status-dot--inactive"></span> ${t('profile.agents.detail.activity.governance.mcpLabel')}: ${t('profile.agents.detail.activity.governance.notConfigured')}`
|
|
202
|
+
}
|
|
203
|
+
${' | '}
|
|
204
|
+
${governance.webhookEnabled
|
|
205
|
+
? `${t('profile.agents.webhook.title')}: ${governance.webhookSuccessCount}/${governance.webhookTotalCount}`
|
|
206
|
+
: t('profile.agents.detail.integration.webhookNotConfigured')
|
|
207
|
+
}`}
|
|
196
208
|
</span>
|
|
197
209
|
</div>
|
|
198
210
|
</div>
|
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
* v1.2.0 -- 2026-06-02 -- Component unification: route handleCopy through the shared
|
|
10
10
|
* copyToClipboard (/js/utils.js) instead of raw navigator.clipboard.writeText, so the
|
|
11
11
|
* insecure-context fallback applies; toast preserved (TIER 3, stays a handler)
|
|
12
|
+
* v1.3.0 -- 2026-06-10 -- AgentDangerZone at the tab bottom: typed-agent-name gate +
|
|
13
|
+
* the shared confirm — replaces the Delete button that sat on every tab's footer.
|
|
12
14
|
*/
|
|
13
15
|
|
|
14
16
|
import { h } from 'preact';
|
|
@@ -67,7 +69,33 @@ function ScheduleBudgetSection({ agent, agentName, showToast }) {
|
|
|
67
69
|
</div>`;
|
|
68
70
|
}
|
|
69
71
|
|
|
70
|
-
|
|
72
|
+
/** Danger zone — deleting the agent lives HERE (not on every tab's footer): a red-bordered box
|
|
73
|
+
* whose Delete needs the agent's name typed first; the final confirm dialog still applies. */
|
|
74
|
+
function AgentDangerZone({ agent, agentName, onDeleteClick }) {
|
|
75
|
+
const [open, setOpen] = useState(false);
|
|
76
|
+
const [typed, setTyped] = useState('');
|
|
77
|
+
if (!onDeleteClick) return null;
|
|
78
|
+
return html`
|
|
79
|
+
<div class="pj-danger pj-danger-box">
|
|
80
|
+
<div class="pj-danger-row">
|
|
81
|
+
<div class="pj-danger-text">
|
|
82
|
+
<div class="pj-danger-title">${t('profile.agents.detail.agent_config.deleteTitle') || 'Delete this agent'}</div>
|
|
83
|
+
<div class="pj-danger-sub">${t('profile.agents.detail.agent_config.deleteDesc') || 'Removes the agent, its credentials and its task history. This cannot be undone.'}</div>
|
|
84
|
+
</div>
|
|
85
|
+
<button class="btn-danger btn-sm" onClick=${() => { setOpen(o => !o); setTyped(''); }}>${t('profile.agents.deleteAgent')}…</button>
|
|
86
|
+
</div>
|
|
87
|
+
${open && html`
|
|
88
|
+
<div class="pj-danger-confirm">
|
|
89
|
+
<label class="pj-field"><span>${(t('profile.agents.detail.agent_config.deleteConfirmLabel') || 'Type the agent’s name to confirm') + ': ' + agentName}</span>
|
|
90
|
+
<input type="text" class="input-field input-sm" value=${typed} onInput=${(e) => setTyped(e.target.value)} placeholder=${agentName} /></label>
|
|
91
|
+
<button class="btn-danger btn-sm" disabled=${typed.trim() !== agentName}
|
|
92
|
+
onClick=${() => onDeleteClick(agent.name)}>${t('profile.agents.deleteAgent')}</button>
|
|
93
|
+
</div>
|
|
94
|
+
`}
|
|
95
|
+
</div>`;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export default function TabAgentConfig({ agent, agentName, session, showToast, onDeleteClick }) {
|
|
71
99
|
const [files, setFiles] = useState([]);
|
|
72
100
|
const [selectedFile, setSelectedFile] = useState(null);
|
|
73
101
|
const [preview, setPreview] = useState('');
|
|
@@ -197,6 +225,7 @@ export default function TabAgentConfig({ agent, agentName, session, showToast })
|
|
|
197
225
|
<input ref=${fileInputRef} type="file" accept=".md,.yaml,.yml,.json" class="pf-agd-hidden-input" onChange=${handleFileUpload} />
|
|
198
226
|
</div>
|
|
199
227
|
<div class="pf-agd-empty">${t('profile.agents.detail.empty.agent_config')}</div>
|
|
228
|
+
<${AgentDangerZone} agent=${agent} agentName=${agentName} onDeleteClick=${onDeleteClick} />
|
|
200
229
|
</div>
|
|
201
230
|
`;
|
|
202
231
|
}
|
|
@@ -248,6 +277,7 @@ export default function TabAgentConfig({ agent, agentName, session, showToast })
|
|
|
248
277
|
`}
|
|
249
278
|
</div>
|
|
250
279
|
`}
|
|
280
|
+
<${AgentDangerZone} agent=${agent} agentName=${agentName} onDeleteClick=${onDeleteClick} />
|
|
251
281
|
</div>
|
|
252
282
|
`;
|
|
253
283
|
}
|
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
* v1.3.0 -- 2026-05-31 -- Make Stored Memory Keys editable (inline textarea + Save) and deletable; make Memory Areas editable (key prefix / description / access) and deletable. Stored-key list now carries `version` for optimistic-lock PUTs. Delete confirmations use the shared useConfirm dialog.
|
|
10
10
|
* v1.4.0 -- 2026-05-31 -- Add "+ Add key" button + create form to Stored Memory Keys. New entries are created under the AGENT's GAII (createMemory passes agent.gaii), not the owner's GHII, so they belong to the agent being viewed.
|
|
11
11
|
* v1.5.0 -- 2026-05-31 -- Stored Memory Keys: show per-key created + last-updated timestamps (relative, full date on hover) and add a sort control (by updated or created, newest/oldest toggle). List now carries createdAt.
|
|
12
|
+
* v1.6.0 -- 2026-06-10 -- Empty sections compact to one row (title + "none" + Add button on the
|
|
13
|
+
* same line) — section order unchanged; a section grows when content arrives.
|
|
12
14
|
*/
|
|
13
15
|
|
|
14
16
|
import { h } from 'preact';
|
|
@@ -365,6 +367,7 @@ export default function TabDataAccess({ agent, agentName, session, showToast, al
|
|
|
365
367
|
<div class="pf-agd-data-section">
|
|
366
368
|
<div class="pf-agd-section-header">
|
|
367
369
|
<span class="pf-agd-section-title">${t('profile.agents.detail.data_access.sharedTagsTitle')}</span>
|
|
370
|
+
${tags.length === 0 && !addingTag && html`<span class="pf-agd-none-inline">${t('profile.agents.detail.data_access.noneInline') || 'none'}</span>`}
|
|
368
371
|
<button class="btn-outline btn-sm" onClick=${() => setAddingTag(!addingTag)}>+ ${t('profile.agents.detail.data_access.addTag')}</button>
|
|
369
372
|
</div>
|
|
370
373
|
${addingTag && html`
|
|
@@ -390,16 +393,14 @@ export default function TabDataAccess({ agent, agentName, session, showToast, al
|
|
|
390
393
|
</div>
|
|
391
394
|
`;
|
|
392
395
|
})}
|
|
393
|
-
${tags.length
|
|
394
|
-
<div class="pf-agd-empty">${t('profile.agents.detail.data_access.noTags')}</div>
|
|
395
|
-
`}
|
|
396
|
-
<div class="pf-agd-help-text">${t('profile.agents.detail.data_access.tagsHelp')}</div>
|
|
396
|
+
${(tags.length > 0 || addingTag) && html`<div class="pf-agd-help-text">${t('profile.agents.detail.data_access.tagsHelp')}</div>`}
|
|
397
397
|
</div>
|
|
398
398
|
|
|
399
399
|
<!-- MEMORY AREAS -->
|
|
400
400
|
<div class="pf-agd-data-section">
|
|
401
401
|
<div class="pf-agd-section-header">
|
|
402
402
|
<span class="pf-agd-section-title">${t('profile.agents.detail.data_access.memoryAreasTitle')}</span>
|
|
403
|
+
${!hasAreas && !addingArea && html`<span class="pf-agd-none-inline">${t('profile.agents.detail.data_access.noneInline') || 'none'}</span>`}
|
|
403
404
|
<button class="btn-outline btn-sm" onClick=${() => setAddingArea(!addingArea)}>+ ${t('profile.agents.detail.data_access.addArea')}</button>
|
|
404
405
|
</div>
|
|
405
406
|
${addingArea && html`
|
|
@@ -443,15 +444,14 @@ export default function TabDataAccess({ agent, agentName, session, showToast, al
|
|
|
443
444
|
</span>
|
|
444
445
|
</div>
|
|
445
446
|
`
|
|
446
|
-
)) :
|
|
447
|
-
<div class="pf-agd-empty">${t('profile.agents.detail.data_access.noAreas')}</div>
|
|
448
|
-
`}
|
|
447
|
+
)) : null}
|
|
449
448
|
</div>
|
|
450
449
|
|
|
451
450
|
<!-- KNOWLEDGE PACKAGES -->
|
|
452
451
|
<div class="pf-agd-data-section">
|
|
453
452
|
<div class="pf-agd-section-header">
|
|
454
453
|
<span class="pf-agd-section-title">${t('profile.agents.detail.data_access.knowledgeTitle')}</span>
|
|
454
|
+
${!hasResources && !addingPackage && html`<span class="pf-agd-none-inline">${t('profile.agents.detail.data_access.noneInline') || 'none'}</span>`}
|
|
455
455
|
<button class="btn-outline btn-sm" onClick=${() => setAddingPackage(!addingPackage)}>+ ${t('profile.agents.detail.data_access.linkPackage')}</button>
|
|
456
456
|
</div>
|
|
457
457
|
${addingPackage && html`
|
|
@@ -470,15 +470,14 @@ export default function TabDataAccess({ agent, agentName, session, showToast, al
|
|
|
470
470
|
<span class="pf-agd-area-desc">${res.description || ''}</span>
|
|
471
471
|
${(res.documentCount || res.count) ? html`<span class="pf-agd-package-count">${res.documentCount || res.count} ${t('profile.agents.detail.data_access.docCount')}</span>` : ''}
|
|
472
472
|
</div>
|
|
473
|
-
`) :
|
|
474
|
-
<div class="pf-agd-empty">${t('profile.agents.detail.data_access.noPackages')}</div>
|
|
475
|
-
`}
|
|
473
|
+
`) : null}
|
|
476
474
|
</div>
|
|
477
475
|
|
|
478
476
|
<!-- STORED MEMORY KEYS -->
|
|
479
477
|
<div class="pf-agd-data-section">
|
|
480
478
|
<div class="pf-agd-section-header">
|
|
481
479
|
<span class="pf-agd-section-title">${t('profile.agents.detail.data_access.storedKeysTitle')}</span>
|
|
480
|
+
${!hasKeys && !addingKey && html`<span class="pf-agd-none-inline">${t('profile.agents.detail.data_access.noneInline') || 'none'}</span>`}
|
|
482
481
|
<div class="pf-agd-keys-controls">
|
|
483
482
|
${hasKeys && html`
|
|
484
483
|
<label class="pf-agd-sort-label">${t('profile.agents.detail.data_access.sortBy')}</label>
|
|
@@ -515,9 +514,6 @@ export default function TabDataAccess({ agent, agentName, session, showToast, al
|
|
|
515
514
|
</div>
|
|
516
515
|
</div>
|
|
517
516
|
`}
|
|
518
|
-
${memoryKeys.length === 0 && !addingKey && html`
|
|
519
|
-
<div class="pf-agd-empty">${t('profile.agents.detail.data_access.noKeys')}</div>
|
|
520
|
-
`}
|
|
521
517
|
${sortedKeys.map(mk => html`
|
|
522
518
|
<div key=${mk.key}>
|
|
523
519
|
<div class="pf-agd-area-row pf-agd-area-row--clickable" onClick=${() => toggleExpandKey(mk)}>
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
* during onboarding or production status (connection, platform, readiness,
|
|
5
5
|
* identity, delivery log) after completion.
|
|
6
6
|
* @version-history
|
|
7
|
+
* v1.7.0 -- 2026-06-10 -- Webhook fields (URL, fail count, Test/Edit) hidden while delivery
|
|
8
|
+
* is polling; a "+ Set up webhook" reveal opens the URL form for switching methods.
|
|
7
9
|
* v1.6.0 -- 2026-06-02 -- Component unification (#1): the 3 copy buttons (agent prompt,
|
|
8
10
|
* install command, curl) now use the canonical <CopyButton> with precomputed text
|
|
9
11
|
* payloads -- dropped 3 copied-state useState hooks, 3 hand-rolled handlers, the
|
|
@@ -302,7 +304,7 @@ function renderProductionView(agent, onboarding, webhook, bundleVersion, display
|
|
|
302
304
|
${(webhook && webhook.url) ? t('profile.agents.detail.deliveryWebhook') : t('profile.agents.detail.deliveryPolling')}
|
|
303
305
|
</span>
|
|
304
306
|
</div>
|
|
305
|
-
${webhook ? html`
|
|
307
|
+
${(webhook && webhook.url) ? html`
|
|
306
308
|
<div class="pf-agd-info-row">
|
|
307
309
|
<span class="pf-agd-info-label">${t('profile.agents.webhook.url')}</span>
|
|
308
310
|
<span class="pf-agd-info-value">${webhook.url || '--'}</span>
|
|
@@ -341,10 +343,34 @@ function renderProductionView(agent, onboarding, webhook, bundleVersion, display
|
|
|
341
343
|
</div>
|
|
342
344
|
`}
|
|
343
345
|
` : html`
|
|
346
|
+
<!-- Polling is the active method: webhook plumbing stays hidden until the owner
|
|
347
|
+
chooses to switch (the "+ Set up webhook" reveal). -->
|
|
344
348
|
<div class="pf-agd-info-row">
|
|
345
349
|
<span class="pf-agd-info-label">${t('profile.agents.detail.integration.pollingInterval')}</span>
|
|
346
350
|
<span class="pf-agd-info-value">${agent.pollingInterval || agent.polling_interval || '60s'}</span>
|
|
347
351
|
</div>
|
|
352
|
+
${editingWebhook ? html`
|
|
353
|
+
<div class="pf-agd-webhook-form">
|
|
354
|
+
<input
|
|
355
|
+
type="url"
|
|
356
|
+
value=${webhookDraft}
|
|
357
|
+
onInput=${e => setWebhookDraft(e.target.value)}
|
|
358
|
+
placeholder="https://..."
|
|
359
|
+
/>
|
|
360
|
+
<button class="btn-primary btn-sm" onClick=${handleSaveWebhook} disabled=${savingWebhook}>
|
|
361
|
+
${savingWebhook ? '...' : t('common.save')}
|
|
362
|
+
</button>
|
|
363
|
+
<button class="btn-outline btn-sm" onClick=${handleCancelWebhook}>
|
|
364
|
+
${t('common.cancel')}
|
|
365
|
+
</button>
|
|
366
|
+
</div>
|
|
367
|
+
` : html`
|
|
368
|
+
<div class="pf-agd-form-actions">
|
|
369
|
+
<button class="btn-ghost btn-sm" onClick=${handleEditWebhook}>
|
|
370
|
+
+ ${t('profile.agents.detail.integration.setupWebhook') || 'Set up webhook'}
|
|
371
|
+
</button>
|
|
372
|
+
</div>
|
|
373
|
+
`}
|
|
348
374
|
`}
|
|
349
375
|
<div class="pf-agd-info-row">
|
|
350
376
|
<span class="pf-agd-info-label">${t('profile.agents.detail.lastSeen')}</span>
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
* @description Messages tab with command palette, "/" autocomplete, and chat area.
|
|
4
4
|
* Wraps the existing messages subtab and adds command discovery.
|
|
5
5
|
* @version-history
|
|
6
|
+
* v1.6.0 -- 2026-06-10 -- Empty command palette is one quiet line ("Agent commands — none
|
|
7
|
+
* registered"), not an expandable empty box.
|
|
6
8
|
* v1.5.0 -- 2026-06-06 -- Thread buttons: fix field-name mismatch (use threadId/lastMessage from the
|
|
7
9
|
* API, not the non-existent id/title/preview) so selecting a thread actually filters and each
|
|
8
10
|
* button shows a real label. Label task-based threads by their task title, snippet others; collapse
|
|
@@ -46,18 +48,11 @@ function CommandPalette({ commands, onSend }) {
|
|
|
46
48
|
const [expanded, setExpanded] = useState(false);
|
|
47
49
|
|
|
48
50
|
if (!commands || commands.length === 0) {
|
|
51
|
+
// No registered commands → one quiet line, not an expandable empty box.
|
|
49
52
|
return html`
|
|
50
|
-
<div class="pf-agd-commands">
|
|
51
|
-
<
|
|
52
|
-
|
|
53
|
-
<span>${expanded ? '▼' : '▶'}</span>
|
|
54
|
-
</div>
|
|
55
|
-
${expanded && html`
|
|
56
|
-
<div class="pf-agd-commands-body">
|
|
57
|
-
<div class="pf-agd-empty">${t('profile.agents.detail.messages.commands.noCommands')}</div>
|
|
58
|
-
<div class="pf-agd-empty-hint">${t('profile.agents.detail.messages.commands.noCommandsHint')}</div>
|
|
59
|
-
</div>
|
|
60
|
-
`}
|
|
53
|
+
<div class="pf-agd-commands pf-agd-commands--empty" title=${t('profile.agents.detail.messages.commands.noCommandsHint')}>
|
|
54
|
+
<span>${t('profile.agents.detail.messages.commands.title')}</span>
|
|
55
|
+
<span class="pf-agd-none-inline">${t('profile.agents.detail.messages.commands.noCommands')}</span>
|
|
61
56
|
</div>
|
|
62
57
|
`;
|
|
63
58
|
}
|
|
@@ -10,6 +10,9 @@
|
|
|
10
10
|
* @structure default export TabQuality({ agentName })
|
|
11
11
|
* @usage rendered by agent-card.js renderTabContent() for the 'quality' tab
|
|
12
12
|
* @version-history
|
|
13
|
+
* v1.3.0 -- 2026-06-10 -- Deliverable rows show date+time (identical titles must be
|
|
14
|
+
* tellable apart) and unrated rows rate via INLINE stars (click submits immediately);
|
|
15
|
+
* the modal remains for re-rates (context/comment).
|
|
13
16
|
* v1.2.0 -- 2026-06-01 -- Stop the empty flash on refresh: only show the loading
|
|
14
17
|
* state on first load; live-update refetches swap data in place (and keep the
|
|
15
18
|
* last good data on a transient error) instead of blanking the tab.
|
|
@@ -45,6 +48,29 @@ function fmtSeconds(secs) {
|
|
|
45
48
|
return `${Number(secs || 0).toLocaleString()}${t('profile.agents.detail.quality.seconds')}`;
|
|
46
49
|
}
|
|
47
50
|
|
|
51
|
+
/** Date + time for a deliverable row — four identical "Iltakirjoitus" rows must be tellable apart. */
|
|
52
|
+
function fmtWhen(s) {
|
|
53
|
+
if (!s) return '';
|
|
54
|
+
const d = new Date(s);
|
|
55
|
+
if (!Number.isFinite(d.getTime())) return '';
|
|
56
|
+
return d.toLocaleString(undefined, { day: 'numeric', month: 'numeric', hour: '2-digit', minute: '2-digit' });
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** Inline 1–5 star picker — hovering previews, clicking submits right in the row (no modal hop).
|
|
60
|
+
* The full modal stays available for re-rates (context/comment edits). */
|
|
61
|
+
function InlineStars({ onPick, disabled }) {
|
|
62
|
+
const [hover, setHover] = useState(0);
|
|
63
|
+
return html`
|
|
64
|
+
<span class="pf-agd-inline-stars" role="radiogroup" onMouseLeave=${() => setHover(0)}>
|
|
65
|
+
${[1, 2, 3, 4, 5].map(n => html`
|
|
66
|
+
<button key=${n} class="pf-agd-inline-star ${n <= hover ? 'pf-agd-inline-star--hot' : ''}"
|
|
67
|
+
disabled=${disabled} aria-label=${String(n)}
|
|
68
|
+
onMouseEnter=${() => setHover(n)}
|
|
69
|
+
onClick=${() => onPick(n)}>★</button>
|
|
70
|
+
`)}
|
|
71
|
+
</span>`;
|
|
72
|
+
}
|
|
73
|
+
|
|
48
74
|
export default function TabQuality({ agentName, showToast }) {
|
|
49
75
|
const [data, setData] = useState(null);
|
|
50
76
|
const [loading, setLoading] = useState(true);
|
|
@@ -82,6 +108,20 @@ export default function TabQuality({ agentName, showToast }) {
|
|
|
82
108
|
setSendingRate(false);
|
|
83
109
|
}
|
|
84
110
|
|
|
111
|
+
// Inline star click — submit immediately with the task's context (or 'other'); the modal
|
|
112
|
+
// remains the path for context/comment edits via re-rate.
|
|
113
|
+
async function handleInlineRate(task, stars) {
|
|
114
|
+
setSendingRate(true);
|
|
115
|
+
try {
|
|
116
|
+
await rateTask(agentName, task.id, { stars, context: task.context || 'other', source_grounded: false });
|
|
117
|
+
showToast?.(t('profile.agents.tasks.rate.success'));
|
|
118
|
+
await loadData();
|
|
119
|
+
} catch (err) {
|
|
120
|
+
showToast?.(err.message || t('profile.agents.tasks.rate.error'), true);
|
|
121
|
+
}
|
|
122
|
+
setSendingRate(false);
|
|
123
|
+
}
|
|
124
|
+
|
|
85
125
|
useEffect(() => { loadData(); }, [agentName]);
|
|
86
126
|
|
|
87
127
|
// Live updates: refresh when a rating lands or tasks change.
|
|
@@ -180,12 +220,12 @@ export default function TabQuality({ agentName, showToast }) {
|
|
|
180
220
|
${[...doneTasks].sort((a, b) => (a.rating ? 1 : 0) - (b.rating ? 1 : 0)).map(task => html`
|
|
181
221
|
<div key=${task.id} class="pf-agd-quality-pending-row">
|
|
182
222
|
<span class="pf-agd-quality-pending-title">${task.title || task.id}</span>
|
|
223
|
+
<span class="pf-agd-quality-pending-when" title=${task.completedAt || ''}>${fmtWhen(task.completedAt || task.updatedAt)}</span>
|
|
183
224
|
${task.rating
|
|
184
|
-
? html
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
</button>
|
|
225
|
+
? html`
|
|
226
|
+
<span class="pf-agd-quality-pending-rated">${starGlyphs(task.rating.stars)} ${ctxLabel(task.rating.context)}</span>
|
|
227
|
+
<button class="btn-ghost btn-sm" onClick=${() => setRateTarget(task)}>${t('profile.agents.tasks.rate.rerate')}</button>`
|
|
228
|
+
: html`<${InlineStars} onPick=${(n) => handleInlineRate(task, n)} disabled=${sendingRate} />`}
|
|
189
229
|
</div>
|
|
190
230
|
`)}
|
|
191
231
|
</div>
|
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
* v1.1.0 -- 2026-03-18 -- Rewrite agent prompt to use device-auth flow; remove connectivity key UI
|
|
9
9
|
* v1.2.0 -- 2026-03-19 -- Replace profile-initiated device auth with inline pending request approval
|
|
10
10
|
* v1.3.0 -- 2026-05-21 -- Shorten agent prompt to delegate to tier1; add Download/Copy Instructions buttons
|
|
11
|
+
* v1.x — 2026-06-10 — External deep-link entry: sessionStorage `aimeat.agents.open` (set by the
|
|
12
|
+
* home dashboard's Agents card) expands that agent's card on mount and scrolls it into view.
|
|
11
13
|
* v1.4.0 -- 2026-05-21 -- Add sub-tab navigation (Tasks, Directives) in expanded agent detail view
|
|
12
14
|
* v1.5.0 -- 2026-05-22 -- Add Capabilities sub-tab with technical/domain skill display
|
|
13
15
|
* v1.6.0 -- 2026-06-02 -- Component unification (#2): scope modal uses the canonical
|
|
@@ -35,6 +37,11 @@
|
|
|
35
37
|
* (connect command, MCP onboarding, manual agent prompt, task-runner prompt) with the
|
|
36
38
|
* canonical <CopyButton> (className="copy-prompt-btn" preserves appearance); removed the
|
|
37
39
|
* now-dead copiedAction state + markCopied helper.
|
|
40
|
+
* v3.8.0 -- 2026-06-10 -- "Group by: Tag" becomes the default once any agent carries tags
|
|
41
|
+
* (never overrides a user-picked grouping); unseen-change tracking drops memory churn and
|
|
42
|
+
* adds a failed-tasks query so the badge can go red ONLY for unseen failures (tasksFailed);
|
|
43
|
+
* marking the Tasks tab seen also acknowledges failures. External deep-link entry
|
|
44
|
+
* (aimeat.agents.open) from the home dashboard retained from earlier same-day round.
|
|
38
45
|
* v3.7.0 -- 2026-06-09 -- Custom agent groups: new "Custom groups" group-by mode with
|
|
39
46
|
* user-created, drag-to-assign sections (definitions in AIMEAT memory via
|
|
40
47
|
* getAgentGroups/saveAgentGroups) and per-browser collapse/expand state
|
|
@@ -491,6 +498,11 @@ export default function AgentsTab({ session, showToast, onStats }) {
|
|
|
491
498
|
const [changesMap, setChangesMap] = useState({});
|
|
492
499
|
const [tagFilter, setTagFilter] = useState(new Set());
|
|
493
500
|
const [groupBy, setGroupBy] = useState('none'); // 'none' | 'tag' | 'mode' | 'custom'
|
|
501
|
+
// "Group by: Tag" becomes the default once the user actually uses tags — but never
|
|
502
|
+
// override a grouping the user picked themselves (or re-apply after they change it).
|
|
503
|
+
const userPickedGroupBy = useRef(false);
|
|
504
|
+
const groupByDefaultApplied = useRef(false);
|
|
505
|
+
const pickGroupBy = (v) => { userPickedGroupBy.current = true; setGroupBy(v); };
|
|
494
506
|
// Per-browser drag-to-reorder of the agent bars (localStorage-backed).
|
|
495
507
|
const [agentOrder, setAgentOrder] = useState(() => loadAgentOrder(session?.owner));
|
|
496
508
|
const [draggingName, setDraggingName] = useState(null);
|
|
@@ -603,7 +615,9 @@ export default function AgentsTab({ session, showToast, onStats }) {
|
|
|
603
615
|
setChangesMap(prev => {
|
|
604
616
|
const cur = prev[agentName];
|
|
605
617
|
if (!cur || !cur[tab]) return prev;
|
|
606
|
-
|
|
618
|
+
const next = { ...cur, [tab]: 0 };
|
|
619
|
+
if (tab === 'tasks') next.tasksFailed = 0; // seen = acknowledged, incl. failures
|
|
620
|
+
return { ...prev, [agentName]: next };
|
|
607
621
|
});
|
|
608
622
|
};
|
|
609
623
|
|
|
@@ -631,6 +645,10 @@ export default function AgentsTab({ session, showToast, onStats }) {
|
|
|
631
645
|
const list = await listAgents(session.owner);
|
|
632
646
|
setAgents(list);
|
|
633
647
|
onStats?.({ agents: list.length });
|
|
648
|
+
if (!groupByDefaultApplied.current && !userPickedGroupBy.current && list.some(a => (a.tags ?? []).length > 0)) {
|
|
649
|
+
groupByDefaultApplied.current = true;
|
|
650
|
+
setGroupBy('tag');
|
|
651
|
+
}
|
|
634
652
|
const obMap = {};
|
|
635
653
|
await Promise.all(list.map(async (a) => {
|
|
636
654
|
try {
|
|
@@ -646,11 +664,11 @@ export default function AgentsTab({ session, showToast, onStats }) {
|
|
|
646
664
|
const chMap = {};
|
|
647
665
|
await Promise.all(list.map(async (a) => {
|
|
648
666
|
try {
|
|
649
|
-
const [doneResp, activeResp, msgResp,
|
|
667
|
+
const [doneResp, activeResp, msgResp, failedResp] = await Promise.all([
|
|
650
668
|
listTasks(a.name, { status: 'done', per_page: 100 }),
|
|
651
669
|
listTasks(a.name, { status: 'active', per_page: 100 }),
|
|
652
670
|
listMessages(a.name, { perPage: 100 }).catch(() => null),
|
|
653
|
-
|
|
671
|
+
listTasks(a.name, { status: 'failed', per_page: 50 }).catch(() => null),
|
|
654
672
|
]);
|
|
655
673
|
const today = new Date().toISOString().slice(0, 10);
|
|
656
674
|
const doneTasks = doneResp?.data?.tasks || [];
|
|
@@ -665,16 +683,19 @@ export default function AgentsTab({ session, showToast, onStats }) {
|
|
|
665
683
|
const agentSeen = seen[a.name] || (seen[a.name] = {});
|
|
666
684
|
const nowIso = new Date().toISOString();
|
|
667
685
|
const ch = {};
|
|
686
|
+
const failedTasks = failedResp?.data?.tasks || [];
|
|
668
687
|
for (const [tab, items, fields] of [
|
|
669
|
-
|
|
688
|
+
// Tasks badge counts new completions + new failures (the "needs a look" set).
|
|
689
|
+
['tasks', [...doneTasks, ...activeTasks, ...failedTasks], ['updatedAt', 'completedAt', 'createdAt']],
|
|
670
690
|
// Only count agent→owner messages as unread; the owner's own
|
|
671
691
|
// inbound messages are not "new" to them.
|
|
672
692
|
['messages', (msgResp?.data?.messages || []).filter(m => m.direction !== 'inbound'), ['createdAt', 'created_at']],
|
|
673
|
-
['memory', (memResp?.data?.items || memResp?.data || []), ['updated_at', 'updatedAt', 'created_at', 'createdAt']],
|
|
674
693
|
]) {
|
|
675
694
|
if (agentSeen[tab] === undefined) { agentSeen[tab] = nowIso; seenSeeded = true; ch[tab] = 0; }
|
|
676
695
|
else ch[tab] = countNewer(items, agentSeen[tab], fields);
|
|
677
696
|
}
|
|
697
|
+
// Red badge is reserved for unseen FAILED tasks; everything else stays neutral.
|
|
698
|
+
ch.tasksFailed = agentSeen.tasks === nowIso ? 0 : countNewer(failedTasks, agentSeen.tasks, ['updatedAt', 'completedAt', 'createdAt']);
|
|
678
699
|
chMap[a.name] = ch;
|
|
679
700
|
} catch { tsMap[a.name] = null; chMap[a.name] = null; atsMap[a.name] = []; }
|
|
680
701
|
}));
|
|
@@ -713,6 +734,20 @@ export default function AgentsTab({ session, showToast, onStats }) {
|
|
|
713
734
|
setExpandedAgent(prev => prev === name ? null : name);
|
|
714
735
|
}
|
|
715
736
|
|
|
737
|
+
// External deep-link: the home dashboard's Agents card primes `aimeat.agents.open` with an
|
|
738
|
+
// agent name before opening this tab — expand that agent and scroll its card into view.
|
|
739
|
+
useEffect(() => {
|
|
740
|
+
try {
|
|
741
|
+
const name = sessionStorage.getItem('aimeat.agents.open');
|
|
742
|
+
if (!name) return;
|
|
743
|
+
sessionStorage.removeItem('aimeat.agents.open');
|
|
744
|
+
setExpandedAgent(name);
|
|
745
|
+
setTimeout(() => {
|
|
746
|
+
document.querySelector(`[data-agent-name="${name}"]`)?.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
|
747
|
+
}, 500);
|
|
748
|
+
} catch { /* noop */ }
|
|
749
|
+
}, []);
|
|
750
|
+
|
|
716
751
|
// Running-now panel → open a specific agent's Tasks tab on a specific task.
|
|
717
752
|
// Expand the agent, record the deep-link (nonce bump re-fires repeat clicks),
|
|
718
753
|
// and scroll the agent's card into view.
|
|
@@ -973,7 +1008,7 @@ export default function AgentsTab({ session, showToast, onStats }) {
|
|
|
973
1008
|
agents=${agents}
|
|
974
1009
|
onOpen=${openAgentTask}
|
|
975
1010
|
/>
|
|
976
|
-
${renderFilterBar(agents, tagFilter, setTagFilter, groupBy,
|
|
1011
|
+
${renderFilterBar(agents, tagFilter, setTagFilter, groupBy, pickGroupBy)}
|
|
977
1012
|
${renderAgentGroups({
|
|
978
1013
|
agents,
|
|
979
1014
|
tagFilter,
|