@theihtisham/agent-shadow-brain 7.1.3 → 7.1.4
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/CHANGELOG.md +20 -0
- package/README.md +125 -90
- package/dist/adapters/index.d.ts +1 -1
- package/dist/adapters/index.d.ts.map +1 -1
- package/dist/adapters/index.js.map +1 -1
- package/dist/brain/activity-journal.d.ts.map +1 -1
- package/dist/brain/activity-journal.js +2 -1
- package/dist/brain/activity-journal.js.map +1 -1
- package/dist/brain/auto-update.js +1 -1
- package/dist/brain/brain-portability.js +1 -1
- package/dist/brain/client-config.d.ts +19 -0
- package/dist/brain/client-config.d.ts.map +1 -0
- package/dist/brain/client-config.js +40 -0
- package/dist/brain/client-config.js.map +1 -0
- package/dist/brain/client-integrations.d.ts +2 -0
- package/dist/brain/client-integrations.d.ts.map +1 -1
- package/dist/brain/client-integrations.js +8 -27
- package/dist/brain/client-integrations.js.map +1 -1
- package/dist/brain/context-assembly.d.ts +10 -2
- package/dist/brain/context-assembly.d.ts.map +1 -1
- package/dist/brain/context-assembly.js +238 -14
- package/dist/brain/context-assembly.js.map +1 -1
- package/dist/brain/context-request.d.ts +4 -0
- package/dist/brain/context-request.d.ts.map +1 -0
- package/dist/brain/context-request.js +22 -0
- package/dist/brain/context-request.js.map +1 -0
- package/dist/brain/context-retrieval.d.ts +88 -0
- package/dist/brain/context-retrieval.d.ts.map +1 -0
- package/dist/brain/context-retrieval.js +300 -0
- package/dist/brain/context-retrieval.js.map +1 -0
- package/dist/brain/feature-settings.d.ts.map +1 -1
- package/dist/brain/feature-settings.js +2 -1
- package/dist/brain/feature-settings.js.map +1 -1
- package/dist/brain/file-identity.d.ts +4 -0
- package/dist/brain/file-identity.d.ts.map +1 -0
- package/dist/brain/file-identity.js +27 -0
- package/dist/brain/file-identity.js.map +1 -0
- package/dist/brain/global-brain.d.ts +11 -1
- package/dist/brain/global-brain.d.ts.map +1 -1
- package/dist/brain/global-brain.js +58 -6
- package/dist/brain/global-brain.js.map +1 -1
- package/dist/brain/mcp-server.d.ts +9 -0
- package/dist/brain/mcp-server.d.ts.map +1 -1
- package/dist/brain/mcp-server.js +237 -53
- package/dist/brain/mcp-server.js.map +1 -1
- package/dist/brain/mcp-stdio.d.ts.map +1 -1
- package/dist/brain/mcp-stdio.js +10 -4
- package/dist/brain/mcp-stdio.js.map +1 -1
- package/dist/brain/memory-annotations.d.ts.map +1 -1
- package/dist/brain/memory-annotations.js +2 -1
- package/dist/brain/memory-annotations.js.map +1 -1
- package/dist/brain/memory-inspection.d.ts +72 -0
- package/dist/brain/memory-inspection.d.ts.map +1 -0
- package/dist/brain/memory-inspection.js +131 -0
- package/dist/brain/memory-inspection.js.map +1 -0
- package/dist/brain/memory-mcp-content.d.ts +44 -0
- package/dist/brain/memory-mcp-content.d.ts.map +1 -0
- package/dist/brain/memory-mcp-content.js +91 -0
- package/dist/brain/memory-mcp-content.js.map +1 -0
- package/dist/brain/orchestrator.js +1 -1
- package/dist/brain/project-feedback.d.ts +63 -0
- package/dist/brain/project-feedback.d.ts.map +1 -0
- package/dist/brain/project-feedback.js +289 -0
- package/dist/brain/project-feedback.js.map +1 -0
- package/dist/brain/project-hub-contract.d.ts +326 -0
- package/dist/brain/project-hub-contract.d.ts.map +1 -0
- package/dist/brain/project-hub-contract.js +56 -0
- package/dist/brain/project-hub-contract.js.map +1 -0
- package/dist/brain/project-hub-mcp.d.ts +168 -0
- package/dist/brain/project-hub-mcp.d.ts.map +1 -0
- package/dist/brain/project-hub-mcp.js +41 -0
- package/dist/brain/project-hub-mcp.js.map +1 -0
- package/dist/brain/project-hub-pdf-worker.d.ts +13 -0
- package/dist/brain/project-hub-pdf-worker.d.ts.map +1 -0
- package/dist/brain/project-hub-pdf-worker.js +84 -0
- package/dist/brain/project-hub-pdf-worker.js.map +1 -0
- package/dist/brain/project-hub-store.d.ts +38 -0
- package/dist/brain/project-hub-store.d.ts.map +1 -0
- package/dist/brain/project-hub-store.js +189 -0
- package/dist/brain/project-hub-store.js.map +1 -0
- package/dist/brain/project-hub.d.ts +127 -0
- package/dist/brain/project-hub.d.ts.map +1 -0
- package/dist/brain/project-hub.js +381 -0
- package/dist/brain/project-hub.js.map +1 -0
- package/dist/brain/project-kit-inspection.d.ts +28 -0
- package/dist/brain/project-kit-inspection.d.ts.map +1 -0
- package/dist/brain/project-kit-inspection.js +200 -0
- package/dist/brain/project-kit-inspection.js.map +1 -0
- package/dist/brain/project-kit-paths.d.ts +13 -0
- package/dist/brain/project-kit-paths.d.ts.map +1 -0
- package/dist/brain/project-kit-paths.js +141 -0
- package/dist/brain/project-kit-paths.js.map +1 -0
- package/dist/brain/project-kit.d.ts +41 -0
- package/dist/brain/project-kit.d.ts.map +1 -0
- package/dist/brain/project-kit.js +255 -0
- package/dist/brain/project-kit.js.map +1 -0
- package/dist/brain/project-memory.d.ts +38 -0
- package/dist/brain/project-memory.d.ts.map +1 -0
- package/dist/brain/project-memory.js +76 -0
- package/dist/brain/project-memory.js.map +1 -0
- package/dist/brain/subconscious.js +2 -2
- package/dist/brain/subconscious.js.map +1 -1
- package/dist/brain/workflow-skills.d.ts.map +1 -1
- package/dist/brain/workflow-skills.js +3 -2
- package/dist/brain/workflow-skills.js.map +1 -1
- package/dist/cli.js +22 -3
- package/dist/cli.js.map +1 -1
- package/dist/context-cli.d.ts.map +1 -1
- package/dist/context-cli.js +39 -5
- package/dist/context-cli.js.map +1 -1
- package/dist/dashboard/brain-hub-actions.d.ts +2 -0
- package/dist/dashboard/brain-hub-actions.d.ts.map +1 -0
- package/dist/dashboard/brain-hub-actions.js +137 -0
- package/dist/dashboard/brain-hub-actions.js.map +1 -0
- package/dist/dashboard/brain-hub-client.d.ts +2 -0
- package/dist/dashboard/brain-hub-client.d.ts.map +1 -0
- package/dist/dashboard/brain-hub-client.js +335 -0
- package/dist/dashboard/brain-hub-client.js.map +1 -0
- package/dist/dashboard/brain-hub-graph.d.ts +2 -0
- package/dist/dashboard/brain-hub-graph.d.ts.map +1 -0
- package/dist/dashboard/brain-hub-graph.js +176 -0
- package/dist/dashboard/brain-hub-graph.js.map +1 -0
- package/dist/dashboard/brain-hub-html.d.ts +2 -0
- package/dist/dashboard/brain-hub-html.d.ts.map +1 -0
- package/dist/dashboard/brain-hub-html.js +30 -0
- package/dist/dashboard/brain-hub-html.js.map +1 -0
- package/dist/dashboard/brain-hub-project-views.d.ts +2 -0
- package/dist/dashboard/brain-hub-project-views.d.ts.map +1 -0
- package/dist/dashboard/brain-hub-project-views.js +79 -0
- package/dist/dashboard/brain-hub-project-views.js.map +1 -0
- package/dist/dashboard/brain-hub-views.d.ts +2 -0
- package/dist/dashboard/brain-hub-views.d.ts.map +1 -0
- package/dist/dashboard/brain-hub-views.js +150 -0
- package/dist/dashboard/brain-hub-views.js.map +1 -0
- package/dist/dashboard/demo-workspace.d.ts +11 -0
- package/dist/dashboard/demo-workspace.d.ts.map +1 -0
- package/dist/dashboard/demo-workspace.js +178 -0
- package/dist/dashboard/demo-workspace.js.map +1 -0
- package/dist/dashboard/live-workspace-html.d.ts.map +1 -1
- package/dist/dashboard/live-workspace-html.js +177 -28
- package/dist/dashboard/live-workspace-html.js.map +1 -1
- package/dist/dashboard/project-feedback-html.d.ts +5 -0
- package/dist/dashboard/project-feedback-html.d.ts.map +1 -0
- package/dist/dashboard/project-feedback-html.js +216 -0
- package/dist/dashboard/project-feedback-html.js.map +1 -0
- package/dist/dashboard/project-hub-api.d.ts +5 -0
- package/dist/dashboard/project-hub-api.d.ts.map +1 -0
- package/dist/dashboard/project-hub-api.js +121 -0
- package/dist/dashboard/project-hub-api.js.map +1 -0
- package/dist/dashboard/project-kit-html.d.ts +4 -0
- package/dist/dashboard/project-kit-html.d.ts.map +1 -0
- package/dist/dashboard/project-kit-html.js +359 -0
- package/dist/dashboard/project-kit-html.js.map +1 -0
- package/dist/dashboard/project-workspace.d.ts +16 -0
- package/dist/dashboard/project-workspace.d.ts.map +1 -0
- package/dist/dashboard/project-workspace.js +106 -0
- package/dist/dashboard/project-workspace.js.map +1 -0
- package/dist/dashboard/server.d.ts +1 -0
- package/dist/dashboard/server.d.ts.map +1 -1
- package/dist/dashboard/server.js +15 -4
- package/dist/dashboard/server.js.map +1 -1
- package/dist/dashboard/v6-dashboard-html.d.ts +1 -1
- package/dist/dashboard/v6-dashboard-html.d.ts.map +1 -1
- package/dist/dashboard/v6-dashboard-html.js +27 -27
- package/dist/dashboard/workspace-api.d.ts +6 -0
- package/dist/dashboard/workspace-api.d.ts.map +1 -1
- package/dist/dashboard/workspace-api.js +154 -34
- package/dist/dashboard/workspace-api.js.map +1 -1
- package/dist/dashboard/workspace-html.d.ts.map +1 -1
- package/dist/dashboard/workspace-html.js +487 -81
- package/dist/dashboard/workspace-html.js.map +1 -1
- package/dist/dashboard/workspace-status.d.ts +50 -0
- package/dist/dashboard/workspace-status.d.ts.map +1 -0
- package/dist/dashboard/workspace-status.js +22 -0
- package/dist/dashboard/workspace-status.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/dist/integration-cli.d.ts.map +1 -1
- package/dist/integration-cli.js +6 -4
- package/dist/integration-cli.js.map +1 -1
- package/dist/project-cli.d.ts +3 -0
- package/dist/project-cli.d.ts.map +1 -0
- package/dist/project-cli.js +100 -0
- package/dist/project-cli.js.map +1 -0
- package/dist/types.d.ts +1 -1
- package/dist/types.d.ts.map +1 -1
- package/docs/COMPARISON.md +22 -0
- package/docs/COMPONENTS.md +66 -0
- package/docs/CONTEXT_LAB.md +79 -0
- package/docs/FEATURES_AND_LIMITS.md +24 -0
- package/docs/INTEGRATIONS.md +68 -0
- package/docs/LEARNING.md +46 -0
- package/docs/PROJECT_KIT.md +93 -0
- package/docs/QUICKSTART.md +44 -0
- package/docs/README.md +33 -0
- package/docs/ROADMAP-v7.md +147 -0
- package/docs/SHARING.md +13 -0
- package/docs/SHOWCASE.md +87 -0
- package/docs/STATS.md +21 -0
- package/docs/TROUBLESHOOTING.md +42 -0
- package/docs/UPGRADE_PLAN_v7.0.0.md +203 -0
- package/docs/VIRAL-PLAYBOOK.md +259 -0
- package/docs/VISUAL_GUIDE_v7.1.4.md +70 -0
- package/docs/WORKFLOW_INTEGRATION.md +19 -1
- package/docs/WORKSPACE.md +17 -91
- package/docs/assets/7.1.4-collaboration-design-preview.png +0 -0
- package/docs/assets/7.1.4-comparison.png +0 -0
- package/docs/assets/7.1.4-context-lab.png +0 -0
- package/docs/assets/7.1.4-control-room-dense-preview.png +0 -0
- package/docs/assets/7.1.4-control-room-focus-preview.png +0 -0
- package/docs/assets/7.1.4-features.png +0 -0
- package/docs/assets/7.1.4-graph.png +0 -0
- package/docs/assets/7.1.4-hub-control-room.png +0 -0
- package/docs/assets/7.1.4-hub-empty.png +0 -0
- package/docs/assets/7.1.4-hub-knowledge.png +0 -0
- package/docs/assets/7.1.4-hub-learning.png +0 -0
- package/docs/assets/7.1.4-hub-mobile.png +0 -0
- package/docs/assets/7.1.4-hub-public-docs-source.png +0 -0
- package/docs/assets/7.1.4-hub-public-docs.gif +0 -0
- package/docs/assets/7.1.4-hub-public-docs.png +0 -0
- package/docs/assets/7.1.4-hub-setup.png +0 -0
- package/docs/assets/7.1.4-hub-walkthrough.gif +0 -0
- package/docs/assets/7.1.4-integrations.png +0 -0
- package/docs/assets/7.1.4-knowledge-design-preview.png +0 -0
- package/docs/assets/7.1.4-learning-design-preview.png +0 -0
- package/docs/assets/7.1.4-learning.png +0 -0
- package/docs/assets/7.1.4-live.png +0 -0
- package/docs/assets/7.1.4-memory-review.png +0 -0
- package/docs/assets/7.1.4-mobile.png +0 -0
- package/docs/assets/7.1.4-models-design-preview.png +0 -0
- package/docs/assets/7.1.4-outcome-ranking.png +0 -0
- package/docs/assets/7.1.4-overview.png +0 -0
- package/docs/assets/7.1.4-project-kit.png +0 -0
- package/docs/assets/7.1.4-project-skill-preview.png +0 -0
- package/docs/assets/7.1.4-replay.png +0 -0
- package/docs/assets/7.1.4-setup-design-preview.png +0 -0
- package/docs/assets/7.1.4-usage-design-preview.png +0 -0
- package/docs/assets/context-v7.1.3.png +0 -0
- package/docs/assets/features-v7.1.3.png +0 -0
- package/docs/assets/graph-v7.1.3.png +0 -0
- package/docs/assets/integrations-v7.1.3.png +0 -0
- package/docs/assets/live-v7.1.4.gif +0 -0
- package/docs/evaluation/CONTEXT_EVALUATION_v7.1.4.json +1818 -0
- package/docs/evaluation/CONTEXT_EVALUATION_v7.1.4.md +36 -0
- package/docs/launch/COMPONENT_MAP_v7.1.4.md +307 -0
- package/docs/launch/PROJECT_KIT_PLAN_v7.1.4.md +110 -0
- package/docs/launch/PROJECT_LEARNING_PLAN_v7.1.4.md +63 -0
- package/docs/launch/RELEASE_NOTES_v7.1.4.md +30 -0
- package/docs/launch/RESEARCH_AND_PLAN_v7.1.4.md +255 -0
- package/package.json +25 -7
- package/skills/shadow-research/SKILL.md +2 -0
- package/skills/shadow-workflow/SKILL.md +6 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// Dependency-free local workspace. The advanced dashboard is served separately.
|
|
2
|
+
import { PROJECT_KIT_MARKUP, PROJECT_KIT_SCRIPT, PROJECT_KIT_STYLE } from './project-kit-html.js';
|
|
2
3
|
export const WORKSPACE_HTML = String.raw `<!doctype html>
|
|
3
4
|
<html lang="en" data-theme="light" data-motion="system">
|
|
4
5
|
<head>
|
|
@@ -300,8 +301,105 @@ export const WORKSPACE_HTML = String.raw `<!doctype html>
|
|
|
300
301
|
.save-status { padding: 8px 19px; min-height: 35px; border-top: 1px solid var(--line); }
|
|
301
302
|
.save-status[data-error="true"] { color: var(--bad); }
|
|
302
303
|
.notice { margin: 0 0 16px; }
|
|
303
|
-
|
|
304
|
-
|
|
304
|
+
:root { --signal: #8fe5d3; --instrument: #142d3b; --instrument-deep: #102333; --instrument-ink: #f3f9fd; --instrument-muted: #b6cbd5; --instrument-line: #395663; }
|
|
305
|
+
.rail { gap: 35px; }
|
|
306
|
+
.nav-link[aria-current="page"] { box-shadow: inset 0 0 0 1px #426371; }
|
|
307
|
+
.rail-live { margin-top: 11px; }
|
|
308
|
+
.rail-live .icon { color: var(--rail-highlight); }
|
|
309
|
+
.page-head h1 { font-size: 2.27rem; }
|
|
310
|
+
.page-head .head-actions { align-items: end; }
|
|
311
|
+
.page-head .head-actions .button { align-self: end; }
|
|
312
|
+
.demo-notice { display: none; }
|
|
313
|
+
html[data-demo="true"] .demo-notice { display: flex; gap: 7px 10px; flex-wrap: wrap; padding: 8px 12px; margin-bottom: 16px; background: var(--amber-bg); color: var(--amber); border-radius: 7px; font-size: .83rem; }
|
|
314
|
+
html[data-demo="true"] .advanced-link { display: none; }
|
|
315
|
+
.overview-summary { display: grid; grid-template-columns: minmax(0,1.1fr) minmax(0,1fr); color: var(--instrument-ink); background: var(--instrument); border-radius: 12px; overflow: hidden; margin-bottom: 17px; }
|
|
316
|
+
.overview-summary .summary { grid-template-columns: repeat(3,minmax(0,1fr)); background: var(--instrument-deep); color: var(--instrument-ink); border: 0; border-radius: 0; margin: 0; }
|
|
317
|
+
.overview-summary .summary-item { flex-direction: column; align-items: start; justify-content: center; gap: 11px; padding: 20px 16px; }
|
|
318
|
+
.overview-summary .summary-item + .summary-item { border-color: var(--instrument-line); }
|
|
319
|
+
.overview-summary .summary dt { color: var(--instrument-muted); font-size: .83rem; }
|
|
320
|
+
.overview-summary .summary dd { font-size: 1.72rem; }
|
|
321
|
+
.overview-summary .tile-icon { color: var(--signal); background: #234550; }
|
|
322
|
+
.overview-lead { display: flex; align-items: center; gap: 19px; padding: 21px; min-width: 0; }
|
|
323
|
+
.overview-lead h2 { font-size: 1.28rem; }
|
|
324
|
+
.overview-lead p { color: var(--instrument-muted); margin-top: 5px; }
|
|
325
|
+
.overview-lead .button { color: var(--signal); border-color: var(--instrument-line); margin-top: 12px; }
|
|
326
|
+
.overview-lead .button:hover { background: #254350; }
|
|
327
|
+
.coverage-ring { flex: none; display: grid; place-items: center; width: 98px; aspect-ratio: 1; border-radius: 50%; background: conic-gradient(var(--signal) var(--coverage), #3b5665 0); }
|
|
328
|
+
.coverage-ring span { display: grid; place-items: center; width: 80px; aspect-ratio: 1; border-radius: 50%; background: var(--instrument); font-size: 1.46rem; font-weight: 720; font-variant-numeric: tabular-nums; }
|
|
329
|
+
.overview-columns { grid-template-columns: minmax(0,1.33fr) minmax(0,1fr); }
|
|
330
|
+
.overview-activity .panel-head { background: var(--inset); }
|
|
331
|
+
.attention-list { max-height: 355px; overflow: auto; }
|
|
332
|
+
.attention-row { display: grid; grid-template-columns: 30px minmax(0,1fr); gap: 11px; align-items: start; padding: 12px 19px; }
|
|
333
|
+
.attention-row .tile-icon { width: 30px; height: 30px; background: var(--amber-bg); color: var(--amber); }
|
|
334
|
+
.attention-row .tags { margin-top: 5px; }
|
|
335
|
+
.graph-stage {
|
|
336
|
+
--canvas: #142534; --surface: #203546; --ink: #f0f7fc; --muted: #bed0db; --line: #4b6679;
|
|
337
|
+
--project: #a3e8d5; --project-bg: #234651; --agent: #d3c5ff; --agent-bg: #3a3e5e; --memory: #c2daf2; --memory-bg: #344d64;
|
|
338
|
+
--graph-line: #8ba9bd; --graph-project: #82b8ab; --graph-agent: #aa9ed0; --graph-dot: #40566a; --teal: #9ce9d8; --bad: #ff9eab;
|
|
339
|
+
height: 520px; color: var(--ink); color-scheme: dark;
|
|
340
|
+
}
|
|
341
|
+
.graph-stage .button:hover { background: #30485a; }
|
|
342
|
+
.graph-stage .cluster-area { fill-opacity: .47; stroke-opacity: .34; }
|
|
343
|
+
.graph-node { transition: opacity var(--ease); }
|
|
344
|
+
.graph-node.selected-memory .node-surface { stroke: var(--teal); }
|
|
345
|
+
.graph-stage .graph-edge.supports { stroke: var(--teal); }
|
|
346
|
+
.graph-inspector, .graph-list { max-height: 520px; }
|
|
347
|
+
.graph-body[data-lens="true"] .graph-stage { height: 390px; }
|
|
348
|
+
.graph-body[data-lens="true"] :is(.graph-inspector,.graph-list) { max-height: 390px; }
|
|
349
|
+
.graph-lens { display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 8px; padding: 8px 14px; border-bottom: 1px solid var(--line); }
|
|
350
|
+
.legend-line.supports { border-color: var(--teal); }
|
|
351
|
+
.legend-line.contradicts { border-color: var(--bad); border-top-style: dashed; }
|
|
352
|
+
.legend-line.supersedes { border-color: var(--teal); border-top-style: dotted; }
|
|
353
|
+
.context-layout { grid-template-columns: minmax(255px,.68fr) minmax(0,1.75fr); }
|
|
354
|
+
.context-config { gap: 16px; }
|
|
355
|
+
.context-config .form-actions .primary { width: 100%; }
|
|
356
|
+
.context-settings-pair { display: grid; grid-template-columns: minmax(0,1fr) minmax(0,1fr); gap: 10px; }
|
|
357
|
+
.context-result-head { background: var(--inset); }
|
|
358
|
+
.context-output-head { display: grid; grid-template-columns: minmax(0,1fr) auto; align-items: start; gap: 10px; }
|
|
359
|
+
.context-output-head .form-actions { justify-content: end; }
|
|
360
|
+
.context-metrics { display: grid; grid-template-columns: repeat(3,minmax(0,1fr)); border-block: 1px solid var(--line); }
|
|
361
|
+
.context-metrics > div { padding: 11px 10px; min-width: 0; }
|
|
362
|
+
.context-metrics > div + div { border-left: 1px solid var(--line); }
|
|
363
|
+
.context-metrics dt { font-size: .78rem; color: var(--muted); }
|
|
364
|
+
.context-metrics dd { font-size: 1.21rem; font-weight: 710; overflow-wrap: anywhere; }
|
|
365
|
+
.context-budget-track { height: 6px; border-radius: 4px; background: var(--line); overflow: hidden; margin-top: 5px; }
|
|
366
|
+
.context-budget-track span { display: block; height: 100%; background: var(--teal-fill); border-radius: inherit; }
|
|
367
|
+
.context-section { display: grid; gap: 11px; min-width: 0; }
|
|
368
|
+
.context-section > summary, .candidate > summary { cursor: pointer; font-weight: 680; }
|
|
369
|
+
.context-section > summary { color: var(--teal); }
|
|
370
|
+
.context-section[open] > summary { margin-bottom: 10px; }
|
|
371
|
+
.retrieval-flow { display: grid; grid-template-columns: repeat(auto-fit,minmax(97px,1fr)); gap: 1px; list-style: none; padding: 1px; border-radius: 8px; background: var(--instrument-line); overflow: hidden; }
|
|
372
|
+
.retrieval-flow li { display: grid; grid-template-rows: auto 1fr auto; gap: 5px; min-width: 0; background: var(--instrument-deep); color: var(--instrument-ink); padding: 10px; }
|
|
373
|
+
.retrieval-flow strong { font-size: 1.28rem; font-variant-numeric: tabular-nums; }
|
|
374
|
+
.retrieval-flow span { font-size: .78rem; color: var(--instrument-muted); overflow-wrap: anywhere; }
|
|
375
|
+
.retrieval-flow li:last-child { background: var(--instrument); }
|
|
376
|
+
.retrieval-flow li:last-child strong { color: var(--signal); }
|
|
377
|
+
.retrieval-stage-bar { height: 3px; background: var(--instrument-line); border-radius: 2px; overflow: hidden; }
|
|
378
|
+
.retrieval-stage-bar i { display: block; height: 100%; background: var(--signal); opacity: .74; }
|
|
379
|
+
.candidate-list { max-height: 415px; overflow: auto; border-block: 1px solid var(--line); }
|
|
380
|
+
.candidate { padding: 9px 9px 9px 12px; }
|
|
381
|
+
.candidate > summary { color: var(--ink); }
|
|
382
|
+
.candidate > summary:hover { color: var(--teal); }
|
|
383
|
+
.candidate-title { display: inline-grid; grid-template-columns: auto minmax(0,1fr) auto; align-items: baseline; gap: 7px; width: calc(100% - 20px); vertical-align: top; }
|
|
384
|
+
.candidate-title .rank { color: var(--muted); font: .8rem Consolas,monospace; }
|
|
385
|
+
.candidate-body { display: grid; gap: 7px; padding: 9px 0 4px; }
|
|
386
|
+
.candidate-signals { display: grid; grid-template-columns: repeat(auto-fit,minmax(110px,1fr)); gap: 5px; }
|
|
387
|
+
.candidate-signals div { background: var(--inset); border-radius: 5px; padding: 6px; }
|
|
388
|
+
.candidate-signals dt { color: var(--muted); font-size: .75rem; }
|
|
389
|
+
.candidate-signals dd { font-size: .89rem; font-variant-numeric: tabular-nums; }
|
|
390
|
+
.context-compare { display: grid; gap: 8px; }
|
|
391
|
+
.compare-grid { display: grid; grid-template-columns: repeat(2,minmax(0,1fr)); border: 1px solid var(--line); border-radius: 7px; overflow: hidden; }
|
|
392
|
+
.compare-grid > div { padding: 10px; min-width: 0; }
|
|
393
|
+
.compare-grid > div + div { border-left: 1px solid var(--line); }
|
|
394
|
+
.compare-grid ul { padding-left: 16px; }
|
|
395
|
+
.compare-grid h3 { margin-bottom: 5px; }
|
|
396
|
+
.integration-meta { display: flex; flex-wrap: wrap; gap: 7px; padding: 12px 19px; border-bottom: 1px solid var(--line); }
|
|
397
|
+
.integration-config { display: grid; gap: 8px; }
|
|
398
|
+
.integration-config > summary { cursor: pointer; color: var(--teal); font-weight: 650; }
|
|
399
|
+
.integration-config[open] > summary { margin-bottom: 8px; }
|
|
400
|
+
.integration-config .context-preview { margin-block: 7px; max-height: 280px; }
|
|
401
|
+
.setting .settings-description { display: flex; align-items: start; gap: 11px; }
|
|
402
|
+
.setting .tile-icon { width: 32px; height: 32px; }
|
|
305
403
|
html[data-motion="reduce"] *, html[data-motion="reduce"] *::before, html[data-motion="reduce"] *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
|
|
306
404
|
@media (prefers-reduced-motion: reduce) {
|
|
307
405
|
*, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
|
|
@@ -328,6 +426,7 @@ export const WORKSPACE_HTML = String.raw `<!doctype html>
|
|
|
328
426
|
:root { --header: 48px; font-size: 14px; }
|
|
329
427
|
.shell { display: block; }
|
|
330
428
|
.rail { z-index: var(--sticky); height: auto; flex-direction: row; align-items: center; gap: 7px; padding: 5px 10px; }
|
|
429
|
+
.rail-live { display: none; }
|
|
331
430
|
.rail-nav { display: flex; gap: 3px; }
|
|
332
431
|
.nav-link { padding: 7px 9px; min-height: 35px; }
|
|
333
432
|
.rail-foot { margin: 0 0 0 auto; padding: 0; border: 0; }
|
|
@@ -335,7 +434,7 @@ export const WORKSPACE_HTML = String.raw `<!doctype html>
|
|
|
335
434
|
.top { padding: 7px 13px; }
|
|
336
435
|
.top-actions { gap: 8px; }
|
|
337
436
|
.content { padding: 22px 12px 32px; }
|
|
338
|
-
h1 { font-size: 1.68rem; }
|
|
437
|
+
h1, .page-head h1 { font-size: 1.68rem; }
|
|
339
438
|
.page-head { gap: 8px; margin-bottom: 17px; flex-wrap: wrap; }
|
|
340
439
|
.summary { margin-bottom: 13px; }
|
|
341
440
|
.summary-item { gap: 6px; padding: 11px 9px; }
|
|
@@ -349,20 +448,36 @@ export const WORKSPACE_HTML = String.raw `<!doctype html>
|
|
|
349
448
|
.check-row .tag { grid-column: 2; grid-row: 1; }
|
|
350
449
|
.graph-body { grid-template-columns: minmax(0,1fr); }
|
|
351
450
|
.graph-stage, .graph-list { height: 365px; }
|
|
451
|
+
.graph-body[data-lens="true"] .graph-stage { height: 310px; }
|
|
352
452
|
.graph-inspector { border-left: 0; border-top: 1px solid var(--line); max-height: 340px; }
|
|
353
453
|
.panel-head, .panel-body, .memory-row, .setting { padding-left: 12px; padding-right: 12px; }
|
|
354
454
|
.project-row, .event { padding-left: 12px; padding-right: 12px; }
|
|
355
455
|
.list-footer { flex-wrap: wrap; }
|
|
356
456
|
.graph-mode { margin-left: 0; }
|
|
457
|
+
.overview-summary { grid-template-columns: minmax(0,1fr); }
|
|
458
|
+
.overview-summary .summary-item { padding: 11px 10px; }
|
|
459
|
+
.overview-summary .summary dd { font-size: 1.42rem; }
|
|
460
|
+
.overview-lead { padding: 15px; gap: 12px; }
|
|
461
|
+
.coverage-ring { width: 77px; }
|
|
462
|
+
.coverage-ring span { width: 63px; font-size: 1.16rem; }
|
|
463
|
+
.context-output-head { grid-template-columns: minmax(0,1fr); }
|
|
464
|
+
.context-output-head .form-actions { justify-content: start; }
|
|
465
|
+
#context-result, #attention-heading { scroll-margin-top: 55px; }
|
|
466
|
+
.context-metrics > div { padding: 8px 6px; }
|
|
467
|
+
.context-metrics dd { font-size: 1rem; }
|
|
468
|
+
.retrieval-flow { grid-template-columns: repeat(3,minmax(0,1fr)); }
|
|
469
|
+
.candidate-title { grid-template-columns: auto minmax(0,1fr); }
|
|
470
|
+
.candidate-title .tag { grid-column: 2; justify-self: start; }
|
|
357
471
|
}
|
|
358
472
|
@media (max-width: 355px) {
|
|
359
473
|
.rail { gap: 3px; }
|
|
360
|
-
.nav-link { padding-left:
|
|
474
|
+
.nav-link { padding-left: 5px; padding-right: 5px; }
|
|
361
475
|
.crumb > .muted, .crumb .icon { display: none; }
|
|
362
476
|
.filters { grid-template-columns: repeat(2,minmax(0,1fr)); }
|
|
363
477
|
.filters .search-field { grid-column: 1 / -1; }
|
|
364
478
|
.filters .button { grid-row: auto; grid-column: auto; }
|
|
365
479
|
}
|
|
480
|
+
${PROJECT_KIT_STYLE}
|
|
366
481
|
</style>
|
|
367
482
|
</head>
|
|
368
483
|
<body>
|
|
@@ -376,12 +491,14 @@ export const WORKSPACE_HTML = String.raw `<!doctype html>
|
|
|
376
491
|
<a class="nav-link" href="#overview" aria-label="Overview" title="Overview" data-view="overview" aria-current="page"><span data-icon="overview"></span><span class="nav-label">Overview</span></a>
|
|
377
492
|
<a class="nav-link" href="#memories" aria-label="Memories" title="Memories" data-view="memories"><span data-icon="memory"></span><span class="nav-label">Memories</span></a>
|
|
378
493
|
<a class="nav-link" href="#graph" aria-label="Graph" title="Graph" data-view="graph"><span data-icon="graph"></span><span class="nav-label">Graph</span></a>
|
|
379
|
-
<a class="nav-link" href="#context" aria-label="Context" title="Context" data-view="context"><span data-icon="context"></span><span class="nav-label">Context</span></a>
|
|
494
|
+
<a class="nav-link" href="#context" aria-label="Context Lab" title="Context Lab" data-view="context"><span data-icon="context"></span><span class="nav-label">Context Lab</span></a>
|
|
495
|
+
<a class="nav-link" href="#project-kit" aria-label="Project Kit" title="Project Kit" data-view="project-kit"><span data-icon="project"></span><span class="nav-label">Project Kit</span></a>
|
|
380
496
|
<a class="nav-link" href="#integrations" aria-label="Integrations and health" title="Integrations and health" data-view="integrations"><span data-icon="integrations"></span><span class="nav-label">Integrations</span></a>
|
|
381
497
|
<a class="nav-link" href="#features" aria-label="Features" title="Features" data-view="features"><span data-icon="settings"></span><span class="nav-label">Features</span></a>
|
|
498
|
+
<a class="nav-link rail-live" href="/live" aria-label="Live operations" title="Live operations"><span data-icon="activity"></span><span class="nav-label">Live operations</span></a>
|
|
382
499
|
</nav>
|
|
383
500
|
<div class="rail-foot">
|
|
384
|
-
<a class="nav-link" href="/advanced" aria-label="Advanced dashboard" title="Advanced dashboard"><span data-icon="advanced"></span><span class="nav-label">Advanced tools</span><span class="arrow" data-icon="diagonal"></span></a>
|
|
501
|
+
<a class="nav-link advanced-link" href="/advanced" aria-label="Advanced dashboard" title="Advanced dashboard"><span data-icon="advanced"></span><span class="nav-label">Advanced tools</span><span class="arrow" data-icon="diagonal"></span></a>
|
|
385
502
|
<p class="rail-build" id="rail-version">Local workspace</p>
|
|
386
503
|
</div>
|
|
387
504
|
</aside>
|
|
@@ -395,11 +512,14 @@ export const WORKSPACE_HTML = String.raw `<!doctype html>
|
|
|
395
512
|
</div>
|
|
396
513
|
</header>
|
|
397
514
|
<main id="main-content" class="content" tabindex="-1">
|
|
515
|
+
<div class="demo-notice"><strong>Synthetic demo</strong><span>Scripted local MCP calls use sample data. Changes affect this temporary demo only.</span></div>
|
|
516
|
+
<div class="project-local-notice"><strong>Project workspace</strong><span>Memory and settings are stored with this project.</span><a href="#project-kit">Open Project Kit</a></div>
|
|
398
517
|
<div class="notice" id="workspace-notice" role="status" hidden></div>
|
|
399
518
|
<section id="page-overview" aria-labelledby="title-overview">
|
|
400
519
|
<div class="page-head">
|
|
401
|
-
<div><h1 id="title-overview" tabindex="-1">
|
|
402
|
-
<
|
|
520
|
+
<div><h1 id="title-overview" tabindex="-1">Memory workspace</h1><p class="muted">Review saved knowledge and prepare a brief for your next task.</p></div>
|
|
521
|
+
<div class="form-actions head-actions"><label class="label" for="overview-quality-project">Project<select id="overview-quality-project"><option value="">All projects</option></select></label>
|
|
522
|
+
<a href="#context" id="overview-context" class="button primary"><span data-icon="context"></span>Open Context Lab</a></div>
|
|
403
523
|
</div>
|
|
404
524
|
<div id="overview-body" aria-busy="true"></div>
|
|
405
525
|
</section>
|
|
@@ -423,6 +543,7 @@ export const WORKSPACE_HTML = String.raw `<!doctype html>
|
|
|
423
543
|
<div class="form-actions" id="detail-actions" hidden>
|
|
424
544
|
<a id="detail-graph" class="button" href="#graph"><span data-icon="graph"></span>View on graph</a>
|
|
425
545
|
<a id="detail-context" class="button" href="#context"><span data-icon="context"></span>Assemble context</a>
|
|
546
|
+
<a id="detail-outcome" class="button" href="#project-kit" hidden><span data-icon="activity"></span>Record outcome</a>
|
|
426
547
|
</div>
|
|
427
548
|
</div>
|
|
428
549
|
<div id="detail-body" aria-busy="true"></div>
|
|
@@ -442,6 +563,7 @@ export const WORKSPACE_HTML = String.raw `<!doctype html>
|
|
|
442
563
|
</div>
|
|
443
564
|
<div class="panel" id="graph-panel" aria-busy="true">
|
|
444
565
|
<div class="panel-head"><h2>Memory relationships</h2><span id="graph-count" class="muted small" role="status"></span></div>
|
|
566
|
+
<div id="graph-lens" class="graph-lens" hidden><p class="small muted" id="graph-lens-label"></p><button class="button" type="button" id="graph-lens-clear">Show full graph</button></div>
|
|
445
567
|
<div id="graph-status"></div>
|
|
446
568
|
<div class="graph-body" id="graph-body" hidden>
|
|
447
569
|
<div class="graph-stage" id="graph-stage">
|
|
@@ -459,28 +581,35 @@ export const WORKSPACE_HTML = String.raw `<!doctype html>
|
|
|
459
581
|
<div id="graph-legend" class="legend" hidden>
|
|
460
582
|
<span><i class="legend-glyph project"></i> Project</span><span><i class="legend-glyph agent"></i> Agent</span><span><i class="legend-glyph memory"></i> Memory</span>
|
|
461
583
|
<span><i class="legend-line project-edge"></i> Belongs to project</span><span><i class="legend-line agent-edge"></i> Recorded by agent</span>
|
|
462
|
-
<span><i class="legend-line recorded-edge"></i>
|
|
584
|
+
<span><i class="legend-line recorded-edge"></i> Related</span><span><i class="legend-line supports"></i> Supports</span>
|
|
585
|
+
<span><i class="legend-line contradicts"></i> Contradicts</span><span><i class="legend-line supersedes"></i> Supersedes</span>
|
|
463
586
|
</div>
|
|
464
587
|
</div>
|
|
465
588
|
</div>
|
|
466
589
|
</section>
|
|
467
590
|
<section id="page-context" aria-labelledby="title-context" hidden>
|
|
468
|
-
<div class="page-head"><div><h1 id="title-context" tabindex="-1">Context</h1><p class="muted">
|
|
591
|
+
<div class="page-head"><div><h1 id="title-context" tabindex="-1">Context Lab</h1><p class="muted">Assemble a task brief, inspect its evidence, and compare retrieval profiles.</p></div></div>
|
|
469
592
|
<div class="split context-layout">
|
|
470
593
|
<div class="panel">
|
|
471
|
-
<div class="panel-head"><h2>
|
|
594
|
+
<div class="panel-head"><h2>Build a brief</h2></div>
|
|
472
595
|
<form class="panel-body context-config" id="context-form">
|
|
473
596
|
<label class="label" for="context-project">Project<select id="context-project" required><option value="">Select a project</option></select></label>
|
|
474
597
|
<label class="label" for="context-task">Task<textarea id="context-task" rows="5" maxlength="4096" required placeholder="Describe what the agent will work on."></textarea></label>
|
|
475
|
-
<
|
|
598
|
+
<div class="context-settings-pair">
|
|
599
|
+
<label class="label" for="context-budget">Token budget<input id="context-budget" type="number" inputmode="numeric" min="0" max="12000" step="1" value="2000" required aria-describedby="context-estimate"></label>
|
|
600
|
+
<label class="label" for="context-profile">Retrieval<select id="context-profile"><option value="adaptive">Adaptive</option><option value="legacy">Legacy</option></select></label>
|
|
601
|
+
</div>
|
|
602
|
+
<p class="small muted" id="context-estimate">Token usage is estimated for the assembled brief.</p>
|
|
603
|
+
<label class="inline-check small" id="context-related-row"><input type="checkbox" id="context-related" checked>Expand through recorded supporting and related links</label>
|
|
476
604
|
<label class="inline-check small" id="context-cross-row" hidden><input type="checkbox" id="context-cross">Include eligible memories from other projects</label>
|
|
477
605
|
<div id="context-gate"></div>
|
|
478
606
|
<div class="form-actions"><button class="button primary" id="context-submit" type="submit" disabled><span data-icon="context"></span>Assemble context</button></div>
|
|
479
607
|
</form>
|
|
480
608
|
</div>
|
|
481
|
-
<div class="panel" id="context-result"><div class="panel-head"><h2>
|
|
609
|
+
<div class="panel" id="context-result"><div class="panel-head context-result-head"><h2>Brief and evidence</h2><span class="small muted" id="context-result-state" role="status">Ready for a task</span></div><div id="context-output"></div></div>
|
|
482
610
|
</div>
|
|
483
611
|
</section>
|
|
612
|
+
${PROJECT_KIT_MARKUP}
|
|
484
613
|
<section id="page-integrations" aria-labelledby="title-integrations" hidden>
|
|
485
614
|
<div class="page-head">
|
|
486
615
|
<div><h1 id="title-integrations" tabindex="-1">Integrations & health</h1><p class="muted">Check local storage and see which capabilities each agent supports.</p></div>
|
|
@@ -534,7 +663,7 @@ const glyphs = {
|
|
|
534
663
|
warning: '<path d="m12 3 10 17H2L12 3zm0 6v4m0 3h.01"/>',
|
|
535
664
|
refresh: '<path d="M19.5 9a8 8 0 1 0 .3 5.5M20 4v5h-5"/>'
|
|
536
665
|
};
|
|
537
|
-
const viewNames = { overview: 'Overview', memories: 'Memories', memory: 'Memory detail', graph: 'Graph', context: 'Context', integrations: 'Integrations', features: 'Features' };
|
|
666
|
+
const viewNames = { overview: 'Overview', memories: 'Memories', memory: 'Memory detail', graph: 'Graph', context: 'Context Lab', 'project-kit': 'Project Kit', integrations: 'Integrations', features: 'Features' };
|
|
538
667
|
const reviewStates = { active: 'Active', contested: 'Needs review', archived: 'Archived', superseded: 'Superseded' };
|
|
539
668
|
const linkTypes = { related: 'Related', supports: 'Supports', contradicts: 'Contradicts', supersedes: 'Supersedes' };
|
|
540
669
|
const definitions = [
|
|
@@ -560,10 +689,11 @@ const TIME = new Intl.DateTimeFormat(undefined, { month: 'short', day: 'numeric'
|
|
|
560
689
|
const state = {
|
|
561
690
|
view: '', route: '', projects: [], overviewLoaded: false, overviewPending: null, overviewScope: '', overviewRequest: 0, overviewRequestScope: '',
|
|
562
691
|
activity: [], activityEnabled: null, activityPending: false, features: null, featurePending: null, featureSaving: false,
|
|
692
|
+
health: { snapshot: null, project: '', filter: '', request: 0 }, projectKit: null,
|
|
563
693
|
memory: { query: null, request: 0, controller: null, limit: 20, offset: 0 },
|
|
564
694
|
detail: { snapshot: null, id: '', project: '', back: '#memories', request: 0, targetRequest: 0, saving: false },
|
|
565
|
-
graph: { snapshot: null, project: null, mode: matchMedia('(max-width: 690px)').matches ? 'list' : 'map', selected: '', selectedEdge: '', focusMemory: '', nodes: [], edges: [], layout: null, zoom: 1, panX: 0, panY: 0, request: 0, controller: null, drag: null },
|
|
566
|
-
context: { pack: null, pending: false, dirty: false, routeProject: '' },
|
|
695
|
+
graph: { snapshot: null, project: null, mode: matchMedia('(max-width: 690px)').matches ? 'list' : 'map', selected: '', selectedEdge: '', focusMemory: '', lens: '', nodes: [], edges: [], layout: null, zoom: 1, panX: 0, panY: 0, request: 0, controller: null, drag: null },
|
|
696
|
+
context: { pack: null, params: null, comparison: null, comparing: false, pending: false, dirty: false, routeProject: '' },
|
|
567
697
|
integrations: { snapshot: null, pending: false }
|
|
568
698
|
};
|
|
569
699
|
|
|
@@ -664,11 +794,24 @@ function reviewTag(value) {
|
|
|
664
794
|
|
|
665
795
|
function renderSummary(totals) {
|
|
666
796
|
return '<dl class="summary">' + [
|
|
667
|
-
['memory', '
|
|
797
|
+
['memory', 'Total stored memories', totals.memories], ['project', 'Projects', totals.projects], ['agent', 'Contributing agents', totals.agents]
|
|
668
798
|
].map(([image, label, value]) => '<div class="summary-item"><span class="tile-icon">' + icon(image) +
|
|
669
799
|
'</span><div><dt>' + label + '</dt><dd>' + number(value) + '</dd></div></div>').join('') + '</dl>';
|
|
670
800
|
}
|
|
671
801
|
|
|
802
|
+
function renderOverviewSummary(data) {
|
|
803
|
+
const counts = data.quality || {};
|
|
804
|
+
const total = Number(counts.total) || 0;
|
|
805
|
+
const sources = Number(counts.sourceBacked) || 0;
|
|
806
|
+
const percent = total ? Math.round(Math.min(1, sources / total) * 100) : 0;
|
|
807
|
+
const project = data.scope?.projectId;
|
|
808
|
+
const scope = project ? state.projects.find((item) => item.id === project)?.name || project : 'All projects';
|
|
809
|
+
return '<div class="overview-summary"><div class="overview-lead"><div class="coverage-ring" aria-hidden="true" style="--coverage:' + percent + '%"><span>' +
|
|
810
|
+
(total ? percent + '%' : '—') + '</span></div><div><h2>Recorded source coverage</h2><p class="small">' +
|
|
811
|
+
esc(scope) + ' · ' + number(sources) + ' of ' + number(total) + (data.truncated ? ' sampled memories' : ' memories') +
|
|
812
|
+
'</p><button class="button quiet" type="button" id="attention-jump">Review attention queue ' + icon('chevron', true) + '</button></div></div>' + renderSummary(data.totals || {}) + '</div>';
|
|
813
|
+
}
|
|
814
|
+
|
|
672
815
|
function renderProjects(projects) {
|
|
673
816
|
if (!projects.length) return blank('project', 'No projects yet', 'Projects appear after an agent stores a memory with a project scope.');
|
|
674
817
|
const max = Math.max(1, ...projects.map((project) => Number(project.memories) || 0));
|
|
@@ -698,8 +841,6 @@ function renderQuality(data) {
|
|
|
698
841
|
const project = data.scope?.projectId || '';
|
|
699
842
|
const scope = data.truncated ? 'Based on the latest ' + number(data.inventoryLimit) + ' stored memories.' :
|
|
700
843
|
project ? 'Stored memories in this project.' : 'Stored memories across projects.';
|
|
701
|
-
const options = state.projects.map((item) => '<option value="' + esc(item.id) + '"' +
|
|
702
|
-
(item.id === project ? ' selected' : '') + '>' + esc(item.name || item.id) + '</option>').join('');
|
|
703
844
|
const statusCounts = Object.entries(reviewStates).map(([key, label]) => ({ key, label, count: Number(quality[key]) || 0 }));
|
|
704
845
|
const coverage = quality.total ? Math.max(0, Math.min(100, Number(quality.sourceBacked || 0) / quality.total * 100)) : 0;
|
|
705
846
|
const statusBars = statusCounts.map(({ key, count }) =>
|
|
@@ -707,8 +848,7 @@ function renderQuality(data) {
|
|
|
707
848
|
const statusLinks = statusCounts.map(({ key, label, count }) => '<a href="' + esc(routeLink('memories', { project, state: key })) +
|
|
708
849
|
'"><i aria-hidden="true" class="quality-' + key + '"></i>' + esc(label) + ' <strong>' + number(count) + '</strong></a>').join('');
|
|
709
850
|
return '<div class="panel"><div class="panel-head"><div><h2>Review and sources</h2><p class="small muted">' + esc(scope) +
|
|
710
|
-
'</p></div
|
|
711
|
-
options + '</select></label></div>' + (quality.total ? '<div class="panel-body stack"><div class="stack" style="gap:8px"><h3>Memory status</h3>' +
|
|
851
|
+
'</p></div></div>' + (quality.total ? '<div class="panel-body stack"><div class="stack" style="gap:8px"><h3>Memory status</h3>' +
|
|
712
852
|
'<div class="quality-track" aria-hidden="true">' + statusBars + '</div><div class="quality-labels">' + statusLinks + '</div></div>' +
|
|
713
853
|
'<div class="stack" style="gap:8px"><div class="quality-source"><h3>Recorded sources</h3><span class="small muted">' +
|
|
714
854
|
number(quality.sourceBacked) + ' of ' + number(quality.total) + ' memories</span></div>' +
|
|
@@ -717,6 +857,61 @@ function renderQuality(data) {
|
|
|
717
857
|
'</div>' : blank('memory', 'No memories in scope', 'Save a memory to see review and source counts here.')) + '</div>';
|
|
718
858
|
}
|
|
719
859
|
|
|
860
|
+
const healthIssues = {
|
|
861
|
+
contested: 'Needs review', contradiction: 'Contradictory link', 'orphaned-link': 'Missing linked memory',
|
|
862
|
+
duplicate: 'Repeated content', 'no-source': 'No recorded source', 'older-memory': 'Older than 90 days'
|
|
863
|
+
};
|
|
864
|
+
|
|
865
|
+
function renderAttention() {
|
|
866
|
+
const target = $('attention-results');
|
|
867
|
+
const store = state.health;
|
|
868
|
+
if (!target || !store.snapshot || store.project !== state.overviewScope) return;
|
|
869
|
+
const data = store.snapshot;
|
|
870
|
+
const counts = data.counts || {};
|
|
871
|
+
const rows = list(data.queue).filter((item) => !store.filter || list(item.issues).some((issue) => issue.kind === store.filter));
|
|
872
|
+
const options = Object.entries(healthIssues).map(([value, label]) => '<option value="' + value + '">' + label + '</option>').join('');
|
|
873
|
+
const controls = $('attention-filter');
|
|
874
|
+
if (!controls.childElementCount) controls.innerHTML = '<option value="">All issues</option>' + options;
|
|
875
|
+
controls.value = store.filter;
|
|
876
|
+
controls.disabled = !list(data.queue).length;
|
|
877
|
+
const scopeNote = (data.coverage?.truncated ? 'Checked the latest ' + number(data.coverage.limit) + ' memories in scope.' : 'Checked ' + number(counts.total) + ' memories in scope.');
|
|
878
|
+
$('attention-scope').textContent = scopeNote;
|
|
879
|
+
const warnings = list(data.warnings).map((warning) => '<p class="small muted panel-body">' + esc(warning) + '</p>').join('');
|
|
880
|
+
const count = '<p class="small muted panel-body">Showing ' + number(rows.length) + ' of ' + number(data.queueTotal) + ' flagged memories' +
|
|
881
|
+
(store.filter ? ' · filter applied to loaded items' : '') + '.</p>';
|
|
882
|
+
const items = rows.map((item) => '<li class="attention-row"><span class="tile-icon">' + icon('warning', true) + '</span><div>' +
|
|
883
|
+
memoryLink(item.id, item.projectId, item.title || item.id) + '<div class="tags">' +
|
|
884
|
+
tags([['project', state.projects.find((project) => project.id === item.projectId)?.name || item.projectId], ['memory', nice(item.category)]]) +
|
|
885
|
+
list(item.issues).map((issue) => '<span class="tag check-' + (issue.severity === 'review' ? 'warn' : '') + '">' +
|
|
886
|
+
esc(issue.label || healthIssues[issue.kind] || 'Review') + '</span>').join('') + '</div></div></li>').join('');
|
|
887
|
+
target.innerHTML = rows.length ? count + '<ul class="list attention-list" tabindex="0" aria-label="Flagged memories">' + items + '</ul>' + warnings :
|
|
888
|
+
blank('memory', store.filter ? 'No loaded items match' : 'No attention items', store.filter ? 'Choose another issue or show all loaded items.' : 'Review flags will appear here as the memory store changes.') + warnings;
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
async function loadHealth(project) {
|
|
892
|
+
const target = $('attention-results');
|
|
893
|
+
if (!target) return;
|
|
894
|
+
const store = state.health;
|
|
895
|
+
const request = ++store.request;
|
|
896
|
+
if (store.project !== project) store.filter = '';
|
|
897
|
+
store.project = project;
|
|
898
|
+
store.snapshot = null;
|
|
899
|
+
$('attention-filter').disabled = true;
|
|
900
|
+
$('attention-scope').textContent = '';
|
|
901
|
+
target.innerHTML = skeleton('Checking memory health…');
|
|
902
|
+
setBusy(target, true);
|
|
903
|
+
try {
|
|
904
|
+
const snapshot = await api(queryPath('memory-health', { project, limit: 30 }));
|
|
905
|
+
if (request !== store.request || target !== $('attention-results')) return;
|
|
906
|
+
store.snapshot = snapshot;
|
|
907
|
+
renderAttention();
|
|
908
|
+
} catch (error) {
|
|
909
|
+
if (request === store.request && target === $('attention-results')) target.innerHTML = errorMarkup(error.message, 'health');
|
|
910
|
+
} finally {
|
|
911
|
+
if (request === store.request && target === $('attention-results')) setBusy(target, false);
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
|
|
720
915
|
function renderActivity() {
|
|
721
916
|
const target = $('activity-body');
|
|
722
917
|
if (!target) return;
|
|
@@ -745,12 +940,18 @@ function renderOverview(data) {
|
|
|
745
940
|
number(data.inventoryLimit) + ' stored memories.</p>' : '';
|
|
746
941
|
const pending = data.storageHealth?.status === 'pending' ? '<p class="status small muted notice">The memory store has pending writes.</p>' : '';
|
|
747
942
|
const projectNote = state.projects.length > 8 ? 'Top projects by saved memory count' : 'Saved memories by project';
|
|
748
|
-
|
|
749
|
-
|
|
943
|
+
optionSet('overview-quality-project', 'All projects', state.projects, data.scope?.projectId || '');
|
|
944
|
+
$('overview-context').href = routeLink('context', { project: data.scope?.projectId });
|
|
945
|
+
$('overview-body').innerHTML = '<div id="overview-refresh"></div>' + pending + renderOverviewSummary(data) + sample +
|
|
946
|
+
'<div class="split overview-columns"><div class="stack"><section class="panel" aria-labelledby="attention-heading"><div class="panel-head"><div>' +
|
|
947
|
+
'<h2 id="attention-heading" tabindex="-1">Attention queue</h2><p class="small muted" id="attention-scope"></p></div>' +
|
|
948
|
+
'<label class="label" for="attention-filter">Issue<select id="attention-filter" disabled></select></label></div>' +
|
|
949
|
+
'<div id="attention-results"></div></section>' + renderQuality(data) + '<div class="panel"><div class="panel-head"><div><h2>Project inventory</h2>' +
|
|
750
950
|
'<p class="muted small">' + projectNote + '</p></div><a class="button quiet" href="#memories">Browse ' + icon('chevron', true) +
|
|
751
951
|
'</a></div>' + renderProjects(state.projects) + '</div>' + renderOverviewMemories(list(data.recentMemories)) +
|
|
752
|
-
'</div><div class="panel"><div class="panel-head"><h2>Recent activity</h2><span id="activity-status" class="small muted"></span></div><div id="activity-body"></div></div></div>';
|
|
952
|
+
'</div><div class="panel overview-activity"><div class="panel-head"><div><h2>Recent activity</h2><span id="activity-status" class="small muted"></span></div><a class="button quiet" href="/live">Open live operations ' + icon('chevron', true) + '</a></div><div id="activity-body"></div></div></div>';
|
|
753
953
|
renderActivity();
|
|
954
|
+
if (state.view === 'overview') void loadHealth(data.scope?.projectId || '');
|
|
754
955
|
}
|
|
755
956
|
|
|
756
957
|
function syncProjectOptions() {
|
|
@@ -768,6 +969,8 @@ async function loadOverview(force = false, project = '') {
|
|
|
768
969
|
state.overviewRequestScope = project;
|
|
769
970
|
const target = $('overview-body');
|
|
770
971
|
if (!state.overviewLoaded) target.innerHTML = '<div class="panel">' + skeleton('Loading workspace…') + '</div>';
|
|
972
|
+
else if (state.overviewScope !== project && $('overview-refresh')) $('overview-refresh').innerHTML =
|
|
973
|
+
'<div class="notice status small muted" role="status">Loading the selected project. Showing the previous scope.</div>';
|
|
771
974
|
setBusy(target, true);
|
|
772
975
|
state.overviewPending = (async () => {
|
|
773
976
|
try {
|
|
@@ -776,6 +979,7 @@ async function loadOverview(force = false, project = '') {
|
|
|
776
979
|
state.overviewLoaded = true;
|
|
777
980
|
state.overviewScope = project;
|
|
778
981
|
state.projects = list(data.projects);
|
|
982
|
+
state.projectKit = data.projectKit ?? null;
|
|
779
983
|
state.activity = list(data.activity);
|
|
780
984
|
if (typeof data.features?.liveActivity === 'boolean') state.activityEnabled = data.features.liveActivity;
|
|
781
985
|
if (data.version) $('rail-version').textContent = 'Version ' + data.version;
|
|
@@ -931,6 +1135,9 @@ function renderDetail(snapshot) {
|
|
|
931
1135
|
]) + (memory.createdAt || memory.updatedAt ? '<div class="small muted">' + dateMarkup(memory.createdAt || memory.updatedAt, true) + '</div>' : '');
|
|
932
1136
|
$('detail-graph').href = routeLink('graph', { project, memory: memory.id });
|
|
933
1137
|
$('detail-context').href = routeLink('context', { project });
|
|
1138
|
+
const projectFeedback = document.documentElement.dataset.projectLocal === 'true' || state.projectKit?.projectId === project;
|
|
1139
|
+
$('detail-outcome').hidden = !projectFeedback;
|
|
1140
|
+
$('detail-outcome').href = routeLink('project-kit', { memory: memory.id });
|
|
934
1141
|
$('detail-actions').hidden = false;
|
|
935
1142
|
const linkRows = list(links).map((link) => {
|
|
936
1143
|
const outgoing = link.fromId === memory.id;
|
|
@@ -1048,9 +1255,9 @@ async function saveDetail(kind, payload, focus) {
|
|
|
1048
1255
|
await api(kind, { body: { projectId: project, expectedRevision: store.snapshot.revision, ...payload } });
|
|
1049
1256
|
state.graph.snapshot = null;
|
|
1050
1257
|
state.overviewLoaded = false;
|
|
1051
|
-
if (state.context.pack) {
|
|
1258
|
+
if (state.context.pack || state.context.pending) {
|
|
1052
1259
|
state.context.dirty = true;
|
|
1053
|
-
renderContext();
|
|
1260
|
+
if (!state.context.pending) renderContext();
|
|
1054
1261
|
}
|
|
1055
1262
|
if (request !== store.request || state.view !== 'memory') return;
|
|
1056
1263
|
if (await loadDetail(id, project, 'Saved. Could not reload the memory. ')) detailStatus(status, 'Saved.');
|
|
@@ -1317,6 +1524,10 @@ function centerGraphNode(id) {
|
|
|
1317
1524
|
const position = graph.layout?.positions.get(id);
|
|
1318
1525
|
if (!position || graph.mode !== 'map') return;
|
|
1319
1526
|
const { width, height } = graphViewport();
|
|
1527
|
+
const left = graph.panX + position.x * graph.zoom;
|
|
1528
|
+
const top = graph.panY + position.y * graph.zoom;
|
|
1529
|
+
if (graph.zoom >= .8 && left >= 14 && top >= 14 && left + position.width * graph.zoom <= width - 14 &&
|
|
1530
|
+
top + position.height * graph.zoom <= height - 52) return;
|
|
1320
1531
|
const zoom = Math.max(.8, graph.zoom);
|
|
1321
1532
|
graph.zoom = zoom;
|
|
1322
1533
|
graph.panX = width / 2 - (position.x + position.width / 2) * zoom;
|
|
@@ -1352,9 +1563,10 @@ function renderGraphInspector() {
|
|
|
1352
1563
|
const from = all.get(selectedEdge.source);
|
|
1353
1564
|
const to = all.get(selectedEdge.target);
|
|
1354
1565
|
const record = (node) => node ? memoryLink(graphMemoryId(node), node.project, node.label || node.id) : '';
|
|
1566
|
+
const endpoint = (label, node) => (selectedEdge.kind === 'related' ? '' : '<p class="small muted">' + label + '</p>') + '<p>' + record(node) + '</p>';
|
|
1355
1567
|
inspector.innerHTML = '<div class="panel-head"><h3>Link details</h3></div><div class="panel-body">' +
|
|
1356
|
-
'<
|
|
1357
|
-
'<
|
|
1568
|
+
'<div>' + endpoint('From memory', from) + '</div>' + tags([['memory', graphEdgeLabels[selectedEdge.kind]], ['agent', 'Recorded memory link']]) +
|
|
1569
|
+
'<div>' + endpoint('To memory', to) + '</div>' + (selectedEdge.note ? '<p class="small muted detail-note">' + esc(selectedEdge.note) + '</p>' : '') + '</div>';
|
|
1358
1570
|
return;
|
|
1359
1571
|
}
|
|
1360
1572
|
if (!selected) {
|
|
@@ -1367,7 +1579,7 @@ function renderGraphInspector() {
|
|
|
1367
1579
|
adjacent.map(({ id, edge }) => {
|
|
1368
1580
|
const node = all.get(id);
|
|
1369
1581
|
if (recordedEdge(edge)) return '<button type="button" class="button quiet" data-edge-record="' + esc(edge.id) +
|
|
1370
|
-
'"><span>' + esc(
|
|
1582
|
+
'"><span>' + esc(linkCaption({ fromId: edge.source, type: edge.kind }, selected.id)) + ' · ' + esc(node.label || node.id) + '</span></button>';
|
|
1371
1583
|
return '<button type="button" class="button quiet" data-related="' + esc(id) + '" title="' +
|
|
1372
1584
|
esc(graphEdgeLabels[edge.kind] || nice(edge.kind) || 'Connection') + '">' + icon(node.kind, true) + '<span>' +
|
|
1373
1585
|
esc(node.label || node.id) + '</span></button>';
|
|
@@ -1375,11 +1587,14 @@ function renderGraphInspector() {
|
|
|
1375
1587
|
const project = state.projects.find((item) => item.id === selected.project)?.name || selected.project;
|
|
1376
1588
|
const snippet = compact(selected.snippet) && compact(selected.snippet) !== compact(selected.label)
|
|
1377
1589
|
? '<p class="small">' + esc(selected.snippet) + '</p>' : '';
|
|
1590
|
+
const canFocus = selected.kind === 'memory' && adjacent.some(({ edge }) => recordedEdge(edge)) && graph.lens !== selected.id;
|
|
1378
1591
|
inspector.innerHTML = '<div class="panel-head"><h3>Node details</h3></div><div class="panel-body">' +
|
|
1379
1592
|
tags([[selected.kind, graphKinds[selected.kind]], ['memory', nice(selected.category)], ['state-' + (selected.effectiveState || ''), reviewLabel(selected.effectiveState)]]) +
|
|
1380
1593
|
'<h3>' + (selected.kind === 'memory' ? memoryLink(graphMemoryId(selected), selected.project, selected.label || selected.id) : esc(selected.label || selected.id)) + '</h3>' +
|
|
1381
1594
|
(project && selected.kind !== 'project' ? '<p class="muted small">' + esc(project) + '</p>' : '') + snippet +
|
|
1382
|
-
(selected.kind === 'memory' ? sourceMarkup([...list(selected.sources), selected.source]) : '') +
|
|
1595
|
+
(selected.kind === 'memory' ? sourceMarkup([...list(selected.sources), selected.source]) : '') +
|
|
1596
|
+
(canFocus ? '<button class="button" type="button" data-graph-lens="' + esc(selected.id) + '">' + icon('graph', true) + 'Focus recorded links</button>' : '') +
|
|
1597
|
+
connected + '</div>';
|
|
1383
1598
|
}
|
|
1384
1599
|
|
|
1385
1600
|
function updateGraphSelection() {
|
|
@@ -1396,6 +1611,7 @@ function updateGraphSelection() {
|
|
|
1396
1611
|
element.setAttribute('aria-pressed', String(id === nodeId));
|
|
1397
1612
|
if (element instanceof SVGElement) {
|
|
1398
1613
|
element.classList.toggle('unrelated', hasSelection && !connected.has(nodeId));
|
|
1614
|
+
element.classList.toggle('selected-memory', id === nodeId && nodeId.startsWith('memory:'));
|
|
1399
1615
|
element.setAttribute('tabindex', nodeId === tabStop ? '0' : '-1');
|
|
1400
1616
|
}
|
|
1401
1617
|
});
|
|
@@ -1446,14 +1662,22 @@ function renderGraph() {
|
|
|
1446
1662
|
const search = $('graph-query').value.trim().toLowerCase();
|
|
1447
1663
|
const kind = $('graph-kind').value;
|
|
1448
1664
|
const relation = $('graph-relation').value;
|
|
1449
|
-
const
|
|
1665
|
+
const allNodes = list(graph.snapshot.nodes).filter((node) => Object.hasOwn(graphKinds, node.kind));
|
|
1666
|
+
const allEdges = list(graph.snapshot.edges);
|
|
1667
|
+
const anchor = allNodes.find((node) => node.id === graph.lens);
|
|
1668
|
+
const edges = anchor ? allEdges.filter((edge) => recordedEdge(edge) && (edge.source === anchor.id || edge.target === anchor.id)) : allEdges;
|
|
1669
|
+
const lensIds = anchor ? new Set([anchor.id, ...edges.flatMap((edge) => [edge.source, edge.target])]) : null;
|
|
1670
|
+
const nodes = lensIds ? allNodes.filter((node) => lensIds.has(node.id)) : allNodes;
|
|
1671
|
+
$('graph-lens').hidden = !anchor;
|
|
1672
|
+
$('graph-body').dataset.lens = String(!!anchor);
|
|
1673
|
+
$('graph-lens-label').textContent = anchor ? 'Recorded links for ' + shorten(compact(anchor.label || anchor.id), 94) : '';
|
|
1450
1674
|
const matches = nodes.filter((node) => (!kind || node.kind === kind) &&
|
|
1451
1675
|
(!search || [node.label, node.snippet, node.project, node.category].filter(Boolean).join(' ').toLowerCase().includes(search)));
|
|
1452
1676
|
const ids = new Set(matches.map((node) => node.id));
|
|
1453
1677
|
if (search && !kind) {
|
|
1454
|
-
matches.forEach((node) => graphNeighbors(
|
|
1678
|
+
matches.forEach((node) => graphNeighbors(edges, node.id).forEach((item) => ids.add(item.id)));
|
|
1455
1679
|
}
|
|
1456
|
-
const matchingEdges =
|
|
1680
|
+
const matchingEdges = edges.filter((edge) => ids.has(edge.source) && ids.has(edge.target) &&
|
|
1457
1681
|
(!relation || (relation === 'recorded' ? recordedEdge(edge) : edge.kind === relation)));
|
|
1458
1682
|
if (relation) {
|
|
1459
1683
|
const endpoints = new Set(matchingEdges.flatMap((edge) => [edge.source, edge.target]));
|
|
@@ -1467,8 +1691,8 @@ function renderGraph() {
|
|
|
1467
1691
|
$('graph-count').textContent = matchingCount + countLabel(graph.nodes.length, 'node') + ' · ' + countLabel(graph.edges.length, 'connection');
|
|
1468
1692
|
$('graph-body').hidden = !graph.nodes.length;
|
|
1469
1693
|
$('graph-legend').hidden = !graph.nodes.length;
|
|
1470
|
-
const note = graph.snapshot.truncated ? '<div class="panel-body small muted">
|
|
1471
|
-
number(graph.snapshot.shownMemories) + ' memories
|
|
1694
|
+
const note = graph.snapshot.truncated ? '<div class="panel-body small muted">This snapshot includes ' +
|
|
1695
|
+
number(graph.snapshot.shownMemories) + ' memories. Filter by project to explore a narrower set.</div>' : '';
|
|
1472
1696
|
const focused = graph.focusMemory && graph.nodes.find((node) => graphMemoryId(node) === graph.focusMemory);
|
|
1473
1697
|
const missing = graph.focusMemory && !focused ? '<p class="panel-body small muted">This memory is outside the current graph view.</p>' : '';
|
|
1474
1698
|
$('graph-status').innerHTML = graph.nodes.length ? note + missing : missing + blank('graph', search || kind || relation ? 'No matching nodes' : 'No relationships yet',
|
|
@@ -1498,6 +1722,7 @@ async function loadGraph(project, force = false, memory = '') {
|
|
|
1498
1722
|
const controller = new AbortController();
|
|
1499
1723
|
graph.controller = controller;
|
|
1500
1724
|
graph.snapshot = null;
|
|
1725
|
+
if (graph.project !== project || memory) graph.lens = '';
|
|
1501
1726
|
graph.project = project;
|
|
1502
1727
|
graph.selected = '';
|
|
1503
1728
|
graph.selectedEdge = '';
|
|
@@ -1505,6 +1730,7 @@ async function loadGraph(project, force = false, memory = '') {
|
|
|
1505
1730
|
$('graph-status').innerHTML = skeleton('Loading relationships…');
|
|
1506
1731
|
$('graph-count').textContent = '';
|
|
1507
1732
|
$('graph-body').hidden = true;
|
|
1733
|
+
$('graph-lens').hidden = true;
|
|
1508
1734
|
$('graph-legend').hidden = true;
|
|
1509
1735
|
try {
|
|
1510
1736
|
const snapshot = await api(queryPath('graph', { project, memory }), { signal: AbortSignal.any([controller.signal, AbortSignal.timeout(12000)]) });
|
|
@@ -1521,10 +1747,11 @@ async function loadGraph(project, force = false, memory = '') {
|
|
|
1521
1747
|
function renderContextControls() {
|
|
1522
1748
|
const input = $('context-cross');
|
|
1523
1749
|
const toggle = state.features?.features;
|
|
1524
|
-
const canCross = toggle?.contextAssembly === true && toggle?.crossProjectContext === true;
|
|
1750
|
+
const canCross = document.documentElement.dataset.projectLocal !== 'true' && toggle?.contextAssembly === true && toggle?.crossProjectContext === true;
|
|
1525
1751
|
$('context-cross-row').hidden = !canCross;
|
|
1526
1752
|
if (!canCross) input.checked = false;
|
|
1527
1753
|
$('context-submit').disabled = !toggle?.contextAssembly || !state.projects.length || state.context.pending;
|
|
1754
|
+
$('context-related-row').hidden = $('context-profile').value !== 'adaptive';
|
|
1528
1755
|
const gate = $('context-gate');
|
|
1529
1756
|
if (!toggle && state.featurePending) {
|
|
1530
1757
|
gate.innerHTML = '<p class="muted small" role="status">Checking feature settings…</p>';
|
|
@@ -1547,11 +1774,99 @@ function contextReasonList(items, format) {
|
|
|
1547
1774
|
return '<ul class="list">' + items.map(format).join('') + '</ul>';
|
|
1548
1775
|
}
|
|
1549
1776
|
|
|
1777
|
+
const contextReasons = {
|
|
1778
|
+
selected: 'Included in the brief.', duplicate: 'Matches a memory already considered.', budget: 'Would exceed the selected budget.',
|
|
1779
|
+
limit: 'Beyond the brief’s memory limit.', 'candidate-limit': 'Beyond the evaluated candidate limit.', empty: 'Contains no memory text.',
|
|
1780
|
+
lookback: 'Falls outside the selected time range.', archived: 'Archived in a recorded review.', contested: 'Marked as needing review.',
|
|
1781
|
+
superseded: 'Superseded by a recorded replacement.'
|
|
1782
|
+
};
|
|
1783
|
+
const rankScore = (value) => Number.isFinite(value) ? value.toLocaleString(undefined, { maximumFractionDigits: 3 }) : '—';
|
|
1784
|
+
|
|
1785
|
+
function renderRetrieval(pack) {
|
|
1786
|
+
const retrieval = pack.retrieval;
|
|
1787
|
+
if (!retrieval || !pack.enabled) return '';
|
|
1788
|
+
const counts = list(retrieval.stages);
|
|
1789
|
+
const max = Math.max(1, ...counts.map((stage) => Number(stage.count) || 0));
|
|
1790
|
+
const stages = counts.map((stage) => '<li><strong>' + number(stage.count) + '</strong><span>' + esc(stage.label) +
|
|
1791
|
+
'</span><div class="retrieval-stage-bar" aria-hidden="true"><i style="width:' + Math.max(0, (Number(stage.count) || 0) / max * 100) + '%"></i></div></li>').join('');
|
|
1792
|
+
const candidates = list(retrieval.candidates);
|
|
1793
|
+
const labels = new Map([...list(pack.entries), ...candidates].map((item) => [item.id, item.title || shorten(compact(item.excerpt), 95) || item.id]));
|
|
1794
|
+
const rows = candidates.map((candidate) => {
|
|
1795
|
+
const signals = list(candidate.signals).map((signal) => {
|
|
1796
|
+
const sign = signal.label === 'Project task feedback' && signal.value > 0 ? '+' : '';
|
|
1797
|
+
return '<div><dt>' + esc(signal.label) + '</dt><dd>' + sign + esc(rankScore(signal.value)) + '</dd></div>';
|
|
1798
|
+
}).join('');
|
|
1799
|
+
const terms = list(candidate.matchedTerms);
|
|
1800
|
+
const fields = list(candidate.matchedFields);
|
|
1801
|
+
const paths = list(candidate.paths).map((path) => '<li><span class="tag agent">' + esc(linkTypes[path.relationType] || nice(path.relationType)) +
|
|
1802
|
+
'</span> ' + memoryLink(path.fromId, candidate.projectId, labels.get(path.fromId) || path.fromId) + ' ' + icon('chevron', true) + ' ' +
|
|
1803
|
+
memoryLink(path.toId, candidate.projectId, labels.get(path.toId) || path.toId) + '</li>').join('');
|
|
1804
|
+
const feedback = candidate.feedback;
|
|
1805
|
+
const reporters = list(feedback?.reporterKinds).map((kind) => kind === 'agent' ? 'Agent' : 'User');
|
|
1806
|
+
const feedbackSource = feedback ? '<p class="small muted">' + countLabel(list(feedback.recordIds).length, 'matching task report') +
|
|
1807
|
+
(reporters.length ? ' · ' + esc(reporters.join(' and ')) : '') +
|
|
1808
|
+
(state.projectKit?.projectId === candidate.projectId ? ' · <a href="' + esc(routeLink('project-kit', { memory: candidate.id })) + '">Review project outcomes</a>' : '') + '</p>' : '';
|
|
1809
|
+
const included = candidate.decision === 'selected';
|
|
1810
|
+
return '<li><details class="candidate"><summary><span class="candidate-title"><span class="rank">#' + number(candidate.rank) + '</span>' +
|
|
1811
|
+
'<span>' + esc(candidate.title || candidate.id) + '</span><span class="tag check-' + (included ? 'ok' : 'warn') + '">' +
|
|
1812
|
+
(included ? 'Included' : 'Excluded') + '</span></span></summary><div class="candidate-body"><p class="small muted">' +
|
|
1813
|
+
esc(contextReasons[candidate.reason] || nice(candidate.reason)) + ' Rank score ' + esc(rankScore(candidate.score)) + '.</p>' +
|
|
1814
|
+
(terms.length ? '<p class="small"><strong>Matched terms</strong> ' + esc(terms.join(', ')) + '</p>' : '') +
|
|
1815
|
+
(fields.length ? '<p class="small"><strong>Matched fields</strong> ' + esc(fields.map(nice).join(', ')) + '</p>' : '') +
|
|
1816
|
+
(signals ? '<dl class="candidate-signals" aria-label="Ranking contributions">' + signals + '</dl>' : '') + feedbackSource + sourceMarkup(candidate.sources) +
|
|
1817
|
+
(paths ? '<div><h3>Recorded link paths</h3><ul class="list">' + paths + '</ul></div>' : '') +
|
|
1818
|
+
'<p>' + memoryLink(candidate.id, candidate.projectId, 'Open memory') + '</p></div></details></li>';
|
|
1819
|
+
}).join('');
|
|
1820
|
+
const reportCount = retrieval.truncated ? ' Candidate diagnostics are bounded to ' + number(retrieval.candidateLimit) + ' records.' : '';
|
|
1821
|
+
return '<section class="context-section" aria-labelledby="retrieval-heading"><h3 id="retrieval-heading">Retrieval pipeline</h3>' +
|
|
1822
|
+
'<ol class="retrieval-flow" aria-label="Retrieval stages">' + stages + '</ol><p class="small muted">Scanned ' + number(retrieval.scanned) +
|
|
1823
|
+
' memories. Ranking contributions explain ordering.' + esc(reportCount) + '</p>' +
|
|
1824
|
+
(rows ? '<details class="context-section" open><summary>Candidate decisions · ' + number(candidates.length) + '</summary>' +
|
|
1825
|
+
'<ul class="list candidate-list" aria-label="Candidate decisions">' + rows + '</ul></details>' : '') + '</section>';
|
|
1826
|
+
}
|
|
1827
|
+
|
|
1828
|
+
function renderComparison() {
|
|
1829
|
+
const target = $('context-comparison');
|
|
1830
|
+
if (!target) return;
|
|
1831
|
+
const { comparison, comparing, dirty } = state.context;
|
|
1832
|
+
if (dirty || !comparison && !comparing) {
|
|
1833
|
+
target.replaceChildren();
|
|
1834
|
+
return;
|
|
1835
|
+
}
|
|
1836
|
+
if (comparing) {
|
|
1837
|
+
target.innerHTML = skeleton('Comparing retrieval profiles…');
|
|
1838
|
+
return;
|
|
1839
|
+
}
|
|
1840
|
+
if (comparison.error) {
|
|
1841
|
+
target.innerHTML = errorMarkup(comparison.error);
|
|
1842
|
+
return;
|
|
1843
|
+
}
|
|
1844
|
+
const { legacy, adaptive, delta } = comparison;
|
|
1845
|
+
const shared = list(delta?.sharedIds);
|
|
1846
|
+
const column = (label, pack, ids) => {
|
|
1847
|
+
const unique = new Set(ids);
|
|
1848
|
+
const entries = list(pack.entries);
|
|
1849
|
+
const differences = entries.filter((entry) => unique.has(entry.id));
|
|
1850
|
+
return '<div><h3>' + label + '</h3><p class="small muted">' + countLabel(entries.length, 'included memory', 'included memories') + ' · ' +
|
|
1851
|
+
number(pack.budget?.estimatedTokens) + ' estimated tokens</p><p class="small"><strong>' + number(differences.length) + ' unique to ' + label + '</strong></p>' +
|
|
1852
|
+
(differences.length ? '<ul class="small">' + differences.map((entry) => '<li>' +
|
|
1853
|
+
memoryLink(entry.id, entry.projectId, shorten(compact(entry.excerpt), 95) || entry.id) + '</li>').join('') + '</ul>' : '') + '</div>';
|
|
1854
|
+
};
|
|
1855
|
+
target.innerHTML = '<h3>Profile comparison</h3><p class="small muted">Same task, scope, and requested budget · ' +
|
|
1856
|
+
countLabel(shared.length, 'shared memory', 'shared memories') + '</p><div class="compare-grid">' +
|
|
1857
|
+
column('Adaptive', adaptive, list(delta?.addedIds)) + column('Legacy', legacy, list(delta?.removedIds)) + '</div>' +
|
|
1858
|
+
list(comparison.warnings).map((warning) => '<p class="small muted">' + esc(warning) + '</p>').join('');
|
|
1859
|
+
}
|
|
1860
|
+
|
|
1550
1861
|
function renderContext() {
|
|
1551
1862
|
const output = $('context-output');
|
|
1552
|
-
const { pack, dirty } = state.context;
|
|
1863
|
+
const { pack, dirty, params } = state.context;
|
|
1864
|
+
const status = $('context-result-state');
|
|
1553
1865
|
if (!pack) {
|
|
1554
|
-
|
|
1866
|
+
const enabled = state.features?.features?.contextAssembly !== false;
|
|
1867
|
+
status.textContent = enabled ? '' : 'Disabled';
|
|
1868
|
+
output.innerHTML = enabled ? blank('context', 'Ready for a task', 'Choose a project and describe the work to see the context and its sources here.') :
|
|
1869
|
+
blank('context', 'Context assembly is turned off', 'Enable it in Features to build a brief.');
|
|
1555
1870
|
return;
|
|
1556
1871
|
}
|
|
1557
1872
|
const entries = list(pack.entries);
|
|
@@ -1559,7 +1874,9 @@ function renderContext() {
|
|
|
1559
1874
|
const budget = pack.budget || {};
|
|
1560
1875
|
const warnings = list(pack.warnings);
|
|
1561
1876
|
const allowed = state.features?.features?.contextAssembly === true;
|
|
1562
|
-
const
|
|
1877
|
+
const canInspect = allowed && !dirty && pack.enabled;
|
|
1878
|
+
const canCopy = canInspect && !!pack.markdown && entries.length > 0;
|
|
1879
|
+
status.textContent = dirty ? 'Rebuild needed' : pack.enabled ? 'Assembled' : 'Disabled';
|
|
1563
1880
|
const warningMarkup = warnings.map((warning) => '<p class="small muted">' + esc(warning) + '</p>').join('');
|
|
1564
1881
|
const selection = contextReasonList(entries, (entry) => {
|
|
1565
1882
|
const title = shorten(compact(entry.excerpt), 120) || nice(entry.category) || entry.id;
|
|
@@ -1573,34 +1890,29 @@ function renderContext() {
|
|
|
1573
1890
|
esc([entry.projectName, entry.agentTool, nice(entry.category)].filter(Boolean).join(' · ')) +
|
|
1574
1891
|
'</div>' + reason + sourceMarkup(entry.sources) + links + '</li>';
|
|
1575
1892
|
});
|
|
1576
|
-
const reasonLabels = {
|
|
1577
|
-
duplicate: 'Matches a memory already considered.',
|
|
1578
|
-
budget: 'Would exceed the selected budget.',
|
|
1579
|
-
limit: 'Beyond the brief’s memory limit.',
|
|
1580
|
-
empty: 'Contains no memory text.',
|
|
1581
|
-
lookback: 'Falls outside the selected time range.',
|
|
1582
|
-
archived: 'Archived in a recorded review.',
|
|
1583
|
-
contested: 'Marked as needing review.',
|
|
1584
|
-
superseded: 'Superseded by a recorded replacement.'
|
|
1585
|
-
};
|
|
1586
1893
|
const rejections = contextReasonList(excluded, (entry) => '<li><strong class="mono">' +
|
|
1587
1894
|
memoryLink(entry.id, entry.projectId || (pack.scope === 'project' ? pack.projectId : ''), entry.title || entry.id) +
|
|
1588
|
-
'</strong><p class="small muted">' + esc(
|
|
1895
|
+
'</strong><p class="small muted">' + esc(contextReasons[entry.reason] || nice(entry.reason)) + '</p></li>');
|
|
1589
1896
|
const projectName = state.projects.find((item) => item.id === pack.projectId)?.name || pack.projectId;
|
|
1590
1897
|
const scope = pack.scope === 'cross-project' ? 'Cross-project · ' + projectName : projectName;
|
|
1898
|
+
const usage = budget.tokenBudget > 0 ? Math.min(100, Math.max(0, budget.estimatedTokens / budget.tokenBudget * 100)) : 0;
|
|
1591
1899
|
output.innerHTML = '<div class="panel-body stack">' + (dirty ? '<p class="status small" role="status">This preview is out of date. Assemble again to refresh it.</p>' : '') +
|
|
1592
|
-
'<div class="
|
|
1593
|
-
(
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
(
|
|
1599
|
-
|
|
1900
|
+
'<div class="context-output-head">' + tags([['project', scope], ['memory', params?.profile === 'adaptive' ? 'Adaptive' : 'Legacy']]) +
|
|
1901
|
+
'<div class="form-actions">' + (canInspect && params ? '<button type="button" class="button" id="context-compare-button"' +
|
|
1902
|
+
(state.context.comparing ? ' disabled' : '') + '>Compare profiles</button>' : '') +
|
|
1903
|
+
(canCopy ? '<button class="button" id="context-download" type="button">Download .md</button>' +
|
|
1904
|
+
'<button class="button primary" id="context-copy" type="button">' + icon('copy') + 'Copy brief</button>' : '') + '</div></div>' +
|
|
1905
|
+
'<p id="copy-status" class="small muted" role="status" hidden></p><dl class="context-metrics">' +
|
|
1906
|
+
'<div><dt>Estimated tokens</dt><dd>' + number(budget.estimatedTokens) + ' / ' + number(budget.tokenBudget) + '</dd><div class="context-budget-track" aria-hidden="true"><span style="width:' + usage + '%"></span></div></div>' +
|
|
1907
|
+
'<div><dt>Characters</dt><dd>' + number(budget.usedChars) + ' / ' + number(budget.maxChars) + '</dd></div>' +
|
|
1908
|
+
'<div><dt>Included / excluded</dt><dd>' + number(entries.length) + ' / ' + number(excluded.length) + '</dd></div></dl>' +
|
|
1909
|
+
warningMarkup + '<section class="context-compare" id="context-comparison" aria-live="polite"></section>' + renderRetrieval(pack) +
|
|
1600
1910
|
'<div class="context-reasons">' +
|
|
1601
|
-
(entries.length ? '<details
|
|
1602
|
-
(excluded.length ? '<details><summary>Excluded · ' + number(excluded.length) + '</summary>' + rejections + '</details>' : '') +
|
|
1603
|
-
'</div></
|
|
1911
|
+
(entries.length ? '<details class="context-section"><summary>Included memories · ' + number(entries.length) + '</summary>' + selection + '</details>' : '') +
|
|
1912
|
+
(excluded.length ? '<details class="context-section"><summary>Excluded memories · ' + number(excluded.length) + '</summary>' + rejections + '</details>' : '') +
|
|
1913
|
+
'</div>' + (pack.markdown && pack.enabled && entries.length ? '<details class="context-section" open><summary>Assembled brief</summary><pre class="context-preview mono" id="context-text" tabindex="0" aria-label="Assembled context markdown">' + esc(pack.markdown) + '</pre></details>' :
|
|
1914
|
+
blank('context', pack.enabled ? 'No memories fit this task' : 'Context assembly is turned off', pack.enabled ? 'Review any exclusions or try a different task.' : 'Enable it in Features to build a brief.')) + '</div>';
|
|
1915
|
+
renderComparison();
|
|
1604
1916
|
}
|
|
1605
1917
|
|
|
1606
1918
|
async function assembleContext() {
|
|
@@ -1615,18 +1927,29 @@ async function assembleContext() {
|
|
|
1615
1927
|
$('context-task').reportValidity();
|
|
1616
1928
|
return;
|
|
1617
1929
|
}
|
|
1618
|
-
const
|
|
1930
|
+
const profile = $('context-profile').value;
|
|
1931
|
+
const body = { query, projectId, tokenBudget, includeCrossProject: toggle.crossProjectContext && $('context-cross').checked,
|
|
1932
|
+
profile, ...(profile === 'adaptive' ? { expandRelated: $('context-related').checked } : {}) };
|
|
1619
1933
|
store.pending = true;
|
|
1620
1934
|
store.dirty = false;
|
|
1935
|
+
store.pack = null;
|
|
1936
|
+
store.params = body;
|
|
1937
|
+
store.comparison = null;
|
|
1938
|
+
store.comparing = false;
|
|
1621
1939
|
renderContextControls();
|
|
1622
1940
|
setBusy($('context-result'), true);
|
|
1941
|
+
$('context-result-state').textContent = 'Assembling';
|
|
1623
1942
|
$('context-output').innerHTML = skeleton('Assembling context…');
|
|
1624
1943
|
try {
|
|
1625
|
-
|
|
1944
|
+
const pack = await api('context', { body });
|
|
1945
|
+
const current = state.features?.features;
|
|
1946
|
+
if (store.params === body && current?.contextAssembly && (pack.scope !== 'cross-project' || current.crossProjectContext)) store.pack = pack;
|
|
1626
1947
|
renderContext();
|
|
1627
1948
|
} catch (error) {
|
|
1628
|
-
store.
|
|
1629
|
-
|
|
1949
|
+
if (store.params === body) {
|
|
1950
|
+
$('context-result-state').textContent = 'Request failed';
|
|
1951
|
+
$('context-output').innerHTML = errorMarkup(error.message, 'context');
|
|
1952
|
+
}
|
|
1630
1953
|
} finally {
|
|
1631
1954
|
store.pending = false;
|
|
1632
1955
|
setBusy($('context-result'), false);
|
|
@@ -1634,10 +1957,44 @@ async function assembleContext() {
|
|
|
1634
1957
|
}
|
|
1635
1958
|
}
|
|
1636
1959
|
|
|
1960
|
+
async function compareContext() {
|
|
1961
|
+
const store = state.context;
|
|
1962
|
+
if (!store.params || store.dirty || store.pending || store.comparing || !store.pack?.enabled) return;
|
|
1963
|
+
const params = store.params;
|
|
1964
|
+
const { profile, ...body } = params;
|
|
1965
|
+
store.comparing = true;
|
|
1966
|
+
$('context-compare-button').disabled = true;
|
|
1967
|
+
renderComparison();
|
|
1968
|
+
try {
|
|
1969
|
+
const result = await api('context-compare', { body });
|
|
1970
|
+
if (!result.adaptive || !result.legacy || !result.delta) throw new Error('The server returned an unreadable comparison.');
|
|
1971
|
+
if (store.params === params && !store.dirty) store.comparison = result;
|
|
1972
|
+
} catch (error) {
|
|
1973
|
+
if (store.params === params && !store.dirty) store.comparison = { error: error.message };
|
|
1974
|
+
} finally {
|
|
1975
|
+
if (store.params === params) {
|
|
1976
|
+
store.comparing = false;
|
|
1977
|
+
if ($('context-compare-button')) $('context-compare-button').disabled = false;
|
|
1978
|
+
renderComparison();
|
|
1979
|
+
}
|
|
1980
|
+
}
|
|
1981
|
+
}
|
|
1982
|
+
|
|
1983
|
+
function downloadContext() {
|
|
1984
|
+
const { pack, dirty } = state.context;
|
|
1985
|
+
if (!pack?.markdown || !pack.enabled || dirty || !state.features?.features.contextAssembly) return;
|
|
1986
|
+
const url = URL.createObjectURL(new Blob([pack.markdown], { type: 'text/markdown;charset=utf-8' }));
|
|
1987
|
+
const link = document.createElement('a');
|
|
1988
|
+
link.href = url;
|
|
1989
|
+
link.download = 'shadow-brain-context.md';
|
|
1990
|
+
link.click();
|
|
1991
|
+
setTimeout(() => URL.revokeObjectURL(url), 1000);
|
|
1992
|
+
}
|
|
1993
|
+
|
|
1637
1994
|
async function copyContext() {
|
|
1638
1995
|
const store = state.context;
|
|
1639
1996
|
const status = $('copy-status');
|
|
1640
|
-
if (!store.pack?.markdown || store.dirty || !status) return;
|
|
1997
|
+
if (!store.pack?.markdown || !store.pack.enabled || store.dirty || !status || !state.features?.features.contextAssembly) return;
|
|
1641
1998
|
try {
|
|
1642
1999
|
await navigator.clipboard.writeText(store.pack.markdown);
|
|
1643
2000
|
status.textContent = 'Brief copied.';
|
|
@@ -1682,6 +2039,12 @@ function renderIntegrations(data) {
|
|
|
1682
2039
|
const agentRows = agents.map((agent) => '<li class="check-row"><h3>' + esc(agent.label || agent.id) + '</h3><div class="check-result">' +
|
|
1683
2040
|
tags(list(agent.capabilities).map((value) => ['memory', value])) + (agent.detail ? '<p class="small muted">' + esc(agent.detail) + '</p>' : '') +
|
|
1684
2041
|
(agent.note ? '<p class="small muted">' + esc(agent.note) + '</p>' : '') + commandMarkup(agent.command) +
|
|
2042
|
+
(typeof agent.config?.content === 'string' ? '<details class="integration-config"><summary>View MCP setup example</summary>' +
|
|
2043
|
+
'<p class="small muted">' + esc([agent.config.format, agent.config.filename].filter(Boolean).join(' · ')) + '</p>' +
|
|
2044
|
+
'<pre class="context-preview mono" tabindex="0">' + esc(agent.config.content) + '</pre>' +
|
|
2045
|
+
list(agent.config.notes).map((note) => '<p class="small muted">' + esc(note) + '</p>').join('') +
|
|
2046
|
+
'<div class="form-actions"><button type="button" class="button quiet" data-copy-command="' + esc(agent.config.content) + '">' +
|
|
2047
|
+
icon('copy', true) + 'Copy example</button><span class="small muted" role="status"></span></div></details>' : '') +
|
|
1685
2048
|
'<div class="form-actions">' + docsLink(agent.docs) + '</div></div>' + checkTag(agent.installation, installStates) + '</li>').join('');
|
|
1686
2049
|
$('integrations-body').innerHTML = '<div class="stack"><section class="panel"><div class="panel-head"><div><h2>Local diagnostics</h2>' +
|
|
1687
2050
|
(data.checkedAt ? '<p class="small muted">Last checked ' + dateMarkup(data.checkedAt) + '</p>' : '') + '</div>' +
|
|
@@ -1689,7 +2052,8 @@ function renderIntegrations(data) {
|
|
|
1689
2052
|
'Copy report</button><span class="small muted" role="status"></span></div>' : '') + '</div>' +
|
|
1690
2053
|
(checkRows ? '<ul class="list">' + checkRows + '</ul>' : blank('activity', 'No diagnostic results', 'Run checks to refresh the local status.')) +
|
|
1691
2054
|
'</section><section class="panel"><div class="panel-head"><div><h2>Supported agents</h2>' +
|
|
1692
|
-
'<p class="small muted">Installation status reflects
|
|
2055
|
+
'<p class="small muted">Installation status reflects project skill files. Use Live operations to inspect recorded sessions.</p></div></div>' +
|
|
2056
|
+
'<div class="integration-meta"><span class="tag project">Project skill files</span><span class="tag memory">MCP setup examples</span><a class="small" href="/live">Recorded sessions ' + icon('chevron', true) + '</a></div>' +
|
|
1693
2057
|
(agentRows ? '<ul class="list">' + agentRows + '</ul>' : blank('integrations', 'No agent data', 'Run checks to load the support catalog.')) +
|
|
1694
2058
|
'</section></div>';
|
|
1695
2059
|
}
|
|
@@ -1725,18 +2089,25 @@ async function copyIntegrationText(value, message, button) {
|
|
|
1725
2089
|
}
|
|
1726
2090
|
}
|
|
1727
2091
|
|
|
2092
|
+
function projectFeatureLimit(id) {
|
|
2093
|
+
if (document.documentElement.dataset.projectLocal !== 'true') return undefined;
|
|
2094
|
+
return { crossProjectContext: 'Project memory stays scoped to this project.', automaticBriefing: 'Automatic briefing requires a legacy analysis session.' }[id];
|
|
2095
|
+
}
|
|
2096
|
+
|
|
1728
2097
|
function renderFeatures() {
|
|
1729
2098
|
const target = $('feature-list');
|
|
1730
2099
|
if (!state.features) return;
|
|
1731
2100
|
const current = state.features.features;
|
|
1732
2101
|
const overrides = new Map(list(state.features.definitions).map((item) => [item.id, item]));
|
|
2102
|
+
const icons = { contextAssembly: 'context', crossProjectContext: 'graph', automaticBriefing: 'agent', liveActivity: 'activity', activityRecording: 'memory' };
|
|
1733
2103
|
target.innerHTML = '<ul class="list">' + definitions.map((definition) => {
|
|
1734
2104
|
const display = overrides.get(definition.id) || definition;
|
|
1735
|
-
const
|
|
1736
|
-
|
|
1737
|
-
|
|
2105
|
+
const reason = projectFeatureLimit(definition.id);
|
|
2106
|
+
const on = !reason && current[definition.id] === true;
|
|
2107
|
+
return '<li class="setting"><div class="settings-description"><span class="tile-icon">' + icon(icons[definition.id], true) + '</span><div><h3 id="label-' + definition.id + '">' + esc(display.label) + '</h3><p class="muted small" id="desc-' +
|
|
2108
|
+
definition.id + '">' + esc(reason || display.description) + '</p></div></div><button type="button" class="button switch" role="switch" aria-checked="' +
|
|
1738
2109
|
on + '" aria-labelledby="label-' + definition.id + '" aria-describedby="desc-' + definition.id + '" data-feature="' + definition.id + '"' +
|
|
1739
|
-
(state.featureSaving ? ' disabled' : '') + '><span aria-hidden="true">' + (on ? 'On' : 'Off') + '</span><span class="switch-track" aria-hidden="true"></span></button></li>';
|
|
2110
|
+
(state.featureSaving || reason ? ' disabled' : '') + '><span aria-hidden="true">' + (reason ? 'Unavailable' : on ? 'On' : 'Off') + '</span><span class="switch-track" aria-hidden="true"></span></button></li>';
|
|
1740
2111
|
}).join('') + '</ul>';
|
|
1741
2112
|
}
|
|
1742
2113
|
|
|
@@ -1749,11 +2120,17 @@ function applyFeatures(snapshot) {
|
|
|
1749
2120
|
if (state.features && snapshot.revision < state.features.revision) return;
|
|
1750
2121
|
state.features = snapshot;
|
|
1751
2122
|
state.activityEnabled = current.liveActivity;
|
|
1752
|
-
|
|
2123
|
+
const context = state.context;
|
|
2124
|
+
if (!current.contextAssembly || !current.crossProjectContext && context.params?.includeCrossProject) {
|
|
2125
|
+
context.pack = null;
|
|
2126
|
+
context.params = null;
|
|
2127
|
+
context.comparison = null;
|
|
2128
|
+
context.comparing = false;
|
|
2129
|
+
}
|
|
1753
2130
|
renderFeatures();
|
|
1754
2131
|
renderActivity();
|
|
1755
2132
|
renderContextControls();
|
|
1756
|
-
if (
|
|
2133
|
+
if (!context.pending) renderContext();
|
|
1757
2134
|
if (current.liveActivity && before?.liveActivity !== true) void refreshActivity();
|
|
1758
2135
|
}
|
|
1759
2136
|
|
|
@@ -1788,7 +2165,7 @@ async function loadFeatures(force = false) {
|
|
|
1788
2165
|
}
|
|
1789
2166
|
|
|
1790
2167
|
async function toggleFeature(key) {
|
|
1791
|
-
if (state.featureSaving || !state.features || !definitions.some((definition) => definition.id === key)) return;
|
|
2168
|
+
if (state.featureSaving || !state.features || projectFeatureLimit(key) || !definitions.some((definition) => definition.id === key)) return;
|
|
1792
2169
|
state.featureSaving = true;
|
|
1793
2170
|
$('feature-list').querySelectorAll('[data-feature]').forEach((button) => { button.disabled = true; });
|
|
1794
2171
|
featureStatus('Saving…');
|
|
@@ -1859,12 +2236,10 @@ function changeView(moveFocus = false) {
|
|
|
1859
2236
|
for (const name of Object.keys(viewNames)) {
|
|
1860
2237
|
const section = $('page-' + name);
|
|
1861
2238
|
section.hidden = name !== view;
|
|
1862
|
-
section.classList.remove('entered');
|
|
1863
2239
|
const link = document.querySelector('[data-view="' + name + '"]');
|
|
1864
2240
|
if (name === view || name === 'memories' && view === 'memory') link?.setAttribute('aria-current', 'page');
|
|
1865
2241
|
else link?.removeAttribute('aria-current');
|
|
1866
2242
|
}
|
|
1867
|
-
if (previous !== view) $('page-' + view).classList.add('entered');
|
|
1868
2243
|
if (moveFocus && (previous !== view || view === 'memory')) {
|
|
1869
2244
|
window.scrollTo(0, 0);
|
|
1870
2245
|
$('title-' + view).focus({ preventScroll: true });
|
|
@@ -1906,9 +2281,9 @@ function changeView(moveFocus = false) {
|
|
|
1906
2281
|
if (project) {
|
|
1907
2282
|
state.context.routeProject = project;
|
|
1908
2283
|
syncProjectOptions();
|
|
1909
|
-
if (state.context.
|
|
2284
|
+
if (state.context.params && state.context.params.projectId !== project) {
|
|
1910
2285
|
state.context.dirty = true;
|
|
1911
|
-
renderContext();
|
|
2286
|
+
if (!state.context.pending) renderContext();
|
|
1912
2287
|
}
|
|
1913
2288
|
}
|
|
1914
2289
|
void loadOverview();
|
|
@@ -1919,6 +2294,9 @@ function changeView(moveFocus = false) {
|
|
|
1919
2294
|
featureStatus('');
|
|
1920
2295
|
void loadFeatures(true);
|
|
1921
2296
|
break;
|
|
2297
|
+
case 'project-kit':
|
|
2298
|
+
void loadProjectKit();
|
|
2299
|
+
break;
|
|
1922
2300
|
case 'integrations':
|
|
1923
2301
|
if (state.integrations.snapshot) renderIntegrations(state.integrations.snapshot);
|
|
1924
2302
|
else void loadIntegrations();
|
|
@@ -1986,8 +2364,7 @@ $('theme-setting').addEventListener('change', (event) => setPreference('theme',
|
|
|
1986
2364
|
$('motion-setting').addEventListener('change', (event) => setPreference('motion', event.target.value));
|
|
1987
2365
|
$('memory-form').addEventListener('submit', (event) => { event.preventDefault(); changeMemorySearch(); });
|
|
1988
2366
|
['memory-project', 'memory-category', 'memory-agent', 'memory-state'].forEach((id) => $(id).addEventListener('change', changeMemorySearch));
|
|
1989
|
-
$('overview-
|
|
1990
|
-
if (event.target.id !== 'overview-quality-project') return;
|
|
2367
|
+
$('overview-quality-project').addEventListener('change', (event) => {
|
|
1991
2368
|
const project = event.target.value;
|
|
1992
2369
|
const route = routeLink('overview', { project });
|
|
1993
2370
|
window.history.replaceState(null, '', route);
|
|
@@ -1996,6 +2373,14 @@ $('overview-body').addEventListener('change', (event) => {
|
|
|
1996
2373
|
if (state.view === 'overview' && state.route === route) $('overview-quality-project')?.focus();
|
|
1997
2374
|
});
|
|
1998
2375
|
});
|
|
2376
|
+
$('overview-body').addEventListener('change', (event) => {
|
|
2377
|
+
if (event.target.id !== 'attention-filter') return;
|
|
2378
|
+
state.health.filter = event.target.value;
|
|
2379
|
+
renderAttention();
|
|
2380
|
+
});
|
|
2381
|
+
$('overview-body').addEventListener('click', (event) => {
|
|
2382
|
+
if (event.target.closest('#attention-jump')) $('attention-heading')?.focus();
|
|
2383
|
+
});
|
|
1999
2384
|
$('integrations-refresh').addEventListener('click', () => { void loadIntegrations(); });
|
|
2000
2385
|
$('graph-query').addEventListener('input', renderGraph);
|
|
2001
2386
|
$('graph-kind').addEventListener('change', renderGraph);
|
|
@@ -2012,6 +2397,13 @@ $('graph-project').addEventListener('change', (event) => {
|
|
|
2012
2397
|
renderGraph();
|
|
2013
2398
|
}));
|
|
2014
2399
|
$('graph-fit').addEventListener('click', () => fitGraph());
|
|
2400
|
+
$('graph-lens-clear').addEventListener('click', () => {
|
|
2401
|
+
const anchor = state.graph.lens;
|
|
2402
|
+
state.graph.lens = '';
|
|
2403
|
+
renderGraph();
|
|
2404
|
+
if (state.graph.nodes.some((node) => node.id === anchor)) selectGraphNode(anchor, { focus: true });
|
|
2405
|
+
else $('graph-query').focus();
|
|
2406
|
+
});
|
|
2015
2407
|
$('graph-in').addEventListener('click', () => zoomGraph(1.35));
|
|
2016
2408
|
$('graph-out').addEventListener('click', () => zoomGraph(1 / 1.35));
|
|
2017
2409
|
$('graph-svg').addEventListener('keydown', handleGraphKeyboard);
|
|
@@ -2048,6 +2440,7 @@ window.addEventListener('resize', () => {
|
|
|
2048
2440
|
$('context-form').addEventListener('submit', (event) => { event.preventDefault(); void assembleContext(); });
|
|
2049
2441
|
$('context-form').addEventListener('input', () => {
|
|
2050
2442
|
$('context-task').setCustomValidity('');
|
|
2443
|
+
$('context-related-row').hidden = $('context-profile').value !== 'adaptive';
|
|
2051
2444
|
const store = state.context;
|
|
2052
2445
|
if (store.pack || store.pending) {
|
|
2053
2446
|
if (!store.dirty) {
|
|
@@ -2076,12 +2469,14 @@ $('detail-body').addEventListener('submit', (event) => {
|
|
|
2076
2469
|
});
|
|
2077
2470
|
|
|
2078
2471
|
document.addEventListener('click', (event) => {
|
|
2079
|
-
const element = event.target.closest('[data-retry],[data-memory-clear],[data-memory-page],[data-node],[data-related],[data-edge-record],[data-feature],[data-unlink],[data-copy-command],#diagnostics-copy,#context-copy,.skip');
|
|
2472
|
+
const element = event.target.closest('[data-retry],[data-memory-clear],[data-memory-page],[data-node],[data-related],[data-edge-record],[data-graph-lens],[data-feature],[data-unlink],[data-copy-command],#diagnostics-copy,#context-copy,#context-download,#context-compare-button,.skip');
|
|
2080
2473
|
if (!element) return;
|
|
2081
2474
|
const data = element.dataset;
|
|
2082
2475
|
if (data.retry) {
|
|
2083
2476
|
switch (data.retry) {
|
|
2084
2477
|
case 'overview': void loadOverview(true, state.view === 'overview' ? routeParams().get('project') || '' : ''); break;
|
|
2478
|
+
case 'health': void loadHealth(state.overviewScope); break;
|
|
2479
|
+
case 'kit-profile': void loadProjectKit(true); break;
|
|
2085
2480
|
case 'memories': void loadMemories(state.memory.query || memoryQuery(), state.memory.offset); break;
|
|
2086
2481
|
case 'graph': void loadGraph(state.graph.project, true, state.graph.focusMemory); break;
|
|
2087
2482
|
case 'detail': void loadDetail(state.detail.id, state.detail.project); break;
|
|
@@ -2104,6 +2499,11 @@ document.addEventListener('click', (event) => {
|
|
|
2104
2499
|
graphSelectFromList(data.related, true);
|
|
2105
2500
|
} else if (data.edgeRecord) {
|
|
2106
2501
|
selectGraphEdge(data.edgeRecord, $('graph-inspector').contains(element));
|
|
2502
|
+
} else if (data.graphLens) {
|
|
2503
|
+
state.graph.lens = data.graphLens;
|
|
2504
|
+
['graph-query', 'graph-kind', 'graph-relation'].forEach((id) => { $(id).value = ''; });
|
|
2505
|
+
renderGraph();
|
|
2506
|
+
$('graph-lens-clear').focus();
|
|
2107
2507
|
} else if (data.unlink) {
|
|
2108
2508
|
void saveDetail('memory-unlink', { memoryId: state.detail.id, linkId: data.unlink }, 'link-editor');
|
|
2109
2509
|
} else if (data.copyCommand) {
|
|
@@ -2112,6 +2512,10 @@ document.addEventListener('click', (event) => {
|
|
|
2112
2512
|
void toggleFeature(data.feature);
|
|
2113
2513
|
} else if (element.id === 'context-copy') {
|
|
2114
2514
|
void copyContext();
|
|
2515
|
+
} else if (element.id === 'context-download') {
|
|
2516
|
+
downloadContext();
|
|
2517
|
+
} else if (element.id === 'context-compare-button') {
|
|
2518
|
+
void compareContext();
|
|
2115
2519
|
} else if (element.id === 'diagnostics-copy') {
|
|
2116
2520
|
void copyIntegrationText(state.integrations.snapshot?.diagnostics, 'Diagnostic report copied.', element);
|
|
2117
2521
|
} else if (element.classList.contains('skip')) {
|
|
@@ -2120,6 +2524,8 @@ document.addEventListener('click', (event) => {
|
|
|
2120
2524
|
}
|
|
2121
2525
|
});
|
|
2122
2526
|
|
|
2527
|
+
${PROJECT_KIT_SCRIPT}
|
|
2528
|
+
|
|
2123
2529
|
window.addEventListener('hashchange', () => changeView(true));
|
|
2124
2530
|
document.addEventListener('visibilitychange', () => { if (!document.hidden) void refreshActivity(); });
|
|
2125
2531
|
setInterval(() => { void refreshActivity(); }, 10000);
|