aimeat 1.24.0 → 1.24.1
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 +9 -1
- package/dist/locales/fi.json +9 -1
- package/dist/public/css/views/profile.css +21 -0
- package/dist/public/css/views/workflows.css +6 -1
- package/dist/public/js/services/organisms.js +18 -0
- package/dist/public/js/services/workflows.js +5 -0
- package/dist/public/views/profile/organisms-tab.js +51 -0
- package/dist/public/views/profile/workflows-tab.js +67 -11
- package/dist/src/generated/api-types.d.ts +286 -1
- package/dist/src/generated/api-types.d.ts.map +1 -1
- package/dist/src/mcp/annotations.d.ts.map +1 -1
- package/dist/src/mcp/annotations.js +2 -0
- package/dist/src/mcp/annotations.js.map +1 -1
- package/dist/src/mcp/catalog/definitions.d.ts.map +1 -1
- package/dist/src/mcp/catalog/definitions.js +17 -0
- 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/workspaces.d.ts +3 -0
- package/dist/src/mcp/workspaces.d.ts.map +1 -1
- package/dist/src/mcp/workspaces.js +17 -0
- package/dist/src/mcp/workspaces.js.map +1 -1
- package/dist/src/models/agent-onboarding-schemas.d.ts +1 -1
- package/dist/src/models/agent-onboarding-schemas.d.ts.map +1 -1
- package/dist/src/models/agent-onboarding-schemas.js +12 -0
- package/dist/src/models/agent-onboarding-schemas.js.map +1 -1
- package/dist/src/models/offer-schemas.d.ts +2 -2
- package/dist/src/models/offer-schemas.d.ts.map +1 -1
- package/dist/src/models/offer-schemas.js +3 -1
- package/dist/src/models/offer-schemas.js.map +1 -1
- package/dist/src/models/workflow-schemas.d.ts +1 -1
- package/dist/src/models/workflow-schemas.d.ts.map +1 -1
- package/dist/src/routes/agent-skill-bundle.d.ts +1 -0
- package/dist/src/routes/agent-skill-bundle.d.ts.map +1 -1
- package/dist/src/routes/agent-skill-bundle.js +3 -2
- package/dist/src/routes/agent-skill-bundle.js.map +1 -1
- package/dist/src/routes/memory.d.ts.map +1 -1
- package/dist/src/routes/memory.js +4 -21
- package/dist/src/routes/memory.js.map +1 -1
- package/dist/src/routes/organisms.d.ts +4 -0
- package/dist/src/routes/organisms.d.ts.map +1 -1
- package/dist/src/routes/organisms.js +76 -0
- package/dist/src/routes/organisms.js.map +1 -1
- package/dist/src/routes/prompts.d.ts +4 -0
- package/dist/src/routes/prompts.d.ts.map +1 -1
- package/dist/src/routes/prompts.js +50 -0
- package/dist/src/routes/prompts.js.map +1 -1
- package/dist/src/routes/workflows.d.ts.map +1 -1
- package/dist/src/routes/workflows.js +12 -0
- package/dist/src/routes/workflows.js.map +1 -1
- package/dist/src/services/apps-backup-export.d.ts.map +1 -1
- package/dist/src/services/apps-backup-export.js +3 -2
- package/dist/src/services/apps-backup-export.js.map +1 -1
- package/dist/src/services/draft-offer-prompt.d.ts +19 -0
- package/dist/src/services/draft-offer-prompt.d.ts.map +1 -0
- package/dist/src/services/draft-offer-prompt.js +80 -0
- package/dist/src/services/draft-offer-prompt.js.map +1 -0
- package/dist/src/services/handbooks/agent.d.ts +6 -1
- package/dist/src/services/handbooks/agent.d.ts.map +1 -1
- package/dist/src/services/handbooks/agent.js +19 -0
- package/dist/src/services/handbooks/agent.js.map +1 -1
- package/dist/src/services/offerings-handbook.d.ts +17 -0
- package/dist/src/services/offerings-handbook.d.ts.map +1 -0
- package/dist/src/services/offerings-handbook.js +75 -0
- package/dist/src/services/offerings-handbook.js.map +1 -0
- package/dist/src/services/onboarding-validator.d.ts.map +1 -1
- package/dist/src/services/onboarding-validator.js +73 -0
- package/dist/src/services/onboarding-validator.js.map +1 -1
- package/dist/src/services/organism-export.d.ts.map +1 -1
- package/dist/src/services/organism-export.js +3 -2
- package/dist/src/services/organism-export.js.map +1 -1
- package/dist/src/services/owner-memory.d.ts +32 -0
- package/dist/src/services/owner-memory.d.ts.map +1 -0
- package/dist/src/services/owner-memory.js +37 -0
- package/dist/src/services/owner-memory.js.map +1 -0
- package/dist/src/services/package-zip.d.ts +1 -0
- package/dist/src/services/package-zip.d.ts.map +1 -1
- package/dist/src/services/package-zip.js +3 -2
- package/dist/src/services/package-zip.js.map +1 -1
- package/dist/src/services/structure-overview.d.ts +87 -0
- package/dist/src/services/structure-overview.d.ts.map +1 -0
- package/dist/src/services/structure-overview.js +234 -0
- package/dist/src/services/structure-overview.js.map +1 -0
- package/dist/src/services/workflow/engine.d.ts +7 -0
- package/dist/src/services/workflow/engine.d.ts.map +1 -1
- package/dist/src/services/workflow/engine.js +29 -0
- package/dist/src/services/workflow/engine.js.map +1 -1
- package/dist/src/services/workflow/eval-context.d.ts +5 -1
- package/dist/src/services/workflow/eval-context.d.ts.map +1 -1
- package/dist/src/services/workflow/eval-context.js +8 -2
- package/dist/src/services/workflow/eval-context.js.map +1 -1
- package/dist/src/services/workspace-export.d.ts.map +1 -1
- package/dist/src/services/workspace-export.js +3 -2
- package/dist/src/services/workspace-export.js.map +1 -1
- package/package.json +27 -28
package/dist/locales/en.json
CHANGED
|
@@ -45,6 +45,8 @@
|
|
|
45
45
|
"profile.workflows.form.cancel": "Cancel",
|
|
46
46
|
"profile.workflows.form.save": "Save",
|
|
47
47
|
"profile.workflows.form.saved": "Workflow saved",
|
|
48
|
+
"profile.workflows.cancelRun": "Cancel run",
|
|
49
|
+
"profile.workflows.cancelled": "Run cancelled",
|
|
48
50
|
"profile.tabs.scheduler": "Scheduler",
|
|
49
51
|
"profile.agents.detail.tabs.schedules": "Schedules",
|
|
50
52
|
"profile.scheduler.title": "Scheduler",
|
|
@@ -5897,6 +5899,9 @@
|
|
|
5897
5899
|
"moreActions": "More actions",
|
|
5898
5900
|
"policyLabel": "Join policy",
|
|
5899
5901
|
"tabWorkspaces": "Workspaces",
|
|
5902
|
+
"structureOverviewOrg": "Organism structure overview",
|
|
5903
|
+
"structureOverviewWs": "Workspace structure overview",
|
|
5904
|
+
"structEmpty": "No structure to show yet.",
|
|
5900
5905
|
"tabMembers": "Members",
|
|
5901
5906
|
"tabAgents": "Agents",
|
|
5902
5907
|
"tabBoard": "Board",
|
|
@@ -6402,7 +6407,10 @@
|
|
|
6402
6407
|
"complete_test_task": "Agent executes and completes the test task",
|
|
6403
6408
|
"publish_commands": "agents.{name}.commands memory has a non-empty array of { name, description, category }",
|
|
6404
6409
|
"publish_config": "At least one agents.config.{name}.* memory entry exists describing this runtime",
|
|
6405
|
-
"declare_services": "Agent declares offered services (optional)"
|
|
6410
|
+
"declare_services": "Agent declares offered services (optional)",
|
|
6411
|
+
"declare_offerings": "Agent publishes at least one offer (id + title + ask) to agents.{name}.offers so the owner can find what it does (optional)",
|
|
6412
|
+
"make_workflow_compatible": "At least one offer declares success_signal + required_to_function + deliverable.location, so it can be a step in an Agent Workflow (optional)",
|
|
6413
|
+
"price_offer": "At least one offer is sellable cross-owner: price + visibility public + a callable binding (optional)"
|
|
6406
6414
|
},
|
|
6407
6415
|
"errors": {
|
|
6408
6416
|
"accessDenied": "Access denied",
|
package/dist/locales/fi.json
CHANGED
|
@@ -45,6 +45,8 @@
|
|
|
45
45
|
"profile.workflows.form.cancel": "Peruuta",
|
|
46
46
|
"profile.workflows.form.save": "Tallenna",
|
|
47
47
|
"profile.workflows.form.saved": "Työnkulku tallennettu",
|
|
48
|
+
"profile.workflows.cancelRun": "Keskeytä ajo",
|
|
49
|
+
"profile.workflows.cancelled": "Ajo keskeytetty",
|
|
48
50
|
"profile.tabs.scheduler": "Ajastin",
|
|
49
51
|
"profile.agents.detail.tabs.schedules": "Ajastukset",
|
|
50
52
|
"profile.scheduler.title": "Ajastin",
|
|
@@ -5897,6 +5899,9 @@
|
|
|
5897
5899
|
"moreActions": "Lisätoiminnot",
|
|
5898
5900
|
"policyLabel": "Liittymiskäytäntö",
|
|
5899
5901
|
"tabWorkspaces": "Työtilat",
|
|
5902
|
+
"structureOverviewOrg": "Organismin rakenteen yleiskuva",
|
|
5903
|
+
"structureOverviewWs": "Työtilan rakenteen yleiskuva",
|
|
5904
|
+
"structEmpty": "Ei vielä rakennetta näytettäväksi.",
|
|
5900
5905
|
"tabMembers": "Jäsenet",
|
|
5901
5906
|
"tabAgents": "Agentit",
|
|
5902
5907
|
"tabBoard": "Taulu",
|
|
@@ -6402,7 +6407,10 @@
|
|
|
6402
6407
|
"complete_test_task": "Agentti suorittaa ja viimeistelee testitehtävän",
|
|
6403
6408
|
"publish_commands": "agents.{name}.commands -muistissa on epätyhjä { name, description, category } -taulu",
|
|
6404
6409
|
"publish_config": "Vähintään yksi agents.config.{name}.* -muistitietue kuvaa tätä runtimea",
|
|
6405
|
-
"declare_services": "Agentti ilmoittaa tarjoamansa palvelut (valinnainen)"
|
|
6410
|
+
"declare_services": "Agentti ilmoittaa tarjoamansa palvelut (valinnainen)",
|
|
6411
|
+
"declare_offerings": "Agentti julkaisee vähintään yhden tarjouksen (id + title + ask) avaimeen agents.{name}.offers, jotta omistaja löytää mitä se tekee (valinnainen)",
|
|
6412
|
+
"make_workflow_compatible": "Vähintään yksi tarjous määrittää success_signal + required_to_function + deliverable.location, jolloin se voi olla työnkulun vaihe (valinnainen)",
|
|
6413
|
+
"price_offer": "Vähintään yksi tarjous on myytävissä omistajien välillä: price + visibility public + kutsuttava sidonta (valinnainen)"
|
|
6406
6414
|
},
|
|
6407
6415
|
"errors": {
|
|
6408
6416
|
"accessDenied": "Pääsy estetty",
|
|
@@ -2492,6 +2492,27 @@
|
|
|
2492
2492
|
.pj-org-tab-count { color: var(--muted); font-size: 0.75rem; margin-left: 0.3rem; }
|
|
2493
2493
|
.pj-org-boardrow { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; }
|
|
2494
2494
|
|
|
2495
|
+
/* ── OKF-style structure overview (collapsible Markdown map of an organism / workspace) ── */
|
|
2496
|
+
.pj-struct-overview { margin: 0.4rem 0 0.8rem; }
|
|
2497
|
+
.pj-struct-toggle { display: inline-flex; align-items: center; gap: 0.4rem; background: none; border: none; padding: 0.3rem 0; font-size: 0.85rem; color: var(--text-dim); cursor: pointer; }
|
|
2498
|
+
.pj-struct-toggle:hover { color: var(--text); }
|
|
2499
|
+
.pj-struct-caret { color: var(--muted); font-size: 0.8rem; width: 0.8rem; }
|
|
2500
|
+
.pj-struct-body { margin-top: 0.4rem; max-height: 32rem; overflow: auto; padding: 0.75rem 0.9rem; }
|
|
2501
|
+
/* Compact, on-theme typography so the rendered map reads as part of the dashboard, not a raw doc. */
|
|
2502
|
+
.pj-struct-body .md-body { font-size: 0.85rem; color: var(--text); line-height: 1.5; }
|
|
2503
|
+
.pj-struct-body .md-body > :first-child { margin-top: 0; }
|
|
2504
|
+
.pj-struct-body .md-body h1 { font-size: 1rem; font-weight: 700; margin: 0 0 0.3rem; color: var(--text); }
|
|
2505
|
+
.pj-struct-body .md-body h2 { font-size: 0.92rem; font-weight: 700; margin: 0.95rem 0 0.35rem; padding-top: 0.55rem; border-top: 1px solid var(--border); color: var(--text); }
|
|
2506
|
+
.pj-struct-body .md-body h3 { font-size: 0.83rem; font-weight: 600; margin: 0.55rem 0 0.2rem; color: var(--text-dim); text-transform: none; }
|
|
2507
|
+
.pj-struct-body .md-body p { margin: 0.2rem 0; }
|
|
2508
|
+
.pj-struct-body .md-body blockquote { margin: 0.2rem 0; padding: 0 0 0 0.6rem; border-left: 2px solid var(--border); color: var(--muted); font-size: 0.8rem; }
|
|
2509
|
+
.pj-struct-body .md-body blockquote p { margin: 0.1rem 0; }
|
|
2510
|
+
.pj-struct-body .md-body ul { margin: 0.2rem 0 0.4rem; padding-left: 1.15rem; }
|
|
2511
|
+
.pj-struct-body .md-body li { margin: 0.12rem 0; }
|
|
2512
|
+
.pj-struct-body .md-body code { background: var(--bg-dim); border: 1px solid var(--border); border-radius: 4px; padding: 0.02rem 0.32rem; font-size: 0.78rem; }
|
|
2513
|
+
.pj-struct-body .md-body strong { font-weight: 600; }
|
|
2514
|
+
.pj-struct-body .md-body em { color: var(--muted); font-style: normal; }
|
|
2515
|
+
|
|
2495
2516
|
/* ── Workspace renew (phase 2): header actions, review banner, add-space tab ── */
|
|
2496
2517
|
.pj-ws-head-actions { margin-left: auto; display: flex; gap: 0.4rem; align-items: center; }
|
|
2497
2518
|
.pj-ws-banner { display: flex; align-items: center; gap: 0.75rem; flex-wrap: wrap; border: 1px solid var(--border); border-left: 3px solid var(--warn, var(--accent)); border-radius: 10px; background: var(--card); padding: 0.55rem 0.75rem; margin: 0.6rem 0 0.2rem; }
|
|
@@ -47,8 +47,13 @@
|
|
|
47
47
|
|
|
48
48
|
/* ── detail ── */
|
|
49
49
|
.wf-detail-head { display: flex; align-items: center; gap: 0.75rem; flex-wrap: wrap; }
|
|
50
|
-
.wf-detail-
|
|
50
|
+
.wf-detail-titlebox { flex: 1; display: flex; flex-direction: column; gap: 0.1rem; min-width: 0; }
|
|
51
|
+
.wf-detail-title { font-size: 1.1rem; font-weight: 700; color: var(--text); }
|
|
52
|
+
.wf-detail-sub { font-size: 0.8rem; color: var(--text-dim); }
|
|
53
|
+
.wf-detail-sub code { font-family: var(--font-mono, monospace); }
|
|
54
|
+
.wf-detail-desc { color: var(--text-dim); font-size: 0.9rem; margin: -0.3rem 0 0.3rem; }
|
|
51
55
|
.wf-detail-actions { display: flex; gap: 0.4rem; }
|
|
56
|
+
.wf-node-desc { font-weight: 400; color: var(--text-dim); font-size: 0.85rem; }
|
|
52
57
|
|
|
53
58
|
.wf-graph { display: flex; flex-direction: column; gap: 0.5rem; }
|
|
54
59
|
.wf-node {
|
|
@@ -491,6 +491,24 @@ export async function getWorkspace(orgId, wsId) {
|
|
|
491
491
|
return resp?.data || null;
|
|
492
492
|
}
|
|
493
493
|
|
|
494
|
+
/** OKF-style STRUCTURE OVERVIEW (Markdown) of the whole organism — every workspace's space
|
|
495
|
+
* breakdown + totals, deterministic, size-bounded. Returns '' on failure (caller shows a notice). */
|
|
496
|
+
export async function getOrganismOverview(orgId) {
|
|
497
|
+
try {
|
|
498
|
+
const r = await apiGet(`/v1/organisms/${encodeURIComponent(orgId)}/overview`);
|
|
499
|
+
return r?.data?.markdown || '';
|
|
500
|
+
} catch { return ''; }
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
/** OKF-style STRUCTURE OVERVIEW (Markdown) of ONE workspace — per space the most-recent entries
|
|
504
|
+
* (ids + titles) and totals. Returns '' on failure. */
|
|
505
|
+
export async function getWorkspaceOverview(orgId, wsId) {
|
|
506
|
+
try {
|
|
507
|
+
const r = await apiGet(`/v1/organisms/${encodeURIComponent(orgId)}/workspace/overview?ws=${encodeURIComponent(wsId)}`);
|
|
508
|
+
return r?.data?.markdown || '';
|
|
509
|
+
} catch { return ''; }
|
|
510
|
+
}
|
|
511
|
+
|
|
494
512
|
/** Overwrite a workspace's manifest (e.g. edited name/summary/policy from Settings). */
|
|
495
513
|
export async function saveManifest(orgId, wsId, manifest) {
|
|
496
514
|
return apiPost('/v1/memory', { key: `${wsRoot(orgId, wsId)}.meta.manifest`, value: manifest, visibility: 'private' });
|
|
@@ -55,3 +55,8 @@ export async function getRun(id, runId) {
|
|
|
55
55
|
export async function runWorkflow(id, mode, vars) {
|
|
56
56
|
return apiPost(`/v1/workflows/${encodeURIComponent(id)}/run`, { mode, ...(vars ? { vars } : {}) });
|
|
57
57
|
}
|
|
58
|
+
|
|
59
|
+
/** Cancel an in-flight run (stuck / gone wrong). */
|
|
60
|
+
export async function cancelRun(id, runId) {
|
|
61
|
+
return apiPost(`/v1/workflows/${encodeURIComponent(id)}/runs/${encodeURIComponent(runId)}/cancel`, {});
|
|
62
|
+
}
|
|
@@ -148,6 +148,11 @@
|
|
|
148
148
|
* auto-activates; §7c) — the agent joins/provisions its own spaces and the task completion is
|
|
149
149
|
* the ack. An agent already working in THIS workspace (per the participants data) shows a
|
|
150
150
|
* "✓ active here" badge instead of Adopt. Convention agreed with the crewaimeat side 2026-06-10.
|
|
151
|
+
* v1.29.0 — 2026-06-13 — OKF-style structure overview: a collapsible <${'StructureOverview'}> panel in
|
|
152
|
+
* OrganismHome (📐 Organism structure overview — every workspace's space breakdown + totals) and in
|
|
153
|
+
* Workspace (📐 Workspace structure overview — per-space recent ids + titles). Lazy-loads a
|
|
154
|
+
* deterministic Markdown map from the server (orgService.getOrganismOverview / getWorkspaceOverview)
|
|
155
|
+
* and renders it via the safe Markdown component. Collapsed by default (no cost until opened).
|
|
151
156
|
* v1.28.0 — 2026-06-12 — Overview landing tab: the whole workspace on one vertical scroll — a
|
|
152
157
|
* "what happened here" strip (last 8 activity events, humanized + clickable) above every
|
|
153
158
|
* manifest space stacked in order (records: compact rows max 5 + "Show all N →"; documents:
|
|
@@ -237,6 +242,46 @@ function KebabMenu({ items, label, trigger, btnClass }) {
|
|
|
237
242
|
|
|
238
243
|
/** Tag chips + inline input — Enter/comma adds, × or Backspace-on-empty removes, blur commits.
|
|
239
244
|
* Shows immediately how the value parses (vs. a raw "comma separated" text field). */
|
|
245
|
+
/** Collapsible OKF-style structure-overview panel. A button that, on first expand, lazy-loads a
|
|
246
|
+
* deterministic Markdown structure map (server projection — never persisted) and renders it via the
|
|
247
|
+
* safe Markdown component. Used at organism level (every workspace's space breakdown) and workspace
|
|
248
|
+
* level (per-space recent ids + titles). Collapsed by default so it costs nothing until asked for. */
|
|
249
|
+
function StructureOverview({ load, label }) {
|
|
250
|
+
const [open, setOpen] = useState(false);
|
|
251
|
+
const [md, setMd] = useState(null); // null = not loaded yet; '' = loaded but empty/failed
|
|
252
|
+
const [busy, setBusy] = useState(false);
|
|
253
|
+
const toggle = async () => {
|
|
254
|
+
const next = !open;
|
|
255
|
+
setOpen(next);
|
|
256
|
+
if (next && md === null && !busy) {
|
|
257
|
+
setBusy(true);
|
|
258
|
+
// For the human view, strip the OKF YAML frontmatter (machine metadata — kept in the raw
|
|
259
|
+
// server/MCP output) AND the leading "# … — structure overview" H1 (the panel toggle already
|
|
260
|
+
// names it; the page header already shows the org/workspace name). The body starts at the
|
|
261
|
+
// description / totals line.
|
|
262
|
+
try {
|
|
263
|
+
const raw = (await load()) || '';
|
|
264
|
+
setMd(raw.replace(/^---\n[\s\S]*?\n---\n+/, '').replace(/^#\s+.*\n+/, ''));
|
|
265
|
+
} finally { setBusy(false); }
|
|
266
|
+
}
|
|
267
|
+
};
|
|
268
|
+
return html`
|
|
269
|
+
<div class="pj-struct-overview">
|
|
270
|
+
<button class="pj-struct-toggle" aria-expanded=${open} onClick=${toggle}>
|
|
271
|
+
<span class="pj-struct-caret">${open ? '▾' : '▸'}</span>
|
|
272
|
+
<span>${'📐 '}${label}</span>
|
|
273
|
+
</button>
|
|
274
|
+
${open ? html`
|
|
275
|
+
<div class="pj-struct-body card-detail">
|
|
276
|
+
${busy
|
|
277
|
+
? html`<${Spinner} text=${t('organisms.loading') || 'Loading...'} />`
|
|
278
|
+
: (md
|
|
279
|
+
? html`<${Markdown} text=${md} />`
|
|
280
|
+
: html`<div class="section-desc">${t('organisms.structEmpty') || 'No structure to show yet.'}</div>`)}
|
|
281
|
+
</div>` : null}
|
|
282
|
+
</div>`;
|
|
283
|
+
}
|
|
284
|
+
|
|
240
285
|
function TagInput({ tags, onChange, placeholder }) {
|
|
241
286
|
const [val, setVal] = useState('');
|
|
242
287
|
const add = () => { const v = val.trim().replace(/,+$/, ''); if (v && !tags.includes(v)) onChange([...tags, v]); setVal(''); };
|
|
@@ -1413,6 +1458,9 @@ function OrganismHome({ org, ghii, showToast, initialSettings, onOpenWs, onBack,
|
|
|
1413
1458
|
</div>
|
|
1414
1459
|
</div>
|
|
1415
1460
|
|
|
1461
|
+
<${StructureOverview} label=${t('organisms.structureOverviewOrg') || 'Organism structure overview'}
|
|
1462
|
+
load=${() => orgService.getOrganismOverview(org.id)} />
|
|
1463
|
+
|
|
1416
1464
|
<div class="pj-org-tabs" role="tablist">
|
|
1417
1465
|
${tabs.map(tb => html`
|
|
1418
1466
|
<button class="pj-org-tab ${activeHomeTab === tb.id ? 'active' : ''}" role="tab" aria-selected=${activeHomeTab === tb.id} key=${tb.id}
|
|
@@ -2951,6 +2999,9 @@ function Workspace({ org, wsId, showToast, onBack, onBackToList }) {
|
|
|
2951
2999
|
</div>
|
|
2952
3000
|
${ws.manifest?.summary ? html`<div class="section-desc">${(ws.manifest.summary)}</div>` : null}
|
|
2953
3001
|
|
|
3002
|
+
<${StructureOverview} label=${t('organisms.structureOverviewWs') || 'Workspace structure overview'}
|
|
3003
|
+
load=${() => orgService.getWorkspaceOverview(orgId, wsId)} />
|
|
3004
|
+
|
|
2954
3005
|
${approvals.length > 0 && activeTab !== 'review' ? html`
|
|
2955
3006
|
<div class="pj-ws-banner" role="status">
|
|
2956
3007
|
<span class="pj-ws-banner-text">
|
|
@@ -16,7 +16,7 @@ import { useState, useEffect, useRef, useCallback } from 'preact/hooks';
|
|
|
16
16
|
import htm from 'htm';
|
|
17
17
|
import { t } from '/js/i18n.js';
|
|
18
18
|
import { timeAgo } from '/js/utils.js';
|
|
19
|
-
import { listWorkflows, getWorkflow, getBlueprint, getHealth, listRuns, getRun, runWorkflow } from '/js/services/workflows.js';
|
|
19
|
+
import { listWorkflows, getWorkflow, getBlueprint, getHealth, listRuns, getRun, runWorkflow, cancelRun } from '/js/services/workflows.js';
|
|
20
20
|
import WorkflowForm from './workflows-form.js';
|
|
21
21
|
|
|
22
22
|
const html = htm.bind(h);
|
|
@@ -39,7 +39,7 @@ function triggerSummary(trigger) {
|
|
|
39
39
|
function statusClass(status) {
|
|
40
40
|
if (status === 'done' || status === 'green') return 'wf-badge--ok';
|
|
41
41
|
if (status === 'partial' || status === 'red' || (typeof status === 'string' && status.endsWith('-red')) || status === 'timed-out') return 'wf-badge--err';
|
|
42
|
-
if (status === 'skipped') return 'wf-badge--muted';
|
|
42
|
+
if (status === 'skipped' || status === 'cancelled') return 'wf-badge--muted';
|
|
43
43
|
return 'wf-badge--run';
|
|
44
44
|
}
|
|
45
45
|
|
|
@@ -111,7 +111,7 @@ export default function WorkflowsTab({ showToast }) {
|
|
|
111
111
|
if (view.name === 'edit') return html`<${EditFormView} id=${view.id} showToast=${showToast}
|
|
112
112
|
onCancel=${() => setView({ name: 'detail', id: view.id })} onSaved=${(id) => setView({ name: 'detail', id })} />`;
|
|
113
113
|
if (view.name === 'detail') return html`<${DetailView} id=${view.id} onBack=${() => { setView({ name: 'list' }); loadList(); }} onOpenRun=${(runId) => setView({ name: 'run', id: view.id, runId })} onRun=${doRun} onEdit=${() => setView({ name: 'edit', id: view.id })} />`;
|
|
114
|
-
if (view.name === 'run') return html`<${RunView} id=${view.id} runId=${view.runId} onBack=${() => setView({ name: 'detail', id: view.id })} />`;
|
|
114
|
+
if (view.name === 'run') return html`<${RunView} id=${view.id} runId=${view.runId} showToast=${showToast} onBack=${() => setView({ name: 'detail', id: view.id })} />`;
|
|
115
115
|
|
|
116
116
|
// ── list ──
|
|
117
117
|
return html`
|
|
@@ -161,35 +161,55 @@ function EditFormView({ id, onCancel, onSaved, showToast }) {
|
|
|
161
161
|
}
|
|
162
162
|
|
|
163
163
|
function DetailView({ id, onBack, onOpenRun, onRun, onEdit }) {
|
|
164
|
+
const [def, setDef] = useState(null);
|
|
164
165
|
const [blueprint, setBlueprint] = useState(null);
|
|
165
166
|
const [runs, setRuns] = useState([]);
|
|
166
167
|
const [err, setErr] = useState(null);
|
|
167
168
|
|
|
168
169
|
const load = useCallback(async () => {
|
|
169
|
-
const [bp, rr] = await Promise.all([
|
|
170
|
+
const [d, bp, rr] = await Promise.all([
|
|
171
|
+
getWorkflow(id).catch(() => null),
|
|
172
|
+
getBlueprint(id).catch(e => ({ _err: e.message })),
|
|
173
|
+
listRuns(id).catch(() => null),
|
|
174
|
+
]);
|
|
175
|
+
setDef(d?.data || null);
|
|
170
176
|
if (bp?._err) setErr(bp._err); else setBlueprint(bp?.data || null);
|
|
171
177
|
setRuns(rr?.data?.runs || []);
|
|
172
178
|
}, [id]);
|
|
173
179
|
useEffect(() => { load(); }, [load]);
|
|
180
|
+
// Live updates: re-fetch the blueprint + recent runs as runs advance (engine emitChange → SSE).
|
|
181
|
+
const liveRef = useRef(load); liveRef.current = load;
|
|
182
|
+
useEffect(() => {
|
|
183
|
+
const h = () => liveRef.current();
|
|
184
|
+
window.addEventListener('aimeat-live-update', h);
|
|
185
|
+
return () => window.removeEventListener('aimeat-live-update', h);
|
|
186
|
+
}, []);
|
|
187
|
+
|
|
188
|
+
const stepDesc = (stepId) => loc((def?.steps || []).find(s => s.id === stepId)?.description);
|
|
189
|
+
const triggerLine = def ? triggerSummary(def.trigger) : '';
|
|
174
190
|
|
|
175
191
|
return html`
|
|
176
192
|
<div class="wf-tab">
|
|
177
193
|
<div class="wf-detail-head">
|
|
178
194
|
<button class="btn-ghost" onClick=${onBack}>← ${t('profile.workflows.back')}</button>
|
|
179
|
-
<div class="wf-detail-
|
|
195
|
+
<div class="wf-detail-titlebox">
|
|
196
|
+
<div class="wf-detail-title">${def ? loc(def.title) || id : id}</div>
|
|
197
|
+
<div class="wf-detail-sub"><code>${id}</code>${triggerLine ? html` · ${triggerLine}` : ''}</div>
|
|
198
|
+
</div>
|
|
180
199
|
<div class="wf-detail-actions">
|
|
181
200
|
<button class="btn-ghost" onClick=${onEdit}>${t('profile.workflows.edit')}</button>
|
|
182
201
|
<button class="btn-outline" onClick=${() => onRun(id, 'signals-only')}>${t('profile.workflows.check')}</button>
|
|
183
202
|
<button class="btn-primary" onClick=${() => onRun(id, 'full')}>${t('profile.workflows.run')}</button>
|
|
184
203
|
</div>
|
|
185
204
|
</div>
|
|
205
|
+
${def && loc(def.description) && html`<div class="wf-detail-desc">${loc(def.description)}</div>`}
|
|
186
206
|
|
|
187
207
|
${err && html`<div class="wf-error">${err}</div>`}
|
|
188
208
|
|
|
189
209
|
<div class="wf-section-title">${t('profile.workflows.blueprint')}</div>
|
|
190
210
|
${blueprint && html`<div class="wf-graph">
|
|
191
211
|
${blueprint.nodes.map(n => html`<div class="wf-node" key=${n.stepId}>
|
|
192
|
-
<div class="wf-node-id">${n.stepId}</div>
|
|
212
|
+
<div class="wf-node-id">${n.stepId}${stepDesc(n.stepId) ? html` <span class="wf-node-desc">— ${stepDesc(n.stepId)}</span>` : ''}</div>
|
|
193
213
|
<div class="wf-node-agent">${(n.agents || []).join(', ')} · ${n.offerId}</div>
|
|
194
214
|
${n.reads.length > 0 && html`<div class="wf-node-io">↘ ${n.reads.join(', ')}</div>`}
|
|
195
215
|
${n.writes.length > 0 && html`<div class="wf-node-io">↗ ${n.writes.join(', ')}</div>`}
|
|
@@ -214,30 +234,66 @@ function DetailView({ id, onBack, onOpenRun, onRun, onEdit }) {
|
|
|
214
234
|
}
|
|
215
235
|
|
|
216
236
|
// ── Run: per-step timeline ──────────────────────────────────────────────────────
|
|
217
|
-
function RunView({ id, runId, onBack }) {
|
|
237
|
+
function RunView({ id, runId, onBack, showToast }) {
|
|
218
238
|
const [run, setRun] = useState(null);
|
|
219
239
|
const [err, setErr] = useState(null);
|
|
220
|
-
|
|
240
|
+
const [cancelling, setCancelling] = useState(false);
|
|
241
|
+
const loadRun = useCallback(() => getRun(id, runId).then(r => setRun(r?.data || null)).catch(e => setErr(e.message)), [id, runId]);
|
|
242
|
+
useEffect(() => { loadRun(); }, [loadRun]);
|
|
243
|
+
// Live updates: the engine emits emitChange('workflows') as the run advances (dispatch → green →
|
|
244
|
+
// next step → done) → SSE → aimeat-live-update. Re-fetch so the timeline updates without a manual reload.
|
|
245
|
+
const liveRef = useRef(loadRun); liveRef.current = loadRun;
|
|
246
|
+
useEffect(() => {
|
|
247
|
+
const h = () => liveRef.current();
|
|
248
|
+
window.addEventListener('aimeat-live-update', h);
|
|
249
|
+
return () => window.removeEventListener('aimeat-live-update', h);
|
|
250
|
+
}, []);
|
|
251
|
+
|
|
252
|
+
const inFlight = run && (run.status === 'running' || run.status === 'waiting-step');
|
|
253
|
+
const doCancel = async () => {
|
|
254
|
+
setCancelling(true);
|
|
255
|
+
try { await cancelRun(id, runId); showToast?.(t('profile.workflows.cancelled'), false); await loadRun(); }
|
|
256
|
+
catch (e) { showToast?.(e?.message || 'Cancel failed', true); }
|
|
257
|
+
finally { setCancelling(false); }
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
// The run pins the full definition (defSnapshot), so we can name the workflow + each step
|
|
261
|
+
// without any extra fetch — and show exactly the def THIS run executed (even if it changed since).
|
|
262
|
+
const def = run?.defSnapshot;
|
|
263
|
+
const stepDef = (stepId) => (def?.steps || []).find(s => s.id === stepId);
|
|
221
264
|
|
|
222
265
|
return html`
|
|
223
266
|
<div class="wf-tab">
|
|
224
267
|
<div class="wf-detail-head">
|
|
225
268
|
<button class="btn-ghost" onClick=${onBack}>← ${t('profile.workflows.back')}</button>
|
|
226
|
-
<div class="wf-detail-
|
|
269
|
+
<div class="wf-detail-titlebox">
|
|
270
|
+
<div class="wf-detail-title">${def ? loc(def.title) || run.workflowId : t('profile.workflows.run')}</div>
|
|
271
|
+
<div class="wf-detail-sub">
|
|
272
|
+
${run ? html`<code>${run.workflowId}</code> · ${t('profile.workflows.run')} ${timeAgo(run.startedAt)} · ${run.mode}` : runId.slice(0, 8)}
|
|
273
|
+
</div>
|
|
274
|
+
</div>
|
|
275
|
+
${inFlight && html`<button class="btn-danger-solid" disabled=${cancelling} onClick=${doCancel}>${cancelling ? '…' : t('profile.workflows.cancelRun')}</button>`}
|
|
227
276
|
${run && html`<${StatusBadge} status=${run.status} />`}
|
|
228
277
|
</div>
|
|
278
|
+
${run && def && loc(def.description) && html`<div class="wf-detail-desc">${loc(def.description)}</div>`}
|
|
229
279
|
${err && html`<div class="wf-error">${err}</div>`}
|
|
230
280
|
${run && html`<div class="wf-steps">
|
|
231
|
-
${Object.entries(run.steps).map(([stepId, s]) =>
|
|
281
|
+
${Object.entries(run.steps).map(([stepId, s]) => {
|
|
282
|
+
const sd = stepDef(stepId);
|
|
283
|
+
const agents = sd ? (Array.isArray(sd.agent) ? sd.agent.join(', ') : sd.agent) : null;
|
|
284
|
+
return html`<div class="wf-step" key=${stepId}>
|
|
232
285
|
<div class="wf-step-row">
|
|
233
286
|
<${StatusBadge} status=${s.state} />
|
|
234
287
|
<span class="wf-step-id">${stepId}</span>
|
|
288
|
+
${sd && loc(sd.description) && html`<span class="wf-node-desc">— ${loc(sd.description)}</span>`}
|
|
235
289
|
${s.reads?.length > 0 && html`<span class="wf-muted">↘ ${s.reads.length}</span>`}
|
|
236
290
|
${s.writes?.length > 0 && html`<span class="wf-muted">↗ ${s.writes.length}</span>`}
|
|
237
291
|
${s.attempt > 0 && html`<span class="wf-muted">${t('profile.workflows.attempt')} ${s.attempt + 1}</span>`}
|
|
238
292
|
</div>
|
|
293
|
+
${agents && html`<div class="wf-node-agent">${agents} · ${sd.offer}</div>`}
|
|
239
294
|
${(s.outputObserved || s.inputObserved) && html`<pre class="wf-observed">${JSON.stringify(s.outputObserved || s.inputObserved, null, 2)}</pre>`}
|
|
240
|
-
</div
|
|
295
|
+
</div>`;
|
|
296
|
+
})}
|
|
241
297
|
${(run.inspections || []).length > 0 && html`<div class="wf-inspections">${t('profile.workflows.inspectorDispatched', { count: run.inspections.length })}</div>`}
|
|
242
298
|
</div>`}
|
|
243
299
|
</div>`;
|