@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
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import * as fs from 'node:fs';
|
|
2
|
+
import * as os from 'node:os';
|
|
3
|
+
import * as path from 'node:path';
|
|
4
|
+
import * as http from 'node:http';
|
|
5
|
+
import { GlobalBrain } from '../brain/global-brain.js';
|
|
6
|
+
import { FeatureSettingsStore } from '../brain/feature-settings.js';
|
|
7
|
+
import { memoryAnnotationsFor } from '../brain/memory-annotations.js';
|
|
8
|
+
import { ActivityJournal } from '../brain/activity-journal.js';
|
|
9
|
+
import { MCPServer } from '../brain/mcp-server.js';
|
|
10
|
+
import { handleWorkspaceRequest } from './workspace-api.js';
|
|
11
|
+
import { WORKSPACE_HTML } from './workspace-html.js';
|
|
12
|
+
import { LIVE_WORKSPACE_HTML } from './live-workspace-html.js';
|
|
13
|
+
import { BRAIN_HUB_HTML } from './brain-hub-html.js';
|
|
14
|
+
import { WorkspaceRuntime } from './workspace-status.js';
|
|
15
|
+
const projectId = 'demo-checkout';
|
|
16
|
+
const seeds = [
|
|
17
|
+
['decision', 'Retry only idempotent checkout requests.\nA stable idempotency key keeps a retry from charging twice.', 'docs/checkout/decision.md'],
|
|
18
|
+
['pattern', 'retryBudgetPolicy limits reconnect attempts.\nUse capped exponential backoff with jitter; retries share a request budget.', 'src/retryBudgetPolicy.ts'],
|
|
19
|
+
['verification', 'A retry test proves one charge after a connection reset.\nThe synthetic fixture records three attempts and one committed operation.', 'tests/checkout-retry.test.ts'],
|
|
20
|
+
['warning', 'Do not retry validation failures.\nOnly transient connection failures enter the retry queue.', 'docs/checkout/errors.md'],
|
|
21
|
+
['lesson', 'The old retry loop reused stale request bodies.', 'docs/checkout/history.md'],
|
|
22
|
+
['decision', 'A reviewed retry queue preserves the original request identity.', 'docs/checkout/replacement.md'],
|
|
23
|
+
['lesson', 'A team note proposes retrying all failures.', ''],
|
|
24
|
+
['research', 'Latency measurements distinguish queue wait from tool execution.', 'docs/telemetry.md'],
|
|
25
|
+
['pattern', 'Cancellation releases the queue slot before admitting another request.', 'src/cancel-request.ts'],
|
|
26
|
+
['decision', 'Project context remains scoped unless broader retrieval is explicitly enabled.', 'docs/context-policy.md'],
|
|
27
|
+
['reference', 'Import replay uses the recorded checksum to deduplicate work.', 'src/import/replay.ts'],
|
|
28
|
+
['verification', 'A bounded importer rejects duplicate events without changing prior commits.', 'tests/import/replay.test.ts'],
|
|
29
|
+
['release', 'Release checks include migrations, rollback and retry regression cases.', 'docs/release.md'],
|
|
30
|
+
['research', 'Java worker interop uses the stable queue protocol.', 'docs/java-worker.md'],
|
|
31
|
+
['pattern', 'JavaScript UI state is separate from the Java worker protocol.', 'docs/ui-state.md'],
|
|
32
|
+
['lesson', 'Review the remaining retry assumption with the team.', ''],
|
|
33
|
+
['lesson', 'Review the remaining retry assumption with the team.', ''],
|
|
34
|
+
['warning', 'Exception boundaries must preserve the original request identifier.', 'src/errors.ts'],
|
|
35
|
+
['decision', 'A separate billing worker owns settlement reconciliation.', 'docs/billing.md', 'demo-billing'],
|
|
36
|
+
['pattern', 'Billing retry limits follow the settlement queue policy.', 'src/billing/retry.ts', 'demo-billing'],
|
|
37
|
+
];
|
|
38
|
+
/** An isolated loopback tour. Never discovers clients or opens default memory/provider configuration. */
|
|
39
|
+
export async function startDemoWorkspace(options = {}) {
|
|
40
|
+
const port = options.port ?? 0;
|
|
41
|
+
if (!Number.isSafeInteger(port) || port < 0 || port > 65535)
|
|
42
|
+
throw new TypeError('Demo port must be an integer from 0 to 65535.');
|
|
43
|
+
const tempRoot = fs.realpathSync(os.tmpdir());
|
|
44
|
+
const directory = fs.mkdtempSync(path.join(tempRoot, 'shadow-brain-demo-'));
|
|
45
|
+
const dbPath = path.join(directory, 'global.json');
|
|
46
|
+
const brain = GlobalBrain.getInstance({ dbPath, syncIntervalMs: 60000 });
|
|
47
|
+
if (brain.dbPath !== dbPath) {
|
|
48
|
+
fs.rmdirSync(directory);
|
|
49
|
+
throw new Error('Run demo in a separate CLI process so its memory store stays isolated.');
|
|
50
|
+
}
|
|
51
|
+
const settings = new FeatureSettingsStore({ filePath: path.join(directory, 'feature-settings.json') });
|
|
52
|
+
const journal = new ActivityJournal({ filePath: path.join(directory, 'activity-journal.json') });
|
|
53
|
+
const servers = [];
|
|
54
|
+
const runtime = new WorkspaceRuntime('demo');
|
|
55
|
+
let listener;
|
|
56
|
+
let timer;
|
|
57
|
+
let task;
|
|
58
|
+
let closing;
|
|
59
|
+
let stopped = false;
|
|
60
|
+
const close = () => closing ?? (closing = (async () => {
|
|
61
|
+
stopped = true;
|
|
62
|
+
if (timer)
|
|
63
|
+
clearTimeout(timer);
|
|
64
|
+
if (listener?.listening) {
|
|
65
|
+
listener.closeAllConnections();
|
|
66
|
+
await new Promise((resolve, reject) => listener.close(error => error ? reject(error) : resolve()));
|
|
67
|
+
}
|
|
68
|
+
if (task)
|
|
69
|
+
await task.catch(() => { });
|
|
70
|
+
for (const server of servers)
|
|
71
|
+
await server.finishMemorySession();
|
|
72
|
+
await brain.shutdown();
|
|
73
|
+
const resolved = path.resolve(directory);
|
|
74
|
+
const relative = path.relative(tempRoot, resolved);
|
|
75
|
+
if (!relative.startsWith('shadow-brain-demo-') || relative.includes(path.sep) ||
|
|
76
|
+
fs.lstatSync(resolved).isSymbolicLink() || fs.realpathSync(resolved) !== resolved)
|
|
77
|
+
throw new Error('Demo cleanup path changed; temporary files were retained.');
|
|
78
|
+
fs.rmSync(resolved, { recursive: true });
|
|
79
|
+
})());
|
|
80
|
+
try {
|
|
81
|
+
await brain.init();
|
|
82
|
+
const ids = seeds.map(([category, content, source, project], index) => brain.writeSync({
|
|
83
|
+
projectId: project ?? projectId, projectName: project ? 'Billing worker · demo' : 'Checkout API · demo',
|
|
84
|
+
category, content, agentTool: ['codex', 'claude-code', 'opencode'][index % 3],
|
|
85
|
+
importance: category === 'warning' ? 0.85 : 0.7, metadata: source ? { source } : {},
|
|
86
|
+
}));
|
|
87
|
+
await brain.sync();
|
|
88
|
+
const annotations = memoryAnnotationsFor(brain);
|
|
89
|
+
for (const [from, to, type] of [[2, 0, 'supports'], [0, 1, 'related'], [3, 6, 'contradicts'], [5, 4, 'supersedes'], [10, 11, 'supports'], [1, 12, 'related']]) {
|
|
90
|
+
await annotations.update({ kind: 'link', projectId, fromId: ids[from], toId: ids[to], type, note: 'Synthetic demonstration relationship.' });
|
|
91
|
+
}
|
|
92
|
+
await annotations.update({ kind: 'review', projectId, memoryId: ids[6], state: 'contested', note: 'Synthetic note awaiting evidence.' });
|
|
93
|
+
await settings.update({ activityRecording: true, liveActivity: true });
|
|
94
|
+
for (let i = 0; i < 3; i++) {
|
|
95
|
+
const server = new MCPServer(null, { toolProfile: 'memory', authToken: '' }, { brain, settings, projectDir: directory, projectId });
|
|
96
|
+
servers.push(server);
|
|
97
|
+
await server.handleRequest({ jsonrpc: '2.0', id: 1, method: 'initialize', params: {
|
|
98
|
+
protocolVersion: '2025-11-25', clientInfo: { name: 'synthetic-demo-' + i, version: '1' }, capabilities: {},
|
|
99
|
+
} });
|
|
100
|
+
}
|
|
101
|
+
let step = 0;
|
|
102
|
+
const tick = async () => {
|
|
103
|
+
const server = servers[step % servers.length];
|
|
104
|
+
const phase = ['understand', 'plan', 'work', 'verify'][Math.floor(step / servers.length) % 4];
|
|
105
|
+
await server.handleRequest({ jsonrpc: '2.0', id: 2, method: 'tools/call', params: {
|
|
106
|
+
name: 'activity_report', arguments: { kind: 'phase', phase, agent: 'demo-worker-' + (step % servers.length + 1) },
|
|
107
|
+
} });
|
|
108
|
+
const calls = [
|
|
109
|
+
{ name: 'context_pack', arguments: { projectId, query: 'Fix checkout retryBudgetPolicy', profile: 'adaptive', tokenBudget: 1800 } },
|
|
110
|
+
{ name: 'memory_health', arguments: { projectId, limit: 5 } },
|
|
111
|
+
{ name: 'memory_inspect', arguments: { projectId, memoryId: ids[step % 18] } },
|
|
112
|
+
];
|
|
113
|
+
await server.handleRequest({ jsonrpc: '2.0', id: 3, method: 'tools/call', params: calls[step % calls.length] });
|
|
114
|
+
step++;
|
|
115
|
+
};
|
|
116
|
+
for (let i = 0; i < 9; i++)
|
|
117
|
+
await tick();
|
|
118
|
+
listener = http.createServer((req, res) => {
|
|
119
|
+
const actualPort = listener.address().port;
|
|
120
|
+
if (!['127.0.0.1:' + actualPort, 'localhost:' + actualPort].includes(req.headers.host ?? '')) {
|
|
121
|
+
res.writeHead(403);
|
|
122
|
+
res.end('Unsupported host.');
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
if (req.url?.startsWith('/api/workspace/')) {
|
|
126
|
+
void handleWorkspaceRequest(req, res, { brain, settings, annotations, journal, demo: true, runtime });
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
if (req.method !== 'GET') {
|
|
130
|
+
res.writeHead(405);
|
|
131
|
+
res.end('Method not allowed.');
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
let pathname;
|
|
135
|
+
try {
|
|
136
|
+
pathname = new URL(req.url ?? '/', 'http://localhost').pathname;
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
res.writeHead(400);
|
|
140
|
+
res.end('Invalid request URL.');
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
if (pathname === '/favicon.ico') {
|
|
144
|
+
res.writeHead(204);
|
|
145
|
+
res.end();
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
const html = pathname === '/' || pathname === '/hub' ? BRAIN_HUB_HTML : pathname === '/workspace' || pathname === '/memory-workspace' ? WORKSPACE_HTML : pathname === '/live' ? LIVE_WORKSPACE_HTML : null;
|
|
149
|
+
if (!html) {
|
|
150
|
+
res.writeHead(404);
|
|
151
|
+
res.end('This demo serves /workspace and /live.');
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8', 'Cache-Control': 'no-store', 'X-Content-Type-Options': 'nosniff', 'Referrer-Policy': 'no-referrer' });
|
|
155
|
+
res.end(html.replace('<html ', '<html data-demo="true" '));
|
|
156
|
+
});
|
|
157
|
+
await new Promise((resolve, reject) => {
|
|
158
|
+
listener.once('error', reject);
|
|
159
|
+
listener.listen(port, '127.0.0.1', () => { listener.off('error', reject); resolve(); });
|
|
160
|
+
});
|
|
161
|
+
if (options.activity !== false) {
|
|
162
|
+
const schedule = () => {
|
|
163
|
+
if (stopped)
|
|
164
|
+
return;
|
|
165
|
+
timer = setTimeout(() => {
|
|
166
|
+
task = tick().catch(() => { console.error('A synthetic demo activity cycle failed; the workspace remains available.'); }).finally(schedule);
|
|
167
|
+
}, 1800);
|
|
168
|
+
};
|
|
169
|
+
schedule();
|
|
170
|
+
}
|
|
171
|
+
return { url: 'http://127.0.0.1:' + listener.address().port, directory, close };
|
|
172
|
+
}
|
|
173
|
+
catch (error) {
|
|
174
|
+
await close();
|
|
175
|
+
throw error;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
//# sourceMappingURL=demo-workspace.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"demo-workspace.js","sourceRoot":"","sources":["../../src/dashboard/demo-workspace.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"live-workspace-html.d.ts","sourceRoot":"","sources":["../../src/dashboard/live-workspace-html.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,mBAAmB,
|
|
1
|
+
{"version":3,"file":"live-workspace-html.d.ts","sourceRoot":"","sources":["../../src/dashboard/live-workspace-html.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,mBAAmB,QA+gCxB,CAAC"}
|
|
@@ -150,6 +150,36 @@ export const LIVE_WORKSPACE_HTML = String.raw `<!doctype html>
|
|
|
150
150
|
.event-link { border: 0; background: transparent; color: var(--ink); padding: 0; text-align: left; font: inherit; cursor: pointer; }
|
|
151
151
|
.event-link:hover, .event-link[aria-pressed="true"] { color: var(--cyan); text-decoration: underline; }
|
|
152
152
|
.event-row .tag { justify-self: end; }
|
|
153
|
+
h1 { font-size: 2.25rem; }
|
|
154
|
+
.stats { background: #172b38; }
|
|
155
|
+
.stat { padding: 15px 16px; }
|
|
156
|
+
.stat dd { font-size: 1.55rem; }
|
|
157
|
+
.stat:first-child dd { color: var(--cyan); }
|
|
158
|
+
.network-body { background: radial-gradient(ellipse at 50% 50%, #1c3c4b, #121f2d 64%); }
|
|
159
|
+
.network-panel { border-color: #456679; }
|
|
160
|
+
.topology-ring { stroke-opacity: .44; }
|
|
161
|
+
.network-core .core-ring { fill: none; stroke: var(--cyan); stroke-width: 1; stroke-opacity: .36; stroke-dasharray: 2 5; }
|
|
162
|
+
.network-edge.failed { stroke: var(--rose); }
|
|
163
|
+
.network-edge.active.failed { stroke: var(--rose); }
|
|
164
|
+
.network-edge.active.reported { stroke: var(--amber); }
|
|
165
|
+
.network-node.selected-event .node-surface { stroke-width: 2.6; stroke: currentColor; }
|
|
166
|
+
.session-row[aria-pressed="true"] { box-shadow: inset 0 0 0 1px #526e80; }
|
|
167
|
+
.legend-line.failed { border-color: var(--rose); }
|
|
168
|
+
.replay-bar { display: grid; grid-template-columns: auto minmax(150px,1fr) auto; align-items: end; gap: 11px; margin-bottom: 15px; padding: 12px 15px; background: #192d3b; }
|
|
169
|
+
.replay-bar h2 { color: var(--cyan); margin-bottom: 4px; }
|
|
170
|
+
.replay-bar .replay-caption { grid-column: 1 / -1; color: var(--muted); }
|
|
171
|
+
.replay-scrub { display: grid; gap: 3px; min-width: 0; }
|
|
172
|
+
.replay-scrub label { display: flex; justify-content: space-between; align-items: baseline; flex-wrap: wrap; gap: 4px; color: var(--muted); }
|
|
173
|
+
.replay-scrub input { width: 100%; min-height: 30px; margin: 0; accent-color: var(--cyan); }
|
|
174
|
+
.replay-buttons { display: flex; flex-wrap: wrap; gap: 5px; }
|
|
175
|
+
.replay-buttons .icon-button { width: 36px; padding: 0; }
|
|
176
|
+
.demo-notice { display: none; }
|
|
177
|
+
html[data-demo="true"] .demo-notice { display: flex; gap: 7px 10px; flex-wrap: wrap; padding: 8px 12px; margin-bottom: 14px; background: var(--amber-tint); color: var(--amber); border-radius: 7px; font-size: .83rem; }
|
|
178
|
+
.project-journal-notice { display: none; }
|
|
179
|
+
html[data-project-local="true"] .project-journal-notice { display: flex; gap: 4px 10px; flex-wrap: wrap; padding: 8px 12px; margin-bottom: 14px; background: var(--cyan-tint); color: var(--cyan); border-radius: 7px; font-size: .83rem; }
|
|
180
|
+
.project-journal-notice a { text-decoration: underline; text-underline-offset: 3px; }
|
|
181
|
+
.event-row[data-selected="true"] { background: var(--cyan-tint); }
|
|
182
|
+
.event-row[data-selected="true"] .event-link { color: var(--cyan); }
|
|
153
183
|
@keyframes arrive { from { background: var(--cyan-tint); opacity: .8; } to { background: transparent; opacity: 1; } }
|
|
154
184
|
html[data-motion="reduce"] *, html[data-motion="reduce"] *::before, html[data-motion="reduce"] *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
|
|
155
185
|
@media (prefers-reduced-motion: reduce) {
|
|
@@ -167,7 +197,9 @@ export const LIVE_WORKSPACE_HTML = String.raw `<!doctype html>
|
|
|
167
197
|
.main-nav { gap: 2px; }
|
|
168
198
|
.top-version { display: none; }
|
|
169
199
|
.head { flex-wrap: wrap; }
|
|
200
|
+
h1 { font-size: 1.82rem; }
|
|
170
201
|
.controls { justify-content: start; }
|
|
202
|
+
.replay-bar { grid-template-columns: minmax(0,1fr); }
|
|
171
203
|
.stats { grid-template-columns: repeat(2,minmax(0,1fr)); }
|
|
172
204
|
.stat + .stat { border-left: 0; }
|
|
173
205
|
.stat:nth-child(even) { border-left: 1px solid var(--line); }
|
|
@@ -191,20 +223,34 @@ export const LIVE_WORKSPACE_HTML = String.raw `<!doctype html>
|
|
|
191
223
|
<div class="top-inner">
|
|
192
224
|
<a class="brand" href="/" aria-label="Agent Shadow Brain workspace"><span class="brand-mark" data-icon="brand"></span><span>Agent Shadow Brain</span></a>
|
|
193
225
|
<nav class="main-nav" aria-label="Navigation"><a href="/">Workspace</a><a href="/live" aria-current="page">Live</a></nav>
|
|
194
|
-
<div class="top-state"><span class="small muted mono top-version">7.1.
|
|
226
|
+
<div class="top-state"><span class="small muted mono top-version">7.1.4</span><span id="demo-tag" class="tag warn" hidden>Synthetic demo</span><span id="stream-tag" class="tag"><span class="dot"></span><span id="stream-label">Connecting</span></span></div>
|
|
195
227
|
</div>
|
|
196
228
|
</header>
|
|
197
229
|
<main id="live-main" tabindex="-1">
|
|
230
|
+
<div class="demo-notice"><strong>Synthetic demo</strong><span>Scripted local MCP calls use sample data. Changes affect this temporary demo only.</span></div>
|
|
231
|
+
<div class="project-journal-notice"><strong>Project journal</strong><span>Live activity comes from this project’s local store.</span><a href="/#project-kit">Open Project Kit</a></div>
|
|
198
232
|
<div class="head">
|
|
199
233
|
<div><h1>Live operations</h1><p class="muted small">Follow recorded agent sessions, tool calls, and reported task phases.</p></div>
|
|
200
234
|
<div class="controls" aria-label="Live view controls">
|
|
201
235
|
<label for="time-window" class="label">Window<select id="time-window"><option value="1">1 minute</option><option value="5">5 minutes</option><option value="15" selected>15 minutes</option><option value="60">1 hour</option></select></label>
|
|
202
236
|
<button class="button" type="button" id="motion-control" aria-pressed="false"><span data-icon="motion"></span>Reduce motion</button>
|
|
203
237
|
<button class="button" type="button" id="refresh"><span data-icon="refresh"></span>Refresh</button>
|
|
238
|
+
<button class="button" type="button" id="replay-start" disabled><span data-icon="replay"></span>Replay loaded events</button>
|
|
204
239
|
<button class="button primary" type="button" id="pause"><span data-icon="pause"></span><span id="pause-label">Pause stream</span></button>
|
|
205
240
|
</div>
|
|
206
241
|
</div>
|
|
207
242
|
<div class="notice" id="stream-notice" role="status">Connecting to the local event journal…</div>
|
|
243
|
+
<section class="panel replay-bar" id="replay-bar" aria-labelledby="replay-heading" hidden>
|
|
244
|
+
<div><h2 id="replay-heading" tabindex="-1">Journal replay</h2><div class="replay-buttons" aria-label="Replay controls">
|
|
245
|
+
<button class="button icon-button" type="button" id="replay-prev" aria-label="Previous event" title="Previous event"><span data-icon="prev"></span></button>
|
|
246
|
+
<button class="button" type="button" id="replay-play">Play</button>
|
|
247
|
+
<button class="button icon-button" type="button" id="replay-next" aria-label="Next event" title="Next event"><span data-icon="next"></span></button>
|
|
248
|
+
</div></div>
|
|
249
|
+
<div class="replay-scrub"><label for="replay-range"><span>Event position</span><output for="replay-range" class="small mono" id="replay-position" aria-live="off"></output></label>
|
|
250
|
+
<input type="range" min="0" max="0" value="0" id="replay-range" aria-describedby="replay-caption"></div>
|
|
251
|
+
<button class="button primary" type="button" id="replay-exit">Return to live</button>
|
|
252
|
+
<p class="small replay-caption" id="replay-caption"></p>
|
|
253
|
+
</section>
|
|
208
254
|
<dl class="stats" id="live-stats" aria-label="Tool metrics in the selected window"></dl>
|
|
209
255
|
<div class="ops-grid">
|
|
210
256
|
<section class="panel">
|
|
@@ -214,7 +260,7 @@ export const LIVE_WORKSPACE_HTML = String.raw `<!doctype html>
|
|
|
214
260
|
<section class="panel network-panel">
|
|
215
261
|
<div class="panel-head"><div><h2>Activity network</h2><p class="small muted" id="network-count">Recorded session activity</p></div><span id="network-status" class="tag"></span></div>
|
|
216
262
|
<div class="network-body"><svg id="network-svg" viewBox="0 0 720 405" role="group" aria-label="Activity network. Use arrow keys to navigate sessions."></svg></div>
|
|
217
|
-
<div class="network-caption"><span><i class="legend-line"></i>Measured activity</span><span><i class="legend-line reported"></i>Host-reported activity</span></div>
|
|
263
|
+
<div class="network-caption"><span><i class="legend-line"></i>Measured activity</span><span><i class="legend-line reported"></i>Host-reported activity</span><span><i class="legend-line failed"></i>Error or cancellation</span></div>
|
|
218
264
|
</section>
|
|
219
265
|
<section class="panel inspect-panel">
|
|
220
266
|
<div class="panel-head"><h2>Session details</h2></div><div id="inspection" class="inspect-body"></div>
|
|
@@ -227,6 +273,7 @@ export const LIVE_WORKSPACE_HTML = String.raw `<!doctype html>
|
|
|
227
273
|
<section class="panel">
|
|
228
274
|
<div class="panel-head"><div><h2>Event timeline</h2><p class="small muted" id="timeline-scope">All sessions</p></div><div class="controls">
|
|
229
275
|
<label class="label" for="event-filter">Event source<select id="event-filter"><option value="">All sources</option><option value="measured">Measured</option><option value="reported">Reported</option></select></label>
|
|
276
|
+
<label class="label" for="transport-filter">Transport<select id="transport-filter"><option value="">All transports</option><option value="mcp">MCP</option><option value="cli">CLI</option><option value="host">Host</option></select></label>
|
|
230
277
|
<button class="button quiet" type="button" id="clear-session" hidden>Show all sessions</button></div>
|
|
231
278
|
</div><div id="events" class="events"></div>
|
|
232
279
|
</section>
|
|
@@ -240,6 +287,9 @@ const glyphs = {
|
|
|
240
287
|
refresh: '<path d="M19.5 9a8 8 0 1 0 .3 5.5M20 4v5h-5"/>',
|
|
241
288
|
pause: '<path d="M9 5v14m6-14v14"/>',
|
|
242
289
|
play: '<path d="m8 5 11 7-11 7z"/>',
|
|
290
|
+
replay: '<path d="M4 11a8 8 0 1 1 2 6M4 5v6h6m2-3v5l3 2"/>',
|
|
291
|
+
prev: '<path d="M6 5v14m12-13-9 6 9 6z"/>',
|
|
292
|
+
next: '<path d="M18 5v14M6 6l9 6-9 6z"/>',
|
|
243
293
|
agent: '<rect x="4.5" y="7" width="15" height="12" rx="3"/><path d="M12 7V4m-8 9H2m20 0h-2m-11-.5h.02m5.98 0H15m-5 3h4"/>',
|
|
244
294
|
activity: '<path d="M3 12h4l3-7 4 14 3-7h4"/>',
|
|
245
295
|
warning: '<path d="m12 3 10 17H2L12 3zm0 6v4m0 3h.01"/>'
|
|
@@ -261,7 +311,7 @@ const motionPreference = matchMedia('(prefers-reduced-motion: reduce)');
|
|
|
261
311
|
const state = {
|
|
262
312
|
events: [], journalId: null, cursor: null, retained: 0, dropped: 0, gap: false, reset: false,
|
|
263
313
|
loaded: false, paused: false, pending: false, controller: null, problem: '', checkedAt: 0, recording: null, delivery: null, demo: false,
|
|
264
|
-
selected: '', selectedEvent: '', renderKey: '', model: null, newIds: new Set()
|
|
314
|
+
selected: '', selectedEvent: '', renderKey: '', model: null, newIds: new Set(), replay: null
|
|
265
315
|
};
|
|
266
316
|
|
|
267
317
|
document.querySelectorAll('[data-icon]').forEach((element) => { element.innerHTML = icon(element.dataset.icon); });
|
|
@@ -325,7 +375,7 @@ function eventClass(event) {
|
|
|
325
375
|
return event.source === 'reported' ? 'reported' : 'live';
|
|
326
376
|
}
|
|
327
377
|
|
|
328
|
-
function buildModel(now, minutes) {
|
|
378
|
+
function buildModel(now, minutes, events = state.events) {
|
|
329
379
|
const start = now - minutes * 60_000;
|
|
330
380
|
const measuredStarts = new Map();
|
|
331
381
|
const matched = [];
|
|
@@ -333,7 +383,7 @@ function buildModel(now, minutes) {
|
|
|
333
383
|
const ended = new Set();
|
|
334
384
|
const visible = [];
|
|
335
385
|
let unmatchedEnds = 0;
|
|
336
|
-
for (const event of
|
|
386
|
+
for (const event of events) {
|
|
337
387
|
const timestamp = Date.parse(event.timestamp);
|
|
338
388
|
if (!Number.isFinite(timestamp) || timestamp > now) continue;
|
|
339
389
|
const key = sessionKey(event);
|
|
@@ -451,7 +501,7 @@ function pointPath(a, b, control = 0) {
|
|
|
451
501
|
}
|
|
452
502
|
|
|
453
503
|
function motionAllowed() {
|
|
454
|
-
return document.documentElement.dataset.motion !== 'reduce' && !motionPreference.matches && !state.paused && !document.hidden;
|
|
504
|
+
return document.documentElement.dataset.motion !== 'reduce' && !motionPreference.matches && !state.paused && !state.replay && !document.hidden;
|
|
455
505
|
}
|
|
456
506
|
|
|
457
507
|
function pulse(path, tone, index) {
|
|
@@ -471,8 +521,8 @@ function renderNetwork(model, animate) {
|
|
|
471
521
|
$('network-count').textContent = displayedEvents ? number(displayedEvents) + ' recent events across ' + number(mapSessions.length) + ' displayed sessions' :
|
|
472
522
|
'Recorded session activity';
|
|
473
523
|
const omitted = model.sessions.length - mapSessions.length;
|
|
474
|
-
$('network-status').textContent = omitted > 0 ? number(omitted) + ' more in Sessions' : state.paused ? 'Paused' : '';
|
|
475
|
-
$('network-status').hidden = !omitted && !state.paused;
|
|
524
|
+
$('network-status').textContent = omitted > 0 ? number(omitted) + ' more in Sessions' : state.replay ? 'Replay' : state.paused ? 'Paused' : '';
|
|
525
|
+
$('network-status').hidden = !omitted && !state.paused && !state.replay;
|
|
476
526
|
const first = state.selected || nodes[0]?.session.key;
|
|
477
527
|
const primary = [];
|
|
478
528
|
const links = [];
|
|
@@ -482,21 +532,21 @@ function renderNetwork(model, animate) {
|
|
|
482
532
|
for (const { session, point, satellites: events } of nodes) {
|
|
483
533
|
const selected = session.key === state.selected;
|
|
484
534
|
const tone = session.pending.length ? 'live' : eventClass(session.latest);
|
|
485
|
-
const source = session.latest.source === 'reported' ? ' reported' : '';
|
|
535
|
+
const source = session.latest.source === 'reported' ? ' reported' : tone === 'failed' ? ' failed' : '';
|
|
486
536
|
links.push('<path class="network-edge' + source + (selected ? ' active' : state.selected ? ' dimmed' : '') +
|
|
487
537
|
'" d="' + pointPath(core, point, 10) + '"/>');
|
|
488
538
|
for (const item of events) {
|
|
489
539
|
const event = item.event;
|
|
490
540
|
const eventTone = eventClass(event);
|
|
491
541
|
const path = pointPath(point, item, 4);
|
|
492
|
-
links.push('<path class="network-edge' + (eventTone === 'reported' ? ' reported' : '') +
|
|
542
|
+
links.push('<path class="network-edge' + (eventTone === 'reported' ? ' reported' : eventTone === 'failed' ? ' failed' : '') +
|
|
493
543
|
(event.id === state.selectedEvent ? ' active' : state.selected && !selected ? ' dimmed' : '') + '" d="' + path + '"/>');
|
|
494
544
|
if (animate && state.newIds.has(event.id)) {
|
|
495
545
|
pulses.push(pulse(pointPath(core, point, 10), eventTone, pulses.length));
|
|
496
546
|
pulses.push(pulse(path, eventTone, pulses.length));
|
|
497
547
|
}
|
|
498
548
|
const eventLabel = describeEvent(event) + ' · ' + labelAgent(session.agent, session.transport);
|
|
499
|
-
satellites.push('<g class="network-node ' + eventTone + '" data-live-event="' + esc(event.id) + '" role="button" tabindex="' +
|
|
549
|
+
satellites.push('<g class="network-node ' + eventTone + (event.id === state.selectedEvent ? ' selected-event' : '') + '" data-live-event="' + esc(event.id) + '" role="button" tabindex="' +
|
|
500
550
|
(event.id === firstEvent ? 0 : -1) + '" aria-pressed="' + (event.id === state.selectedEvent) + '" aria-label="' + esc(eventLabel) +
|
|
501
551
|
'" transform="translate(' + item.x.toFixed(1) + ' ' + item.y.toFixed(1) + ')"><title>' + esc(eventLabel) +
|
|
502
552
|
'</title><circle r="8" fill="transparent"/><circle class="node-surface" r="5.5"/><circle class="node-indicator" r="2.3"/></g>');
|
|
@@ -514,7 +564,7 @@ function renderNetwork(model, animate) {
|
|
|
514
564
|
const base = '<defs><pattern id="network-grid" width="16" height="16" patternUnits="userSpaceOnUse"><circle cx="1" cy="1" r=".8" fill="var(--grid)"/></pattern></defs>' +
|
|
515
565
|
'<rect width="720" height="405" fill="url(#network-grid)"/><ellipse class="topology-ring" cx="360" cy="202.5" rx="239" ry="143"/>' +
|
|
516
566
|
'<ellipse class="topology-ring" cx="360" cy="202.5" rx="202" ry="113"/><ellipse class="topology-ring" cx="360" cy="202.5" rx="131" ry="79"/>';
|
|
517
|
-
const hub = '<g class="network-core" aria-label="Local event journal"><circle cx="360" cy="202.5" r="54"/>' +
|
|
567
|
+
const hub = '<g class="network-core" aria-label="Local event journal"><circle class="core-ring" cx="360" cy="202.5" r="64"/><circle cx="360" cy="202.5" r="54"/>' +
|
|
518
568
|
'<circle class="core-inner" cx="360" cy="202.5" r="47"/><text text-anchor="middle" x="360" y="201">Shadow Brain</text>' +
|
|
519
569
|
'<text class="node-subtitle" text-anchor="middle" x="360" y="217">Event journal</text></g>';
|
|
520
570
|
svg.innerHTML = base + '<g aria-hidden="true">' + links.join('') + '</g>' + hub + satellites.join('') + primary.join('') +
|
|
@@ -547,6 +597,7 @@ function renderInspector(model) {
|
|
|
547
597
|
fact('Source', event.source === 'reported' ? 'Host report' : 'Measured') +
|
|
548
598
|
fact('Recorded at', clockText(event.timestamp)) + fact('Transport', transports[event.transport]) +
|
|
549
599
|
fact('Duration', Number.isFinite(event.durationMs) ? durationText(event.durationMs) : '') +
|
|
600
|
+
fact('Correlation ID', event.correlationId) +
|
|
550
601
|
fact('Sequence', String(event.sequence)) + '</dl>' : '';
|
|
551
602
|
const projectLink = session.project ? '<a class="button quiet" href="/#memories?project=' + esc(encodeURIComponent(session.project)) +
|
|
552
603
|
'">Open project memories</a>' : '';
|
|
@@ -636,21 +687,22 @@ function renderChart(id, buckets) {
|
|
|
636
687
|
function renderEvents(model) {
|
|
637
688
|
const session = model.sessions.find((item) => item.key === state.selected);
|
|
638
689
|
const filter = $('event-filter').value;
|
|
639
|
-
const
|
|
690
|
+
const transport = $('transport-filter').value;
|
|
691
|
+
const data = (session ? session.events : model.visible).filter((event) => (!filter || event.source === filter) && (!transport || event.transport === transport));
|
|
640
692
|
$('timeline-scope').textContent = (session ? labelAgent(session.agent, session.transport) + ' session' : 'All sessions') +
|
|
641
693
|
' · ' + number(data.length) + ' recorded events';
|
|
642
694
|
$('clear-session').hidden = !session;
|
|
643
695
|
const target = $('events');
|
|
644
696
|
if (!data.length) {
|
|
645
|
-
target.innerHTML = blank('activity', 'No matching events', state.loaded ? 'Choose a different window or
|
|
697
|
+
target.innerHTML = blank('activity', 'No matching events', state.loaded ? 'Choose a different window, source, or transport.' : 'Reading retained journal events.');
|
|
646
698
|
return;
|
|
647
699
|
}
|
|
648
700
|
target.innerHTML = '<ul class="list">' + [...data].reverse().slice(0, 150).map((event) => {
|
|
649
701
|
const tone = eventClass(event);
|
|
650
702
|
const source = event.source === 'reported' ? 'Reported' : 'Measured';
|
|
651
703
|
const extra = Number.isFinite(event.durationMs) ? ' · ' + durationText(event.durationMs) : '';
|
|
652
|
-
const meta = [event.agent ? labelAgent(event.agent, event.transport) : transports[event.transport], event.projectId].filter(Boolean).join(' · ');
|
|
653
|
-
return '<li class="event-row' + (state.newIds.has(event.id) ? ' new' : '') + '">' + timeMarkup(event.timestamp) +
|
|
704
|
+
const meta = [event.agent ? labelAgent(event.agent, event.transport) : '', transports[event.transport], event.projectId].filter(Boolean).join(' · ');
|
|
705
|
+
return '<li class="event-row' + (state.newIds.has(event.id) ? ' new' : '') + '" data-selected="' + (event.id === state.selectedEvent) + '">' + timeMarkup(event.timestamp) +
|
|
654
706
|
'<span class="event-meta small muted">' + esc(meta) + '</span><div class="event-title"><button class="event-link" type="button" data-live-event="' +
|
|
655
707
|
esc(event.id) + '" aria-pressed="' + (event.id === state.selectedEvent) + '">' + esc(describeEvent(event)) +
|
|
656
708
|
'</button><span class="small muted">' + esc(extra) + '</span></div>' + tag(source, tone === 'reported' ? 'warn' : tone === 'failed' ? 'bad' : 'ok') + '</li>';
|
|
@@ -659,21 +711,27 @@ function renderEvents(model) {
|
|
|
659
711
|
|
|
660
712
|
function renderStatus(model) {
|
|
661
713
|
const badge = $('stream-tag');
|
|
662
|
-
const label = state.problem ? 'Disconnected' : !state.loaded ? 'Connecting' : state.paused ? 'Paused' : !state.delivery ? 'Delivery off' : 'Live';
|
|
663
|
-
badge.className = 'tag ' + (state.problem ? 'bad' : state.loaded && state.delivery && !state.paused ? 'ok' : 'warn');
|
|
714
|
+
const label = state.replay ? 'Replay' : state.problem ? 'Disconnected' : !state.loaded ? 'Connecting' : state.paused ? 'Paused' : !state.delivery ? 'Delivery off' : 'Live';
|
|
715
|
+
badge.className = 'tag ' + (state.replay ? 'warn' : state.problem ? 'bad' : state.loaded && state.delivery && !state.paused ? 'ok' : 'warn');
|
|
664
716
|
badge.title = state.checkedAt ? 'Last checked ' + clockText(state.checkedAt) : '';
|
|
665
717
|
$('stream-label').textContent = label;
|
|
666
|
-
|
|
718
|
+
const demoBanner = document.documentElement.dataset.demo === 'true';
|
|
719
|
+
$('demo-tag').hidden = !state.demo || demoBanner;
|
|
667
720
|
$('pause-label').textContent = state.paused ? 'Resume stream' : 'Pause stream';
|
|
668
721
|
$('pause').querySelector('[data-icon]').innerHTML = icon(state.paused ? 'play' : 'pause');
|
|
722
|
+
$('pause').hidden = !!state.replay;
|
|
669
723
|
$('pause').disabled = !state.loaded || state.delivery === false;
|
|
670
|
-
$('refresh').
|
|
724
|
+
$('refresh').hidden = !!state.replay;
|
|
725
|
+
$('refresh').disabled = state.pending || !!state.replay;
|
|
726
|
+
$('replay-start').hidden = !!state.replay;
|
|
727
|
+
$('replay-start').disabled = !state.events.length || !!state.replay || state.delivery === false;
|
|
671
728
|
const messages = [];
|
|
672
|
-
if (state.
|
|
729
|
+
if (state.replay) messages.push('Replaying a frozen snapshot of ' + number(state.replay.events.length) + ' loaded events.');
|
|
730
|
+
else if (state.problem) messages.push(state.problem);
|
|
673
731
|
else if (!state.loaded) messages.push('Connecting to the local event journal…');
|
|
674
732
|
else {
|
|
675
733
|
messages.push(number(model.visible.length) + ' loaded events · Last ' + model.minutes + (model.minutes === 1 ? ' minute' : ' minutes'));
|
|
676
|
-
if (state.demo) messages.push('Scripted local activity.');
|
|
734
|
+
if (state.demo && !demoBanner) messages.push('Scripted local activity.');
|
|
677
735
|
if (state.recording === false) messages.push('Activity recording is off.');
|
|
678
736
|
if (state.delivery === false) messages.push('Live delivery is off.');
|
|
679
737
|
if (state.paused) messages.push('Stream paused.');
|
|
@@ -685,13 +743,70 @@ function renderStatus(model) {
|
|
|
685
743
|
if (model.unmatchedEnds || model.stale) messages.push('Unmatched spans are excluded from measured result metrics.');
|
|
686
744
|
}
|
|
687
745
|
const notice = $('stream-notice');
|
|
688
|
-
notice.className = 'notice' + (state.problem ? ' error' : '');
|
|
746
|
+
notice.className = 'notice' + (state.problem && !state.replay ? ' error' : '');
|
|
689
747
|
const settings = state.loaded && (state.recording === false || state.delivery === false);
|
|
690
748
|
const markup = messages.map((message) => '<span>' + esc(message) + '</span>').join('') +
|
|
691
749
|
(settings ? '<a class="button quiet" href="/#features">Open Features</a>' : '');
|
|
692
750
|
if (notice.innerHTML !== markup) notice.innerHTML = markup;
|
|
693
751
|
}
|
|
694
752
|
|
|
753
|
+
function renderReplay() {
|
|
754
|
+
const replay = state.replay;
|
|
755
|
+
$('replay-bar').hidden = !replay;
|
|
756
|
+
if (!replay) return;
|
|
757
|
+
const { events, index, timer, incomplete } = replay;
|
|
758
|
+
const event = events[index];
|
|
759
|
+
const slider = $('replay-range');
|
|
760
|
+
slider.max = String(events.length - 1);
|
|
761
|
+
slider.value = String(index);
|
|
762
|
+
slider.disabled = events.length < 2;
|
|
763
|
+
const position = number(index + 1) + ' / ' + number(events.length) + ' · ' + clockText(event.timestamp);
|
|
764
|
+
slider.setAttribute('aria-valuetext', position + ', ' + describeEvent(event));
|
|
765
|
+
$('replay-position').textContent = position;
|
|
766
|
+
$('replay-prev').disabled = index === 0;
|
|
767
|
+
$('replay-next').disabled = index === events.length - 1;
|
|
768
|
+
$('replay-play').disabled = events.length < 2;
|
|
769
|
+
$('replay-play').textContent = timer ? 'Pause replay' : index === events.length - 1 ? 'Play from start' : 'Play replay';
|
|
770
|
+
$('replay-caption').textContent = 'Loaded sequence ' + number(events[0].sequence) + '–' + number(events.at(-1).sequence) +
|
|
771
|
+
' · Playback advances two events per second. The time window ends at the selected event.' +
|
|
772
|
+
(incomplete ? ' Earlier events may be outside this snapshot.' : '');
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
function stopReplayPlayback() {
|
|
776
|
+
if (!state.replay?.timer) return;
|
|
777
|
+
clearInterval(state.replay.timer);
|
|
778
|
+
state.replay.timer = null;
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
function moveReplay(index) {
|
|
782
|
+
const replay = state.replay;
|
|
783
|
+
if (!replay || !Number.isInteger(index)) return;
|
|
784
|
+
replay.index = Math.max(0, Math.min(replay.events.length - 1, index));
|
|
785
|
+
if (replay.index === replay.events.length - 1) stopReplayPlayback();
|
|
786
|
+
const event = replay.events[replay.index];
|
|
787
|
+
state.selected = sessionKey(event);
|
|
788
|
+
state.selectedEvent = event.id;
|
|
789
|
+
render(true);
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
function startReplay() {
|
|
793
|
+
if (!state.events.length || state.replay || state.delivery === false) return;
|
|
794
|
+
state.controller?.abort();
|
|
795
|
+
state.replay = { events: [...state.events], index: 0, timer: null,
|
|
796
|
+
incomplete: state.gap || state.dropped > 0 || state.retained > state.events.length || state.events[0].sequence > 1 };
|
|
797
|
+
moveReplay(state.replay.events.length - 1);
|
|
798
|
+
$('replay-heading').focus();
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
function exitReplay() {
|
|
802
|
+
stopReplayPlayback();
|
|
803
|
+
state.replay = null;
|
|
804
|
+
state.paused = false;
|
|
805
|
+
render(true);
|
|
806
|
+
$('replay-start').focus();
|
|
807
|
+
void poll();
|
|
808
|
+
}
|
|
809
|
+
|
|
695
810
|
function focusKey() {
|
|
696
811
|
const active = document.activeElement;
|
|
697
812
|
const value = active?.dataset.session || active?.dataset.liveEvent;
|
|
@@ -701,12 +816,15 @@ function focusKey() {
|
|
|
701
816
|
}
|
|
702
817
|
|
|
703
818
|
function render(force = false, animate = false) {
|
|
704
|
-
const
|
|
819
|
+
const replay = state.replay;
|
|
820
|
+
const replayEvent = replay?.events[replay.index];
|
|
821
|
+
const now = replayEvent ? Date.parse(replayEvent.timestamp) : Math.max(state.checkedAt || Date.now(), Date.parse(state.events.at(-1)?.timestamp) || 0);
|
|
705
822
|
const minutes = Number($('time-window').value);
|
|
706
|
-
const model = buildModel(now, minutes);
|
|
823
|
+
const model = buildModel(now, minutes, replay ? replay.events.slice(0, replay.index + 1) : state.events);
|
|
707
824
|
state.model = model;
|
|
708
825
|
renderStatus(model);
|
|
709
|
-
|
|
826
|
+
renderReplay();
|
|
827
|
+
const key = [state.loaded, state.journalId, state.cursor, Math.floor(now / 15000), minutes, replayEvent?.sequence].join('|');
|
|
710
828
|
if (!force && key === state.renderKey) return;
|
|
711
829
|
state.renderKey = key;
|
|
712
830
|
if (!model.sessions.some((session) => session.key === state.selected)) state.selected = '';
|
|
@@ -781,7 +899,7 @@ function acceptPage(page, animate) {
|
|
|
781
899
|
}
|
|
782
900
|
|
|
783
901
|
async function poll(manual = false) {
|
|
784
|
-
if (state.pending || (!manual && (state.paused || state.delivery === false || document.hidden))) return;
|
|
902
|
+
if (state.pending || state.replay || (!manual && (state.paused || state.delivery === false || document.hidden))) return;
|
|
785
903
|
state.pending = true;
|
|
786
904
|
$('refresh').disabled = true;
|
|
787
905
|
const controller = new AbortController();
|
|
@@ -859,8 +977,35 @@ document.addEventListener('click', (event) => {
|
|
|
859
977
|
$('network-svg').addEventListener('keydown', keyboardNetwork);
|
|
860
978
|
$('time-window').addEventListener('change', () => render(true));
|
|
861
979
|
$('event-filter').addEventListener('change', () => renderEvents(state.model));
|
|
980
|
+
$('transport-filter').addEventListener('change', () => renderEvents(state.model));
|
|
862
981
|
$('clear-session').addEventListener('click', () => chooseSession(''));
|
|
863
982
|
$('refresh').addEventListener('click', () => { void poll(true); });
|
|
983
|
+
$('replay-start').addEventListener('click', startReplay);
|
|
984
|
+
$('replay-exit').addEventListener('click', exitReplay);
|
|
985
|
+
$('replay-range').addEventListener('input', (event) => {
|
|
986
|
+
stopReplayPlayback();
|
|
987
|
+
moveReplay(Number(event.target.value));
|
|
988
|
+
});
|
|
989
|
+
$('replay-prev').addEventListener('click', () => {
|
|
990
|
+
stopReplayPlayback();
|
|
991
|
+
moveReplay(state.replay.index - 1);
|
|
992
|
+
});
|
|
993
|
+
$('replay-next').addEventListener('click', () => {
|
|
994
|
+
stopReplayPlayback();
|
|
995
|
+
moveReplay(state.replay.index + 1);
|
|
996
|
+
});
|
|
997
|
+
$('replay-play').addEventListener('click', () => {
|
|
998
|
+
const replay = state.replay;
|
|
999
|
+
if (!replay) return;
|
|
1000
|
+
if (replay.timer) {
|
|
1001
|
+
stopReplayPlayback();
|
|
1002
|
+
renderReplay();
|
|
1003
|
+
return;
|
|
1004
|
+
}
|
|
1005
|
+
if (replay.index === replay.events.length - 1) moveReplay(0);
|
|
1006
|
+
replay.timer = setInterval(() => moveReplay(replay.index + 1), 500);
|
|
1007
|
+
renderReplay();
|
|
1008
|
+
});
|
|
864
1009
|
$('pause').addEventListener('click', () => {
|
|
865
1010
|
state.paused = !state.paused;
|
|
866
1011
|
if (state.paused) {
|
|
@@ -880,7 +1025,11 @@ $('motion-control').addEventListener('click', () => {
|
|
|
880
1025
|
});
|
|
881
1026
|
motionPreference.addEventListener('change', syncMotion);
|
|
882
1027
|
document.addEventListener('visibilitychange', () => {
|
|
883
|
-
if (document.hidden)
|
|
1028
|
+
if (document.hidden) {
|
|
1029
|
+
$('network-pulses')?.replaceChildren();
|
|
1030
|
+
stopReplayPlayback();
|
|
1031
|
+
renderReplay();
|
|
1032
|
+
}
|
|
884
1033
|
else void poll();
|
|
885
1034
|
});
|
|
886
1035
|
syncMotion();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"live-workspace-html.js","sourceRoot":"","sources":["../../src/dashboard/live-workspace-html.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,MAAM,CAAC,MAAM,mBAAmB,GAAG,MAAM,CAAC,GAAG,CAAA
|
|
1
|
+
{"version":3,"file":"live-workspace-html.js","sourceRoot":"","sources":["../../src/dashboard/live-workspace-html.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,MAAM,CAAC,MAAM,mBAAmB,GAAG,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QA+gCrC,CAAC"}
|