@miller-tech/uap 2.21.3 → 2.36.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -10
- package/config/model-profiles/qwen38-coder390.json +46 -0
- package/config/model-profiles/qwen38.json +3 -2
- package/config/model-registry.json +110 -0
- package/dist/.tsbuildinfo +1 -1
- package/dist/benchmarks/paired/types.d.ts +2 -2
- package/dist/bin/cli.js +315 -20
- package/dist/bin/cli.js.map +1 -1
- package/dist/cli/attention.d.ts +6 -0
- package/dist/cli/attention.d.ts.map +1 -0
- package/dist/cli/attention.js +115 -0
- package/dist/cli/attention.js.map +1 -0
- package/dist/cli/bench-report.d.ts +82 -0
- package/dist/cli/bench-report.d.ts.map +1 -0
- package/dist/cli/bench-report.js +237 -0
- package/dist/cli/bench-report.js.map +1 -0
- package/dist/cli/clients.d.ts +6 -0
- package/dist/cli/clients.d.ts.map +1 -0
- package/dist/cli/clients.js +142 -0
- package/dist/cli/clients.js.map +1 -0
- package/dist/cli/dashboard-grants.d.ts +26 -0
- package/dist/cli/dashboard-grants.d.ts.map +1 -0
- package/dist/cli/dashboard-grants.js +69 -0
- package/dist/cli/dashboard-grants.js.map +1 -0
- package/dist/cli/dashboard-pace.d.ts +31 -0
- package/dist/cli/dashboard-pace.d.ts.map +1 -0
- package/dist/cli/dashboard-pace.js +42 -0
- package/dist/cli/dashboard-pace.js.map +1 -0
- package/dist/cli/dashboard-session.d.ts +25 -0
- package/dist/cli/dashboard-session.d.ts.map +1 -0
- package/dist/cli/dashboard-session.js +814 -0
- package/dist/cli/dashboard-session.js.map +1 -0
- package/dist/cli/dashboard-types.d.ts +18 -0
- package/dist/cli/dashboard-types.d.ts.map +1 -0
- package/dist/cli/dashboard-types.js +9 -0
- package/dist/cli/dashboard-types.js.map +1 -0
- package/dist/cli/dashboard.d.ts +2 -18
- package/dist/cli/dashboard.d.ts.map +1 -1
- package/dist/cli/dashboard.js +43 -793
- package/dist/cli/dashboard.js.map +1 -1
- package/dist/cli/deliver.d.ts +35 -0
- package/dist/cli/deliver.d.ts.map +1 -1
- package/dist/cli/deliver.js +93 -9
- package/dist/cli/deliver.js.map +1 -1
- package/dist/cli/diff.d.ts +85 -0
- package/dist/cli/diff.d.ts.map +1 -0
- package/dist/cli/diff.js +293 -0
- package/dist/cli/diff.js.map +1 -0
- package/dist/cli/eta.d.ts +35 -0
- package/dist/cli/eta.d.ts.map +1 -0
- package/dist/cli/eta.js +101 -0
- package/dist/cli/eta.js.map +1 -0
- package/dist/cli/handsfree.d.ts +7 -0
- package/dist/cli/handsfree.d.ts.map +1 -1
- package/dist/cli/handsfree.js +27 -0
- package/dist/cli/handsfree.js.map +1 -1
- package/dist/cli/hooks.d.ts.map +1 -1
- package/dist/cli/hooks.js +126 -5
- package/dist/cli/hooks.js.map +1 -1
- package/dist/cli/loops.d.ts +24 -5
- package/dist/cli/loops.d.ts.map +1 -1
- package/dist/cli/loops.js +92 -12
- package/dist/cli/loops.js.map +1 -1
- package/dist/cli/models.d.ts +62 -0
- package/dist/cli/models.d.ts.map +1 -0
- package/dist/cli/models.js +567 -0
- package/dist/cli/models.js.map +1 -0
- package/dist/cli/plan.d.ts +9 -0
- package/dist/cli/plan.d.ts.map +1 -1
- package/dist/cli/plan.js +57 -4
- package/dist/cli/plan.js.map +1 -1
- package/dist/cli/proxy-relay.d.ts +55 -0
- package/dist/cli/proxy-relay.d.ts.map +1 -0
- package/dist/cli/proxy-relay.js +116 -0
- package/dist/cli/proxy-relay.js.map +1 -0
- package/dist/cli/proxy.d.ts +4 -0
- package/dist/cli/proxy.d.ts.map +1 -1
- package/dist/cli/proxy.js +26 -1
- package/dist/cli/proxy.js.map +1 -1
- package/dist/cli/sandbox.d.ts +101 -4
- package/dist/cli/sandbox.d.ts.map +1 -1
- package/dist/cli/sandbox.js +393 -44
- package/dist/cli/sandbox.js.map +1 -1
- package/dist/cli/self.d.ts +13 -0
- package/dist/cli/self.d.ts.map +1 -0
- package/dist/cli/self.js +94 -0
- package/dist/cli/self.js.map +1 -0
- package/dist/cli/systemd-services.d.ts +2 -8
- package/dist/cli/systemd-services.d.ts.map +1 -1
- package/dist/cli/systemd-services.js +5 -20
- package/dist/cli/systemd-services.js.map +1 -1
- package/dist/cli/task.js +1 -1
- package/dist/cli/task.js.map +1 -1
- package/dist/cli/wizard-config.d.ts.map +1 -1
- package/dist/cli/wizard-config.js +31 -2
- package/dist/cli/wizard-config.js.map +1 -1
- package/dist/config/settings-registry.d.ts +1 -1
- package/dist/config/settings-registry.d.ts.map +1 -1
- package/dist/config/settings-registry.js +108 -0
- package/dist/config/settings-registry.js.map +1 -1
- package/dist/coordination/capability-router.js +2 -2
- package/dist/coordination/capability-router.js.map +1 -1
- package/dist/coordination/database.d.ts +13 -0
- package/dist/coordination/database.d.ts.map +1 -1
- package/dist/coordination/database.js +63 -7
- package/dist/coordination/database.js.map +1 -1
- package/dist/coordination/eta-inject.d.ts +32 -0
- package/dist/coordination/eta-inject.d.ts.map +1 -0
- package/dist/coordination/eta-inject.js +64 -0
- package/dist/coordination/eta-inject.js.map +1 -0
- package/dist/coordination/reactor.d.ts.map +1 -1
- package/dist/coordination/reactor.js +14 -0
- package/dist/coordination/reactor.js.map +1 -1
- package/dist/coordination/service.d.ts +18 -8
- package/dist/coordination/service.d.ts.map +1 -1
- package/dist/coordination/service.js +38 -28
- package/dist/coordination/service.js.map +1 -1
- package/dist/dashboard/client-registry.d.ts +163 -0
- package/dist/dashboard/client-registry.d.ts.map +1 -0
- package/dist/dashboard/client-registry.js +549 -0
- package/dist/dashboard/client-registry.js.map +1 -0
- package/dist/dashboard/controls.d.ts.map +1 -1
- package/dist/dashboard/controls.js +33 -4
- package/dist/dashboard/controls.js.map +1 -1
- package/dist/dashboard/data-seeder.d.ts +10 -7
- package/dist/dashboard/data-seeder.d.ts.map +1 -1
- package/dist/dashboard/data-seeder.js +31 -75
- package/dist/dashboard/data-seeder.js.map +1 -1
- package/dist/dashboard/data-service.d.ts +9 -0
- package/dist/dashboard/data-service.d.ts.map +1 -1
- package/dist/dashboard/data-service.js +32 -3
- package/dist/dashboard/data-service.js.map +1 -1
- package/dist/dashboard/placement-routes.d.ts +119 -0
- package/dist/dashboard/placement-routes.d.ts.map +1 -0
- package/dist/dashboard/placement-routes.js +331 -0
- package/dist/dashboard/placement-routes.js.map +1 -0
- package/dist/dashboard/server.d.ts.map +1 -1
- package/dist/dashboard/server.js +408 -2
- package/dist/dashboard/server.js.map +1 -1
- package/dist/delivery/attention.d.ts +130 -0
- package/dist/delivery/attention.d.ts.map +1 -0
- package/dist/delivery/attention.js +341 -0
- package/dist/delivery/attention.js.map +1 -0
- package/dist/delivery/decompose.d.ts +18 -0
- package/dist/delivery/decompose.d.ts.map +1 -1
- package/dist/delivery/decompose.js +22 -1
- package/dist/delivery/decompose.js.map +1 -1
- package/dist/delivery/eta-estimate.d.ts +111 -0
- package/dist/delivery/eta-estimate.d.ts.map +1 -0
- package/dist/delivery/eta-estimate.js +171 -0
- package/dist/delivery/eta-estimate.js.map +1 -0
- package/dist/delivery/eta.d.ts +23 -0
- package/dist/delivery/eta.d.ts.map +1 -0
- package/dist/delivery/eta.js +59 -0
- package/dist/delivery/eta.js.map +1 -0
- package/dist/delivery/orchestrated-mission.d.ts +10 -0
- package/dist/delivery/orchestrated-mission.d.ts.map +1 -1
- package/dist/delivery/orchestrated-mission.js +15 -1
- package/dist/delivery/orchestrated-mission.js.map +1 -1
- package/dist/delivery/plan-check.d.ts +7 -1
- package/dist/delivery/plan-check.d.ts.map +1 -1
- package/dist/delivery/plan-check.js +23 -2
- package/dist/delivery/plan-check.js.map +1 -1
- package/dist/delivery/run-state.d.ts +1 -1
- package/dist/delivery/run-state.d.ts.map +1 -1
- package/dist/delivery/run-state.js +8 -1
- package/dist/delivery/run-state.js.map +1 -1
- package/dist/delivery/task-orchestrator.d.ts +8 -3
- package/dist/delivery/task-orchestrator.d.ts.map +1 -1
- package/dist/delivery/task-orchestrator.js +75 -43
- package/dist/delivery/task-orchestrator.js.map +1 -1
- package/dist/delivery/task-sync.d.ts +21 -0
- package/dist/delivery/task-sync.d.ts.map +1 -1
- package/dist/delivery/task-sync.js +44 -8
- package/dist/delivery/task-sync.js.map +1 -1
- package/dist/delivery/task-workspace.d.ts +3 -3
- package/dist/delivery/task-workspace.js +3 -3
- package/dist/generators/self-card.d.ts +65 -0
- package/dist/generators/self-card.d.ts.map +1 -0
- package/dist/generators/self-card.js +256 -0
- package/dist/generators/self-card.js.map +1 -0
- package/dist/inference/probe.js +1 -1
- package/dist/inference/probe.js.map +1 -1
- package/dist/memory/prepopulate.d.ts.map +1 -1
- package/dist/memory/prepopulate.js +2 -0
- package/dist/memory/prepopulate.js.map +1 -1
- package/dist/models/analytics.d.ts +32 -0
- package/dist/models/analytics.d.ts.map +1 -1
- package/dist/models/analytics.js +68 -5
- package/dist/models/analytics.js.map +1 -1
- package/dist/models/plan-readability.d.ts +55 -0
- package/dist/models/plan-readability.d.ts.map +1 -0
- package/dist/models/plan-readability.js +339 -0
- package/dist/models/plan-readability.js.map +1 -0
- package/dist/placement/admission.d.ts +59 -0
- package/dist/placement/admission.d.ts.map +1 -0
- package/dist/placement/admission.js +197 -0
- package/dist/placement/admission.js.map +1 -0
- package/dist/placement/auto.d.ts +44 -0
- package/dist/placement/auto.d.ts.map +1 -0
- package/dist/placement/auto.js +212 -0
- package/dist/placement/auto.js.map +1 -0
- package/dist/placement/enforce.d.ts +128 -0
- package/dist/placement/enforce.d.ts.map +1 -0
- package/dist/placement/enforce.js +655 -0
- package/dist/placement/enforce.js.map +1 -0
- package/dist/placement/idle.d.ts +50 -0
- package/dist/placement/idle.d.ts.map +1 -0
- package/dist/placement/idle.js +213 -0
- package/dist/placement/idle.js.map +1 -0
- package/dist/placement/ledger.d.ts +323 -0
- package/dist/placement/ledger.d.ts.map +1 -0
- package/dist/placement/ledger.js +263 -0
- package/dist/placement/ledger.js.map +1 -0
- package/dist/placement/preview.d.ts +51 -0
- package/dist/placement/preview.d.ts.map +1 -0
- package/dist/placement/preview.js +61 -0
- package/dist/placement/preview.js.map +1 -0
- package/dist/placement/probes.d.ts +47 -0
- package/dist/placement/probes.d.ts.map +1 -0
- package/dist/placement/probes.js +207 -0
- package/dist/placement/probes.js.map +1 -0
- package/dist/placement/proxy-env.d.ts +21 -0
- package/dist/placement/proxy-env.d.ts.map +1 -0
- package/dist/placement/proxy-env.js +42 -0
- package/dist/placement/proxy-env.js.map +1 -0
- package/dist/placement/registry.d.ts +1038 -0
- package/dist/placement/registry.d.ts.map +1 -0
- package/dist/placement/registry.js +274 -0
- package/dist/placement/registry.js.map +1 -0
- package/dist/policies/liveness.d.ts +6 -8
- package/dist/policies/liveness.d.ts.map +1 -1
- package/dist/policies/liveness.js +6 -25
- package/dist/policies/liveness.js.map +1 -1
- package/dist/policies/sandbox-anchor.d.ts +91 -0
- package/dist/policies/sandbox-anchor.d.ts.map +1 -0
- package/dist/policies/sandbox-anchor.js +187 -0
- package/dist/policies/sandbox-anchor.js.map +1 -0
- package/dist/policies/sandbox-grants.d.ts +131 -0
- package/dist/policies/sandbox-grants.d.ts.map +1 -0
- package/dist/policies/sandbox-grants.js +562 -0
- package/dist/policies/sandbox-grants.js.map +1 -0
- package/dist/state/manifest.d.ts +4 -2
- package/dist/state/manifest.d.ts.map +1 -1
- package/dist/state/manifest.js +32 -16
- package/dist/state/manifest.js.map +1 -1
- package/dist/utils/checkout-root.d.ts +2 -0
- package/dist/utils/checkout-root.d.ts.map +1 -0
- package/dist/utils/checkout-root.js +43 -0
- package/dist/utils/checkout-root.js.map +1 -0
- package/dist/utils/resolve-uap-bin.d.ts +5 -0
- package/dist/utils/resolve-uap-bin.d.ts.map +1 -0
- package/dist/utils/resolve-uap-bin.js +33 -0
- package/dist/utils/resolve-uap-bin.js.map +1 -0
- package/dist/utils/terminal-safe.d.ts +12 -0
- package/dist/utils/terminal-safe.d.ts.map +1 -0
- package/dist/utils/terminal-safe.js +53 -0
- package/dist/utils/terminal-safe.js.map +1 -0
- package/docs/ATTRIBUTION.md +1 -0
- package/docs/DASHBOARD_UPLIFT_SPEC.md +8 -8
- package/docs/INDEX.md +6 -5
- package/docs/architecture/OVERVIEW.md +15 -3
- package/docs/architecture/PROTOCOL.md +7 -1
- package/docs/architecture/adr/0006-operator-directed-model-placement.md +86 -0
- package/docs/architecture/adr/0007-auto-displacement-allowlist-as-standing-consent.md +79 -0
- package/docs/architecture/adr/0008-fleet-clients-link-out.md +92 -0
- package/docs/architecture/adr/0009-completion-triggered-dispatch-and-per-leaf-model-dials.md +71 -0
- package/docs/architecture/adr/0010-attention-queue-and-afk-auto-decider.md +159 -0
- package/docs/architecture/adr/0011-sandbox-grants-and-network-egress-boundary.md +219 -0
- package/docs/architecture/adr/0012-operator-legibility-surfaces.md +175 -0
- package/docs/getting-started/INSTALLATION.md +1 -1
- package/docs/guides/AUTOMATIC_FEATURES.md +8 -0
- package/docs/guides/LOCAL_MODELS.md +1 -1
- package/docs/guides/PROXY.md +2 -1
- package/docs/guides/SANDBOX.md +91 -4
- package/docs/integrations/MCP_ROUTER.md +1 -1
- package/docs/plans/model-performance-proof-options.md +176 -0
- package/docs/reference/API.md +1 -1
- package/docs/reference/CLI.md +169 -4
- package/docs/reference/COMPARISON.md +1 -1
- package/docs/reference/CONFIGURATION.md +12 -3
- package/docs/reference/CONFIGURATION_REFERENCE.md +269 -14
- package/docs/reference/DATABASE_SCHEMA.md +1 -1
- package/docs/reference/FEATURES.md +15 -3
- package/docs/reference/PATTERNS.md +1 -1
- package/docs/reference/PLATFORMS.md +14 -1
- package/docs/specs/operator-model-placement.md +1314 -0
- package/docs/specs/operator-model-placement.review.md +339 -0
- package/package.json +2 -2
- package/scripts/maintenance/publish-npm.sh +23 -11
- package/scripts/version-bump.sh +6 -51
- package/src/policies/enforcers/__pycache__/_common.cpython-311.pyc +0 -0
- package/src/policies/enforcers/__pycache__/expert_review_required.cpython-311.pyc +0 -0
- package/src/policies/enforcers/__pycache__/quality_metrics_gate.cpython-311.pyc +0 -0
- package/src/policies/schemas/policies/mandatory-testing-deployment.md +2 -5
- package/templates/hooks/__pycache__/deliver_autoroute.cpython-311.pyc +0 -0
- package/templates/hooks/session-start.sh +44 -0
- package/tools/agents/UAP/cli.py +14 -3
- package/tools/agents/UAP/paths.py +50 -0
- package/tools/agents/scripts/__pycache__/toolcall_path_normalizer.cpython-311.pyc +0 -0
- package/tools/agents/scripts/anthropic_proxy.py +1386 -99
- package/tools/agents/scripts/toolcall_path_normalizer.py +46 -1
- package/tools/agents/tests/test_anthropic_proxy_streaming.py +29 -6
- package/tools/agents/tests/test_doubling_break.py +64 -5
- package/tools/agents/tests/test_error_loop_break.py +10 -4
- package/tools/agents/tests/test_error_loop_ignores_correctives.py +13 -2
- package/tools/agents/tests/test_lockstep_escalation.py +280 -9
- package/tools/agents/tests/test_path_containment.py +94 -0
- package/tools/agents/tests/test_proxy_unix_socket.py +162 -0
- package/tools/agents/tests/test_signature_quality.py +349 -0
- package/tools/agents/tests/test_uap_compliance.py +11 -1
- package/web/dash/core.js +1 -0
- package/web/dash/tab-clients.js +196 -0
- package/web/dash/tab-models.js +387 -8
- package/web/dash/tab-policies.js +87 -4
- package/web/dash/tabs.js +77 -73
- package/web/dashboard.html +6 -0
- package/src/policies/enforcers/__pycache__/_common.cpython-312.pyc +0 -0
- package/src/policies/enforcers/__pycache__/expert_review_required.cpython-312.pyc +0 -0
- package/src/policies/enforcers/__pycache__/quality_metrics_gate.cpython-312.pyc +0 -0
- package/templates/hooks/__pycache__/deliver_autoroute.cpython-312.pyc +0 -0
- package/tools/agents/scripts/__pycache__/toolcall_path_normalizer.cpython-312.pyc +0 -0
- package/web/dash/tab-agents.js +0 -21
- package/web/dash/tab-deliver.js +0 -12
- package/web/dash/tab-memory.js +0 -12
- package/web/dash/tab-orchestration.js +0 -21
- package/web/dash/tab-overview.js +0 -21
- package/web/dash/tab-tasks.js +0 -21
|
@@ -0,0 +1,814 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The dashboard's SESSION operator surface, split from src/cli/dashboard.ts
|
|
3
|
+
* (that module was the repo's worst LOC offender and every new surface was
|
|
4
|
+
* growing it; the grants + pace sections moved out first, these follow the
|
|
5
|
+
* same pattern). Three views live here because they are one family:
|
|
6
|
+
*
|
|
7
|
+
* - showSessionDashboard — `uap dashboard session`: the operator's live
|
|
8
|
+
* one-glance state (version, git, tasks, memory, patterns, skills, droids,
|
|
9
|
+
* the Sandbox Grants section with its anchor verdict, the summary box).
|
|
10
|
+
* - showDashboard — the legacy one-shot "Real-Time Benchmark Dashboard"
|
|
11
|
+
* (direct read-only DB reads; kept for `uap dashboard benchmark`).
|
|
12
|
+
* - compactSessionSummary — the one-line terminal-title/brief summary other
|
|
13
|
+
* CLI surfaces print after their own work (task flows).
|
|
14
|
+
*/
|
|
15
|
+
import chalk from 'chalk';
|
|
16
|
+
import ora from 'ora';
|
|
17
|
+
import { existsSync, statSync, readFileSync, readdirSync } from 'fs';
|
|
18
|
+
import { join } from 'path';
|
|
19
|
+
import { execSync } from 'child_process';
|
|
20
|
+
import Database from 'better-sqlite3';
|
|
21
|
+
import { progressBar, stackedBar, stackedBarLegend, box, sectionHeader, keyValue, divider, bulletList, } from './visualize.js';
|
|
22
|
+
import { getPolicyMemoryManager } from '../policies/policy-memory.js';
|
|
23
|
+
import { sandboxGrantsLines } from './dashboard-grants.js';
|
|
24
|
+
export async function showSessionDashboard(options) {
|
|
25
|
+
if (options.compact) {
|
|
26
|
+
compactSessionSummary();
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
const spinner = ora('Loading session dashboard...').start();
|
|
30
|
+
try {
|
|
31
|
+
const cwd = process.cwd();
|
|
32
|
+
// ── Gather data from all sources ──
|
|
33
|
+
const memDbPath = join(cwd, 'agents/data/memory/short_term.db');
|
|
34
|
+
const coordDbPath = join(cwd, 'agents/data/coordination/coordination.db');
|
|
35
|
+
const taskDbPath = join(cwd, '.uap/tasks/tasks.db');
|
|
36
|
+
// Package version
|
|
37
|
+
let version = '?';
|
|
38
|
+
try {
|
|
39
|
+
const pkg = JSON.parse(readFileSync(join(cwd, 'package.json'), 'utf-8'));
|
|
40
|
+
version = pkg.version || '?';
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
/* ignore */
|
|
44
|
+
}
|
|
45
|
+
// Git info
|
|
46
|
+
let gitBranch = '?';
|
|
47
|
+
let gitDirty = 0;
|
|
48
|
+
let gitAhead = 0;
|
|
49
|
+
let lastCommit = '';
|
|
50
|
+
try {
|
|
51
|
+
gitBranch = execSync('git branch --show-current', {
|
|
52
|
+
encoding: 'utf-8',
|
|
53
|
+
cwd,
|
|
54
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
55
|
+
}).trim();
|
|
56
|
+
gitDirty = execSync('git status --porcelain', {
|
|
57
|
+
encoding: 'utf-8',
|
|
58
|
+
cwd,
|
|
59
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
60
|
+
})
|
|
61
|
+
.trim()
|
|
62
|
+
.split('\n')
|
|
63
|
+
.filter(Boolean).length;
|
|
64
|
+
gitAhead =
|
|
65
|
+
parseInt(execSync('git rev-list --count @{u}..HEAD 2>/dev/null || echo 0', {
|
|
66
|
+
encoding: 'utf-8',
|
|
67
|
+
cwd,
|
|
68
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
69
|
+
}).trim(), 10) || 0;
|
|
70
|
+
lastCommit = execSync('git log -1 --format="%h %s" 2>/dev/null', {
|
|
71
|
+
encoding: 'utf-8',
|
|
72
|
+
cwd,
|
|
73
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
74
|
+
}).trim();
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
/* ignore */
|
|
78
|
+
}
|
|
79
|
+
// Memory stats
|
|
80
|
+
let memEntries = 0;
|
|
81
|
+
let memSizeKB = 0;
|
|
82
|
+
let recentMemories = [];
|
|
83
|
+
if (existsSync(memDbPath)) {
|
|
84
|
+
try {
|
|
85
|
+
const memDb = new Database(memDbPath, { readonly: true });
|
|
86
|
+
memEntries = memDb.prepare('SELECT COUNT(*) as c FROM memories').get().c;
|
|
87
|
+
memSizeKB = Math.round(statSync(memDbPath).size / 1024);
|
|
88
|
+
recentMemories = memDb
|
|
89
|
+
.prepare("SELECT type, substr(content, 1, 80) as content FROM memories WHERE timestamp >= datetime('now', '-1 day') ORDER BY id DESC LIMIT 5")
|
|
90
|
+
.all();
|
|
91
|
+
memDb.close();
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
/* ignore */
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
// Session memories (open loops)
|
|
98
|
+
let sessionMemCount = 0;
|
|
99
|
+
let openLoops = [];
|
|
100
|
+
if (existsSync(memDbPath)) {
|
|
101
|
+
try {
|
|
102
|
+
const memDb = new Database(memDbPath, { readonly: true });
|
|
103
|
+
const tables = memDb
|
|
104
|
+
.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='session_memories'")
|
|
105
|
+
.all();
|
|
106
|
+
if (tables.length > 0) {
|
|
107
|
+
sessionMemCount = memDb.prepare('SELECT COUNT(*) as c FROM session_memories').get().c;
|
|
108
|
+
openLoops = memDb
|
|
109
|
+
.prepare("SELECT content FROM session_memories WHERE type IN ('action','goal','decision') AND importance >= 7 ORDER BY id DESC LIMIT 5")
|
|
110
|
+
.all();
|
|
111
|
+
}
|
|
112
|
+
memDb.close();
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
/* ignore */
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
// Coordination stats
|
|
119
|
+
let activeAgents = 0;
|
|
120
|
+
let activeClaims = 0;
|
|
121
|
+
let pendingDeploys = 0;
|
|
122
|
+
if (existsSync(coordDbPath)) {
|
|
123
|
+
try {
|
|
124
|
+
const coordDb = new Database(coordDbPath, { readonly: true });
|
|
125
|
+
activeAgents = coordDb
|
|
126
|
+
.prepare("SELECT COUNT(*) as c FROM agent_registry WHERE status='active'")
|
|
127
|
+
.get().c;
|
|
128
|
+
activeClaims = coordDb.prepare('SELECT COUNT(*) as c FROM work_claims').get().c;
|
|
129
|
+
pendingDeploys = coordDb
|
|
130
|
+
.prepare("SELECT COUNT(*) as c FROM deploy_queue WHERE status='pending'")
|
|
131
|
+
.get().c;
|
|
132
|
+
coordDb.close();
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
/* ignore */
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
// Task stats
|
|
139
|
+
let taskTotal = 0;
|
|
140
|
+
let taskOpen = 0;
|
|
141
|
+
let taskProgress = 0;
|
|
142
|
+
let taskBlocked = 0;
|
|
143
|
+
let taskDone = 0;
|
|
144
|
+
let activeTasks = [];
|
|
145
|
+
if (existsSync(taskDbPath)) {
|
|
146
|
+
try {
|
|
147
|
+
const taskDb = new Database(taskDbPath, { readonly: true });
|
|
148
|
+
taskTotal = taskDb.prepare('SELECT COUNT(*) as c FROM tasks').get().c;
|
|
149
|
+
taskOpen = taskDb.prepare("SELECT COUNT(*) as c FROM tasks WHERE status='open'").get().c;
|
|
150
|
+
taskProgress = taskDb.prepare("SELECT COUNT(*) as c FROM tasks WHERE status='in_progress'").get().c;
|
|
151
|
+
taskBlocked = taskDb.prepare("SELECT COUNT(*) as c FROM tasks WHERE status='blocked'").get().c;
|
|
152
|
+
taskDone = taskDb
|
|
153
|
+
.prepare("SELECT COUNT(*) as c FROM tasks WHERE status='done' OR status='wont_do'")
|
|
154
|
+
.get().c;
|
|
155
|
+
activeTasks = taskDb
|
|
156
|
+
.prepare("SELECT id, title, priority FROM tasks WHERE status='in_progress' ORDER BY priority ASC LIMIT 5")
|
|
157
|
+
.all();
|
|
158
|
+
taskDb.close();
|
|
159
|
+
}
|
|
160
|
+
catch {
|
|
161
|
+
/* ignore */
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
// Qdrant status
|
|
165
|
+
let qdrantStatus = 'Stopped';
|
|
166
|
+
let qdrantUptime = '';
|
|
167
|
+
try {
|
|
168
|
+
const dockerOut = execSync('docker ps --filter name=qdrant --format "{{.Status}}"', {
|
|
169
|
+
encoding: 'utf-8',
|
|
170
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
171
|
+
}).trim();
|
|
172
|
+
if (dockerOut) {
|
|
173
|
+
qdrantStatus = 'Running';
|
|
174
|
+
qdrantUptime = dockerOut;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
catch {
|
|
178
|
+
/* ignore */
|
|
179
|
+
}
|
|
180
|
+
// Patterns
|
|
181
|
+
let patternCount = 0;
|
|
182
|
+
let patternNames = [];
|
|
183
|
+
const patternIndexPath = join(cwd, '.factory/patterns/index.json');
|
|
184
|
+
if (existsSync(patternIndexPath)) {
|
|
185
|
+
try {
|
|
186
|
+
const patternData = JSON.parse(readFileSync(patternIndexPath, 'utf-8'));
|
|
187
|
+
const patterns = patternData.patterns || [];
|
|
188
|
+
patternCount = patterns.length;
|
|
189
|
+
patternNames = patterns
|
|
190
|
+
.slice(0, 5)
|
|
191
|
+
.map((p) => p.title || p.name || p.abbreviation || (p.id != null ? `P${p.id}` : '?'));
|
|
192
|
+
}
|
|
193
|
+
catch {
|
|
194
|
+
/* ignore */
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
// Skills
|
|
198
|
+
let skillNames = [];
|
|
199
|
+
const skillDirs = [join(cwd, '.claude/skills'), join(cwd, '.factory/skills')];
|
|
200
|
+
for (const dir of skillDirs) {
|
|
201
|
+
if (existsSync(dir)) {
|
|
202
|
+
try {
|
|
203
|
+
const entries = readdirSync(dir, { withFileTypes: true });
|
|
204
|
+
for (const entry of entries) {
|
|
205
|
+
if (entry.isDirectory() && existsSync(join(dir, entry.name, 'SKILL.md'))) {
|
|
206
|
+
skillNames.push(entry.name);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
catch {
|
|
211
|
+
/* ignore */
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
// Droids
|
|
216
|
+
let droidNames = [];
|
|
217
|
+
const droidDir = join(cwd, '.factory/droids');
|
|
218
|
+
if (existsSync(droidDir)) {
|
|
219
|
+
try {
|
|
220
|
+
const entries = readdirSync(droidDir).filter((f) => f.endsWith('.md') && !f.startsWith('test-droid-'));
|
|
221
|
+
droidNames = entries.map((f) => f.replace('.md', ''));
|
|
222
|
+
}
|
|
223
|
+
catch {
|
|
224
|
+
/* ignore */
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
// Worktrees
|
|
228
|
+
let worktreeCount = 0;
|
|
229
|
+
const worktreeDir = join(cwd, '.worktrees');
|
|
230
|
+
if (existsSync(worktreeDir)) {
|
|
231
|
+
try {
|
|
232
|
+
worktreeCount = readdirSync(worktreeDir, { withFileTypes: true }).filter((e) => e.isDirectory()).length;
|
|
233
|
+
}
|
|
234
|
+
catch {
|
|
235
|
+
/* ignore */
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
spinner.stop();
|
|
239
|
+
// ── Render ──
|
|
240
|
+
console.log('');
|
|
241
|
+
console.log(chalk.bold.cyan(' UAP Session Dashboard'));
|
|
242
|
+
console.log(divider(62));
|
|
243
|
+
console.log('');
|
|
244
|
+
// System info
|
|
245
|
+
console.log(sectionHeader('System'));
|
|
246
|
+
console.log('');
|
|
247
|
+
for (const line of keyValue([
|
|
248
|
+
['Version', `v${version}`],
|
|
249
|
+
[
|
|
250
|
+
'Branch',
|
|
251
|
+
`${gitBranch}${gitDirty > 0 ? chalk.yellow(` (${gitDirty} uncommitted)`) : chalk.green(' (clean)')}`,
|
|
252
|
+
],
|
|
253
|
+
['Ahead', gitAhead > 0 ? chalk.yellow(`${gitAhead} commits`) : chalk.dim('up to date')],
|
|
254
|
+
['Last Commit', lastCommit.length > 55 ? lastCommit.slice(0, 55) + '...' : lastCommit],
|
|
255
|
+
]))
|
|
256
|
+
console.log(line);
|
|
257
|
+
console.log('');
|
|
258
|
+
// Task progress
|
|
259
|
+
console.log(sectionHeader('Tasks'));
|
|
260
|
+
console.log('');
|
|
261
|
+
if (taskTotal > 0) {
|
|
262
|
+
const pct = Math.round((taskDone / taskTotal) * 100);
|
|
263
|
+
console.log(` ${progressBar(taskDone, taskTotal, 30, {
|
|
264
|
+
label: 'Progress',
|
|
265
|
+
filled: pct >= 80 ? chalk.green : pct >= 50 ? chalk.yellow : chalk.white,
|
|
266
|
+
})}`);
|
|
267
|
+
console.log('');
|
|
268
|
+
const segments = [
|
|
269
|
+
{ value: taskDone, color: chalk.green, label: 'Done' },
|
|
270
|
+
{ value: taskProgress, color: chalk.cyan, label: 'Active' },
|
|
271
|
+
{ value: taskOpen, color: chalk.white, label: 'Open' },
|
|
272
|
+
{ value: taskBlocked, color: chalk.red, label: 'Blocked' },
|
|
273
|
+
];
|
|
274
|
+
console.log(` ${stackedBar(segments, taskTotal, 40)}`);
|
|
275
|
+
console.log(` ${stackedBarLegend(segments)}`);
|
|
276
|
+
console.log('');
|
|
277
|
+
if (activeTasks.length > 0) {
|
|
278
|
+
console.log(chalk.dim(' Active:'));
|
|
279
|
+
for (const t of activeTasks) {
|
|
280
|
+
console.log(` ${chalk.cyan(t.id)} P${t.priority} ${t.title.slice(0, 45)}${t.title.length > 45 ? '...' : ''}`);
|
|
281
|
+
}
|
|
282
|
+
console.log('');
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
else {
|
|
286
|
+
console.log(chalk.dim(' No tasks tracked. Create with: uap task create --title "..."'));
|
|
287
|
+
console.log('');
|
|
288
|
+
}
|
|
289
|
+
// Memory layers
|
|
290
|
+
console.log(sectionHeader('Memory System'));
|
|
291
|
+
console.log('');
|
|
292
|
+
const memItems = [
|
|
293
|
+
{
|
|
294
|
+
text: `L1 Working Memory: ${chalk.bold(memEntries + ' entries')} ${chalk.dim(`(${memSizeKB} KB)`)}`,
|
|
295
|
+
status: existsSync(memDbPath) ? 'ok' : 'warn',
|
|
296
|
+
},
|
|
297
|
+
{
|
|
298
|
+
text: `L2 Session Memory: ${chalk.bold(sessionMemCount + ' entries')} ${openLoops.length > 0 ? chalk.yellow(`(${openLoops.length} open loops)`) : ''}`,
|
|
299
|
+
status: sessionMemCount > 0 ? 'ok' : 'info',
|
|
300
|
+
},
|
|
301
|
+
{
|
|
302
|
+
text: `L3 Semantic Memory: ${qdrantStatus === 'Running' ? chalk.green('Qdrant ' + qdrantUptime) : chalk.dim('Qdrant stopped')}`,
|
|
303
|
+
status: qdrantStatus === 'Running' ? 'ok' : 'warn',
|
|
304
|
+
},
|
|
305
|
+
{
|
|
306
|
+
text: `L4 Knowledge Graph: ${existsSync(memDbPath) ? chalk.green('Active') : chalk.dim('Not initialized')}`,
|
|
307
|
+
status: existsSync(memDbPath) ? 'ok' : 'warn',
|
|
308
|
+
},
|
|
309
|
+
];
|
|
310
|
+
for (const line of bulletList(memItems))
|
|
311
|
+
console.log(line);
|
|
312
|
+
if (recentMemories.length > 0) {
|
|
313
|
+
console.log('');
|
|
314
|
+
console.log(chalk.dim(' Recent memories (24h):'));
|
|
315
|
+
for (const mem of recentMemories.slice(0, 3)) {
|
|
316
|
+
console.log(` ${chalk.dim((mem.type || 'unknown') + ':')} ${mem.content || ''}`);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
console.log('');
|
|
320
|
+
// Coordination
|
|
321
|
+
console.log(sectionHeader('Coordination'));
|
|
322
|
+
console.log('');
|
|
323
|
+
for (const line of keyValue([
|
|
324
|
+
['Active Agents', activeAgents > 0 ? chalk.green(String(activeAgents)) : chalk.dim('0')],
|
|
325
|
+
['Resource Claims', activeClaims > 0 ? chalk.yellow(String(activeClaims)) : chalk.dim('0')],
|
|
326
|
+
[
|
|
327
|
+
'Pending Deploys',
|
|
328
|
+
pendingDeploys > 0 ? chalk.yellow(String(pendingDeploys)) : chalk.dim('0'),
|
|
329
|
+
],
|
|
330
|
+
['Worktrees', worktreeCount > 0 ? chalk.yellow(String(worktreeCount)) : chalk.dim('0')],
|
|
331
|
+
]))
|
|
332
|
+
console.log(line);
|
|
333
|
+
console.log('');
|
|
334
|
+
// Patterns & Skills
|
|
335
|
+
console.log(sectionHeader('Intelligence'));
|
|
336
|
+
console.log('');
|
|
337
|
+
if (patternCount > 0) {
|
|
338
|
+
console.log(` ${chalk.blue('Patterns')} ${chalk.bold(String(patternCount))} loaded`);
|
|
339
|
+
if (patternNames.length > 0) {
|
|
340
|
+
for (const name of patternNames) {
|
|
341
|
+
console.log(` ${chalk.dim('-')} ${name}`);
|
|
342
|
+
}
|
|
343
|
+
if (patternCount > 5)
|
|
344
|
+
console.log(chalk.dim(` ... and ${patternCount - 5} more`));
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
else {
|
|
348
|
+
console.log(chalk.dim(' Patterns: None loaded'));
|
|
349
|
+
}
|
|
350
|
+
console.log('');
|
|
351
|
+
if (skillNames.length > 0) {
|
|
352
|
+
console.log(` ${chalk.green('Skills')} ${chalk.bold(String(skillNames.length))} available`);
|
|
353
|
+
for (const name of skillNames) {
|
|
354
|
+
console.log(` ${chalk.dim('-')} ${name}`);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
else {
|
|
358
|
+
console.log(chalk.dim(' Skills: None configured'));
|
|
359
|
+
}
|
|
360
|
+
console.log('');
|
|
361
|
+
if (droidNames.length > 0) {
|
|
362
|
+
console.log(` ${chalk.magenta('Droids')} ${chalk.bold(String(droidNames.length))} registered`);
|
|
363
|
+
for (const name of droidNames.slice(0, 5)) {
|
|
364
|
+
console.log(` ${chalk.dim('-')} ${name}`);
|
|
365
|
+
}
|
|
366
|
+
if (droidNames.length > 5)
|
|
367
|
+
console.log(chalk.dim(` ... and ${droidNames.length - 5} more`));
|
|
368
|
+
}
|
|
369
|
+
else {
|
|
370
|
+
console.log(chalk.dim(' Droids: None registered'));
|
|
371
|
+
}
|
|
372
|
+
console.log('');
|
|
373
|
+
// Policies (DB-driven)
|
|
374
|
+
console.log(sectionHeader('Policies'));
|
|
375
|
+
console.log('');
|
|
376
|
+
try {
|
|
377
|
+
const policyMgr = getPolicyMemoryManager();
|
|
378
|
+
const allPolicies = await policyMgr.getAllPolicies();
|
|
379
|
+
if (allPolicies.length > 0) {
|
|
380
|
+
for (const policy of allPolicies) {
|
|
381
|
+
const stageLabel = policy.enforcementStage || 'pre-exec';
|
|
382
|
+
const levelColor = policy.level === 'REQUIRED'
|
|
383
|
+
? chalk.red
|
|
384
|
+
: policy.level === 'RECOMMENDED'
|
|
385
|
+
? chalk.yellow
|
|
386
|
+
: chalk.dim;
|
|
387
|
+
console.log(` ${levelColor(policy.level.padEnd(14))} ${policy.name.slice(0, 30).padEnd(30)} ${chalk.dim(stageLabel)}`);
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
else {
|
|
391
|
+
console.log(chalk.dim(' No policies configured. Add with: uap policy add -f <file>'));
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
catch {
|
|
395
|
+
console.log(chalk.dim(' Policy DB not initialized'));
|
|
396
|
+
}
|
|
397
|
+
console.log('');
|
|
398
|
+
// Open loops
|
|
399
|
+
if (openLoops.length > 0) {
|
|
400
|
+
console.log(sectionHeader('Open Loops'));
|
|
401
|
+
console.log('');
|
|
402
|
+
for (const loop of openLoops) {
|
|
403
|
+
console.log(` ${chalk.yellow('>')} ${loop.content.slice(0, 70)}${loop.content.length > 70 ? '...' : ''}`);
|
|
404
|
+
}
|
|
405
|
+
console.log('');
|
|
406
|
+
}
|
|
407
|
+
// Summary box
|
|
408
|
+
const summaryLines = [
|
|
409
|
+
`v${version} on ${chalk.cyan(gitBranch)}${gitDirty > 0 ? chalk.yellow(' *') : ''}`,
|
|
410
|
+
`${chalk.bold(String(taskTotal))} tasks (${taskDone} done, ${taskProgress} active, ${taskBlocked} blocked)`,
|
|
411
|
+
`${chalk.bold(String(memEntries))} memories | Qdrant: ${qdrantStatus === 'Running' ? chalk.green('ON') : chalk.dim('OFF')}`,
|
|
412
|
+
`${patternCount} patterns | ${skillNames.length} skills | ${droidNames.length} droids`,
|
|
413
|
+
];
|
|
414
|
+
for (const line of box('UAP Session', summaryLines, { borderColor: chalk.cyan })) {
|
|
415
|
+
console.log(` ${line}`);
|
|
416
|
+
}
|
|
417
|
+
console.log('');
|
|
418
|
+
// Sandbox grants (the ADR 0011-named surface): what extra
|
|
419
|
+
// writable holes are open, for which sessions, and whether the consent
|
|
420
|
+
// ledger verifies against its out-of-checkout trust anchor. Grants are
|
|
421
|
+
// SESSION authority, so this renders in the session view (the review
|
|
422
|
+
// caught an accidental placement in the models view). ⚠ lines are
|
|
423
|
+
// warnings — color them red.
|
|
424
|
+
const grantsSection = sandboxGrantsLines(process.cwd());
|
|
425
|
+
for (const l of grantsSection.lines)
|
|
426
|
+
console.log(l.trimStart().startsWith('⚠') ? chalk.red(l) : l);
|
|
427
|
+
console.log('');
|
|
428
|
+
}
|
|
429
|
+
catch (error) {
|
|
430
|
+
spinner.fail('Failed to load session dashboard');
|
|
431
|
+
console.error(chalk.red(error instanceof Error ? error.message : String(error)));
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
export function compactSessionSummary() {
|
|
435
|
+
const cwd = process.cwd();
|
|
436
|
+
const memDbPath = join(cwd, 'agents/data/memory/short_term.db');
|
|
437
|
+
const coordDbPath = join(cwd, 'agents/data/coordination/coordination.db');
|
|
438
|
+
const taskDbPath = join(cwd, '.uap/tasks/tasks.db');
|
|
439
|
+
// Version
|
|
440
|
+
let version = '?';
|
|
441
|
+
try {
|
|
442
|
+
const pkg = JSON.parse(readFileSync(join(cwd, 'package.json'), 'utf-8'));
|
|
443
|
+
version = pkg.version || '?';
|
|
444
|
+
}
|
|
445
|
+
catch {
|
|
446
|
+
/* ignore */
|
|
447
|
+
}
|
|
448
|
+
// Git
|
|
449
|
+
let gitBranch = '?';
|
|
450
|
+
let gitDirty = 0;
|
|
451
|
+
try {
|
|
452
|
+
gitBranch = execSync('git branch --show-current', {
|
|
453
|
+
encoding: 'utf-8',
|
|
454
|
+
cwd,
|
|
455
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
456
|
+
}).trim();
|
|
457
|
+
gitDirty = execSync('git status --porcelain', {
|
|
458
|
+
encoding: 'utf-8',
|
|
459
|
+
cwd,
|
|
460
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
461
|
+
})
|
|
462
|
+
.trim()
|
|
463
|
+
.split('\n')
|
|
464
|
+
.filter(Boolean).length;
|
|
465
|
+
}
|
|
466
|
+
catch {
|
|
467
|
+
/* ignore */
|
|
468
|
+
}
|
|
469
|
+
// Tasks
|
|
470
|
+
let taskTotal = 0;
|
|
471
|
+
let taskDone = 0;
|
|
472
|
+
let taskProgress = 0;
|
|
473
|
+
let taskBlocked = 0;
|
|
474
|
+
let taskOpen = 0;
|
|
475
|
+
if (existsSync(taskDbPath)) {
|
|
476
|
+
try {
|
|
477
|
+
const db = new Database(taskDbPath, { readonly: true });
|
|
478
|
+
taskTotal = db.prepare('SELECT COUNT(*) as c FROM tasks').get().c;
|
|
479
|
+
taskDone = db
|
|
480
|
+
.prepare("SELECT COUNT(*) as c FROM tasks WHERE status='done' OR status='wont_do'")
|
|
481
|
+
.get().c;
|
|
482
|
+
taskProgress = db.prepare("SELECT COUNT(*) as c FROM tasks WHERE status='in_progress'").get().c;
|
|
483
|
+
taskBlocked = db.prepare("SELECT COUNT(*) as c FROM tasks WHERE status='blocked'").get().c;
|
|
484
|
+
taskOpen = db.prepare("SELECT COUNT(*) as c FROM tasks WHERE status='open'").get().c;
|
|
485
|
+
db.close();
|
|
486
|
+
}
|
|
487
|
+
catch {
|
|
488
|
+
/* ignore */
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
// Memory
|
|
492
|
+
let memEntries = 0;
|
|
493
|
+
if (existsSync(memDbPath)) {
|
|
494
|
+
try {
|
|
495
|
+
const db = new Database(memDbPath, { readonly: true });
|
|
496
|
+
memEntries = db.prepare('SELECT COUNT(*) as c FROM memories').get().c;
|
|
497
|
+
db.close();
|
|
498
|
+
}
|
|
499
|
+
catch {
|
|
500
|
+
/* ignore */
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
// Agents
|
|
504
|
+
let activeAgents = 0;
|
|
505
|
+
if (existsSync(coordDbPath)) {
|
|
506
|
+
try {
|
|
507
|
+
const db = new Database(coordDbPath, { readonly: true });
|
|
508
|
+
activeAgents = db.prepare("SELECT COUNT(*) as c FROM agent_registry WHERE status='active'").get().c;
|
|
509
|
+
db.close();
|
|
510
|
+
}
|
|
511
|
+
catch {
|
|
512
|
+
/* ignore */
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
// Qdrant
|
|
516
|
+
let qdrantOn = false;
|
|
517
|
+
try {
|
|
518
|
+
const out = execSync('docker ps --filter name=qdrant --format "{{.Status}}"', {
|
|
519
|
+
encoding: 'utf-8',
|
|
520
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
521
|
+
}).trim();
|
|
522
|
+
qdrantOn = !!out;
|
|
523
|
+
}
|
|
524
|
+
catch {
|
|
525
|
+
/* ignore */
|
|
526
|
+
}
|
|
527
|
+
// Patterns, Skills, Droids counts
|
|
528
|
+
let patternCount = 0;
|
|
529
|
+
let skillCount = 0;
|
|
530
|
+
let droidCount = 0;
|
|
531
|
+
try {
|
|
532
|
+
const pi = join(cwd, '.factory/patterns/index.json');
|
|
533
|
+
if (existsSync(pi)) {
|
|
534
|
+
patternCount = JSON.parse(readFileSync(pi, 'utf-8')).patterns?.length || 0;
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
catch {
|
|
538
|
+
/* ignore */
|
|
539
|
+
}
|
|
540
|
+
for (const dir of [join(cwd, '.claude/skills'), join(cwd, '.factory/skills')]) {
|
|
541
|
+
if (existsSync(dir)) {
|
|
542
|
+
try {
|
|
543
|
+
skillCount += readdirSync(dir, { withFileTypes: true }).filter((e) => e.isDirectory() && existsSync(join(dir, e.name, 'SKILL.md'))).length;
|
|
544
|
+
}
|
|
545
|
+
catch {
|
|
546
|
+
/* ignore */
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
const dd = join(cwd, '.factory/droids');
|
|
551
|
+
if (existsSync(dd)) {
|
|
552
|
+
try {
|
|
553
|
+
droidCount = readdirSync(dd).filter((f) => f.endsWith('.md') && !f.startsWith('test-droid-')).length;
|
|
554
|
+
}
|
|
555
|
+
catch {
|
|
556
|
+
/* ignore */
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
// Build task progress bar
|
|
560
|
+
const barW = 20;
|
|
561
|
+
const pct = taskTotal > 0 ? Math.round((taskDone / taskTotal) * 100) : 0;
|
|
562
|
+
const filledW = taskTotal > 0 ? Math.round((taskDone / taskTotal) * barW) : 0;
|
|
563
|
+
const pctColor = pct >= 80 ? chalk.green : pct >= 50 ? chalk.yellow : chalk.white;
|
|
564
|
+
const taskBar = chalk.green('\u2588'.repeat(filledW)) + chalk.dim('\u2591'.repeat(barW - filledW));
|
|
565
|
+
// Render compact box
|
|
566
|
+
const W = 58;
|
|
567
|
+
// Calculate header content width accurately (without ANSI codes)
|
|
568
|
+
const headerText = ` UAP v${version} on ${gitBranch}${gitDirty > 0 ? ' *' : ''}`;
|
|
569
|
+
const headerPad = Math.max(0, W - headerText.length);
|
|
570
|
+
console.log('');
|
|
571
|
+
console.log(chalk.cyan(` \u256D${'─'.repeat(W)}\u256E`));
|
|
572
|
+
console.log(chalk.cyan(` │`) +
|
|
573
|
+
chalk.bold.white(` UAP v${version}`) +
|
|
574
|
+
chalk.dim(` on ${gitBranch}${gitDirty > 0 ? ' *' : ''}`) +
|
|
575
|
+
' '.repeat(headerPad) +
|
|
576
|
+
chalk.cyan(`│`));
|
|
577
|
+
console.log(chalk.cyan(` ├${'─'.repeat(W)}┤`));
|
|
578
|
+
// Task line
|
|
579
|
+
if (taskTotal > 0) {
|
|
580
|
+
const taskLine = ` ${taskBar} ${pctColor(pct + '%')} ${chalk.dim(`${taskDone}/${taskTotal}`)} ${chalk.green(taskDone + '\u2713')} ${chalk.cyan(taskProgress + '\u25D0')} ${taskBlocked > 0 ? chalk.red(taskBlocked + '\u2744') + ' ' : ''}${chalk.dim(taskOpen + '\u25CB')}`;
|
|
581
|
+
// Use raw length estimation for padding
|
|
582
|
+
const rawLen = ` ${'█'.repeat(barW)} ${pct}% ${taskDone}/${taskTotal} ${taskDone}✓ ${taskProgress}◐ ${taskBlocked > 0 ? taskBlocked + '❄ ' : ''}${taskOpen}○`;
|
|
583
|
+
console.log(chalk.cyan(` │`) + taskLine + ' '.repeat(Math.max(0, W - rawLen.length)) + chalk.cyan(`│`));
|
|
584
|
+
}
|
|
585
|
+
else {
|
|
586
|
+
console.log(chalk.cyan(` │`) + chalk.dim(' No tasks tracked') + ' '.repeat(W - 18) + chalk.cyan(`│`));
|
|
587
|
+
}
|
|
588
|
+
// Memory + Qdrant line
|
|
589
|
+
const memLine = ` Mem: ${memEntries} entries Qdrant: ${qdrantOn ? 'ON' : 'OFF'} Agents: ${activeAgents}`;
|
|
590
|
+
console.log(chalk.cyan(` │`) +
|
|
591
|
+
(qdrantOn ? chalk.white(memLine) : chalk.dim(memLine)) +
|
|
592
|
+
' '.repeat(Math.max(0, W - memLine.length)) +
|
|
593
|
+
chalk.cyan(`│`));
|
|
594
|
+
// Intelligence line
|
|
595
|
+
const intLine = ` ${patternCount}P ${skillCount}S ${droidCount}D L1:ON L2:ON L3:${qdrantOn ? 'ON' : '?'} L4:ON`;
|
|
596
|
+
console.log(chalk.cyan(` │`) +
|
|
597
|
+
chalk.dim(intLine) +
|
|
598
|
+
' '.repeat(Math.max(0, W - intLine.length)) +
|
|
599
|
+
chalk.cyan(`│`));
|
|
600
|
+
console.log(chalk.cyan(` \u2570${'─'.repeat(W)}\u256F`));
|
|
601
|
+
console.log('');
|
|
602
|
+
}
|
|
603
|
+
// ==================== Real-Time Benchmark Dashboard ====================
|
|
604
|
+
/**
|
|
605
|
+
* Show a real-time benchmark dashboard with memory, model routing,
|
|
606
|
+
* deploy batch, and pattern success stats from local databases.
|
|
607
|
+
*
|
|
608
|
+
* Uses simple ASCII formatting with no external dependencies beyond chalk.
|
|
609
|
+
*/
|
|
610
|
+
export function showDashboard() {
|
|
611
|
+
const cwd = process.cwd();
|
|
612
|
+
// Database paths
|
|
613
|
+
const shortTermDbPath = join(cwd, 'agents/data/memory/short_term.db');
|
|
614
|
+
const coordDbPath = join(cwd, 'agents/data/coordination/coordination.db');
|
|
615
|
+
const modelDbPath = join(cwd, 'agents/data/memory/model_fingerprints.db');
|
|
616
|
+
const patternIndexPath = join(cwd, '.factory/patterns/index.json');
|
|
617
|
+
const W = 60;
|
|
618
|
+
const sep = '─'.repeat(W);
|
|
619
|
+
console.log('');
|
|
620
|
+
console.log(chalk.bold.cyan(' Real-Time Benchmark Dashboard'));
|
|
621
|
+
console.log(` ${sep}`);
|
|
622
|
+
console.log('');
|
|
623
|
+
// ── Memory Stats ──
|
|
624
|
+
console.log(chalk.bold(' Memory Stats'));
|
|
625
|
+
console.log(` ${chalk.dim('─'.repeat(W - 2))}`);
|
|
626
|
+
let shortTermCount = 0;
|
|
627
|
+
let sessionCount = 0;
|
|
628
|
+
let entityCount = 0;
|
|
629
|
+
let relationCount = 0;
|
|
630
|
+
let shortTermSizeKB = 0;
|
|
631
|
+
if (existsSync(shortTermDbPath)) {
|
|
632
|
+
try {
|
|
633
|
+
const db = new Database(shortTermDbPath, { readonly: true });
|
|
634
|
+
shortTermSizeKB = Math.round(statSync(shortTermDbPath).size / 1024);
|
|
635
|
+
shortTermCount = db.prepare('SELECT COUNT(*) as c FROM memories').get().c;
|
|
636
|
+
// Session memories
|
|
637
|
+
const hasSessions = db
|
|
638
|
+
.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='session_memories'")
|
|
639
|
+
.all();
|
|
640
|
+
if (hasSessions.length > 0) {
|
|
641
|
+
sessionCount = db.prepare('SELECT COUNT(*) as c FROM session_memories').get().c;
|
|
642
|
+
}
|
|
643
|
+
// Knowledge graph entities
|
|
644
|
+
const hasEntities = db
|
|
645
|
+
.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='entities'")
|
|
646
|
+
.all();
|
|
647
|
+
if (hasEntities.length > 0) {
|
|
648
|
+
entityCount = db.prepare('SELECT COUNT(*) as c FROM entities').get().c;
|
|
649
|
+
}
|
|
650
|
+
const hasRelations = db
|
|
651
|
+
.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='relationships'")
|
|
652
|
+
.all();
|
|
653
|
+
if (hasRelations.length > 0) {
|
|
654
|
+
relationCount = db.prepare('SELECT COUNT(*) as c FROM relationships').get().c;
|
|
655
|
+
}
|
|
656
|
+
db.close();
|
|
657
|
+
}
|
|
658
|
+
catch {
|
|
659
|
+
/* ignore db errors */
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
const memRows = [
|
|
663
|
+
['Short-term memories', String(shortTermCount)],
|
|
664
|
+
['Session memories', String(sessionCount)],
|
|
665
|
+
['KG entities', String(entityCount)],
|
|
666
|
+
['KG relationships', String(relationCount)],
|
|
667
|
+
['DB size', `${shortTermSizeKB} KB`],
|
|
668
|
+
];
|
|
669
|
+
for (const [label, value] of memRows) {
|
|
670
|
+
console.log(` ${chalk.white(label.padEnd(25))} ${chalk.bold(value)}`);
|
|
671
|
+
}
|
|
672
|
+
console.log('');
|
|
673
|
+
// ── Model Routing Stats ──
|
|
674
|
+
console.log(chalk.bold(' Model Routing Stats'));
|
|
675
|
+
console.log(` ${chalk.dim('─'.repeat(W - 2))}`);
|
|
676
|
+
if (existsSync(modelDbPath)) {
|
|
677
|
+
try {
|
|
678
|
+
const db = new Database(modelDbPath, { readonly: true });
|
|
679
|
+
const tables = db
|
|
680
|
+
.prepare("SELECT name FROM sqlite_master WHERE type='table'")
|
|
681
|
+
.all();
|
|
682
|
+
const tableNames = tables.map((t) => t.name);
|
|
683
|
+
if (tableNames.includes('model_fingerprints')) {
|
|
684
|
+
const fpCount = db.prepare('SELECT COUNT(*) as c FROM model_fingerprints').get().c;
|
|
685
|
+
console.log(` ${chalk.white('Fingerprints'.padEnd(25))} ${chalk.bold(String(fpCount))}`);
|
|
686
|
+
// Try to get distinct models
|
|
687
|
+
try {
|
|
688
|
+
const models = db
|
|
689
|
+
.prepare('SELECT DISTINCT model_id FROM model_fingerprints ORDER BY model_id LIMIT 10')
|
|
690
|
+
.all();
|
|
691
|
+
if (models.length > 0) {
|
|
692
|
+
console.log(` ${chalk.white('Tracked models'.padEnd(25))} ${chalk.bold(String(models.length))}`);
|
|
693
|
+
for (const m of models.slice(0, 5)) {
|
|
694
|
+
console.log(` ${chalk.dim('-')} ${m.model_id}`);
|
|
695
|
+
}
|
|
696
|
+
if (models.length > 5)
|
|
697
|
+
console.log(chalk.dim(` ... and ${models.length - 5} more`));
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
catch {
|
|
701
|
+
/* schema variation */
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
if (tableNames.includes('routing_decisions')) {
|
|
705
|
+
const routeCount = db.prepare('SELECT COUNT(*) as c FROM routing_decisions').get().c;
|
|
706
|
+
console.log(` ${chalk.white('Routing decisions'.padEnd(25))} ${chalk.bold(String(routeCount))}`);
|
|
707
|
+
}
|
|
708
|
+
db.close();
|
|
709
|
+
}
|
|
710
|
+
catch {
|
|
711
|
+
console.log(chalk.dim(' Could not read model fingerprints DB'));
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
else {
|
|
715
|
+
console.log(chalk.dim(' No model fingerprints DB found'));
|
|
716
|
+
}
|
|
717
|
+
console.log('');
|
|
718
|
+
// ── Deploy Batch Stats ──
|
|
719
|
+
console.log(chalk.bold(' Deploy Batch Stats'));
|
|
720
|
+
console.log(` ${chalk.dim('─'.repeat(W - 2))}`);
|
|
721
|
+
let deployPending = 0;
|
|
722
|
+
let deployCompleted = 0;
|
|
723
|
+
let deployFailed = 0;
|
|
724
|
+
let batchCount = 0;
|
|
725
|
+
if (existsSync(coordDbPath)) {
|
|
726
|
+
try {
|
|
727
|
+
const db = new Database(coordDbPath, { readonly: true });
|
|
728
|
+
const hasDQ = db
|
|
729
|
+
.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='deploy_queue'")
|
|
730
|
+
.all();
|
|
731
|
+
if (hasDQ.length > 0) {
|
|
732
|
+
deployPending = db.prepare("SELECT COUNT(*) as c FROM deploy_queue WHERE status='pending'").get().c;
|
|
733
|
+
deployCompleted = db
|
|
734
|
+
.prepare("SELECT COUNT(*) as c FROM deploy_queue WHERE status='completed' OR status='batched'")
|
|
735
|
+
.get().c;
|
|
736
|
+
deployFailed = db.prepare("SELECT COUNT(*) as c FROM deploy_queue WHERE status='failed'").get().c;
|
|
737
|
+
}
|
|
738
|
+
const hasDB = db
|
|
739
|
+
.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='deploy_batches'")
|
|
740
|
+
.all();
|
|
741
|
+
if (hasDB.length > 0) {
|
|
742
|
+
batchCount = db.prepare('SELECT COUNT(*) as c FROM deploy_batches').get()
|
|
743
|
+
.c;
|
|
744
|
+
}
|
|
745
|
+
db.close();
|
|
746
|
+
}
|
|
747
|
+
catch {
|
|
748
|
+
/* ignore */
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
const deployTotal = deployPending + deployCompleted + deployFailed;
|
|
752
|
+
const deployRows = [
|
|
753
|
+
['Pending', String(deployPending)],
|
|
754
|
+
['Completed', String(deployCompleted)],
|
|
755
|
+
['Failed', String(deployFailed)],
|
|
756
|
+
['Total actions', String(deployTotal)],
|
|
757
|
+
['Batches', String(batchCount)],
|
|
758
|
+
];
|
|
759
|
+
for (const [label, value] of deployRows) {
|
|
760
|
+
const color = label === 'Failed' && deployFailed > 0
|
|
761
|
+
? chalk.red
|
|
762
|
+
: label === 'Pending' && deployPending > 0
|
|
763
|
+
? chalk.yellow
|
|
764
|
+
: chalk.white;
|
|
765
|
+
console.log(` ${color(label.padEnd(25))} ${chalk.bold(value)}`);
|
|
766
|
+
}
|
|
767
|
+
console.log('');
|
|
768
|
+
// ── Pattern Success Rates ──
|
|
769
|
+
console.log(chalk.bold(' Pattern Success Rates'));
|
|
770
|
+
console.log(` ${chalk.dim('─'.repeat(W - 2))}`);
|
|
771
|
+
if (existsSync(patternIndexPath)) {
|
|
772
|
+
try {
|
|
773
|
+
const raw = readFileSync(patternIndexPath, 'utf-8');
|
|
774
|
+
const data = JSON.parse(raw);
|
|
775
|
+
const patterns = data.patterns || [];
|
|
776
|
+
const active = patterns.filter((p) => p.active !== false);
|
|
777
|
+
const withRates = active.filter((p) => typeof p.successRate === 'number');
|
|
778
|
+
console.log(` ${chalk.white('Total patterns'.padEnd(25))} ${chalk.bold(String(patterns.length))}`);
|
|
779
|
+
console.log(` ${chalk.white('Active'.padEnd(25))} ${chalk.bold(String(active.length))}`);
|
|
780
|
+
if (withRates.length > 0) {
|
|
781
|
+
const avgRate = withRates.reduce((sum, p) => sum + (p.successRate || 0), 0) / withRates.length;
|
|
782
|
+
console.log(` ${chalk.white('Avg success rate'.padEnd(25))} ${chalk.bold(avgRate.toFixed(1) + '%')}`);
|
|
783
|
+
console.log('');
|
|
784
|
+
// Show top patterns by success rate
|
|
785
|
+
const sorted = [...withRates].sort((a, b) => (b.successRate || 0) - (a.successRate || 0));
|
|
786
|
+
for (const p of sorted.slice(0, 8)) {
|
|
787
|
+
const name = p.title || p.name || p.abbreviation || (p.id != null ? `P${p.id}` : '?');
|
|
788
|
+
const rate = p.successRate || 0;
|
|
789
|
+
const barLen = Math.round(rate / 5);
|
|
790
|
+
const bar = chalk.green('\u2588'.repeat(barLen)) + chalk.dim('\u2591'.repeat(20 - barLen));
|
|
791
|
+
console.log(` ${name.slice(0, 22).padEnd(22)} ${bar} ${rate.toFixed(0)}%`);
|
|
792
|
+
}
|
|
793
|
+
if (sorted.length > 8) {
|
|
794
|
+
console.log(chalk.dim(` ... and ${sorted.length - 8} more`));
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
else {
|
|
798
|
+
console.log(chalk.dim(' No success rate data tracked'));
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
catch {
|
|
802
|
+
console.log(chalk.dim(' Could not parse patterns index'));
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
else {
|
|
806
|
+
console.log(chalk.dim(' No patterns index found'));
|
|
807
|
+
}
|
|
808
|
+
console.log('');
|
|
809
|
+
console.log(` ${sep}`);
|
|
810
|
+
console.log(chalk.dim(' Run: uap dashboard overview for full project dashboard'));
|
|
811
|
+
console.log(chalk.dim(' Run: uap dashboard session for session context'));
|
|
812
|
+
console.log('');
|
|
813
|
+
}
|
|
814
|
+
//# sourceMappingURL=dashboard-session.js.map
|