@miller-tech/uap 2.21.2 → 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
package/dist/cli/dashboard.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import ora from 'ora';
|
|
3
|
-
import { existsSync, statSync
|
|
3
|
+
import { existsSync, statSync } from 'fs';
|
|
4
4
|
import { join } from 'path';
|
|
5
5
|
import { execSync } from 'child_process';
|
|
6
6
|
import Database from 'better-sqlite3';
|
|
@@ -16,6 +16,8 @@ import { ModelRouter } from '../models/router.js';
|
|
|
16
16
|
import { ModelPresets } from '../models/types.js';
|
|
17
17
|
import { getModelAnalytics } from '../models/analytics.js';
|
|
18
18
|
import { detectExecutionProfile } from '../models/execution-profiles.js';
|
|
19
|
+
import { computeMeasuredPace } from './dashboard-pace.js';
|
|
20
|
+
import { showDashboard, showSessionDashboard } from './dashboard-session.js';
|
|
19
21
|
export async function dashboardCommand(action, options = {}) {
|
|
20
22
|
switch (action) {
|
|
21
23
|
case 'overview':
|
|
@@ -104,35 +106,40 @@ async function exportDashboard(options) {
|
|
|
104
106
|
}
|
|
105
107
|
async function showHistory(_options) {
|
|
106
108
|
const cwd = process.cwd();
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
109
|
+
// History lives in telemetry.db's session_history table (written by the
|
|
110
|
+
// dashboard on each refresh). The old path read session_snapshots.db — a
|
|
111
|
+
// table nothing writes, so the command always reported "no history" (dash
|
|
112
|
+
// audit).
|
|
113
|
+
const telemetryDbPath = join(cwd, 'agents', 'data', 'memory', 'telemetry.db');
|
|
114
|
+
if (!existsSync(telemetryDbPath)) {
|
|
115
|
+
console.log(chalk.dim('No session history found. Start the dashboard to record sessions.'));
|
|
110
116
|
return;
|
|
111
117
|
}
|
|
112
118
|
try {
|
|
113
|
-
const db = new Database(
|
|
119
|
+
const db = new Database(telemetryDbPath, { readonly: true });
|
|
114
120
|
const rows = db
|
|
115
|
-
.prepare(
|
|
121
|
+
.prepare(`SELECT session_id, status, started_at, duration_ms, total_cost, task_count, model
|
|
122
|
+
FROM session_history ORDER BY started_at DESC LIMIT 20`)
|
|
116
123
|
.all();
|
|
117
124
|
db.close();
|
|
118
125
|
if (rows.length === 0) {
|
|
119
|
-
console.log(chalk.dim('No session
|
|
126
|
+
console.log(chalk.dim('No session history recorded yet.'));
|
|
120
127
|
return;
|
|
121
128
|
}
|
|
122
129
|
console.log('');
|
|
123
130
|
console.log(chalk.bold.cyan(' Session History'));
|
|
124
131
|
console.log(divider(70));
|
|
125
132
|
console.log('');
|
|
126
|
-
console.log(` ${'
|
|
133
|
+
console.log(` ${'Started'.padEnd(22)} ${'Duration'.padEnd(12)} ${'Cost'.padEnd(10)} ${'Tasks'.padEnd(8)} ${'Status'.padEnd(8)} Model`);
|
|
127
134
|
console.log(` ${'─'.repeat(22)} ${'─'.repeat(12)} ${'─'.repeat(10)} ${'─'.repeat(8)} ${'─'.repeat(16)}`);
|
|
128
135
|
for (const row of rows) {
|
|
129
|
-
const ts = (row.
|
|
136
|
+
const ts = (row.started_at || '').slice(0, 19);
|
|
130
137
|
const dur = row.duration_ms ? `${Math.round(row.duration_ms / 1000)}s` : '?';
|
|
131
138
|
const cost = row.total_cost ? `$${row.total_cost.toFixed(4)}` : '$0';
|
|
132
|
-
const tasks = String(row.
|
|
133
|
-
const
|
|
134
|
-
const
|
|
135
|
-
console.log(` ${ts.padEnd(22)} ${dur.padEnd(12)} ${cost.padEnd(10)} ${tasks.padEnd(8)} ${
|
|
139
|
+
const tasks = String(row.task_count || 0);
|
|
140
|
+
const status = String(row.status || '-');
|
|
141
|
+
const model = String(row.model || 'unknown');
|
|
142
|
+
console.log(` ${ts.padEnd(22)} ${dur.padEnd(12)} ${cost.padEnd(10)} ${tasks.padEnd(8)} ${status.padEnd(8)} ${model}`);
|
|
136
143
|
}
|
|
137
144
|
console.log('');
|
|
138
145
|
}
|
|
@@ -840,406 +847,6 @@ async function showStatsDashboard(_options) {
|
|
|
840
847
|
console.log('');
|
|
841
848
|
}
|
|
842
849
|
// ==================== Session Dashboard ====================
|
|
843
|
-
async function showSessionDashboard(options) {
|
|
844
|
-
if (options.compact) {
|
|
845
|
-
compactSessionSummary();
|
|
846
|
-
return;
|
|
847
|
-
}
|
|
848
|
-
const spinner = ora('Loading session dashboard...').start();
|
|
849
|
-
try {
|
|
850
|
-
const cwd = process.cwd();
|
|
851
|
-
// ── Gather data from all sources ──
|
|
852
|
-
const memDbPath = join(cwd, 'agents/data/memory/short_term.db');
|
|
853
|
-
const coordDbPath = join(cwd, 'agents/data/coordination/coordination.db');
|
|
854
|
-
const taskDbPath = join(cwd, '.uap/tasks/tasks.db');
|
|
855
|
-
// Package version
|
|
856
|
-
let version = '?';
|
|
857
|
-
try {
|
|
858
|
-
const pkg = JSON.parse(readFileSync(join(cwd, 'package.json'), 'utf-8'));
|
|
859
|
-
version = pkg.version || '?';
|
|
860
|
-
}
|
|
861
|
-
catch {
|
|
862
|
-
/* ignore */
|
|
863
|
-
}
|
|
864
|
-
// Git info
|
|
865
|
-
let gitBranch = '?';
|
|
866
|
-
let gitDirty = 0;
|
|
867
|
-
let gitAhead = 0;
|
|
868
|
-
let lastCommit = '';
|
|
869
|
-
try {
|
|
870
|
-
gitBranch = execSync('git branch --show-current', {
|
|
871
|
-
encoding: 'utf-8',
|
|
872
|
-
cwd,
|
|
873
|
-
stdio: ['pipe', 'pipe', 'pipe'],
|
|
874
|
-
}).trim();
|
|
875
|
-
gitDirty = execSync('git status --porcelain', {
|
|
876
|
-
encoding: 'utf-8',
|
|
877
|
-
cwd,
|
|
878
|
-
stdio: ['pipe', 'pipe', 'pipe'],
|
|
879
|
-
})
|
|
880
|
-
.trim()
|
|
881
|
-
.split('\n')
|
|
882
|
-
.filter(Boolean).length;
|
|
883
|
-
gitAhead =
|
|
884
|
-
parseInt(execSync('git rev-list --count @{u}..HEAD 2>/dev/null || echo 0', {
|
|
885
|
-
encoding: 'utf-8',
|
|
886
|
-
cwd,
|
|
887
|
-
stdio: ['pipe', 'pipe', 'pipe'],
|
|
888
|
-
}).trim(), 10) || 0;
|
|
889
|
-
lastCommit = execSync('git log -1 --format="%h %s" 2>/dev/null', {
|
|
890
|
-
encoding: 'utf-8',
|
|
891
|
-
cwd,
|
|
892
|
-
stdio: ['pipe', 'pipe', 'pipe'],
|
|
893
|
-
}).trim();
|
|
894
|
-
}
|
|
895
|
-
catch {
|
|
896
|
-
/* ignore */
|
|
897
|
-
}
|
|
898
|
-
// Memory stats
|
|
899
|
-
let memEntries = 0;
|
|
900
|
-
let memSizeKB = 0;
|
|
901
|
-
let recentMemories = [];
|
|
902
|
-
if (existsSync(memDbPath)) {
|
|
903
|
-
try {
|
|
904
|
-
const memDb = new Database(memDbPath, { readonly: true });
|
|
905
|
-
memEntries = memDb.prepare('SELECT COUNT(*) as c FROM memories').get().c;
|
|
906
|
-
memSizeKB = Math.round(statSync(memDbPath).size / 1024);
|
|
907
|
-
recentMemories = memDb
|
|
908
|
-
.prepare("SELECT type, substr(content, 1, 80) as content FROM memories WHERE timestamp >= datetime('now', '-1 day') ORDER BY id DESC LIMIT 5")
|
|
909
|
-
.all();
|
|
910
|
-
memDb.close();
|
|
911
|
-
}
|
|
912
|
-
catch {
|
|
913
|
-
/* ignore */
|
|
914
|
-
}
|
|
915
|
-
}
|
|
916
|
-
// Session memories (open loops)
|
|
917
|
-
let sessionMemCount = 0;
|
|
918
|
-
let openLoops = [];
|
|
919
|
-
if (existsSync(memDbPath)) {
|
|
920
|
-
try {
|
|
921
|
-
const memDb = new Database(memDbPath, { readonly: true });
|
|
922
|
-
const tables = memDb
|
|
923
|
-
.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='session_memories'")
|
|
924
|
-
.all();
|
|
925
|
-
if (tables.length > 0) {
|
|
926
|
-
sessionMemCount = memDb.prepare('SELECT COUNT(*) as c FROM session_memories').get().c;
|
|
927
|
-
openLoops = memDb
|
|
928
|
-
.prepare("SELECT content FROM session_memories WHERE type IN ('action','goal','decision') AND importance >= 7 ORDER BY id DESC LIMIT 5")
|
|
929
|
-
.all();
|
|
930
|
-
}
|
|
931
|
-
memDb.close();
|
|
932
|
-
}
|
|
933
|
-
catch {
|
|
934
|
-
/* ignore */
|
|
935
|
-
}
|
|
936
|
-
}
|
|
937
|
-
// Coordination stats
|
|
938
|
-
let activeAgents = 0;
|
|
939
|
-
let activeClaims = 0;
|
|
940
|
-
let pendingDeploys = 0;
|
|
941
|
-
if (existsSync(coordDbPath)) {
|
|
942
|
-
try {
|
|
943
|
-
const coordDb = new Database(coordDbPath, { readonly: true });
|
|
944
|
-
activeAgents = coordDb
|
|
945
|
-
.prepare("SELECT COUNT(*) as c FROM agent_registry WHERE status='active'")
|
|
946
|
-
.get().c;
|
|
947
|
-
activeClaims = coordDb.prepare('SELECT COUNT(*) as c FROM work_claims').get().c;
|
|
948
|
-
pendingDeploys = coordDb
|
|
949
|
-
.prepare("SELECT COUNT(*) as c FROM deploy_queue WHERE status='pending'")
|
|
950
|
-
.get().c;
|
|
951
|
-
coordDb.close();
|
|
952
|
-
}
|
|
953
|
-
catch {
|
|
954
|
-
/* ignore */
|
|
955
|
-
}
|
|
956
|
-
}
|
|
957
|
-
// Task stats
|
|
958
|
-
let taskTotal = 0;
|
|
959
|
-
let taskOpen = 0;
|
|
960
|
-
let taskProgress = 0;
|
|
961
|
-
let taskBlocked = 0;
|
|
962
|
-
let taskDone = 0;
|
|
963
|
-
let activeTasks = [];
|
|
964
|
-
if (existsSync(taskDbPath)) {
|
|
965
|
-
try {
|
|
966
|
-
const taskDb = new Database(taskDbPath, { readonly: true });
|
|
967
|
-
taskTotal = taskDb.prepare('SELECT COUNT(*) as c FROM tasks').get().c;
|
|
968
|
-
taskOpen = taskDb.prepare("SELECT COUNT(*) as c FROM tasks WHERE status='open'").get().c;
|
|
969
|
-
taskProgress = taskDb.prepare("SELECT COUNT(*) as c FROM tasks WHERE status='in_progress'").get().c;
|
|
970
|
-
taskBlocked = taskDb.prepare("SELECT COUNT(*) as c FROM tasks WHERE status='blocked'").get().c;
|
|
971
|
-
taskDone = taskDb
|
|
972
|
-
.prepare("SELECT COUNT(*) as c FROM tasks WHERE status='done' OR status='wont_do'")
|
|
973
|
-
.get().c;
|
|
974
|
-
activeTasks = taskDb
|
|
975
|
-
.prepare("SELECT id, title, priority FROM tasks WHERE status='in_progress' ORDER BY priority ASC LIMIT 5")
|
|
976
|
-
.all();
|
|
977
|
-
taskDb.close();
|
|
978
|
-
}
|
|
979
|
-
catch {
|
|
980
|
-
/* ignore */
|
|
981
|
-
}
|
|
982
|
-
}
|
|
983
|
-
// Qdrant status
|
|
984
|
-
let qdrantStatus = 'Stopped';
|
|
985
|
-
let qdrantUptime = '';
|
|
986
|
-
try {
|
|
987
|
-
const dockerOut = execSync('docker ps --filter name=qdrant --format "{{.Status}}"', {
|
|
988
|
-
encoding: 'utf-8',
|
|
989
|
-
stdio: ['pipe', 'pipe', 'pipe'],
|
|
990
|
-
}).trim();
|
|
991
|
-
if (dockerOut) {
|
|
992
|
-
qdrantStatus = 'Running';
|
|
993
|
-
qdrantUptime = dockerOut;
|
|
994
|
-
}
|
|
995
|
-
}
|
|
996
|
-
catch {
|
|
997
|
-
/* ignore */
|
|
998
|
-
}
|
|
999
|
-
// Patterns
|
|
1000
|
-
let patternCount = 0;
|
|
1001
|
-
let patternNames = [];
|
|
1002
|
-
const patternIndexPath = join(cwd, '.factory/patterns/index.json');
|
|
1003
|
-
if (existsSync(patternIndexPath)) {
|
|
1004
|
-
try {
|
|
1005
|
-
const patternData = JSON.parse(readFileSync(patternIndexPath, 'utf-8'));
|
|
1006
|
-
const patterns = patternData.patterns || [];
|
|
1007
|
-
patternCount = patterns.length;
|
|
1008
|
-
patternNames = patterns
|
|
1009
|
-
.slice(0, 5)
|
|
1010
|
-
.map((p) => p.title || p.name || p.abbreviation || (p.id != null ? `P${p.id}` : '?'));
|
|
1011
|
-
}
|
|
1012
|
-
catch {
|
|
1013
|
-
/* ignore */
|
|
1014
|
-
}
|
|
1015
|
-
}
|
|
1016
|
-
// Skills
|
|
1017
|
-
let skillNames = [];
|
|
1018
|
-
const skillDirs = [join(cwd, '.claude/skills'), join(cwd, '.factory/skills')];
|
|
1019
|
-
for (const dir of skillDirs) {
|
|
1020
|
-
if (existsSync(dir)) {
|
|
1021
|
-
try {
|
|
1022
|
-
const entries = readdirSync(dir, { withFileTypes: true });
|
|
1023
|
-
for (const entry of entries) {
|
|
1024
|
-
if (entry.isDirectory() && existsSync(join(dir, entry.name, 'SKILL.md'))) {
|
|
1025
|
-
skillNames.push(entry.name);
|
|
1026
|
-
}
|
|
1027
|
-
}
|
|
1028
|
-
}
|
|
1029
|
-
catch {
|
|
1030
|
-
/* ignore */
|
|
1031
|
-
}
|
|
1032
|
-
}
|
|
1033
|
-
}
|
|
1034
|
-
// Droids
|
|
1035
|
-
let droidNames = [];
|
|
1036
|
-
const droidDir = join(cwd, '.factory/droids');
|
|
1037
|
-
if (existsSync(droidDir)) {
|
|
1038
|
-
try {
|
|
1039
|
-
const entries = readdirSync(droidDir).filter((f) => f.endsWith('.md') && !f.startsWith('test-droid-'));
|
|
1040
|
-
droidNames = entries.map((f) => f.replace('.md', ''));
|
|
1041
|
-
}
|
|
1042
|
-
catch {
|
|
1043
|
-
/* ignore */
|
|
1044
|
-
}
|
|
1045
|
-
}
|
|
1046
|
-
// Worktrees
|
|
1047
|
-
let worktreeCount = 0;
|
|
1048
|
-
const worktreeDir = join(cwd, '.worktrees');
|
|
1049
|
-
if (existsSync(worktreeDir)) {
|
|
1050
|
-
try {
|
|
1051
|
-
worktreeCount = readdirSync(worktreeDir, { withFileTypes: true }).filter((e) => e.isDirectory()).length;
|
|
1052
|
-
}
|
|
1053
|
-
catch {
|
|
1054
|
-
/* ignore */
|
|
1055
|
-
}
|
|
1056
|
-
}
|
|
1057
|
-
spinner.stop();
|
|
1058
|
-
// ── Render ──
|
|
1059
|
-
console.log('');
|
|
1060
|
-
console.log(chalk.bold.cyan(' UAP Session Dashboard'));
|
|
1061
|
-
console.log(divider(62));
|
|
1062
|
-
console.log('');
|
|
1063
|
-
// System info
|
|
1064
|
-
console.log(sectionHeader('System'));
|
|
1065
|
-
console.log('');
|
|
1066
|
-
for (const line of keyValue([
|
|
1067
|
-
['Version', `v${version}`],
|
|
1068
|
-
[
|
|
1069
|
-
'Branch',
|
|
1070
|
-
`${gitBranch}${gitDirty > 0 ? chalk.yellow(` (${gitDirty} uncommitted)`) : chalk.green(' (clean)')}`,
|
|
1071
|
-
],
|
|
1072
|
-
['Ahead', gitAhead > 0 ? chalk.yellow(`${gitAhead} commits`) : chalk.dim('up to date')],
|
|
1073
|
-
['Last Commit', lastCommit.length > 55 ? lastCommit.slice(0, 55) + '...' : lastCommit],
|
|
1074
|
-
]))
|
|
1075
|
-
console.log(line);
|
|
1076
|
-
console.log('');
|
|
1077
|
-
// Task progress
|
|
1078
|
-
console.log(sectionHeader('Tasks'));
|
|
1079
|
-
console.log('');
|
|
1080
|
-
if (taskTotal > 0) {
|
|
1081
|
-
const pct = Math.round((taskDone / taskTotal) * 100);
|
|
1082
|
-
console.log(` ${progressBar(taskDone, taskTotal, 30, {
|
|
1083
|
-
label: 'Progress',
|
|
1084
|
-
filled: pct >= 80 ? chalk.green : pct >= 50 ? chalk.yellow : chalk.white,
|
|
1085
|
-
})}`);
|
|
1086
|
-
console.log('');
|
|
1087
|
-
const segments = [
|
|
1088
|
-
{ value: taskDone, color: chalk.green, label: 'Done' },
|
|
1089
|
-
{ value: taskProgress, color: chalk.cyan, label: 'Active' },
|
|
1090
|
-
{ value: taskOpen, color: chalk.white, label: 'Open' },
|
|
1091
|
-
{ value: taskBlocked, color: chalk.red, label: 'Blocked' },
|
|
1092
|
-
];
|
|
1093
|
-
console.log(` ${stackedBar(segments, taskTotal, 40)}`);
|
|
1094
|
-
console.log(` ${stackedBarLegend(segments)}`);
|
|
1095
|
-
console.log('');
|
|
1096
|
-
if (activeTasks.length > 0) {
|
|
1097
|
-
console.log(chalk.dim(' Active:'));
|
|
1098
|
-
for (const t of activeTasks) {
|
|
1099
|
-
console.log(` ${chalk.cyan(t.id)} P${t.priority} ${t.title.slice(0, 45)}${t.title.length > 45 ? '...' : ''}`);
|
|
1100
|
-
}
|
|
1101
|
-
console.log('');
|
|
1102
|
-
}
|
|
1103
|
-
}
|
|
1104
|
-
else {
|
|
1105
|
-
console.log(chalk.dim(' No tasks tracked. Create with: uap task create --title "..."'));
|
|
1106
|
-
console.log('');
|
|
1107
|
-
}
|
|
1108
|
-
// Memory layers
|
|
1109
|
-
console.log(sectionHeader('Memory System'));
|
|
1110
|
-
console.log('');
|
|
1111
|
-
const memItems = [
|
|
1112
|
-
{
|
|
1113
|
-
text: `L1 Working Memory: ${chalk.bold(memEntries + ' entries')} ${chalk.dim(`(${memSizeKB} KB)`)}`,
|
|
1114
|
-
status: existsSync(memDbPath) ? 'ok' : 'warn',
|
|
1115
|
-
},
|
|
1116
|
-
{
|
|
1117
|
-
text: `L2 Session Memory: ${chalk.bold(sessionMemCount + ' entries')} ${openLoops.length > 0 ? chalk.yellow(`(${openLoops.length} open loops)`) : ''}`,
|
|
1118
|
-
status: sessionMemCount > 0 ? 'ok' : 'info',
|
|
1119
|
-
},
|
|
1120
|
-
{
|
|
1121
|
-
text: `L3 Semantic Memory: ${qdrantStatus === 'Running' ? chalk.green('Qdrant ' + qdrantUptime) : chalk.dim('Qdrant stopped')}`,
|
|
1122
|
-
status: qdrantStatus === 'Running' ? 'ok' : 'warn',
|
|
1123
|
-
},
|
|
1124
|
-
{
|
|
1125
|
-
text: `L4 Knowledge Graph: ${existsSync(memDbPath) ? chalk.green('Active') : chalk.dim('Not initialized')}`,
|
|
1126
|
-
status: existsSync(memDbPath) ? 'ok' : 'warn',
|
|
1127
|
-
},
|
|
1128
|
-
];
|
|
1129
|
-
for (const line of bulletList(memItems))
|
|
1130
|
-
console.log(line);
|
|
1131
|
-
if (recentMemories.length > 0) {
|
|
1132
|
-
console.log('');
|
|
1133
|
-
console.log(chalk.dim(' Recent memories (24h):'));
|
|
1134
|
-
for (const mem of recentMemories.slice(0, 3)) {
|
|
1135
|
-
console.log(` ${chalk.dim((mem.type || 'unknown') + ':')} ${mem.content || ''}`);
|
|
1136
|
-
}
|
|
1137
|
-
}
|
|
1138
|
-
console.log('');
|
|
1139
|
-
// Coordination
|
|
1140
|
-
console.log(sectionHeader('Coordination'));
|
|
1141
|
-
console.log('');
|
|
1142
|
-
for (const line of keyValue([
|
|
1143
|
-
['Active Agents', activeAgents > 0 ? chalk.green(String(activeAgents)) : chalk.dim('0')],
|
|
1144
|
-
['Resource Claims', activeClaims > 0 ? chalk.yellow(String(activeClaims)) : chalk.dim('0')],
|
|
1145
|
-
[
|
|
1146
|
-
'Pending Deploys',
|
|
1147
|
-
pendingDeploys > 0 ? chalk.yellow(String(pendingDeploys)) : chalk.dim('0'),
|
|
1148
|
-
],
|
|
1149
|
-
['Worktrees', worktreeCount > 0 ? chalk.yellow(String(worktreeCount)) : chalk.dim('0')],
|
|
1150
|
-
]))
|
|
1151
|
-
console.log(line);
|
|
1152
|
-
console.log('');
|
|
1153
|
-
// Patterns & Skills
|
|
1154
|
-
console.log(sectionHeader('Intelligence'));
|
|
1155
|
-
console.log('');
|
|
1156
|
-
if (patternCount > 0) {
|
|
1157
|
-
console.log(` ${chalk.blue('Patterns')} ${chalk.bold(String(patternCount))} loaded`);
|
|
1158
|
-
if (patternNames.length > 0) {
|
|
1159
|
-
for (const name of patternNames) {
|
|
1160
|
-
console.log(` ${chalk.dim('-')} ${name}`);
|
|
1161
|
-
}
|
|
1162
|
-
if (patternCount > 5)
|
|
1163
|
-
console.log(chalk.dim(` ... and ${patternCount - 5} more`));
|
|
1164
|
-
}
|
|
1165
|
-
}
|
|
1166
|
-
else {
|
|
1167
|
-
console.log(chalk.dim(' Patterns: None loaded'));
|
|
1168
|
-
}
|
|
1169
|
-
console.log('');
|
|
1170
|
-
if (skillNames.length > 0) {
|
|
1171
|
-
console.log(` ${chalk.green('Skills')} ${chalk.bold(String(skillNames.length))} available`);
|
|
1172
|
-
for (const name of skillNames) {
|
|
1173
|
-
console.log(` ${chalk.dim('-')} ${name}`);
|
|
1174
|
-
}
|
|
1175
|
-
}
|
|
1176
|
-
else {
|
|
1177
|
-
console.log(chalk.dim(' Skills: None configured'));
|
|
1178
|
-
}
|
|
1179
|
-
console.log('');
|
|
1180
|
-
if (droidNames.length > 0) {
|
|
1181
|
-
console.log(` ${chalk.magenta('Droids')} ${chalk.bold(String(droidNames.length))} registered`);
|
|
1182
|
-
for (const name of droidNames.slice(0, 5)) {
|
|
1183
|
-
console.log(` ${chalk.dim('-')} ${name}`);
|
|
1184
|
-
}
|
|
1185
|
-
if (droidNames.length > 5)
|
|
1186
|
-
console.log(chalk.dim(` ... and ${droidNames.length - 5} more`));
|
|
1187
|
-
}
|
|
1188
|
-
else {
|
|
1189
|
-
console.log(chalk.dim(' Droids: None registered'));
|
|
1190
|
-
}
|
|
1191
|
-
console.log('');
|
|
1192
|
-
// Policies (DB-driven)
|
|
1193
|
-
console.log(sectionHeader('Policies'));
|
|
1194
|
-
console.log('');
|
|
1195
|
-
try {
|
|
1196
|
-
const policyMgr = getPolicyMemoryManager();
|
|
1197
|
-
const allPolicies = await policyMgr.getAllPolicies();
|
|
1198
|
-
if (allPolicies.length > 0) {
|
|
1199
|
-
for (const policy of allPolicies) {
|
|
1200
|
-
const stageLabel = policy.enforcementStage || 'pre-exec';
|
|
1201
|
-
const levelColor = policy.level === 'REQUIRED'
|
|
1202
|
-
? chalk.red
|
|
1203
|
-
: policy.level === 'RECOMMENDED'
|
|
1204
|
-
? chalk.yellow
|
|
1205
|
-
: chalk.dim;
|
|
1206
|
-
console.log(` ${levelColor(policy.level.padEnd(14))} ${policy.name.slice(0, 30).padEnd(30)} ${chalk.dim(stageLabel)}`);
|
|
1207
|
-
}
|
|
1208
|
-
}
|
|
1209
|
-
else {
|
|
1210
|
-
console.log(chalk.dim(' No policies configured. Add with: uap policy add -f <file>'));
|
|
1211
|
-
}
|
|
1212
|
-
}
|
|
1213
|
-
catch {
|
|
1214
|
-
console.log(chalk.dim(' Policy DB not initialized'));
|
|
1215
|
-
}
|
|
1216
|
-
console.log('');
|
|
1217
|
-
// Open loops
|
|
1218
|
-
if (openLoops.length > 0) {
|
|
1219
|
-
console.log(sectionHeader('Open Loops'));
|
|
1220
|
-
console.log('');
|
|
1221
|
-
for (const loop of openLoops) {
|
|
1222
|
-
console.log(` ${chalk.yellow('>')} ${loop.content.slice(0, 70)}${loop.content.length > 70 ? '...' : ''}`);
|
|
1223
|
-
}
|
|
1224
|
-
console.log('');
|
|
1225
|
-
}
|
|
1226
|
-
// Summary box
|
|
1227
|
-
const summaryLines = [
|
|
1228
|
-
`v${version} on ${chalk.cyan(gitBranch)}${gitDirty > 0 ? chalk.yellow(' *') : ''}`,
|
|
1229
|
-
`${chalk.bold(String(taskTotal))} tasks (${taskDone} done, ${taskProgress} active, ${taskBlocked} blocked)`,
|
|
1230
|
-
`${chalk.bold(String(memEntries))} memories | Qdrant: ${qdrantStatus === 'Running' ? chalk.green('ON') : chalk.dim('OFF')}`,
|
|
1231
|
-
`${patternCount} patterns | ${skillNames.length} skills | ${droidNames.length} droids`,
|
|
1232
|
-
];
|
|
1233
|
-
for (const line of box('UAP Session', summaryLines, { borderColor: chalk.cyan })) {
|
|
1234
|
-
console.log(` ${line}`);
|
|
1235
|
-
}
|
|
1236
|
-
console.log('');
|
|
1237
|
-
}
|
|
1238
|
-
catch (error) {
|
|
1239
|
-
spinner.fail('Failed to load session dashboard');
|
|
1240
|
-
console.error(chalk.red(error instanceof Error ? error.message : String(error)));
|
|
1241
|
-
}
|
|
1242
|
-
}
|
|
1243
850
|
async function showPoliciesDashboard(options) {
|
|
1244
851
|
const spinner = ora('Loading policies dashboard...').start();
|
|
1245
852
|
try {
|
|
@@ -1443,6 +1050,29 @@ async function showModelsDashboard(options) {
|
|
|
1443
1050
|
console.log(chalk.dim(' No model usage recorded this session'));
|
|
1444
1051
|
console.log('');
|
|
1445
1052
|
}
|
|
1053
|
+
// Measured pace: the agent's own EWMA estimates per
|
|
1054
|
+
// (model, taskType, complexity) key — the operator's legibility surface
|
|
1055
|
+
// for "how long does this model actually take here". Only keys with a
|
|
1056
|
+
// real estimate get a row; the honest caveat (spread, n, failure rate)
|
|
1057
|
+
// travels with the number.
|
|
1058
|
+
const pace = await computeMeasuredPace(analytics);
|
|
1059
|
+
if (pace.rows.length > 0) {
|
|
1060
|
+
console.log(sectionHeader('Measured Pace (ETA — from this project\'s own history)'));
|
|
1061
|
+
console.log('');
|
|
1062
|
+
console.log(` ${'Model'.padEnd(14)} ${'Key'.padEnd(22)} ${'Per task'.padEnd(10)} ${'Spread'.padEnd(16)} ${'N'.padEnd(8)} Success`);
|
|
1063
|
+
console.log(` ${'─'.repeat(14)} ${'─'.repeat(22)} ${'─'.repeat(10)} ${'─'.repeat(16)} ${'─'.repeat(8)} ${'─'.repeat(7)}`);
|
|
1064
|
+
for (const r of pace.rows) {
|
|
1065
|
+
console.log(` ${chalk.cyan(r.modelId.padEnd(14))} ${r.key.padEnd(22)}` +
|
|
1066
|
+
` ${r.perTask.padEnd(10)} ${r.spread.padEnd(16)} ${r.n.padEnd(8)} ${r.successPct}`);
|
|
1067
|
+
}
|
|
1068
|
+
if (pace.more > 0) {
|
|
1069
|
+
console.log(chalk.dim(` (… and ${pace.more} more key(s) with history beyond the top 8 by attempts)`));
|
|
1070
|
+
}
|
|
1071
|
+
if (pace.thin > 0) {
|
|
1072
|
+
console.log(chalk.dim(` (+${pace.thin} more key(s) with history too thin to estimate — needs ≥3 successes)`));
|
|
1073
|
+
}
|
|
1074
|
+
console.log('');
|
|
1075
|
+
}
|
|
1446
1076
|
// Execution profile for executor
|
|
1447
1077
|
const executorModel = roles.executor || 'qwen35-a3b';
|
|
1448
1078
|
const executorApiModel = ModelPresets[executorModel]?.apiModel || executorModel;
|
|
@@ -1513,384 +1143,4 @@ async function showModelsDashboard(options) {
|
|
|
1513
1143
|
* Used after task completion and before context compaction to give
|
|
1514
1144
|
* the agent (and user) a quick snapshot of UAP operational state.
|
|
1515
1145
|
*/
|
|
1516
|
-
export function compactSessionSummary() {
|
|
1517
|
-
const cwd = process.cwd();
|
|
1518
|
-
const memDbPath = join(cwd, 'agents/data/memory/short_term.db');
|
|
1519
|
-
const coordDbPath = join(cwd, 'agents/data/coordination/coordination.db');
|
|
1520
|
-
const taskDbPath = join(cwd, '.uap/tasks/tasks.db');
|
|
1521
|
-
// Version
|
|
1522
|
-
let version = '?';
|
|
1523
|
-
try {
|
|
1524
|
-
const pkg = JSON.parse(readFileSync(join(cwd, 'package.json'), 'utf-8'));
|
|
1525
|
-
version = pkg.version || '?';
|
|
1526
|
-
}
|
|
1527
|
-
catch {
|
|
1528
|
-
/* ignore */
|
|
1529
|
-
}
|
|
1530
|
-
// Git
|
|
1531
|
-
let gitBranch = '?';
|
|
1532
|
-
let gitDirty = 0;
|
|
1533
|
-
try {
|
|
1534
|
-
gitBranch = execSync('git branch --show-current', {
|
|
1535
|
-
encoding: 'utf-8',
|
|
1536
|
-
cwd,
|
|
1537
|
-
stdio: ['pipe', 'pipe', 'pipe'],
|
|
1538
|
-
}).trim();
|
|
1539
|
-
gitDirty = execSync('git status --porcelain', {
|
|
1540
|
-
encoding: 'utf-8',
|
|
1541
|
-
cwd,
|
|
1542
|
-
stdio: ['pipe', 'pipe', 'pipe'],
|
|
1543
|
-
})
|
|
1544
|
-
.trim()
|
|
1545
|
-
.split('\n')
|
|
1546
|
-
.filter(Boolean).length;
|
|
1547
|
-
}
|
|
1548
|
-
catch {
|
|
1549
|
-
/* ignore */
|
|
1550
|
-
}
|
|
1551
|
-
// Tasks
|
|
1552
|
-
let taskTotal = 0;
|
|
1553
|
-
let taskDone = 0;
|
|
1554
|
-
let taskProgress = 0;
|
|
1555
|
-
let taskBlocked = 0;
|
|
1556
|
-
let taskOpen = 0;
|
|
1557
|
-
if (existsSync(taskDbPath)) {
|
|
1558
|
-
try {
|
|
1559
|
-
const db = new Database(taskDbPath, { readonly: true });
|
|
1560
|
-
taskTotal = db.prepare('SELECT COUNT(*) as c FROM tasks').get().c;
|
|
1561
|
-
taskDone = db
|
|
1562
|
-
.prepare("SELECT COUNT(*) as c FROM tasks WHERE status='done' OR status='wont_do'")
|
|
1563
|
-
.get().c;
|
|
1564
|
-
taskProgress = db.prepare("SELECT COUNT(*) as c FROM tasks WHERE status='in_progress'").get().c;
|
|
1565
|
-
taskBlocked = db.prepare("SELECT COUNT(*) as c FROM tasks WHERE status='blocked'").get().c;
|
|
1566
|
-
taskOpen = db.prepare("SELECT COUNT(*) as c FROM tasks WHERE status='open'").get().c;
|
|
1567
|
-
db.close();
|
|
1568
|
-
}
|
|
1569
|
-
catch {
|
|
1570
|
-
/* ignore */
|
|
1571
|
-
}
|
|
1572
|
-
}
|
|
1573
|
-
// Memory
|
|
1574
|
-
let memEntries = 0;
|
|
1575
|
-
if (existsSync(memDbPath)) {
|
|
1576
|
-
try {
|
|
1577
|
-
const db = new Database(memDbPath, { readonly: true });
|
|
1578
|
-
memEntries = db.prepare('SELECT COUNT(*) as c FROM memories').get().c;
|
|
1579
|
-
db.close();
|
|
1580
|
-
}
|
|
1581
|
-
catch {
|
|
1582
|
-
/* ignore */
|
|
1583
|
-
}
|
|
1584
|
-
}
|
|
1585
|
-
// Agents
|
|
1586
|
-
let activeAgents = 0;
|
|
1587
|
-
if (existsSync(coordDbPath)) {
|
|
1588
|
-
try {
|
|
1589
|
-
const db = new Database(coordDbPath, { readonly: true });
|
|
1590
|
-
activeAgents = db.prepare("SELECT COUNT(*) as c FROM agent_registry WHERE status='active'").get().c;
|
|
1591
|
-
db.close();
|
|
1592
|
-
}
|
|
1593
|
-
catch {
|
|
1594
|
-
/* ignore */
|
|
1595
|
-
}
|
|
1596
|
-
}
|
|
1597
|
-
// Qdrant
|
|
1598
|
-
let qdrantOn = false;
|
|
1599
|
-
try {
|
|
1600
|
-
const out = execSync('docker ps --filter name=qdrant --format "{{.Status}}"', {
|
|
1601
|
-
encoding: 'utf-8',
|
|
1602
|
-
stdio: ['pipe', 'pipe', 'pipe'],
|
|
1603
|
-
}).trim();
|
|
1604
|
-
qdrantOn = !!out;
|
|
1605
|
-
}
|
|
1606
|
-
catch {
|
|
1607
|
-
/* ignore */
|
|
1608
|
-
}
|
|
1609
|
-
// Patterns, Skills, Droids counts
|
|
1610
|
-
let patternCount = 0;
|
|
1611
|
-
let skillCount = 0;
|
|
1612
|
-
let droidCount = 0;
|
|
1613
|
-
try {
|
|
1614
|
-
const pi = join(cwd, '.factory/patterns/index.json');
|
|
1615
|
-
if (existsSync(pi)) {
|
|
1616
|
-
patternCount = JSON.parse(readFileSync(pi, 'utf-8')).patterns?.length || 0;
|
|
1617
|
-
}
|
|
1618
|
-
}
|
|
1619
|
-
catch {
|
|
1620
|
-
/* ignore */
|
|
1621
|
-
}
|
|
1622
|
-
for (const dir of [join(cwd, '.claude/skills'), join(cwd, '.factory/skills')]) {
|
|
1623
|
-
if (existsSync(dir)) {
|
|
1624
|
-
try {
|
|
1625
|
-
skillCount += readdirSync(dir, { withFileTypes: true }).filter((e) => e.isDirectory() && existsSync(join(dir, e.name, 'SKILL.md'))).length;
|
|
1626
|
-
}
|
|
1627
|
-
catch {
|
|
1628
|
-
/* ignore */
|
|
1629
|
-
}
|
|
1630
|
-
}
|
|
1631
|
-
}
|
|
1632
|
-
const dd = join(cwd, '.factory/droids');
|
|
1633
|
-
if (existsSync(dd)) {
|
|
1634
|
-
try {
|
|
1635
|
-
droidCount = readdirSync(dd).filter((f) => f.endsWith('.md') && !f.startsWith('test-droid-')).length;
|
|
1636
|
-
}
|
|
1637
|
-
catch {
|
|
1638
|
-
/* ignore */
|
|
1639
|
-
}
|
|
1640
|
-
}
|
|
1641
|
-
// Build task progress bar
|
|
1642
|
-
const barW = 20;
|
|
1643
|
-
const pct = taskTotal > 0 ? Math.round((taskDone / taskTotal) * 100) : 0;
|
|
1644
|
-
const filledW = taskTotal > 0 ? Math.round((taskDone / taskTotal) * barW) : 0;
|
|
1645
|
-
const pctColor = pct >= 80 ? chalk.green : pct >= 50 ? chalk.yellow : chalk.white;
|
|
1646
|
-
const taskBar = chalk.green('\u2588'.repeat(filledW)) + chalk.dim('\u2591'.repeat(barW - filledW));
|
|
1647
|
-
// Render compact box
|
|
1648
|
-
const W = 58;
|
|
1649
|
-
// Calculate header content width accurately (without ANSI codes)
|
|
1650
|
-
const headerText = ` UAP v${version} on ${gitBranch}${gitDirty > 0 ? ' *' : ''}`;
|
|
1651
|
-
const headerPad = Math.max(0, W - headerText.length);
|
|
1652
|
-
console.log('');
|
|
1653
|
-
console.log(chalk.cyan(` \u256D${'─'.repeat(W)}\u256E`));
|
|
1654
|
-
console.log(chalk.cyan(` │`) +
|
|
1655
|
-
chalk.bold.white(` UAP v${version}`) +
|
|
1656
|
-
chalk.dim(` on ${gitBranch}${gitDirty > 0 ? ' *' : ''}`) +
|
|
1657
|
-
' '.repeat(headerPad) +
|
|
1658
|
-
chalk.cyan(`│`));
|
|
1659
|
-
console.log(chalk.cyan(` ├${'─'.repeat(W)}┤`));
|
|
1660
|
-
// Task line
|
|
1661
|
-
if (taskTotal > 0) {
|
|
1662
|
-
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')}`;
|
|
1663
|
-
// Use raw length estimation for padding
|
|
1664
|
-
const rawLen = ` ${'█'.repeat(barW)} ${pct}% ${taskDone}/${taskTotal} ${taskDone}✓ ${taskProgress}◐ ${taskBlocked > 0 ? taskBlocked + '❄ ' : ''}${taskOpen}○`;
|
|
1665
|
-
console.log(chalk.cyan(` │`) + taskLine + ' '.repeat(Math.max(0, W - rawLen.length)) + chalk.cyan(`│`));
|
|
1666
|
-
}
|
|
1667
|
-
else {
|
|
1668
|
-
console.log(chalk.cyan(` │`) + chalk.dim(' No tasks tracked') + ' '.repeat(W - 18) + chalk.cyan(`│`));
|
|
1669
|
-
}
|
|
1670
|
-
// Memory + Qdrant line
|
|
1671
|
-
const memLine = ` Mem: ${memEntries} entries Qdrant: ${qdrantOn ? 'ON' : 'OFF'} Agents: ${activeAgents}`;
|
|
1672
|
-
console.log(chalk.cyan(` │`) +
|
|
1673
|
-
(qdrantOn ? chalk.white(memLine) : chalk.dim(memLine)) +
|
|
1674
|
-
' '.repeat(Math.max(0, W - memLine.length)) +
|
|
1675
|
-
chalk.cyan(`│`));
|
|
1676
|
-
// Intelligence line
|
|
1677
|
-
const intLine = ` ${patternCount}P ${skillCount}S ${droidCount}D L1:ON L2:ON L3:${qdrantOn ? 'ON' : '?'} L4:ON`;
|
|
1678
|
-
console.log(chalk.cyan(` │`) +
|
|
1679
|
-
chalk.dim(intLine) +
|
|
1680
|
-
' '.repeat(Math.max(0, W - intLine.length)) +
|
|
1681
|
-
chalk.cyan(`│`));
|
|
1682
|
-
console.log(chalk.cyan(` \u2570${'─'.repeat(W)}\u256F`));
|
|
1683
|
-
console.log('');
|
|
1684
|
-
}
|
|
1685
|
-
// ==================== Real-Time Benchmark Dashboard ====================
|
|
1686
|
-
/**
|
|
1687
|
-
* Show a real-time benchmark dashboard with memory, model routing,
|
|
1688
|
-
* deploy batch, and pattern success stats from local databases.
|
|
1689
|
-
*
|
|
1690
|
-
* Uses simple ASCII formatting with no external dependencies beyond chalk.
|
|
1691
|
-
*/
|
|
1692
|
-
export function showDashboard() {
|
|
1693
|
-
const cwd = process.cwd();
|
|
1694
|
-
// Database paths
|
|
1695
|
-
const shortTermDbPath = join(cwd, 'agents/data/memory/short_term.db');
|
|
1696
|
-
const coordDbPath = join(cwd, 'agents/data/coordination/coordination.db');
|
|
1697
|
-
const modelDbPath = join(cwd, 'agents/data/memory/model_fingerprints.db');
|
|
1698
|
-
const patternIndexPath = join(cwd, '.factory/patterns/index.json');
|
|
1699
|
-
const W = 60;
|
|
1700
|
-
const sep = '─'.repeat(W);
|
|
1701
|
-
console.log('');
|
|
1702
|
-
console.log(chalk.bold.cyan(' Real-Time Benchmark Dashboard'));
|
|
1703
|
-
console.log(` ${sep}`);
|
|
1704
|
-
console.log('');
|
|
1705
|
-
// ── Memory Stats ──
|
|
1706
|
-
console.log(chalk.bold(' Memory Stats'));
|
|
1707
|
-
console.log(` ${chalk.dim('─'.repeat(W - 2))}`);
|
|
1708
|
-
let shortTermCount = 0;
|
|
1709
|
-
let sessionCount = 0;
|
|
1710
|
-
let entityCount = 0;
|
|
1711
|
-
let relationCount = 0;
|
|
1712
|
-
let shortTermSizeKB = 0;
|
|
1713
|
-
if (existsSync(shortTermDbPath)) {
|
|
1714
|
-
try {
|
|
1715
|
-
const db = new Database(shortTermDbPath, { readonly: true });
|
|
1716
|
-
shortTermSizeKB = Math.round(statSync(shortTermDbPath).size / 1024);
|
|
1717
|
-
shortTermCount = db.prepare('SELECT COUNT(*) as c FROM memories').get().c;
|
|
1718
|
-
// Session memories
|
|
1719
|
-
const hasSessions = db
|
|
1720
|
-
.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='session_memories'")
|
|
1721
|
-
.all();
|
|
1722
|
-
if (hasSessions.length > 0) {
|
|
1723
|
-
sessionCount = db.prepare('SELECT COUNT(*) as c FROM session_memories').get().c;
|
|
1724
|
-
}
|
|
1725
|
-
// Knowledge graph entities
|
|
1726
|
-
const hasEntities = db
|
|
1727
|
-
.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='entities'")
|
|
1728
|
-
.all();
|
|
1729
|
-
if (hasEntities.length > 0) {
|
|
1730
|
-
entityCount = db.prepare('SELECT COUNT(*) as c FROM entities').get().c;
|
|
1731
|
-
}
|
|
1732
|
-
const hasRelations = db
|
|
1733
|
-
.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='relationships'")
|
|
1734
|
-
.all();
|
|
1735
|
-
if (hasRelations.length > 0) {
|
|
1736
|
-
relationCount = db.prepare('SELECT COUNT(*) as c FROM relationships').get().c;
|
|
1737
|
-
}
|
|
1738
|
-
db.close();
|
|
1739
|
-
}
|
|
1740
|
-
catch {
|
|
1741
|
-
/* ignore db errors */
|
|
1742
|
-
}
|
|
1743
|
-
}
|
|
1744
|
-
const memRows = [
|
|
1745
|
-
['Short-term memories', String(shortTermCount)],
|
|
1746
|
-
['Session memories', String(sessionCount)],
|
|
1747
|
-
['KG entities', String(entityCount)],
|
|
1748
|
-
['KG relationships', String(relationCount)],
|
|
1749
|
-
['DB size', `${shortTermSizeKB} KB`],
|
|
1750
|
-
];
|
|
1751
|
-
for (const [label, value] of memRows) {
|
|
1752
|
-
console.log(` ${chalk.white(label.padEnd(25))} ${chalk.bold(value)}`);
|
|
1753
|
-
}
|
|
1754
|
-
console.log('');
|
|
1755
|
-
// ── Model Routing Stats ──
|
|
1756
|
-
console.log(chalk.bold(' Model Routing Stats'));
|
|
1757
|
-
console.log(` ${chalk.dim('─'.repeat(W - 2))}`);
|
|
1758
|
-
if (existsSync(modelDbPath)) {
|
|
1759
|
-
try {
|
|
1760
|
-
const db = new Database(modelDbPath, { readonly: true });
|
|
1761
|
-
const tables = db
|
|
1762
|
-
.prepare("SELECT name FROM sqlite_master WHERE type='table'")
|
|
1763
|
-
.all();
|
|
1764
|
-
const tableNames = tables.map((t) => t.name);
|
|
1765
|
-
if (tableNames.includes('model_fingerprints')) {
|
|
1766
|
-
const fpCount = db.prepare('SELECT COUNT(*) as c FROM model_fingerprints').get().c;
|
|
1767
|
-
console.log(` ${chalk.white('Fingerprints'.padEnd(25))} ${chalk.bold(String(fpCount))}`);
|
|
1768
|
-
// Try to get distinct models
|
|
1769
|
-
try {
|
|
1770
|
-
const models = db
|
|
1771
|
-
.prepare('SELECT DISTINCT model_id FROM model_fingerprints ORDER BY model_id LIMIT 10')
|
|
1772
|
-
.all();
|
|
1773
|
-
if (models.length > 0) {
|
|
1774
|
-
console.log(` ${chalk.white('Tracked models'.padEnd(25))} ${chalk.bold(String(models.length))}`);
|
|
1775
|
-
for (const m of models.slice(0, 5)) {
|
|
1776
|
-
console.log(` ${chalk.dim('-')} ${m.model_id}`);
|
|
1777
|
-
}
|
|
1778
|
-
if (models.length > 5)
|
|
1779
|
-
console.log(chalk.dim(` ... and ${models.length - 5} more`));
|
|
1780
|
-
}
|
|
1781
|
-
}
|
|
1782
|
-
catch {
|
|
1783
|
-
/* schema variation */
|
|
1784
|
-
}
|
|
1785
|
-
}
|
|
1786
|
-
if (tableNames.includes('routing_decisions')) {
|
|
1787
|
-
const routeCount = db.prepare('SELECT COUNT(*) as c FROM routing_decisions').get().c;
|
|
1788
|
-
console.log(` ${chalk.white('Routing decisions'.padEnd(25))} ${chalk.bold(String(routeCount))}`);
|
|
1789
|
-
}
|
|
1790
|
-
db.close();
|
|
1791
|
-
}
|
|
1792
|
-
catch {
|
|
1793
|
-
console.log(chalk.dim(' Could not read model fingerprints DB'));
|
|
1794
|
-
}
|
|
1795
|
-
}
|
|
1796
|
-
else {
|
|
1797
|
-
console.log(chalk.dim(' No model fingerprints DB found'));
|
|
1798
|
-
}
|
|
1799
|
-
console.log('');
|
|
1800
|
-
// ── Deploy Batch Stats ──
|
|
1801
|
-
console.log(chalk.bold(' Deploy Batch Stats'));
|
|
1802
|
-
console.log(` ${chalk.dim('─'.repeat(W - 2))}`);
|
|
1803
|
-
let deployPending = 0;
|
|
1804
|
-
let deployCompleted = 0;
|
|
1805
|
-
let deployFailed = 0;
|
|
1806
|
-
let batchCount = 0;
|
|
1807
|
-
if (existsSync(coordDbPath)) {
|
|
1808
|
-
try {
|
|
1809
|
-
const db = new Database(coordDbPath, { readonly: true });
|
|
1810
|
-
const hasDQ = db
|
|
1811
|
-
.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='deploy_queue'")
|
|
1812
|
-
.all();
|
|
1813
|
-
if (hasDQ.length > 0) {
|
|
1814
|
-
deployPending = db.prepare("SELECT COUNT(*) as c FROM deploy_queue WHERE status='pending'").get().c;
|
|
1815
|
-
deployCompleted = db
|
|
1816
|
-
.prepare("SELECT COUNT(*) as c FROM deploy_queue WHERE status='completed' OR status='batched'")
|
|
1817
|
-
.get().c;
|
|
1818
|
-
deployFailed = db.prepare("SELECT COUNT(*) as c FROM deploy_queue WHERE status='failed'").get().c;
|
|
1819
|
-
}
|
|
1820
|
-
const hasDB = db
|
|
1821
|
-
.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='deploy_batches'")
|
|
1822
|
-
.all();
|
|
1823
|
-
if (hasDB.length > 0) {
|
|
1824
|
-
batchCount = db.prepare('SELECT COUNT(*) as c FROM deploy_batches').get()
|
|
1825
|
-
.c;
|
|
1826
|
-
}
|
|
1827
|
-
db.close();
|
|
1828
|
-
}
|
|
1829
|
-
catch {
|
|
1830
|
-
/* ignore */
|
|
1831
|
-
}
|
|
1832
|
-
}
|
|
1833
|
-
const deployTotal = deployPending + deployCompleted + deployFailed;
|
|
1834
|
-
const deployRows = [
|
|
1835
|
-
['Pending', String(deployPending)],
|
|
1836
|
-
['Completed', String(deployCompleted)],
|
|
1837
|
-
['Failed', String(deployFailed)],
|
|
1838
|
-
['Total actions', String(deployTotal)],
|
|
1839
|
-
['Batches', String(batchCount)],
|
|
1840
|
-
];
|
|
1841
|
-
for (const [label, value] of deployRows) {
|
|
1842
|
-
const color = label === 'Failed' && deployFailed > 0
|
|
1843
|
-
? chalk.red
|
|
1844
|
-
: label === 'Pending' && deployPending > 0
|
|
1845
|
-
? chalk.yellow
|
|
1846
|
-
: chalk.white;
|
|
1847
|
-
console.log(` ${color(label.padEnd(25))} ${chalk.bold(value)}`);
|
|
1848
|
-
}
|
|
1849
|
-
console.log('');
|
|
1850
|
-
// ── Pattern Success Rates ──
|
|
1851
|
-
console.log(chalk.bold(' Pattern Success Rates'));
|
|
1852
|
-
console.log(` ${chalk.dim('─'.repeat(W - 2))}`);
|
|
1853
|
-
if (existsSync(patternIndexPath)) {
|
|
1854
|
-
try {
|
|
1855
|
-
const raw = readFileSync(patternIndexPath, 'utf-8');
|
|
1856
|
-
const data = JSON.parse(raw);
|
|
1857
|
-
const patterns = data.patterns || [];
|
|
1858
|
-
const active = patterns.filter((p) => p.active !== false);
|
|
1859
|
-
const withRates = active.filter((p) => typeof p.successRate === 'number');
|
|
1860
|
-
console.log(` ${chalk.white('Total patterns'.padEnd(25))} ${chalk.bold(String(patterns.length))}`);
|
|
1861
|
-
console.log(` ${chalk.white('Active'.padEnd(25))} ${chalk.bold(String(active.length))}`);
|
|
1862
|
-
if (withRates.length > 0) {
|
|
1863
|
-
const avgRate = withRates.reduce((sum, p) => sum + (p.successRate || 0), 0) / withRates.length;
|
|
1864
|
-
console.log(` ${chalk.white('Avg success rate'.padEnd(25))} ${chalk.bold(avgRate.toFixed(1) + '%')}`);
|
|
1865
|
-
console.log('');
|
|
1866
|
-
// Show top patterns by success rate
|
|
1867
|
-
const sorted = [...withRates].sort((a, b) => (b.successRate || 0) - (a.successRate || 0));
|
|
1868
|
-
for (const p of sorted.slice(0, 8)) {
|
|
1869
|
-
const name = p.title || p.name || p.abbreviation || (p.id != null ? `P${p.id}` : '?');
|
|
1870
|
-
const rate = p.successRate || 0;
|
|
1871
|
-
const barLen = Math.round(rate / 5);
|
|
1872
|
-
const bar = chalk.green('\u2588'.repeat(barLen)) + chalk.dim('\u2591'.repeat(20 - barLen));
|
|
1873
|
-
console.log(` ${name.slice(0, 22).padEnd(22)} ${bar} ${rate.toFixed(0)}%`);
|
|
1874
|
-
}
|
|
1875
|
-
if (sorted.length > 8) {
|
|
1876
|
-
console.log(chalk.dim(` ... and ${sorted.length - 8} more`));
|
|
1877
|
-
}
|
|
1878
|
-
}
|
|
1879
|
-
else {
|
|
1880
|
-
console.log(chalk.dim(' No success rate data tracked'));
|
|
1881
|
-
}
|
|
1882
|
-
}
|
|
1883
|
-
catch {
|
|
1884
|
-
console.log(chalk.dim(' Could not parse patterns index'));
|
|
1885
|
-
}
|
|
1886
|
-
}
|
|
1887
|
-
else {
|
|
1888
|
-
console.log(chalk.dim(' No patterns index found'));
|
|
1889
|
-
}
|
|
1890
|
-
console.log('');
|
|
1891
|
-
console.log(` ${sep}`);
|
|
1892
|
-
console.log(chalk.dim(' Run: uap dashboard overview for full project dashboard'));
|
|
1893
|
-
console.log(chalk.dim(' Run: uap dashboard session for session context'));
|
|
1894
|
-
console.log('');
|
|
1895
|
-
}
|
|
1896
1146
|
//# sourceMappingURL=dashboard.js.map
|