@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,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `uap diff` — the local diff view
|
|
3
|
+
*
|
|
4
|
+
* The operator's one-command answer to "what has the agent changed around
|
|
5
|
+
* here?": uncommitted AND unpushed work, summarized legibly — per-file line
|
|
6
|
+
* deltas with status codes (modified / added / deleted / renamed / untracked),
|
|
7
|
+
* against both HEAD and the base branch, with the exact commands to inspect
|
|
8
|
+
* deeper. A worktree-scoped agent's output lives in `.worktrees/NNN-<slug>/`
|
|
9
|
+
* where a plain `git status` scrolls past; this is the at-a-glance view.
|
|
10
|
+
*
|
|
11
|
+
* Safe-git contract (inherited from supervise/observe): git runs via
|
|
12
|
+
* execFileSync ARG ARRAYS (no shell, no interpolation), 5s timeout, and every
|
|
13
|
+
* failure degrades to `unknown` — the view renders with what it could read,
|
|
14
|
+
* it never throws. Output is capped per section (`--max`, default 40 files)
|
|
15
|
+
* because a monorepo can list thousands.
|
|
16
|
+
*/
|
|
17
|
+
export interface DiffOptions {
|
|
18
|
+
/** Base ref for the unpushed view (default: master). */
|
|
19
|
+
base?: string;
|
|
20
|
+
/** Per-section file cap (default 40). */
|
|
21
|
+
max?: string;
|
|
22
|
+
/** Test/odd-layout seam: pin the working dir (default: process.cwd()). */
|
|
23
|
+
cwd?: string;
|
|
24
|
+
json?: boolean;
|
|
25
|
+
}
|
|
26
|
+
/** What happened to one file. `!` = a delta row whose status could not be read. */
|
|
27
|
+
export type FileStatus = 'M' | 'A' | 'D' | 'R' | '?' | '!';
|
|
28
|
+
/** One file's line delta as `git diff --numstat` reports it. */
|
|
29
|
+
export interface FileDelta {
|
|
30
|
+
path: string;
|
|
31
|
+
/** Lines added; null for binary files. */
|
|
32
|
+
added: number | null;
|
|
33
|
+
/** Lines removed; null for binary files. */
|
|
34
|
+
removed: number | null;
|
|
35
|
+
status: FileStatus;
|
|
36
|
+
}
|
|
37
|
+
export interface DiffFacts {
|
|
38
|
+
/** Current branch name, or null when detached. */
|
|
39
|
+
branch: string | null;
|
|
40
|
+
/** Worktree dir name (NNN-slug) when running inside a UAP worktree. */
|
|
41
|
+
worktree: string | null;
|
|
42
|
+
/** Uncommitted files (vs HEAD): staged + unstaged, one row per path. */
|
|
43
|
+
uncommitted: FileDelta[];
|
|
44
|
+
/** Untracked paths (never added to the index). */
|
|
45
|
+
untracked: string[];
|
|
46
|
+
/** Unpushed commits vs base: oneline subjects, newest first, capped. */
|
|
47
|
+
unpushedCommits: string[];
|
|
48
|
+
/** Ahead/behind counts vs the merge-base, when computable. */
|
|
49
|
+
ahead: number | null;
|
|
50
|
+
behind: number | null;
|
|
51
|
+
/** Aggregate unpushed file deltas (base...HEAD). */
|
|
52
|
+
unpushedFiles: FileDelta[];
|
|
53
|
+
/** The base ref this view compares against. */
|
|
54
|
+
base: string;
|
|
55
|
+
/** The numstat read (uncommitted deltas) succeeded. False ⇒ the empty
|
|
56
|
+
* uncommitted list is UNKNOWN, not clean — the view must not claim
|
|
57
|
+
* cleanliness from absent data. */
|
|
58
|
+
numstatOk: boolean;
|
|
59
|
+
/** The porcelain status read (untracked + status codes) succeeded. */
|
|
60
|
+
statusOk: boolean;
|
|
61
|
+
/** Populated when git itself was unusable — the view says so. */
|
|
62
|
+
gitError: string | null;
|
|
63
|
+
}
|
|
64
|
+
/** Parse `git diff --numstat` output into delta rows (status unknown). */
|
|
65
|
+
export declare function parseNumstat(out: string): FileDelta[];
|
|
66
|
+
/** Fold `git status --porcelain` codes onto delta rows by path. */
|
|
67
|
+
export declare function applyPorcelain(deltas: FileDelta[], porcelain: string): {
|
|
68
|
+
untracked: string[];
|
|
69
|
+
};
|
|
70
|
+
/** Gather the raw facts from git. Degrades to empty on any failure — and
|
|
71
|
+
* records WHICH reads failed, so the view can say "unknown" instead of
|
|
72
|
+
* claiming "clean" from absent data. */
|
|
73
|
+
export declare function gatherDiffFacts(cwd: string, options?: DiffOptions): DiffFacts;
|
|
74
|
+
/**
|
|
75
|
+
* Pure renderer: facts → the operator-facing view. Exported so the tests pin
|
|
76
|
+
* the wording without running git.
|
|
77
|
+
*/
|
|
78
|
+
export declare function renderDiffView(facts: DiffFacts, maxFiles?: number): string;
|
|
79
|
+
/** Parse a positive-integer CLI flag. Returns undefined when the flag is
|
|
80
|
+
* absent (caller applies its default) and null when it is garbage — a LOUD
|
|
81
|
+
* refusal, never NaN math: a truncated view wearing the full totals is a
|
|
82
|
+
* lie. */
|
|
83
|
+
export declare function parsePositiveInt(raw: string | undefined): number | undefined | null;
|
|
84
|
+
export declare function diffCommand(options?: DiffOptions): Promise<void>;
|
|
85
|
+
//# sourceMappingURL=diff.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diff.d.ts","sourceRoot":"","sources":["../../src/cli/diff.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAMH,MAAM,WAAW,WAAW;IAC1B,wDAAwD;IACxD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,yCAAyC;IACzC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,0EAA0E;IAC1E,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAMD,mFAAmF;AACnF,MAAM,MAAM,UAAU,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;AAE3D,gEAAgE;AAChE,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,0CAA0C;IAC1C,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,4CAA4C;IAC5C,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,MAAM,EAAE,UAAU,CAAC;CACpB;AAED,MAAM,WAAW,SAAS;IACxB,kDAAkD;IAClD,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,uEAAuE;IACvE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,wEAAwE;IACxE,WAAW,EAAE,SAAS,EAAE,CAAC;IACzB,kDAAkD;IAClD,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,wEAAwE;IACxE,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,8DAA8D;IAC9D,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,oDAAoD;IACpD,aAAa,EAAE,SAAS,EAAE,CAAC;IAC3B,+CAA+C;IAC/C,IAAI,EAAE,MAAM,CAAC;IACb;;uCAEmC;IACnC,SAAS,EAAE,OAAO,CAAC;IACnB,sEAAsE;IACtE,QAAQ,EAAE,OAAO,CAAC;IAClB,iEAAiE;IACjE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAoBD,0EAA0E;AAC1E,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,EAAE,CAiBrD;AAED,mEAAmE;AACnE,wBAAgB,cAAc,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,SAAS,EAAE,MAAM,GAAG;IAAE,SAAS,EAAE,MAAM,EAAE,CAAA;CAAE,CA6B9F;AAED;;wCAEwC;AACxC,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,SAAS,CA0EjF;AAuBD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,SAAoB,GAAG,MAAM,CAyErF;AAED;;;UAGU;AACV,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,GAAG,IAAI,CAInF;AAED,wBAAsB,WAAW,CAAC,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAuB1E"}
|
package/dist/cli/diff.js
ADDED
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `uap diff` — the local diff view
|
|
3
|
+
*
|
|
4
|
+
* The operator's one-command answer to "what has the agent changed around
|
|
5
|
+
* here?": uncommitted AND unpushed work, summarized legibly — per-file line
|
|
6
|
+
* deltas with status codes (modified / added / deleted / renamed / untracked),
|
|
7
|
+
* against both HEAD and the base branch, with the exact commands to inspect
|
|
8
|
+
* deeper. A worktree-scoped agent's output lives in `.worktrees/NNN-<slug>/`
|
|
9
|
+
* where a plain `git status` scrolls past; this is the at-a-glance view.
|
|
10
|
+
*
|
|
11
|
+
* Safe-git contract (inherited from supervise/observe): git runs via
|
|
12
|
+
* execFileSync ARG ARRAYS (no shell, no interpolation), 5s timeout, and every
|
|
13
|
+
* failure degrades to `unknown` — the view renders with what it could read,
|
|
14
|
+
* it never throws. Output is capped per section (`--max`, default 40 files)
|
|
15
|
+
* because a monorepo can list thousands.
|
|
16
|
+
*/
|
|
17
|
+
import { execFileSync } from 'child_process';
|
|
18
|
+
import chalk from 'chalk';
|
|
19
|
+
import { termSafe } from '../utils/terminal-safe.js';
|
|
20
|
+
const GIT_TIMEOUT_MS = 5000;
|
|
21
|
+
/** Cap a monorepo's file list — the view is a summary, not a log dump. */
|
|
22
|
+
const DEFAULT_MAX_FILES = 40;
|
|
23
|
+
/** Run git, return stdout or null (never throw). `core.quotepath=false`
|
|
24
|
+
* everywhere: git's default quotes non-ASCII paths as octal escapes
|
|
25
|
+
* (`"\303\251clat"`), which would mangle every unicode filename in the
|
|
26
|
+
* view AND break the porcelain↔numstat exact-match fold (numstat's path
|
|
27
|
+
* would carry escapes porcelain stripped). Raw bytes on both sides. */
|
|
28
|
+
function git(args, cwd) {
|
|
29
|
+
try {
|
|
30
|
+
return execFileSync('git', ['-c', 'core.fsmonitor=false', '-c', 'core.untrackedCache=false', '-c', 'core.quotepath=false', ...args], {
|
|
31
|
+
cwd,
|
|
32
|
+
encoding: 'utf-8',
|
|
33
|
+
timeout: GIT_TIMEOUT_MS,
|
|
34
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/** Parse `git diff --numstat` output into delta rows (status unknown). */
|
|
42
|
+
export function parseNumstat(out) {
|
|
43
|
+
const files = [];
|
|
44
|
+
for (const line of out.split('\n')) {
|
|
45
|
+
if (!line)
|
|
46
|
+
continue;
|
|
47
|
+
const m = line.match(/^(\d+|-)\t(\d+|-)\t(.+)$/);
|
|
48
|
+
if (!m)
|
|
49
|
+
continue;
|
|
50
|
+
files.push({
|
|
51
|
+
added: m[1] === '-' ? null : parseInt(m[1], 10),
|
|
52
|
+
removed: m[2] === '-' ? null : parseInt(m[2], 10),
|
|
53
|
+
// Renames arrive as `{old => new}` path shapes; keep the tail verbatim.
|
|
54
|
+
// Outer quotes (git quotes paths with spaces/specials) are stripped so
|
|
55
|
+
// the porcelain fold's exact match sees the same spelling on both sides.
|
|
56
|
+
path: m[3].replace(/^"|"$/g, ''),
|
|
57
|
+
status: '!',
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
return files;
|
|
61
|
+
}
|
|
62
|
+
/** Fold `git status --porcelain` codes onto delta rows by path. */
|
|
63
|
+
export function applyPorcelain(deltas, porcelain) {
|
|
64
|
+
const untracked = [];
|
|
65
|
+
for (const line of porcelain.split('\n')) {
|
|
66
|
+
if (!line)
|
|
67
|
+
continue;
|
|
68
|
+
const code = line.slice(0, 2);
|
|
69
|
+
const raw = line.slice(3).trim().replace(/^"|"$/g, '');
|
|
70
|
+
if (code === '??') {
|
|
71
|
+
untracked.push(raw);
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
// XY: prefer the worktree code (Y) — the file's state on disk is what the
|
|
75
|
+
// operator sees — else the index code (X).
|
|
76
|
+
const y = code[1]?.trim();
|
|
77
|
+
const x = code[0]?.trim();
|
|
78
|
+
const c = y || x || '';
|
|
79
|
+
const status = c === 'D' ? 'D' : c === 'A' ? 'A' : c === 'R' ? 'R' : c === 'M' ? 'M' : '?';
|
|
80
|
+
// Renames: porcelain prints `old -> new` (and sometimes just `new`);
|
|
81
|
+
// numstat prints `{old => new}`. Normalize both spellings before matching
|
|
82
|
+
// so the status lands on the right row. Exact matches win over fuzzy
|
|
83
|
+
// suffix matches (an `endsWith` hit on an earlier row must not steal the
|
|
84
|
+
// status from an exact row). Rows porcelain does not cover keep their
|
|
85
|
+
// `!` — status codes are cosmetic, the deltas are the substance.
|
|
86
|
+
const renameArrow = raw.indexOf(' -> ');
|
|
87
|
+
const effective = (renameArrow >= 0 ? raw.slice(renameArrow + 4) : raw).replace(/^"|"$/g, '');
|
|
88
|
+
const exact = deltas.find((d) => d.path === raw || d.path.replace(/\{[^}]* => ([^}]*)\}/g, '$1') === effective);
|
|
89
|
+
const match = exact ?? deltas.find((d) => d.path.endsWith(raw));
|
|
90
|
+
if (match)
|
|
91
|
+
match.status = status;
|
|
92
|
+
}
|
|
93
|
+
return { untracked };
|
|
94
|
+
}
|
|
95
|
+
/** Gather the raw facts from git. Degrades to empty on any failure — and
|
|
96
|
+
* records WHICH reads failed, so the view can say "unknown" instead of
|
|
97
|
+
* claiming "clean" from absent data. */
|
|
98
|
+
export function gatherDiffFacts(cwd, options = {}) {
|
|
99
|
+
const base = options.base || 'master';
|
|
100
|
+
const facts = {
|
|
101
|
+
branch: null,
|
|
102
|
+
worktree: null,
|
|
103
|
+
uncommitted: [],
|
|
104
|
+
untracked: [],
|
|
105
|
+
unpushedCommits: [],
|
|
106
|
+
ahead: null,
|
|
107
|
+
behind: null,
|
|
108
|
+
unpushedFiles: [],
|
|
109
|
+
base,
|
|
110
|
+
numstatOk: false,
|
|
111
|
+
statusOk: false,
|
|
112
|
+
gitError: null,
|
|
113
|
+
};
|
|
114
|
+
// "Is this a repo" must not be probed with rev-parse HEAD — an unborn
|
|
115
|
+
// branch (fresh init, no commits) has no HEAD and would be misreported as
|
|
116
|
+
// "not a repository". is-inside-work-tree answers the question directly.
|
|
117
|
+
const inside = git(['rev-parse', '--is-inside-work-tree'], cwd);
|
|
118
|
+
if (inside === null || inside.trim() !== 'true') {
|
|
119
|
+
facts.gitError = 'git unavailable or not a repository';
|
|
120
|
+
return facts;
|
|
121
|
+
}
|
|
122
|
+
// symbolic-ref reads the branch even when HEAD is unborn; it fails only
|
|
123
|
+
// when HEAD is detached (no symbolic ref) → null → "(detached)".
|
|
124
|
+
const branch = git(['symbolic-ref', '--short', 'HEAD'], cwd);
|
|
125
|
+
facts.branch = branch === null ? null : branch.trim() || null;
|
|
126
|
+
facts.worktree = /(^|\/)\.worktrees\/([0-9]+-[^/]+)\/?$/.exec(cwd)?.[2] ?? null;
|
|
127
|
+
// Uncommitted: staged + unstaged in ONE numstat pass (vs HEAD), then fold
|
|
128
|
+
// porcelain status codes and untracked paths onto it. --no-ext-diff keeps
|
|
129
|
+
// a repo-configured external diff driver out of the read (numstat bypasses
|
|
130
|
+
// drivers today; the flag is defense-in-depth for future flag changes).
|
|
131
|
+
const numstat = git(['diff', '--no-ext-diff', '--numstat', 'HEAD', '--'], cwd);
|
|
132
|
+
facts.numstatOk = numstat !== null;
|
|
133
|
+
if (numstat !== null) {
|
|
134
|
+
const seen = new Set();
|
|
135
|
+
for (const f of parseNumstat(numstat)) {
|
|
136
|
+
if (seen.has(f.path))
|
|
137
|
+
continue; // same path staged+unstaged: one row
|
|
138
|
+
seen.add(f.path);
|
|
139
|
+
facts.uncommitted.push(f);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
const status = git(['status', '--porcelain', '--untracked-files=all'], cwd);
|
|
143
|
+
facts.statusOk = status !== null;
|
|
144
|
+
if (status !== null) {
|
|
145
|
+
facts.untracked = applyPorcelain(facts.uncommitted, status).untracked;
|
|
146
|
+
}
|
|
147
|
+
// Unpushed: ahead/behind and aggregate deltas vs the merge-base with base.
|
|
148
|
+
const counts = git(['rev-list', '--left-right', '--count', `${base}...HEAD`], cwd);
|
|
149
|
+
if (counts !== null) {
|
|
150
|
+
const m = counts.trim().match(/^(\d+)\s+(\d+)$/);
|
|
151
|
+
if (m) {
|
|
152
|
+
facts.behind = parseInt(m[1], 10);
|
|
153
|
+
facts.ahead = parseInt(m[2], 10);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
if (facts.ahead === null || facts.ahead > 0) {
|
|
157
|
+
const log = git(['log', '--no-ext-diff', '--oneline', '--no-decorate', `${base}..HEAD`, '--'], cwd);
|
|
158
|
+
if (log !== null) {
|
|
159
|
+
facts.unpushedCommits = log
|
|
160
|
+
.split('\n')
|
|
161
|
+
.map((l) => l.trim())
|
|
162
|
+
.filter(Boolean)
|
|
163
|
+
.slice(0, DEFAULT_MAX_FILES);
|
|
164
|
+
}
|
|
165
|
+
const diffBase = git(['diff', '--no-ext-diff', '--numstat', `${base}...HEAD`, '--'], cwd);
|
|
166
|
+
if (diffBase !== null)
|
|
167
|
+
facts.unpushedFiles = parseNumstat(diffBase);
|
|
168
|
+
}
|
|
169
|
+
return facts;
|
|
170
|
+
}
|
|
171
|
+
const fmtDelta = (n) => (n === null ? '±' : String(n));
|
|
172
|
+
function totalDeltas(files) {
|
|
173
|
+
let added = 0;
|
|
174
|
+
let removed = 0;
|
|
175
|
+
for (const f of files) {
|
|
176
|
+
added += f.added ?? 0;
|
|
177
|
+
removed += f.removed ?? 0;
|
|
178
|
+
}
|
|
179
|
+
return { added, removed };
|
|
180
|
+
}
|
|
181
|
+
const STATUS_GLYPH = {
|
|
182
|
+
M: 'M',
|
|
183
|
+
A: 'A',
|
|
184
|
+
D: 'D',
|
|
185
|
+
R: 'R',
|
|
186
|
+
'?': '~',
|
|
187
|
+
'!': '~',
|
|
188
|
+
};
|
|
189
|
+
/**
|
|
190
|
+
* Pure renderer: facts → the operator-facing view. Exported so the tests pin
|
|
191
|
+
* the wording without running git.
|
|
192
|
+
*/
|
|
193
|
+
export function renderDiffView(facts, maxFiles = DEFAULT_MAX_FILES) {
|
|
194
|
+
const lines = [];
|
|
195
|
+
const where = facts.worktree
|
|
196
|
+
? `${facts.branch ?? '(detached)'} in worktree ${facts.worktree}`
|
|
197
|
+
: facts.branch ?? '(detached)';
|
|
198
|
+
lines.push(chalk.bold(`Local changes — ${where}`));
|
|
199
|
+
if (facts.gitError) {
|
|
200
|
+
lines.push(chalk.red(` git: ${facts.gitError}`));
|
|
201
|
+
return lines.join('\n');
|
|
202
|
+
}
|
|
203
|
+
// --- uncommitted ---
|
|
204
|
+
if (!facts.numstatOk || !facts.statusOk) {
|
|
205
|
+
// A git read failed or timed out: the empty lists are UNKNOWN, not clean.
|
|
206
|
+
// An absence of data must never be rendered as a positive claim.
|
|
207
|
+
lines.push(chalk.yellow(' working tree: UNKNOWN — a git read failed or timed out; run `git status` before trusting this view'));
|
|
208
|
+
}
|
|
209
|
+
else if (facts.uncommitted.length === 0 && facts.untracked.length === 0) {
|
|
210
|
+
lines.push(chalk.green(' working tree: clean (nothing uncommitted)'));
|
|
211
|
+
}
|
|
212
|
+
else {
|
|
213
|
+
lines.push(' uncommitted:');
|
|
214
|
+
const sorted = [...facts.uncommitted].sort((a, b) => (b.added ?? 0) - (a.added ?? 0));
|
|
215
|
+
for (const f of sorted.slice(0, maxFiles)) {
|
|
216
|
+
const glyph = STATUS_GLYPH[f.status];
|
|
217
|
+
const tag = f.status === 'D' ? chalk.red(glyph) : f.status === 'A' ? chalk.cyan(glyph) : chalk.yellow(glyph);
|
|
218
|
+
// Column integrity (P5 polish): a path LONGER than the column used to
|
|
219
|
+
// push the +N/-N columns right per row. Cap to the column width (keep
|
|
220
|
+
// the TAIL — the informative half of a path) then pad, so every row
|
|
221
|
+
// lines up exactly.
|
|
222
|
+
const shown = f.path.length > 64 ? `…${f.path.slice(-63)}` : f.path.padEnd(64);
|
|
223
|
+
lines.push(` ${tag} ${shown} ${chalk.green(`+${fmtDelta(f.added)}`)} ${chalk.red(`-${fmtDelta(f.removed)}`)}`);
|
|
224
|
+
}
|
|
225
|
+
if (sorted.length > maxFiles) {
|
|
226
|
+
lines.push(chalk.dim(` … and ${sorted.length - maxFiles} more modified file(s)`));
|
|
227
|
+
}
|
|
228
|
+
for (const u of facts.untracked.slice(0, maxFiles)) {
|
|
229
|
+
lines.push(` ${chalk.cyan('?')} ${u}`);
|
|
230
|
+
}
|
|
231
|
+
if (facts.untracked.length > maxFiles) {
|
|
232
|
+
lines.push(chalk.dim(` … and ${facts.untracked.length - maxFiles} more untracked path(s)`));
|
|
233
|
+
}
|
|
234
|
+
const t = totalDeltas(facts.uncommitted);
|
|
235
|
+
lines.push(chalk.dim(` tracked totals: +${t.added} -${t.removed} across ${facts.uncommitted.length} tracked, ${facts.untracked.length} untracked`));
|
|
236
|
+
}
|
|
237
|
+
// --- unpushed ---
|
|
238
|
+
if (facts.ahead === null && facts.behind === null) {
|
|
239
|
+
lines.push(chalk.dim(` unpushed: unknown (no merge-base with ${facts.base}?)`));
|
|
240
|
+
}
|
|
241
|
+
else if ((facts.ahead ?? 0) === 0) {
|
|
242
|
+
lines.push(chalk.green(` unpushed: none (in sync with ${facts.base})`));
|
|
243
|
+
}
|
|
244
|
+
else {
|
|
245
|
+
const ab = facts.behind && facts.behind > 0 ? `, ${facts.behind} behind` : '';
|
|
246
|
+
lines.push(` unpushed: ${chalk.bold(String(facts.ahead))} commit(s) vs ${facts.base}${ab}:`);
|
|
247
|
+
for (const c of facts.unpushedCommits.slice(0, maxFiles))
|
|
248
|
+
lines.push(chalk.dim(` ${termSafe(c)}`));
|
|
249
|
+
if (facts.unpushedCommits.length > maxFiles) {
|
|
250
|
+
lines.push(chalk.dim(` … and ${facts.unpushedCommits.length - maxFiles} more commit(s)`));
|
|
251
|
+
}
|
|
252
|
+
const t = totalDeltas(facts.unpushedFiles);
|
|
253
|
+
lines.push(chalk.dim(` diff vs ${facts.base}: +${t.added} -${t.removed} across ${facts.unpushedFiles.length} file(s)`));
|
|
254
|
+
}
|
|
255
|
+
lines.push('');
|
|
256
|
+
lines.push(chalk.dim(' inspect: git diff -- <file> · git log -p <commit> · git status'));
|
|
257
|
+
return lines.join('\n');
|
|
258
|
+
}
|
|
259
|
+
/** Parse a positive-integer CLI flag. Returns undefined when the flag is
|
|
260
|
+
* absent (caller applies its default) and null when it is garbage — a LOUD
|
|
261
|
+
* refusal, never NaN math: a truncated view wearing the full totals is a
|
|
262
|
+
* lie. */
|
|
263
|
+
export function parsePositiveInt(raw) {
|
|
264
|
+
if (raw === undefined)
|
|
265
|
+
return undefined;
|
|
266
|
+
const n = parseInt(raw, 10);
|
|
267
|
+
return Number.isFinite(n) && n >= 1 ? n : null;
|
|
268
|
+
}
|
|
269
|
+
export async function diffCommand(options = {}) {
|
|
270
|
+
const cwd = options.cwd || process.cwd();
|
|
271
|
+
if (options.base?.startsWith('-')) {
|
|
272
|
+
// Git parses argv: a ref starting with '-' would be consumed as a git
|
|
273
|
+
// OPTION (e.g. --output=<file>), not a rev. Refnames cannot legitimately
|
|
274
|
+
// start with '-', so refuse loudly instead of letting git act on it.
|
|
275
|
+
console.error(chalk.red(`--base must be a ref, not an option (got '${options.base}')`));
|
|
276
|
+
process.exitCode = 1;
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
const maxRaw = parsePositiveInt(options.max);
|
|
280
|
+
if (options.max !== undefined && maxRaw === null) {
|
|
281
|
+
console.error(chalk.red(`--max must be a positive integer (got '${options.max}')`));
|
|
282
|
+
process.exitCode = 1;
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
const maxFiles = maxRaw ?? DEFAULT_MAX_FILES;
|
|
286
|
+
const facts = gatherDiffFacts(cwd, options);
|
|
287
|
+
if (options.json) {
|
|
288
|
+
console.log(JSON.stringify(facts, null, 2));
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
console.log(renderDiffView(facts, maxFiles));
|
|
292
|
+
}
|
|
293
|
+
//# sourceMappingURL=diff.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diff.js","sourceRoot":"","sources":["../../src/cli/diff.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAYrD,MAAM,cAAc,GAAG,IAAI,CAAC;AAC5B,0EAA0E;AAC1E,MAAM,iBAAiB,GAAG,EAAE,CAAC;AA2C7B;;;;wEAIwE;AACxE,SAAS,GAAG,CAAC,IAAc,EAAE,GAAW;IACtC,IAAI,CAAC;QACH,OAAO,YAAY,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,sBAAsB,EAAE,IAAI,EAAE,2BAA2B,EAAE,IAAI,EAAE,sBAAsB,EAAE,GAAG,IAAI,CAAC,EAAE;YACnI,GAAG;YACH,QAAQ,EAAE,OAAO;YACjB,OAAO,EAAE,cAAc;YACvB,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC;SAClC,CAAC,CAAC;IACL,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,0EAA0E;AAC1E,MAAM,UAAU,YAAY,CAAC,GAAW;IACtC,MAAM,KAAK,GAAgB,EAAE,CAAC;IAC9B,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACnC,IAAI,CAAC,IAAI;YAAE,SAAS;QACpB,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,0BAA0B,CAAC,CAAC;QACjD,IAAI,CAAC,CAAC;YAAE,SAAS;QACjB,KAAK,CAAC,IAAI,CAAC;YACT,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;YAC/C,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;YACjD,wEAAwE;YACxE,uEAAuE;YACvE,yEAAyE;YACzE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC;YAChC,MAAM,EAAE,GAAG;SACZ,CAAC,CAAC;IACL,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,mEAAmE;AACnE,MAAM,UAAU,cAAc,CAAC,MAAmB,EAAE,SAAiB;IACnE,MAAM,SAAS,GAAa,EAAE,CAAC;IAC/B,KAAK,MAAM,IAAI,IAAI,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACzC,IAAI,CAAC,IAAI;YAAE,SAAS;QACpB,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAC9B,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;QACvD,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;YAClB,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACpB,SAAS;QACX,CAAC;QACD,0EAA0E;QAC1E,2CAA2C;QAC3C,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;QAC1B,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;QAC1B,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QACvB,MAAM,MAAM,GAAe,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;QACvG,qEAAqE;QACrE,0EAA0E;QAC1E,qEAAqE;QACrE,yEAAyE;QACzE,sEAAsE;QACtE,iEAAiE;QACjE,MAAM,WAAW,GAAG,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QACxC,MAAM,SAAS,GAAG,CAAC,WAAW,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,WAAW,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;QAC9F,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,GAAG,IAAI,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,uBAAuB,EAAE,IAAI,CAAC,KAAK,SAAS,CAAC,CAAC;QAChH,MAAM,KAAK,GAAG,KAAK,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;QAChE,IAAI,KAAK;YAAE,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC;IACnC,CAAC;IACD,OAAO,EAAE,SAAS,EAAE,CAAC;AACvB,CAAC;AAED;;wCAEwC;AACxC,MAAM,UAAU,eAAe,CAAC,GAAW,EAAE,UAAuB,EAAE;IACpE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,QAAQ,CAAC;IACtC,MAAM,KAAK,GAAc;QACvB,MAAM,EAAE,IAAI;QACZ,QAAQ,EAAE,IAAI;QACd,WAAW,EAAE,EAAE;QACf,SAAS,EAAE,EAAE;QACb,eAAe,EAAE,EAAE;QACnB,KAAK,EAAE,IAAI;QACX,MAAM,EAAE,IAAI;QACZ,aAAa,EAAE,EAAE;QACjB,IAAI;QACJ,SAAS,EAAE,KAAK;QAChB,QAAQ,EAAE,KAAK;QACf,QAAQ,EAAE,IAAI;KACf,CAAC;IAEF,sEAAsE;IACtE,0EAA0E;IAC1E,yEAAyE;IACzE,MAAM,MAAM,GAAG,GAAG,CAAC,CAAC,WAAW,EAAE,uBAAuB,CAAC,EAAE,GAAG,CAAC,CAAC;IAChE,IAAI,MAAM,KAAK,IAAI,IAAI,MAAM,CAAC,IAAI,EAAE,KAAK,MAAM,EAAE,CAAC;QAChD,KAAK,CAAC,QAAQ,GAAG,qCAAqC,CAAC;QACvD,OAAO,KAAK,CAAC;IACf,CAAC;IACD,wEAAwE;IACxE,iEAAiE;IACjE,MAAM,MAAM,GAAG,GAAG,CAAC,CAAC,cAAc,EAAE,SAAS,EAAE,MAAM,CAAC,EAAE,GAAG,CAAC,CAAC;IAC7D,KAAK,CAAC,MAAM,GAAG,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,IAAI,CAAC;IAC9D,KAAK,CAAC,QAAQ,GAAG,uCAAuC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;IAEhF,0EAA0E;IAC1E,0EAA0E;IAC1E,2EAA2E;IAC3E,wEAAwE;IACxE,MAAM,OAAO,GAAG,GAAG,CAAC,CAAC,MAAM,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC;IAC/E,KAAK,CAAC,SAAS,GAAG,OAAO,KAAK,IAAI,CAAC;IACnC,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;QACrB,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;QAC/B,KAAK,MAAM,CAAC,IAAI,YAAY,CAAC,OAAO,CAAC,EAAE,CAAC;YACtC,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;gBAAE,SAAS,CAAC,qCAAqC;YACrE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YACjB,KAAK,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC;IACD,MAAM,MAAM,GAAG,GAAG,CAAC,CAAC,QAAQ,EAAE,aAAa,EAAE,uBAAuB,CAAC,EAAE,GAAG,CAAC,CAAC;IAC5E,KAAK,CAAC,QAAQ,GAAG,MAAM,KAAK,IAAI,CAAC;IACjC,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;QACpB,KAAK,CAAC,SAAS,GAAG,cAAc,CAAC,KAAK,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,SAAS,CAAC;IACxE,CAAC;IAED,2EAA2E;IAC3E,MAAM,MAAM,GAAG,GAAG,CAAC,CAAC,UAAU,EAAE,cAAc,EAAE,SAAS,EAAE,GAAG,IAAI,SAAS,CAAC,EAAE,GAAG,CAAC,CAAC;IACnF,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;QACpB,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC;QACjD,IAAI,CAAC,EAAE,CAAC;YACN,KAAK,CAAC,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAClC,KAAK,CAAC,KAAK,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACnC,CAAC;IACH,CAAC;IACD,IAAI,KAAK,CAAC,KAAK,KAAK,IAAI,IAAI,KAAK,CAAC,KAAK,GAAG,CAAC,EAAE,CAAC;QAC5C,MAAM,GAAG,GAAG,GAAG,CAAC,CAAC,KAAK,EAAE,eAAe,EAAE,WAAW,EAAE,eAAe,EAAE,GAAG,IAAI,QAAQ,EAAE,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC;QACpG,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;YACjB,KAAK,CAAC,eAAe,GAAG,GAAG;iBACxB,KAAK,CAAC,IAAI,CAAC;iBACX,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;iBACpB,MAAM,CAAC,OAAO,CAAC;iBACf,KAAK,CAAC,CAAC,EAAE,iBAAiB,CAAC,CAAC;QACjC,CAAC;QACD,MAAM,QAAQ,GAAG,GAAG,CAAC,CAAC,MAAM,EAAE,eAAe,EAAE,WAAW,EAAE,GAAG,IAAI,SAAS,EAAE,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC;QAC1F,IAAI,QAAQ,KAAK,IAAI;YAAE,KAAK,CAAC,aAAa,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;IACtE,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,QAAQ,GAAG,CAAC,CAAgB,EAAU,EAAE,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;AAE9E,SAAS,WAAW,CAAC,KAAkB;IACrC,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,KAAK,IAAI,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC;QACtB,OAAO,IAAI,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC;IAC5B,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;AAC5B,CAAC;AAED,MAAM,YAAY,GAA+B;IAC/C,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,GAAG,EAAE,GAAG;IACR,GAAG,EAAE,GAAG;CACT,CAAC;AAEF;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,KAAgB,EAAE,QAAQ,GAAG,iBAAiB;IAC3E,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,MAAM,KAAK,GAAG,KAAK,CAAC,QAAQ;QAC1B,CAAC,CAAC,GAAG,KAAK,CAAC,MAAM,IAAI,YAAY,gBAAgB,KAAK,CAAC,QAAQ,EAAE;QACjE,CAAC,CAAC,KAAK,CAAC,MAAM,IAAI,YAAY,CAAC;IACjC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,mBAAmB,KAAK,EAAE,CAAC,CAAC,CAAC;IACnD,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;QACnB,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;QAClD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAED,sBAAsB;IACtB,IAAI,CAAC,KAAK,CAAC,SAAS,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;QACxC,0EAA0E;QAC1E,iEAAiE;QACjE,KAAK,CAAC,IAAI,CACR,KAAK,CAAC,MAAM,CAAC,sGAAsG,CAAC,CACrH,CAAC;IACJ,CAAC;SAAM,IAAI,KAAK,CAAC,WAAW,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1E,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,6CAA6C,CAAC,CAAC,CAAC;IACzE,CAAC;SAAM,CAAC;QACN,KAAK,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;QAC7B,MAAM,MAAM,GAAG,CAAC,GAAG,KAAK,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC;QACtF,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,EAAE,CAAC;YAC1C,MAAM,KAAK,GAAG,YAAY,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;YACrC,MAAM,GAAG,GAAG,CAAC,CAAC,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAC7G,sEAAsE;YACtE,sEAAsE;YACtE,oEAAoE;YACpE,oBAAoB;YACpB,MAAM,KAAK,GAAG,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YAC/E,KAAK,CAAC,IAAI,CACR,OAAO,GAAG,IAAI,KAAK,IAAI,KAAK,CAAC,KAAK,CAAC,IAAI,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,KAAK,CAAC,GAAG,CAAC,IAAI,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CACtG,CAAC;QACJ,CAAC;QACD,IAAI,MAAM,CAAC,MAAM,GAAG,QAAQ,EAAE,CAAC;YAC7B,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,aAAa,MAAM,CAAC,MAAM,GAAG,QAAQ,wBAAwB,CAAC,CAAC,CAAC;QACvF,CAAC;QACD,KAAK,MAAM,CAAC,IAAI,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,EAAE,CAAC;YACnD,KAAK,CAAC,IAAI,CAAC,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC5C,CAAC;QACD,IAAI,KAAK,CAAC,SAAS,CAAC,MAAM,GAAG,QAAQ,EAAE,CAAC;YACtC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,aAAa,KAAK,CAAC,SAAS,CAAC,MAAM,GAAG,QAAQ,yBAAyB,CAAC,CAAC,CAAC;QACjG,CAAC;QACD,MAAM,CAAC,GAAG,WAAW,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;QACzC,KAAK,CAAC,IAAI,CACR,KAAK,CAAC,GAAG,CACP,wBAAwB,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,OAAO,WAAW,KAAK,CAAC,WAAW,CAAC,MAAM,aAAa,KAAK,CAAC,SAAS,CAAC,MAAM,YAAY,CAChI,CACF,CAAC;IACJ,CAAC;IAED,mBAAmB;IACnB,IAAI,KAAK,CAAC,KAAK,KAAK,IAAI,IAAI,KAAK,CAAC,MAAM,KAAK,IAAI,EAAE,CAAC;QAClD,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,2CAA2C,KAAK,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC;IACnF,CAAC;SAAM,IAAI,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;QACpC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,kCAAkC,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC;IAC3E,CAAC;SAAM,CAAC;QACN,MAAM,EAAE,GAAG,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,MAAM,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC;QAC9E,KAAK,CAAC,IAAI,CAAC,eAAe,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,iBAAiB,KAAK,CAAC,IAAI,GAAG,EAAE,GAAG,CAAC,CAAC;QAC9F,KAAK,MAAM,CAAC,IAAI,KAAK,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC;YAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACtG,IAAI,KAAK,CAAC,eAAe,CAAC,MAAM,GAAG,QAAQ,EAAE,CAAC;YAC5C,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,aAAa,KAAK,CAAC,eAAe,CAAC,MAAM,GAAG,QAAQ,iBAAiB,CAAC,CAAC,CAAC;QAC/F,CAAC;QACD,MAAM,CAAC,GAAG,WAAW,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;QAC3C,KAAK,CAAC,IAAI,CACR,KAAK,CAAC,GAAG,CAAC,eAAe,KAAK,CAAC,IAAI,MAAM,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,OAAO,WAAW,KAAK,CAAC,aAAa,CAAC,MAAM,UAAU,CAAC,CAC/G,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,kEAAkE,CAAC,CAAC,CAAC;IAC1F,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED;;;UAGU;AACV,MAAM,UAAU,gBAAgB,CAAC,GAAuB;IACtD,IAAI,GAAG,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IACxC,MAAM,CAAC,GAAG,QAAQ,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IAC5B,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AACjD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,UAAuB,EAAE;IACzD,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IACzC,IAAI,OAAO,CAAC,IAAI,EAAE,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QAClC,sEAAsE;QACtE,yEAAyE;QACzE,qEAAqE;QACrE,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,6CAA6C,OAAO,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC;QACxF,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACrB,OAAO;IACT,CAAC;IACD,MAAM,MAAM,GAAG,gBAAgB,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC7C,IAAI,OAAO,CAAC,GAAG,KAAK,SAAS,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;QACjD,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,0CAA0C,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;QACpF,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACrB,OAAO;IACT,CAAC;IACD,MAAM,QAAQ,GAAG,MAAM,IAAI,iBAAiB,CAAC;IAC7C,MAAM,KAAK,GAAG,eAAe,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IAC5C,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;QACjB,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QAC5C,OAAO;IACT,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC;AAC/C,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `uap eta` — the operator's window into the agent's own measured pace.
|
|
3
|
+
*
|
|
4
|
+
* Prints the EWMA estimate for one (model, taskType, complexity) key — or,
|
|
5
|
+
* with `--all`, every key that has history. The estimate is built ONLY from
|
|
6
|
+
* this project's own recorded attempts (S1a), and it never hides the
|
|
7
|
+
* sample count, the spread, or the failure rate: a number without its
|
|
8
|
+
* provenance is exactly the kind of confident guess this feature exists
|
|
9
|
+
* to replace.
|
|
10
|
+
*/
|
|
11
|
+
import { type EtaEstimate } from '../delivery/eta-estimate.js';
|
|
12
|
+
export interface EtaOptions {
|
|
13
|
+
/** Model id (default: the active/executor model). */
|
|
14
|
+
model?: string;
|
|
15
|
+
/** Sample key: task type (default 'orchestrated'). */
|
|
16
|
+
taskType?: string;
|
|
17
|
+
/** Sample key: complexity tier (default 'medium'). */
|
|
18
|
+
complexity?: string;
|
|
19
|
+
/** List every key with history instead of one key. */
|
|
20
|
+
all?: boolean;
|
|
21
|
+
/** Sample window / half-life overrides. */
|
|
22
|
+
limit?: string;
|
|
23
|
+
halfLife?: string;
|
|
24
|
+
/** Test/odd-layout seam: pin the analytics DB path. */
|
|
25
|
+
db?: string;
|
|
26
|
+
json?: boolean;
|
|
27
|
+
}
|
|
28
|
+
/** Render one estimate as a single operator-scannable line. */
|
|
29
|
+
export declare function renderEtaLine(key: {
|
|
30
|
+
modelId: string;
|
|
31
|
+
taskType: string;
|
|
32
|
+
complexity: string;
|
|
33
|
+
}, est: EtaEstimate): string;
|
|
34
|
+
export declare function etaCommand(options?: EtaOptions): Promise<void>;
|
|
35
|
+
//# sourceMappingURL=eta.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"eta.d.ts","sourceRoot":"","sources":["../../src/cli/eta.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,OAAO,EAIL,KAAK,WAAW,EACjB,MAAM,6BAA6B,CAAC;AAIrC,MAAM,WAAW,UAAU;IACzB,qDAAqD;IACrD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,sDAAsD;IACtD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,sDAAsD;IACtD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,sDAAsD;IACtD,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,2CAA2C;IAC3C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,uDAAuD;IACvD,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,+DAA+D;AAC/D,wBAAgB,aAAa,CAC3B,GAAG,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,EAC9D,GAAG,EAAE,WAAW,GACf,MAAM,CAeR;AAED,wBAAsB,UAAU,CAAC,OAAO,GAAE,UAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAsFxE"}
|
package/dist/cli/eta.js
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `uap eta` — the operator's window into the agent's own measured pace.
|
|
3
|
+
*
|
|
4
|
+
* Prints the EWMA estimate for one (model, taskType, complexity) key — or,
|
|
5
|
+
* with `--all`, every key that has history. The estimate is built ONLY from
|
|
6
|
+
* this project's own recorded attempts (S1a), and it never hides the
|
|
7
|
+
* sample count, the spread, or the failure rate: a number without its
|
|
8
|
+
* provenance is exactly the kind of confident guess this feature exists
|
|
9
|
+
* to replace.
|
|
10
|
+
*/
|
|
11
|
+
import chalk from 'chalk';
|
|
12
|
+
import { resolveActiveModel } from '../delivery/handsfree-config.js';
|
|
13
|
+
import { estimatePace, formatDurationMs, listPaceKeys, } from '../delivery/eta-estimate.js';
|
|
14
|
+
import { parsePositiveInt } from './diff.js';
|
|
15
|
+
import { termSafe } from '../utils/terminal-safe.js';
|
|
16
|
+
/** Render one estimate as a single operator-scannable line. */
|
|
17
|
+
export function renderEtaLine(key, est) {
|
|
18
|
+
const thin = est.confidence === 'thin' ? chalk.yellow(' [thin data]') : '';
|
|
19
|
+
const spread = chalk.dim(` (spread ${formatDurationMs(est.minMs)}–${formatDurationMs(est.maxMs)})`);
|
|
20
|
+
const failures = est.successRate < 1
|
|
21
|
+
? chalk.yellow(` · ${(100 * (1 - est.successRate)).toFixed(0)}% of attempts fail → expect ~${est.attemptsPerSuccess.toFixed(1)}x wall time`)
|
|
22
|
+
: '';
|
|
23
|
+
return (`${chalk.cyan(termSafe(key.modelId))} ${chalk.dim(`${termSafe(key.taskType)}/${termSafe(key.complexity)}`)}: ` +
|
|
24
|
+
chalk.bold(`~${formatDurationMs(est.etaMs)}`) +
|
|
25
|
+
` per successful task, ~${est.etaTurns.toFixed(1)} turns` +
|
|
26
|
+
` ${chalk.dim(`(EWMA n=${est.samples}/${est.observed} attempts, half-life ${est.halfLifeSamples})`)}${spread}${failures}${thin}`);
|
|
27
|
+
}
|
|
28
|
+
export async function etaCommand(options = {}) {
|
|
29
|
+
const cwd = process.cwd();
|
|
30
|
+
// NaN must never reach the fold: `Math.max(1, parseInt('abc'))` is NaN and
|
|
31
|
+
// a NaN half-life would print a confident-looking garbage line. Loud refusal.
|
|
32
|
+
const halfLifeRaw = parsePositiveInt(options.halfLife);
|
|
33
|
+
if (options.halfLife !== undefined && halfLifeRaw === null) {
|
|
34
|
+
console.error(chalk.red(`--half-life must be a positive integer (got '${options.halfLife}')`));
|
|
35
|
+
process.exitCode = 1;
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
const halfLife = halfLifeRaw ?? undefined;
|
|
39
|
+
const limitRaw = parsePositiveInt(options.limit);
|
|
40
|
+
if (options.limit !== undefined && limitRaw === null) {
|
|
41
|
+
console.error(chalk.red(`--limit must be a positive integer (got '${options.limit}')`));
|
|
42
|
+
process.exitCode = 1;
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
const limit = limitRaw ?? undefined;
|
|
46
|
+
if (options.all) {
|
|
47
|
+
// Enumerate every key with history in ONE store open; show the estimates
|
|
48
|
+
// and the keys whose history is still too thin to estimate (so the
|
|
49
|
+
// operator knows WHY a key they expect is missing, and what would fill
|
|
50
|
+
// it). --json stays PURE JSON (guidance text is gated to the human path).
|
|
51
|
+
const { keys, estimates, truncated } = listPaceKeys({
|
|
52
|
+
dbPath: options.db,
|
|
53
|
+
limit,
|
|
54
|
+
halfLifeSamples: halfLife,
|
|
55
|
+
});
|
|
56
|
+
if (keys.length === 0) {
|
|
57
|
+
if (options.json) {
|
|
58
|
+
console.log(JSON.stringify({ keys: [], estimates: [], truncated: false }, null, 2));
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
console.log(chalk.dim('No recorded attempts yet — run an orchestrated mission; the estimator needs'));
|
|
62
|
+
console.log(chalk.dim('at least 3 successful attempts per (model, taskType, complexity) key.'));
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
if (options.json) {
|
|
66
|
+
console.log(JSON.stringify({ keys, estimates: estimates.filter((e) => e.estimate).map((e) => ({ key: e.key, ...e.estimate })), truncated }, null, 2));
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
console.log(chalk.bold('Measured pace — this project\'s own recorded attempts (EWMA):'));
|
|
70
|
+
for (const e of estimates) {
|
|
71
|
+
if (e.estimate) {
|
|
72
|
+
console.log(' ' + renderEtaLine(e.key, e.estimate));
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
console.log(` ${chalk.cyan(termSafe(e.key.modelId))} ${chalk.dim(`${termSafe(e.key.taskType)}/${termSafe(e.key.complexity)}`)}: ` +
|
|
76
|
+
chalk.dim('— too few successful attempts to estimate (needs ≥3)'));
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
if (truncated)
|
|
80
|
+
console.log(chalk.dim(' … and more keys beyond the first 50 (oldest-activity keys elided)'));
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
const modelId = options.model || resolveActiveModel(cwd);
|
|
84
|
+
const taskType = options.taskType || 'orchestrated';
|
|
85
|
+
const complexity = options.complexity || 'medium';
|
|
86
|
+
const key = { modelId, taskType, complexity };
|
|
87
|
+
const est = estimatePace({ modelId, taskType, complexity, limit, halfLifeSamples: halfLife, dbPath: options.db });
|
|
88
|
+
if (options.json) {
|
|
89
|
+
console.log(JSON.stringify({ key, estimate: est }, null, 2));
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
if (!est) {
|
|
93
|
+
console.log(chalk.dim(`No estimate for ${termSafe(modelId)} ${termSafe(taskType)}/${termSafe(complexity)}: fewer than 3 successful attempts recorded.`));
|
|
94
|
+
console.log(chalk.dim(' `uap eta --all` lists every key with history; the estimator will not guess from thin data.'));
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
console.log(chalk.bold('Measured pace — this project\'s own recorded attempts (EWMA):'));
|
|
98
|
+
console.log(' ' + renderEtaLine(key, est));
|
|
99
|
+
console.log(chalk.dim(` newest sample: ${termSafe(est.lastSampleAt)}`));
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=eta.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"eta.js","sourceRoot":"","sources":["../../src/cli/eta.ts"],"names":[],"mappings":"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"}
|
package/dist/cli/handsfree.d.ts
CHANGED
|
@@ -15,6 +15,13 @@
|
|
|
15
15
|
* per-build block/stagnation counters so it can never wedge the agent (the
|
|
16
16
|
* balance between "never stop early" and "never spin forever").
|
|
17
17
|
*/
|
|
18
|
+
/**
|
|
19
|
+
* The status ETA line for `remaining` open ledger items, from the model's own
|
|
20
|
+
* measured pace — or null when there is no estimate (thin data must not guess).
|
|
21
|
+
* Exported for the tests; the optional dbPath is their seam (the status surface
|
|
22
|
+
* always reads the project store).
|
|
23
|
+
*/
|
|
24
|
+
export declare function handsfreeEtaLine(modelId: string, remaining: number, dbPath?: string): string | null;
|
|
18
25
|
/**
|
|
19
26
|
* Stop-hook decision. Pure so it is unit-testable without process/exit:
|
|
20
27
|
* returns { block, message } given the current ledger state + profile + input.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handsfree.d.ts","sourceRoot":"","sources":["../../src/cli/handsfree.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;
|
|
1
|
+
{"version":3,"file":"handsfree.d.ts","sourceRoot":"","sources":["../../src/cli/handsfree.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAsBH;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAanG;AA8CD;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,GAAG,EAAE,MAAM,EACX,cAAc,EAAE,OAAO,GACtB;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,CA2FvD;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,MAAM,GAAG,SAAS,EACvB,GAAG,EAAE,MAAM,GAAG,SAAS,EACvB,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAAC,IAAI,CAAC,CAmKf"}
|
package/dist/cli/handsfree.js
CHANGED
|
@@ -22,6 +22,27 @@ import { findUapConfigPath, modifyUapConfig } from '../utils/config-loader.js';
|
|
|
22
22
|
import { loadLedger, initLedger, markItem, remainingItems, isComplete, formatRemaining, progress, syncLedgerFromTodos, } from '../delivery/completion-ledger.js';
|
|
23
23
|
import { loadPersistenceConfig, resolveActiveModel } from '../delivery/handsfree-config.js';
|
|
24
24
|
import { resolvePersistenceProfile } from '../delivery/persistence-profile.js';
|
|
25
|
+
import { estimatePace, remainingWallMs, formatDurationMs } from '../delivery/eta-estimate.js';
|
|
26
|
+
/**
|
|
27
|
+
* The status ETA line for `remaining` open ledger items, from the model's own
|
|
28
|
+
* measured pace — or null when there is no estimate (thin data must not guess).
|
|
29
|
+
* Exported for the tests; the optional dbPath is their seam (the status surface
|
|
30
|
+
* always reads the project store).
|
|
31
|
+
*/
|
|
32
|
+
export function handsfreeEtaLine(modelId, remaining, dbPath) {
|
|
33
|
+
if (!Number.isFinite(remaining) || remaining <= 0)
|
|
34
|
+
return null;
|
|
35
|
+
// requireExisting: a status READ must not materialize an empty analytics
|
|
36
|
+
// store on a checkout that has no history yet.
|
|
37
|
+
const est = estimatePace({ modelId, dbPath, requireExisting: true });
|
|
38
|
+
const wall = remainingWallMs(est, remaining);
|
|
39
|
+
if (wall === null || !est)
|
|
40
|
+
return null;
|
|
41
|
+
const thin = est.confidence === 'thin' ? chalk.yellow(' (thin data)') : '';
|
|
42
|
+
return (` eta: ${chalk.bold(`~${formatDurationMs(wall)}`)} for the remaining ${remaining} item(s) ` +
|
|
43
|
+
chalk.dim(`(EWMA ~${formatDurationMs(est.etaMs)}/task, n=${est.samples}/${est.observed})`) +
|
|
44
|
+
thin);
|
|
45
|
+
}
|
|
25
46
|
/** Fix C: hard cap on pre-ledger nudges so a planning stall can never wedge. */
|
|
26
47
|
const PRE_LEDGER_MAX = Math.max(0, Number(process.env.UAP_HANDSFREE_PRELEDGER_MAX ?? 1));
|
|
27
48
|
function statePath(cwd) {
|
|
@@ -184,6 +205,12 @@ export async function handsfreeCommand(sub, arg, options = {}) {
|
|
|
184
205
|
const p = progress(ledger);
|
|
185
206
|
console.log(` ledger: ${chalk.bold(`${p.done}/${p.total}`)} done (${p.pct}%), ` +
|
|
186
207
|
`${p.failed} failed, ${p.pending} pending`);
|
|
208
|
+
// Measured-pace ETA for the remaining work: the
|
|
209
|
+
// operator's own history, scaled by this key's attempts-per-success.
|
|
210
|
+
// Shown ONLY when the estimate exists — thin data would guess.
|
|
211
|
+
const etaLine = handsfreeEtaLine(model, p.pending + p.failed);
|
|
212
|
+
if (etaLine)
|
|
213
|
+
console.log(etaLine);
|
|
187
214
|
if (!isComplete(ledger))
|
|
188
215
|
console.log(chalk.dim(' ' + formatRemaining(ledger, 6).replace(/\n/g, '\n ')));
|
|
189
216
|
}
|