@compaction/cli 0.1.4 → 0.3.0
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 +51 -12
- package/dist/cli/commands/activity.d.ts +8 -0
- package/dist/cli/commands/activity.js +35 -0
- package/dist/cli/commands/apply-context.js +68 -0
- package/dist/cli/commands/billing-delta.js +12 -1
- package/dist/cli/commands/capture-claude-code.d.ts +44 -0
- package/dist/cli/commands/capture-claude-code.js +206 -0
- package/dist/cli/commands/capture.js +283 -1
- package/dist/cli/commands/compact.js +24 -11
- package/dist/cli/commands/context.d.ts +2 -0
- package/dist/cli/commands/context.js +130 -0
- package/dist/cli/commands/dev.d.ts +17 -0
- package/dist/cli/commands/dev.js +131 -0
- package/dist/cli/commands/gateway.d.ts +31 -0
- package/dist/cli/commands/gateway.js +312 -0
- package/dist/cli/commands/hooks.d.ts +5 -0
- package/dist/cli/commands/hooks.js +181 -0
- package/dist/cli/commands/import.js +3 -1
- package/dist/cli/commands/init.js +422 -17
- package/dist/cli/commands/input-compaction-ab.d.ts +2 -0
- package/dist/cli/commands/input-compaction-ab.js +125 -0
- package/dist/cli/commands/optimize-hosted.d.ts +54 -0
- package/dist/cli/commands/optimize-hosted.js +123 -0
- package/dist/cli/commands/optimize.js +8 -0
- package/dist/cli/commands/output-shaping-ab.d.ts +2 -0
- package/dist/cli/commands/output-shaping-ab.js +132 -0
- package/dist/cli/commands/output-shaping.d.ts +7 -0
- package/dist/cli/commands/output-shaping.js +43 -0
- package/dist/cli/commands/policies.d.ts +2 -0
- package/dist/cli/commands/policies.js +80 -0
- package/dist/cli/commands/precall.d.ts +19 -0
- package/dist/cli/commands/precall.js +436 -0
- package/dist/cli/commands/recommend.js +1 -1
- package/dist/cli/commands/run.js +310 -18
- package/dist/cli/commands/upgrade-status.d.ts +42 -0
- package/dist/cli/commands/upgrade-status.js +152 -0
- package/dist/cli/cursor-export-read.d.ts +13 -0
- package/dist/cli/cursor-export-read.js +53 -0
- package/dist/cli/cursor-live-preflight.d.ts +19 -0
- package/dist/cli/cursor-live-preflight.js +46 -0
- package/dist/cli/index.js +39 -2
- package/dist/cli/onboarding/GatewayTui.d.ts +33 -0
- package/dist/cli/onboarding/GatewayTui.js +113 -0
- package/dist/cli/onboarding/model.d.ts +32 -1
- package/dist/cli/onboarding/model.js +27 -2
- package/dist/cli/terminal-logo.d.ts +27 -0
- package/dist/cli/terminal-logo.js +49 -0
- package/dist/core/activity-event.d.ts +107 -0
- package/dist/core/activity-event.js +182 -0
- package/dist/core/activity-store.d.ts +63 -0
- package/dist/core/activity-store.js +254 -0
- package/dist/core/activity-view.d.ts +76 -0
- package/dist/core/activity-view.js +120 -0
- package/dist/core/api-client/index.d.ts +3 -1
- package/dist/core/api-client/index.js +4 -0
- package/dist/core/api-client/payload.d.ts +5 -1
- package/dist/core/api-client/payload.js +8 -6
- package/dist/core/api-client/persisted-config.d.ts +57 -0
- package/dist/core/api-client/persisted-config.js +156 -0
- package/dist/core/api-client/tool.d.ts +29 -0
- package/dist/core/api-client/tool.js +50 -0
- package/dist/core/api-client/types.d.ts +15 -4
- package/dist/core/auto-apply-ask.d.ts +58 -0
- package/dist/core/auto-apply-ask.js +105 -0
- package/dist/core/auto-apply-gates.d.ts +76 -0
- package/dist/core/auto-apply-gates.js +113 -0
- package/dist/core/before-call-activity.d.ts +35 -0
- package/dist/core/before-call-activity.js +103 -0
- package/dist/core/before-call-recovery.d.ts +19 -0
- package/dist/core/before-call-recovery.js +46 -0
- package/dist/core/before-call-stdin.d.ts +59 -0
- package/dist/core/before-call-stdin.js +78 -0
- package/dist/core/before-call.d.ts +149 -0
- package/dist/core/before-call.js +358 -0
- package/dist/core/billing-delta/billing-delta-record.d.ts +28 -0
- package/dist/core/billing-delta/billing-delta-record.js +26 -0
- package/dist/core/capture-record.d.ts +40 -0
- package/dist/core/capture-record.js +55 -0
- package/dist/core/claude-code-before-call.d.ts +37 -0
- package/dist/core/claude-code-before-call.js +120 -0
- package/dist/core/claude-code-connect.d.ts +31 -0
- package/dist/core/claude-code-connect.js +87 -0
- package/dist/core/claude-code-hook-record.d.ts +71 -0
- package/dist/core/claude-code-hook-record.js +0 -0
- package/dist/core/claude-code-hooks.d.ts +77 -0
- package/dist/core/claude-code-hooks.js +141 -0
- package/dist/core/codex-capture.d.ts +45 -0
- package/dist/core/codex-capture.js +204 -0
- package/dist/core/command-runner.js +5 -1
- package/dist/core/compaction-artifacts.d.ts +51 -0
- package/dist/core/compaction-artifacts.js +242 -0
- package/dist/core/compactor.d.ts +9 -0
- package/dist/core/compactor.js +95 -0
- package/dist/core/context-store-eval-cases.d.ts +6 -0
- package/dist/core/context-store-eval-cases.js +331 -0
- package/dist/core/context-store-eval.d.ts +140 -0
- package/dist/core/context-store-eval.js +138 -0
- package/dist/core/context-store-fs.d.ts +73 -0
- package/dist/core/context-store-fs.js +157 -0
- package/dist/core/context-store-sufficiency.d.ts +98 -0
- package/dist/core/context-store-sufficiency.js +135 -0
- package/dist/core/context-store.d.ts +155 -0
- package/dist/core/context-store.js +228 -0
- package/dist/core/cross-surface-event.d.ts +306 -0
- package/dist/core/cross-surface-event.js +330 -0
- package/dist/core/cursor-capture.d.ts +54 -0
- package/dist/core/cursor-capture.js +215 -0
- package/dist/core/cursor-preflight-probe.d.ts +8 -0
- package/dist/core/cursor-preflight-probe.js +88 -0
- package/dist/core/cursor-preflight.d.ts +86 -0
- package/dist/core/cursor-preflight.js +126 -0
- package/dist/core/gateway/apply-activation.d.ts +39 -0
- package/dist/core/gateway/apply-activation.js +84 -0
- package/dist/core/gateway/apply-policy.d.ts +64 -0
- package/dist/core/gateway/apply-policy.js +221 -0
- package/dist/core/gateway/apply-receipt.d.ts +36 -0
- package/dist/core/gateway/apply-receipt.js +75 -0
- package/dist/core/gateway/cache-proof.d.ts +45 -0
- package/dist/core/gateway/cache-proof.js +65 -0
- package/dist/core/gateway/configure.d.ts +50 -0
- package/dist/core/gateway/configure.js +169 -0
- package/dist/core/gateway/openai-usage.d.ts +56 -0
- package/dist/core/gateway/openai-usage.js +128 -0
- package/dist/core/gateway/receipt.d.ts +138 -0
- package/dist/core/gateway/receipt.js +120 -0
- package/dist/core/gateway/recovery.d.ts +23 -0
- package/dist/core/gateway/recovery.js +68 -0
- package/dist/core/gateway/server.d.ts +51 -0
- package/dist/core/gateway/server.js +276 -0
- package/dist/core/gateway/status.d.ts +45 -0
- package/dist/core/gateway/status.js +109 -0
- package/dist/core/hook-usage-aggregate.d.ts +47 -0
- package/dist/core/hook-usage-aggregate.js +161 -0
- package/dist/core/input-compaction-ab.d.ts +111 -0
- package/dist/core/input-compaction-ab.js +158 -0
- package/dist/core/local-run-record.d.ts +109 -0
- package/dist/core/local-run-record.js +223 -0
- package/dist/core/output-shaping-ab.d.ts +140 -0
- package/dist/core/output-shaping-ab.js +146 -0
- package/dist/core/output-shaping-attach.d.ts +31 -0
- package/dist/core/output-shaping-attach.js +57 -0
- package/dist/core/output-shaping.d.ts +56 -0
- package/dist/core/output-shaping.js +89 -0
- package/dist/core/policy-middleware.d.ts +121 -0
- package/dist/core/policy-middleware.js +919 -0
- package/dist/core/policy-preferences.d.ts +99 -0
- package/dist/core/policy-preferences.js +232 -0
- package/dist/core/report-generator.d.ts +19 -1
- package/dist/core/report-generator.js +51 -0
- package/dist/core/run-aggregator.d.ts +56 -1
- package/dist/core/run-aggregator.js +93 -2
- package/dist/core/run-flow-report.d.ts +82 -0
- package/dist/core/run-flow-report.js +71 -0
- package/dist/core/safety-report.js +8 -1
- package/dist/core/shim-capture-bridge.d.ts +32 -0
- package/dist/core/shim-capture-bridge.js +88 -0
- package/dist/core/skill-injection-policy.d.ts +72 -0
- package/dist/core/skill-injection-policy.js +183 -0
- package/dist/core/spend-attribution.js +1 -1
- package/dist/core/token-accounting.d.ts +1 -1
- package/dist/core/tool-shim.d.ts +129 -0
- package/dist/core/tool-shim.js +447 -0
- package/dist/core/trace-adapters.d.ts +8 -0
- package/dist/core/trace-adapters.js +4 -0
- package/dist/core/trace-parser.d.ts +13 -13
- package/dist/core/trace-parser.js +6 -6
- package/dist/core/types.d.ts +45 -2
- package/dist/core/waste-detector.d.ts +20 -0
- package/dist/core/waste-detector.js +160 -6
- package/package.json +1 -1
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI glue for the Cursor live-prep preflight. Surfaced before a LIVE `run cursor` / `capture cursor`
|
|
3
|
+
* (no `--export`) so the operator gets a content-free readiness check + exact guidance instead of an
|
|
4
|
+
* opaque "Authentication required" / missing-CLI failure.
|
|
5
|
+
*
|
|
6
|
+
* SAFETY (inherited from the core module): CLI-presence + capability probes ONLY (`--help`), never a
|
|
7
|
+
* real `-p` prompt, never `cursor agent login`, never a CURSOR_API_KEY read. Fail-friendly.
|
|
8
|
+
*
|
|
9
|
+
* The gate is advisory-by-readiness: if the CLI is missing or not capable, the live run cannot succeed,
|
|
10
|
+
* so we print guidance and DECLINE to spawn (returns false). If CLI+capability are present, auth is the
|
|
11
|
+
* only remaining unknown — we cannot detect it safely, so we print a short auth reminder and PROCEED
|
|
12
|
+
* (returns true); if the real run then fails auth, the wrapper's post-run guidance points back here.
|
|
13
|
+
*/
|
|
14
|
+
import chalk from "chalk";
|
|
15
|
+
import { runCursorPreflight } from "../core/cursor-preflight.js";
|
|
16
|
+
import { createSafeCursorProbe } from "../core/cursor-preflight-probe.js";
|
|
17
|
+
/**
|
|
18
|
+
* Run the preflight (safe probes) and return the report. Never throws.
|
|
19
|
+
*
|
|
20
|
+
* `COMPACTION_CURSOR_BIN` (optional): when set to a non-empty path, it is used as the SOLE candidate the
|
|
21
|
+
* safe probe checks — instead of the default PATH names + the hardcoded macOS app path. This is (a) a real
|
|
22
|
+
* operator override for a non-standard Cursor CLI location, and (b) what makes this path deterministic in
|
|
23
|
+
* tests: pointing it at a non-existent binary makes the probe fail fast (ENOENT) so the CLI never spawns
|
|
24
|
+
* the real, possibly-hanging Cursor binary. Still a `--help`/`-v` capability probe only — never `-p`,
|
|
25
|
+
* never `login`, never a key read.
|
|
26
|
+
*/
|
|
27
|
+
export async function cursorLivePreflight() {
|
|
28
|
+
const override = process.env.COMPACTION_CURSOR_BIN?.trim();
|
|
29
|
+
return runCursorPreflight(createSafeCursorProbe(), override ? [override] : undefined);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Print the preflight guidance and decide whether the live run may proceed.
|
|
33
|
+
* - CLI not resolvable OR capability absent → print guidance, return false (do NOT spawn a live run).
|
|
34
|
+
* - CLI present + capable → print the auth reminder, return true (proceed; auth verified only by a real
|
|
35
|
+
* run the operator has authorized).
|
|
36
|
+
*/
|
|
37
|
+
export async function gateCursorLiveRun() {
|
|
38
|
+
const report = await cursorLivePreflight();
|
|
39
|
+
for (const line of report.guidance)
|
|
40
|
+
console.log(report.ready ? line : chalk.yellow(line));
|
|
41
|
+
if (!report.ready) {
|
|
42
|
+
console.log(chalk.yellow(" Live Cursor run not started: fix the above, then retry. (Or use --export <saved output> to process a saved run offline.)"));
|
|
43
|
+
}
|
|
44
|
+
return report.ready;
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=cursor-live-preflight.js.map
|
package/dist/cli/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { Command } from "commander";
|
|
3
3
|
import { registerAnalyzeCommand } from "./commands/analyze.js";
|
|
4
|
+
import { registerActivityCommand } from "./commands/activity.js";
|
|
4
5
|
import { registerAdapterCommand } from "./commands/adapter.js";
|
|
5
6
|
import { registerAggregateCommand } from "./commands/aggregate.js";
|
|
6
7
|
import { registerAuditCommand } from "./commands/audit.js";
|
|
@@ -11,23 +12,43 @@ import { registerBillingDeltaCommand } from "./commands/billing-delta.js";
|
|
|
11
12
|
import { registerInitCommand } from "./commands/init.js";
|
|
12
13
|
import { registerCaptureCommand } from "./commands/capture.js";
|
|
13
14
|
import { registerCompactCommand } from "./commands/compact.js";
|
|
15
|
+
import { registerContextCommand } from "./commands/context.js";
|
|
14
16
|
import { registerEvalCommand } from "./commands/eval.js";
|
|
17
|
+
import { registerDevCommand } from "./commands/dev.js";
|
|
15
18
|
import { registerExportSessionSeedCommand } from "./commands/export-session-seed.js";
|
|
16
19
|
import { registerFeedbackCommand } from "./commands/feedback.js";
|
|
20
|
+
import { registerGatewayCommand } from "./commands/gateway.js";
|
|
21
|
+
import { registerHooksCommand } from "./commands/hooks.js";
|
|
17
22
|
import { registerImportCommand } from "./commands/import.js";
|
|
23
|
+
import { registerInputCompactionAbCommand } from "./commands/input-compaction-ab.js";
|
|
18
24
|
import { registerIntegrationsCommand } from "./commands/integrations.js";
|
|
19
25
|
import { registerLaunchTreatmentSessionCommand } from "./commands/launch-treatment-session.js";
|
|
20
26
|
import { registerOptimizeCommand } from "./commands/optimize.js";
|
|
21
27
|
import { registerRecommendCommand } from "./commands/recommend.js";
|
|
22
28
|
import { registerReviewCommand } from "./commands/review.js";
|
|
29
|
+
import { registerOutputShapingCommand } from "./commands/output-shaping.js";
|
|
30
|
+
import { registerOutputShapingAbCommand } from "./commands/output-shaping-ab.js";
|
|
31
|
+
import { registerPoliciesCommand } from "./commands/policies.js";
|
|
32
|
+
import { registerPrecallCommand } from "./commands/precall.js";
|
|
23
33
|
import { registerRunCommand } from "./commands/run.js";
|
|
24
34
|
import { registerSpendCommand } from "./commands/spend.js";
|
|
25
35
|
import { registerSummaryCommand } from "./commands/summary.js";
|
|
36
|
+
import { registerUpgradeCommand, registerStatusCommand } from "./commands/upgrade-status.js";
|
|
37
|
+
import { compactMarkFor } from "./terminal-logo.js";
|
|
26
38
|
const program = new Command();
|
|
27
39
|
program
|
|
28
40
|
.name("compaction")
|
|
29
41
|
.description("CLI-first trace compaction tools for AI agent workflows.")
|
|
30
|
-
.version("0.
|
|
42
|
+
.version("0.3.0");
|
|
43
|
+
// Brand mark above the TOP-LEVEL help only (compaction --help / bare `compaction`).
|
|
44
|
+
// Derived rendering of apps/web/src/assets/compaction-mark.svg — see
|
|
45
|
+
// docs/brand/terminal-logo.md. Colored only on a TTY with NO_COLOR unset; plain
|
|
46
|
+
// glyphs otherwise. Adds three lines before "Usage:"; no command output,
|
|
47
|
+
// subcommand help, exit code, or --version behavior changes.
|
|
48
|
+
program.addHelpText("before", ({ error }) => {
|
|
49
|
+
return `${compactMarkFor(error ? process.stderr : process.stdout)}\n`;
|
|
50
|
+
});
|
|
51
|
+
registerActivityCommand(program);
|
|
31
52
|
registerAnalyzeCommand(program);
|
|
32
53
|
registerAdapterCommand(program);
|
|
33
54
|
registerAggregateCommand(program);
|
|
@@ -39,18 +60,29 @@ registerBillingDeltaCommand(program);
|
|
|
39
60
|
registerInitCommand(program);
|
|
40
61
|
registerCaptureCommand(program);
|
|
41
62
|
registerCompactCommand(program);
|
|
63
|
+
registerContextCommand(program);
|
|
42
64
|
registerEvalCommand(program);
|
|
65
|
+
registerDevCommand(program);
|
|
43
66
|
registerExportSessionSeedCommand(program);
|
|
44
67
|
registerFeedbackCommand(program);
|
|
68
|
+
registerGatewayCommand(program);
|
|
69
|
+
registerHooksCommand(program);
|
|
45
70
|
registerImportCommand(program);
|
|
71
|
+
registerInputCompactionAbCommand(program);
|
|
46
72
|
registerIntegrationsCommand(program);
|
|
47
73
|
registerLaunchTreatmentSessionCommand(program);
|
|
48
74
|
registerOptimizeCommand(program);
|
|
75
|
+
registerOutputShapingCommand(program);
|
|
76
|
+
registerOutputShapingAbCommand(program);
|
|
77
|
+
registerPoliciesCommand(program);
|
|
78
|
+
registerPrecallCommand(program);
|
|
49
79
|
registerRecommendCommand(program);
|
|
50
80
|
registerReviewCommand(program);
|
|
51
81
|
registerRunCommand(program);
|
|
52
82
|
registerSpendCommand(program);
|
|
53
83
|
registerSummaryCommand(program);
|
|
84
|
+
registerUpgradeCommand(program);
|
|
85
|
+
registerStatusCommand(program);
|
|
54
86
|
// Clean default `--help` surface (v0.1.2): show ONLY the free, local-first commands
|
|
55
87
|
// that work without the private engine / Compaction API. Everything else (engine-gated,
|
|
56
88
|
// API-adjacent, and internal/operator commands) is HIDDEN from the top-level command
|
|
@@ -62,10 +94,15 @@ const PUBLIC_COMMANDS = new Set([
|
|
|
62
94
|
"capture",
|
|
63
95
|
"import",
|
|
64
96
|
"analyze",
|
|
97
|
+
"context",
|
|
65
98
|
"spend",
|
|
66
99
|
"summary",
|
|
67
100
|
"aggregate",
|
|
68
|
-
"feedback"
|
|
101
|
+
"feedback",
|
|
102
|
+
"activity",
|
|
103
|
+
"policies",
|
|
104
|
+
"upgrade",
|
|
105
|
+
"status"
|
|
69
106
|
]);
|
|
70
107
|
for (const cmd of program.commands) {
|
|
71
108
|
if (cmd.name() === "help" || PUBLIC_COMMANDS.has(cmd.name()))
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
/** The deterministic apply policy the TUI can arm (run-17.2). Deterministic only — no LCM, no semantics. */
|
|
3
|
+
export declare const GATEWAY_APPLY_POLICY = "deterministic-dedupe";
|
|
4
|
+
export interface GatewayTuiConfig {
|
|
5
|
+
provider: string;
|
|
6
|
+
upstream: string;
|
|
7
|
+
listen: string;
|
|
8
|
+
/** record is the byte-safe default; `apply` is the EXPERIMENTAL deterministic mode (explicit opt-in only). */
|
|
9
|
+
mode: "record" | "apply";
|
|
10
|
+
/** Present only when mode is `apply`. */
|
|
11
|
+
policy?: string;
|
|
12
|
+
}
|
|
13
|
+
export type GatewayTuiResult = {
|
|
14
|
+
action: "dev";
|
|
15
|
+
config: GatewayTuiConfig;
|
|
16
|
+
} | {
|
|
17
|
+
action: "configure";
|
|
18
|
+
config: GatewayTuiConfig;
|
|
19
|
+
} | {
|
|
20
|
+
action: "start";
|
|
21
|
+
config: GatewayTuiConfig;
|
|
22
|
+
} | {
|
|
23
|
+
action: "back";
|
|
24
|
+
} | {
|
|
25
|
+
action: "quit";
|
|
26
|
+
};
|
|
27
|
+
interface GatewayAppProps {
|
|
28
|
+
onDone: (result: GatewayTuiResult) => void;
|
|
29
|
+
}
|
|
30
|
+
export declare function GatewayApp({ onDone }: GatewayAppProps): React.ReactElement;
|
|
31
|
+
/** Render the gateway setup TUI and resolve with the user's choice (same alt-screen pattern as runInitTui). */
|
|
32
|
+
export declare function runGatewayTui(): Promise<GatewayTuiResult>;
|
|
33
|
+
export {};
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from "react";
|
|
3
|
+
import { Box, Text, useApp, useInput, render } from "ink";
|
|
4
|
+
import { BRAND_HEX, GATEWAY_PROVIDERS, GATEWAY_MODES, GATEWAY_DEFAULT_LISTEN } from "./model.js";
|
|
5
|
+
/**
|
|
6
|
+
* Guided Gateway setup TUI (charter run-17) — a SIBLING of the init chooser (`InitTui`), reusing the
|
|
7
|
+
* same Ink/React stack (no new dependency). Selecting the "Gateway setup" card in `compaction` (or
|
|
8
|
+
* `compaction init`) opens this. Preferred flow: Provider (OpenAI) → Mode (Record) → Start local gateway
|
|
9
|
+
* → the caller starts the gateway (foreground) and its receipts show live.
|
|
10
|
+
*
|
|
11
|
+
* Invariants (same spirit as InitTui): no text input, no network call here, no credential read. It is a
|
|
12
|
+
* configurator that resolves a validated config; the caller starts the real gateway. Raw flags (custom
|
|
13
|
+
* upstream / listen address / manual baseURL) live under "Advanced" — copy-and-run, never typed here.
|
|
14
|
+
*/
|
|
15
|
+
const BLUE = BRAND_HEX;
|
|
16
|
+
const DIM = "gray";
|
|
17
|
+
/** The deterministic apply policy the TUI can arm (run-17.2). Deterministic only — no LCM, no semantics. */
|
|
18
|
+
export const GATEWAY_APPLY_POLICY = "deterministic-dedupe";
|
|
19
|
+
// The routing step (charter run-17.1): after Provider + Mode, "How do you want to route traffic?".
|
|
20
|
+
// Option 1 (run a command through Compaction) is the preferred, no-copy path.
|
|
21
|
+
const MENU = [
|
|
22
|
+
{ key: "dev", label: "Run a command through the Gateway (preferred — no baseURL copy)" },
|
|
23
|
+
{ key: "configure", label: "Configure this project (approval-gated; shows a diff first)" },
|
|
24
|
+
{ key: "start", label: "Start the gateway now (I'll point my client at it)" },
|
|
25
|
+
{ key: "advanced", label: "Show manual / advanced setup" },
|
|
26
|
+
{ key: "back", label: "Back to workflows" }
|
|
27
|
+
];
|
|
28
|
+
export function GatewayApp({ onDone }) {
|
|
29
|
+
const [index, setIndex] = useState(0);
|
|
30
|
+
const [showAdvanced, setShowAdvanced] = useState(false);
|
|
31
|
+
// Experimental deterministic APPLY. Off by default. Arming ('x') shows the risk boundary; apply only
|
|
32
|
+
// engages after an EXPLICIT confirm ('y'). Without the confirm, the started gateway stays in record mode.
|
|
33
|
+
const [applyArmed, setApplyArmed] = useState(false);
|
|
34
|
+
const [applyConfirmed, setApplyConfirmed] = useState(false);
|
|
35
|
+
const { exit } = useApp();
|
|
36
|
+
const provider = GATEWAY_PROVIDERS[0]; // OpenAI (the only available provider today)
|
|
37
|
+
const applyOn = applyArmed && applyConfirmed;
|
|
38
|
+
const config = {
|
|
39
|
+
provider: provider.key,
|
|
40
|
+
upstream: provider.upstream,
|
|
41
|
+
listen: GATEWAY_DEFAULT_LISTEN,
|
|
42
|
+
mode: applyOn ? "apply" : "record",
|
|
43
|
+
...(applyOn ? { policy: GATEWAY_APPLY_POLICY } : {})
|
|
44
|
+
};
|
|
45
|
+
const choose = (key) => {
|
|
46
|
+
if (key === "dev")
|
|
47
|
+
onDone({ action: "dev", config });
|
|
48
|
+
else if (key === "configure")
|
|
49
|
+
onDone({ action: "configure", config });
|
|
50
|
+
else if (key === "start")
|
|
51
|
+
onDone({ action: "start", config });
|
|
52
|
+
else if (key === "back")
|
|
53
|
+
onDone({ action: "back" });
|
|
54
|
+
else {
|
|
55
|
+
setShowAdvanced((a) => !a);
|
|
56
|
+
return; // Advanced toggles in place; it does not exit
|
|
57
|
+
}
|
|
58
|
+
exit();
|
|
59
|
+
};
|
|
60
|
+
useInput((input, key) => {
|
|
61
|
+
if (key.upArrow || input === "k")
|
|
62
|
+
setIndex((i) => (i - 1 + MENU.length) % MENU.length);
|
|
63
|
+
else if (key.downArrow || input === "j")
|
|
64
|
+
setIndex((i) => (i + 1) % MENU.length);
|
|
65
|
+
else if (key.return)
|
|
66
|
+
choose(MENU[index].key);
|
|
67
|
+
else if (input === "a")
|
|
68
|
+
choose("advanced");
|
|
69
|
+
else if (input === "x") {
|
|
70
|
+
// Toggle the experimental apply arm; disarming always clears the confirmation (fail safe).
|
|
71
|
+
setApplyArmed((a) => {
|
|
72
|
+
if (a)
|
|
73
|
+
setApplyConfirmed(false);
|
|
74
|
+
return !a;
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
else if (input === "y") {
|
|
78
|
+
// Explicit confirmation ONLY matters while armed; it never silently enables apply otherwise.
|
|
79
|
+
setApplyConfirmed((c) => (applyArmed ? true : c));
|
|
80
|
+
}
|
|
81
|
+
else if (input === "q") {
|
|
82
|
+
onDone({ action: "quit" });
|
|
83
|
+
exit();
|
|
84
|
+
}
|
|
85
|
+
else if (key.escape) {
|
|
86
|
+
onDone({ action: "back" });
|
|
87
|
+
exit();
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
return (_jsxs(Box, { flexDirection: "column", paddingLeft: 1, paddingTop: 1, children: [_jsx(Text, { color: BLUE, bold: true, children: "\u258C GATEWAY SETUP" }), _jsx(Text, { color: DIM, children: "A local, byte-safe proxy for your model traffic. Content-free receipts; your key never leaves the client." }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsxs(Box, { children: [_jsx(Text, { color: DIM, children: " Provider " }), _jsx(Text, { color: "white", children: provider.label }), _jsx(Text, { color: BLUE, children: " ✓" })] }), _jsx(Box, { flexDirection: "column", children: GATEWAY_MODES.map((m, i) => (_jsxs(Box, { children: [_jsx(Text, { color: DIM, children: i === 0 ? " Mode " : " " }), m.available ? (_jsxs(Text, { color: "white", children: [m.label, _jsx(Text, { color: BLUE, children: " ✓" })] })) : (_jsx(Text, { color: DIM, children: m.label }))] }, m.key))) }), _jsxs(Box, { children: [_jsx(Text, { color: DIM, children: " Listen " }), _jsx(Text, { color: "white", children: GATEWAY_DEFAULT_LISTEN })] }), _jsxs(Box, { children: [_jsx(Text, { color: DIM, children: " Active " }), applyOn ? (_jsx(Text, { color: "yellow", children: "APPLY \u00B7 experimental \u00B7 deterministic-dedupe (original retained locally)" })) : (_jsx(Text, { color: "white", children: "RECORD \u00B7 byte-safe, no mutation" }))] })] }), _jsx(Box, { marginTop: 1, flexDirection: "column", children: !applyArmed ? (_jsx(Text, { color: DIM, children: " x arm experimental deterministic apply (off by default; explicit confirm required)" })) : (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: "yellow", bold: true, children: " ⚠ Experimental: deterministic APPLY" }), _jsx(Text, { color: DIM, children: " Changes model-visible input for KNOWN-SAFE shapes only (removes exact-duplicate large blocks)." }), _jsx(Text, { color: DIM, children: " Deterministic only \u2014 no summarization, no LCM. The ORIGINAL request is retained locally." }), _jsx(Text, { color: DIM, children: " Unknown/complex shapes FAIL CLOSED (forwarded unchanged). System/developer & tool schemas are never touched." }), applyConfirmed ? (_jsx(Text, { color: "yellow", children: " ✓ apply confirmed — 'Start the gateway now' will run APPLY mode. (x to disarm)" })) : (_jsx(Text, { color: "yellow", children: " press y to CONFIRM apply mode, or x to cancel (without confirmation the gateway starts in RECORD mode)" }))] })) }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "white", children: "How do you want to route traffic?" }) }), _jsx(Box, { flexDirection: "column", children: MENU.map((m, i) => (_jsxs(Box, { children: [_jsx(Text, { color: i === index ? BLUE : DIM, children: i === index ? " ▌ " : " ○ " }), _jsx(Text, { color: i === index ? "white" : DIM, children: m.label })] }, m.key))) }), showAdvanced ? (_jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { color: DIM, children: "Advanced \u2014 for a custom provider, upstream, or port, start the gateway directly:" }), _jsx(Text, { color: BLUE, children: ` compaction gateway start --provider openai --upstream ${provider.upstream} --listen ${GATEWAY_DEFAULT_LISTEN}` }), _jsx(Text, { color: DIM, children: "Then point your OpenAI client's baseURL at the listen address + /v1." }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { color: DIM, children: "Already running an app? Compaction cannot safely attach to an already-running process" }), _jsx(Text, { color: DIM, children: "unless it already points at the gateway. Restart it through Compaction to route future calls:" }), _jsx(Text, { color: BLUE, children: " compaction gateway run -- <your command>" })] })] })) : null, _jsx(Box, { marginTop: 1, children: _jsx(Text, { color: DIM, children: "↑/↓ move · Enter select · a advanced · x/y experimental apply · Esc back · q quit" }) })] }));
|
|
91
|
+
}
|
|
92
|
+
const ALT_SCREEN_ENTER = "[?1049h[H[2J";
|
|
93
|
+
const ALT_SCREEN_LEAVE = "[?1049l";
|
|
94
|
+
/** Render the gateway setup TUI and resolve with the user's choice (same alt-screen pattern as runInitTui). */
|
|
95
|
+
export async function runGatewayTui() {
|
|
96
|
+
const out = process.stdout;
|
|
97
|
+
const useAlt = Boolean(out.isTTY);
|
|
98
|
+
if (useAlt)
|
|
99
|
+
out.write(ALT_SCREEN_ENTER);
|
|
100
|
+
let result = { action: "quit" };
|
|
101
|
+
try {
|
|
102
|
+
const app = render(_jsx(GatewayApp, { onDone: (r) => {
|
|
103
|
+
result = r;
|
|
104
|
+
} }));
|
|
105
|
+
await app.waitUntilExit();
|
|
106
|
+
}
|
|
107
|
+
finally {
|
|
108
|
+
if (useAlt)
|
|
109
|
+
out.write(ALT_SCREEN_LEAVE);
|
|
110
|
+
}
|
|
111
|
+
return result;
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=GatewayTui.js.map
|
|
@@ -26,7 +26,38 @@ export interface WorkflowCard {
|
|
|
26
26
|
}
|
|
27
27
|
export declare const PRIMARY: WorkflowCard;
|
|
28
28
|
export declare const SECONDARY: WorkflowCard[];
|
|
29
|
-
/**
|
|
29
|
+
/**
|
|
30
|
+
* The Gateway setup card (charter run-17). SPECIAL: selecting it opens the guided gateway setup flow
|
|
31
|
+
* (`GatewayTui`) rather than printing a copy-paste command — the caller routes on `key === "gateway"`.
|
|
32
|
+
* It is a FREE, local-first workflow (a localhost byte-safe proxy; no Compaction server sees content;
|
|
33
|
+
* the provider key rides through to the provider and is never stored). Kept in the shared model so both
|
|
34
|
+
* onboarding surfaces list it.
|
|
35
|
+
*/
|
|
36
|
+
export declare const GATEWAY_CARD: WorkflowCard;
|
|
37
|
+
/** Gateway providers offered in the guided flow. OpenAI-compatible only today (record mode). */
|
|
38
|
+
export declare const GATEWAY_PROVIDERS: readonly [{
|
|
39
|
+
readonly key: "openai";
|
|
40
|
+
readonly label: "OpenAI (openai-compatible)";
|
|
41
|
+
readonly upstream: "https://api.openai.com/v1";
|
|
42
|
+
readonly available: true;
|
|
43
|
+
}];
|
|
44
|
+
/** Gateway modes. Run-15/16 ship RECORD only; cache/apply are later, separately-gated runs (shown disabled). */
|
|
45
|
+
export declare const GATEWAY_MODES: readonly [{
|
|
46
|
+
readonly key: "record";
|
|
47
|
+
readonly label: "Record — byte-safe; content-free receipts";
|
|
48
|
+
readonly available: true;
|
|
49
|
+
}, {
|
|
50
|
+
readonly key: "cache";
|
|
51
|
+
readonly label: "Cache — coming soon";
|
|
52
|
+
readonly available: false;
|
|
53
|
+
}, {
|
|
54
|
+
readonly key: "apply";
|
|
55
|
+
readonly label: "Apply — coming soon";
|
|
56
|
+
readonly available: false;
|
|
57
|
+
}];
|
|
58
|
+
/** The default local listen address surfaced by the guided flow (editable only via Advanced CLI flags). */
|
|
59
|
+
export declare const GATEWAY_DEFAULT_LISTEN = "http://127.0.0.1:8787";
|
|
60
|
+
/** All workflow cards, primary first — the order shown in the TUI chooser. Gateway is featured second. */
|
|
30
61
|
export declare const WORKFLOW_CARDS: WorkflowCard[];
|
|
31
62
|
/** Lookup a card by key (used by `--path` focus and TUI selection). */
|
|
32
63
|
export declare function findWorkflow(key: string): WorkflowCard | undefined;
|
|
@@ -47,8 +47,33 @@ export const SECONDARY = [
|
|
|
47
47
|
blurb: "Import any local trace / JSONL you already have."
|
|
48
48
|
}
|
|
49
49
|
];
|
|
50
|
-
/**
|
|
51
|
-
|
|
50
|
+
/**
|
|
51
|
+
* The Gateway setup card (charter run-17). SPECIAL: selecting it opens the guided gateway setup flow
|
|
52
|
+
* (`GatewayTui`) rather than printing a copy-paste command — the caller routes on `key === "gateway"`.
|
|
53
|
+
* It is a FREE, local-first workflow (a localhost byte-safe proxy; no Compaction server sees content;
|
|
54
|
+
* the provider key rides through to the provider and is never stored). Kept in the shared model so both
|
|
55
|
+
* onboarding surfaces list it.
|
|
56
|
+
*/
|
|
57
|
+
export const GATEWAY_CARD = {
|
|
58
|
+
key: "gateway",
|
|
59
|
+
title: "Gateway setup",
|
|
60
|
+
command: "compaction gateway start",
|
|
61
|
+
blurb: "Run the local Compaction Gateway — byte-safe proxy; content-free token/cache receipts."
|
|
62
|
+
};
|
|
63
|
+
/** Gateway providers offered in the guided flow. OpenAI-compatible only today (record mode). */
|
|
64
|
+
export const GATEWAY_PROVIDERS = [
|
|
65
|
+
{ key: "openai", label: "OpenAI (openai-compatible)", upstream: "https://api.openai.com/v1", available: true }
|
|
66
|
+
];
|
|
67
|
+
/** Gateway modes. Run-15/16 ship RECORD only; cache/apply are later, separately-gated runs (shown disabled). */
|
|
68
|
+
export const GATEWAY_MODES = [
|
|
69
|
+
{ key: "record", label: "Record — byte-safe; content-free receipts", available: true },
|
|
70
|
+
{ key: "cache", label: "Cache — coming soon", available: false },
|
|
71
|
+
{ key: "apply", label: "Apply — coming soon", available: false }
|
|
72
|
+
];
|
|
73
|
+
/** The default local listen address surfaced by the guided flow (editable only via Advanced CLI flags). */
|
|
74
|
+
export const GATEWAY_DEFAULT_LISTEN = "http://127.0.0.1:8787";
|
|
75
|
+
/** All workflow cards, primary first — the order shown in the TUI chooser. Gateway is featured second. */
|
|
76
|
+
export const WORKFLOW_CARDS = [PRIMARY, GATEWAY_CARD, ...SECONDARY];
|
|
52
77
|
/** Lookup a card by key (used by `--path` focus and TUI selection). */
|
|
53
78
|
export function findWorkflow(key) {
|
|
54
79
|
return WORKFLOW_CARDS.find((c) => c.key === key);
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compact terminal brand mark for CLI headers.
|
|
3
|
+
*
|
|
4
|
+
* MIRROR of the canonical strings in `scripts/render-terminal-logo.mjs` (the
|
|
5
|
+
* single design source for the terminal mark). This mirror exists because
|
|
6
|
+
* TypeScript cannot import from scripts/ (tsconfig rootDir is src/) and
|
|
7
|
+
* scripts/ is not packaged into dist/. `tests/cli/terminal-logo.test.ts`
|
|
8
|
+
* enforces byte-equality between this module and the script, so the two
|
|
9
|
+
* cannot drift — change the script first, then this mirror.
|
|
10
|
+
*
|
|
11
|
+
* Derivation (see docs/brand/terminal-logo.md): the mark is a derived
|
|
12
|
+
* rendering of `apps/web/src/assets/compaction-mark.svg` — three compression
|
|
13
|
+
* bars (16u / 10u / 16u, middle inset 3u) at 1 SVG unit = 1 column, one
|
|
14
|
+
* U+2580 UPPER HALF BLOCK row per bar. The canonical SVG is unchanged.
|
|
15
|
+
*/
|
|
16
|
+
/** Compact lockup, plain (no escape codes). Must byte-match the script's COMPACT_PLAIN. */
|
|
17
|
+
export declare const COMPACT_PLAIN: string;
|
|
18
|
+
/** Brand-blue ramp, identical to src/cli/onboarding/wordmark.ts BLUE_RAMP. */
|
|
19
|
+
export declare const BLUE_RAMP: readonly ["#6d6bff", "#4f46e5", "#3231cd"];
|
|
20
|
+
/** Compact lockup, colored. Must byte-match the script's COMPACT_COLOR. */
|
|
21
|
+
export declare const COMPACT_COLOR: string;
|
|
22
|
+
/**
|
|
23
|
+
* The compact mark for a help banner on the given stream: colored only when
|
|
24
|
+
* the stream is a TTY and NO_COLOR is unset (degrades to plain glyphs in
|
|
25
|
+
* pipes, files, CI, and color-hostile terminals).
|
|
26
|
+
*/
|
|
27
|
+
export declare function compactMarkFor(stream: NodeJS.WriteStream): string;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compact terminal brand mark for CLI headers.
|
|
3
|
+
*
|
|
4
|
+
* MIRROR of the canonical strings in `scripts/render-terminal-logo.mjs` (the
|
|
5
|
+
* single design source for the terminal mark). This mirror exists because
|
|
6
|
+
* TypeScript cannot import from scripts/ (tsconfig rootDir is src/) and
|
|
7
|
+
* scripts/ is not packaged into dist/. `tests/cli/terminal-logo.test.ts`
|
|
8
|
+
* enforces byte-equality between this module and the script, so the two
|
|
9
|
+
* cannot drift — change the script first, then this mirror.
|
|
10
|
+
*
|
|
11
|
+
* Derivation (see docs/brand/terminal-logo.md): the mark is a derived
|
|
12
|
+
* rendering of `apps/web/src/assets/compaction-mark.svg` — three compression
|
|
13
|
+
* bars (16u / 10u / 16u, middle inset 3u) at 1 SVG unit = 1 column, one
|
|
14
|
+
* U+2580 UPPER HALF BLOCK row per bar. The canonical SVG is unchanged.
|
|
15
|
+
*/
|
|
16
|
+
const BAR = "▀";
|
|
17
|
+
/** Compact lockup, plain (no escape codes). Must byte-match the script's COMPACT_PLAIN. */
|
|
18
|
+
export const COMPACT_PLAIN = [
|
|
19
|
+
`${BAR.repeat(16)}`,
|
|
20
|
+
` ${BAR.repeat(10)} compaction`,
|
|
21
|
+
`${BAR.repeat(16)}`
|
|
22
|
+
].join("\n");
|
|
23
|
+
/** Brand-blue ramp, identical to src/cli/onboarding/wordmark.ts BLUE_RAMP. */
|
|
24
|
+
export const BLUE_RAMP = ["#6d6bff", "#4f46e5", "#3231cd"];
|
|
25
|
+
const RESET = "\u001b[0m";
|
|
26
|
+
const BOLD = "\u001b[1m";
|
|
27
|
+
function fg(hex) {
|
|
28
|
+
const n = parseInt(hex.slice(1), 16);
|
|
29
|
+
return `\u001b[38;2;${(n >> 16) & 0xff};${(n >> 8) & 0xff};${n & 0xff}m`;
|
|
30
|
+
}
|
|
31
|
+
/** Compact lockup, colored. Must byte-match the script's COMPACT_COLOR. */
|
|
32
|
+
export const COMPACT_COLOR = COMPACT_PLAIN.split("\n")
|
|
33
|
+
.map((line, i) => {
|
|
34
|
+
let out = line.replace(new RegExp(`${BAR}+`), (run) => `${fg(BLUE_RAMP[i])}${run}${RESET}`);
|
|
35
|
+
if (out.includes("compaction"))
|
|
36
|
+
out = out.replace("compaction", `${BOLD}compaction${RESET}`);
|
|
37
|
+
return out;
|
|
38
|
+
})
|
|
39
|
+
.join("\n");
|
|
40
|
+
/**
|
|
41
|
+
* The compact mark for a help banner on the given stream: colored only when
|
|
42
|
+
* the stream is a TTY and NO_COLOR is unset (degrades to plain glyphs in
|
|
43
|
+
* pipes, files, CI, and color-hostile terminals).
|
|
44
|
+
*/
|
|
45
|
+
export function compactMarkFor(stream) {
|
|
46
|
+
const useColor = stream.isTTY === true && process.env.NO_COLOR === undefined;
|
|
47
|
+
return useColor ? COMPACT_COLOR : COMPACT_PLAIN;
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=terminal-logo.js.map
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { type CrossSurfaceEvent } from "./cross-surface-event.js";
|
|
2
|
+
/** Founder D-list: whether/how the user approved what Compaction did on this run (exact values). */
|
|
3
|
+
export declare const ACTIVITY_APPROVAL_STATUSES: readonly ["not-required", "asked-approved", "asked-declined", "auto-applied-by-policy", "not-asked"];
|
|
4
|
+
export type ActivityApprovalStatus = (typeof ACTIVITY_APPROVAL_STATUSES)[number];
|
|
5
|
+
/**
|
|
6
|
+
* The binary auto-apply preference (founder product model: after a first approval, ONE binary
|
|
7
|
+
* question — default no). `"ask-each-time"` IS the default; `"auto-when-gates-pass"` is only ever
|
|
8
|
+
* an explicit prior user opt-in. Preference STORAGE is a named residual (no storage exists here).
|
|
9
|
+
*/
|
|
10
|
+
export declare const AUTO_APPLY_PREFERENCES: readonly ["ask-each-time", "auto-when-gates-pass"];
|
|
11
|
+
export type AutoApplyPreference = (typeof AUTO_APPLY_PREFERENCES)[number];
|
|
12
|
+
/** Founder D-list sync status. `local-only` is the default: nothing syncs without explicit config. */
|
|
13
|
+
export declare const ACTIVITY_SYNC_STATUSES: readonly ["local-only", "metrics-synced", "hosted-private"];
|
|
14
|
+
export type ActivitySyncStatus = (typeof ACTIVITY_SYNC_STATUSES)[number];
|
|
15
|
+
export declare const DEFAULT_ACTIVITY_SYNC_STATUS: ActivitySyncStatus;
|
|
16
|
+
/**
|
|
17
|
+
* The NOT-applied arm — the only arm most events will ever carry. Any preference, any
|
|
18
|
+
* eligibility, but `applied_automatically` is the LITERAL `false`.
|
|
19
|
+
*/
|
|
20
|
+
export interface AutoApplyNotApplied {
|
|
21
|
+
/** Whether this run's change would even be a candidate for auto-apply (capability, not consent). */
|
|
22
|
+
eligible: boolean;
|
|
23
|
+
/** The user's stored binary preference. Default (and only honest value without stored opt-in): "ask-each-time". */
|
|
24
|
+
preference: AutoApplyPreference;
|
|
25
|
+
applied_automatically: false;
|
|
26
|
+
/** Content-free gate identifiers (e.g. "recoverability-pass"), when gates were evaluated. */
|
|
27
|
+
gates_passed?: string[];
|
|
28
|
+
gates_failed?: string[];
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* The applied arm. STRUCTURALLY opt-in only: `applied_automatically: true` requires the explicit
|
|
32
|
+
* `"auto-when-gates-pass"` preference, `eligible: true`, and a NON-EMPTY `gates_passed` tuple.
|
|
33
|
+
* NOTE: no code in this repo can construct this arm from real behavior — no auto-apply logic
|
|
34
|
+
* exists; the arm exists so the OFF-by-default rule is a type-system fact, not a convention.
|
|
35
|
+
*/
|
|
36
|
+
export interface AutoApplyApplied {
|
|
37
|
+
eligible: true;
|
|
38
|
+
preference: "auto-when-gates-pass";
|
|
39
|
+
applied_automatically: true;
|
|
40
|
+
/** Non-empty BY TYPE: an auto-apply with zero passed gates is unrepresentable. */
|
|
41
|
+
gates_passed: [string, ...string[]];
|
|
42
|
+
gates_failed?: string[];
|
|
43
|
+
}
|
|
44
|
+
export type ActivityAutoApply = AutoApplyNotApplied | AutoApplyApplied;
|
|
45
|
+
/** Founder D-list recovery: whether the original was retained, and where (path/pointer, NEVER content). */
|
|
46
|
+
export interface ActivityRecovery {
|
|
47
|
+
original_retained: boolean;
|
|
48
|
+
/** Content-free location of the retained original (a filesystem path or artifact pointer). */
|
|
49
|
+
location?: string;
|
|
50
|
+
}
|
|
51
|
+
/** The additive activity fields. ALL optional on the event type (the STORE requires id + sync). */
|
|
52
|
+
export interface ActivityExtension {
|
|
53
|
+
/** Deterministic content-free id — `act-` + 24 hex chars of sha-256 over the canonical event. */
|
|
54
|
+
activity_event_id?: string;
|
|
55
|
+
approval_status?: ActivityApprovalStatus;
|
|
56
|
+
auto_apply?: ActivityAutoApply;
|
|
57
|
+
recovery?: ActivityRecovery;
|
|
58
|
+
/** Default: "local-only" (applied by the store when absent). */
|
|
59
|
+
sync_status?: ActivitySyncStatus;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* ONE metrics-only activity event = the existing cross-surface event (same arms, same D5/D6
|
|
63
|
+
* guardrails — the intersection distributes over the union) + the activity fields.
|
|
64
|
+
*/
|
|
65
|
+
export type ActivityEvent = CrossSurfaceEvent & ActivityExtension;
|
|
66
|
+
type Assert<T extends true> = T;
|
|
67
|
+
type AutoApplyAppliedArm = Extract<ActivityAutoApply, {
|
|
68
|
+
applied_automatically: true;
|
|
69
|
+
}>;
|
|
70
|
+
/** The applied arm exists (so the guards below can never pass vacuously via `never`). */
|
|
71
|
+
export type StructuralGuard_AppliedArmExists = Assert<[AutoApplyAppliedArm] extends [never] ? false : true>;
|
|
72
|
+
/** Auto-apply is opt-in ONLY: the applied arm can only carry the explicit opt-in preference. */
|
|
73
|
+
export type StructuralGuard_AppliedRequiresOptInPreference = Assert<AutoApplyAppliedArm["preference"] extends "auto-when-gates-pass" ? true : false>;
|
|
74
|
+
/** The applied arm requires eligibility. */
|
|
75
|
+
export type StructuralGuard_AppliedRequiresEligible = Assert<AutoApplyAppliedArm["eligible"] extends true ? true : false>;
|
|
76
|
+
/** The applied arm requires a NON-EMPTY gates_passed (an empty tuple is unrepresentable). */
|
|
77
|
+
export type StructuralGuard_AppliedRequiresNonEmptyGates = Assert<AutoApplyAppliedArm["gates_passed"] extends [string, ...string[]] ? true : false>;
|
|
78
|
+
/** "Applied automatically under ask-each-time" is not a representable state at all. */
|
|
79
|
+
export type StructuralGuard_NoAutoApplyUnderAskEachTime = Assert<[
|
|
80
|
+
Extract<ActivityAutoApply, {
|
|
81
|
+
applied_automatically: true;
|
|
82
|
+
preference: "ask-each-time";
|
|
83
|
+
}>
|
|
84
|
+
] extends [never] ? true : false>;
|
|
85
|
+
export declare const ACTIVITY_EVENT_ID_PATTERN: RegExp;
|
|
86
|
+
/**
|
|
87
|
+
* Compute the deterministic content-free id: sha-256 over the canonicalized event EXCLUDING any
|
|
88
|
+
* existing `activity_event_id` (so recomputing on a stored event reproduces the same id). The id
|
|
89
|
+
* is derived only from the metrics-only fields the event already carries — no randomness, no
|
|
90
|
+
* clock, no content.
|
|
91
|
+
*/
|
|
92
|
+
export declare function computeActivityEventId(event: CrossSurfaceEvent & ActivityExtension): string;
|
|
93
|
+
export interface ActivityEventValidation {
|
|
94
|
+
problems: string[];
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Validate one parsed/unknown activity event. Runs the EXISTING cross-surface validator first
|
|
98
|
+
* (all D5/D6/tier/silent-zero rules stay binding), then the activity rules:
|
|
99
|
+
* 1. exact enums for approval_status / sync_status / auto_apply.preference;
|
|
100
|
+
* 2. auto-apply OFF-by-default: applied_automatically=true requires the explicit opt-in
|
|
101
|
+
* preference AND eligible=true AND non-empty gates_passed;
|
|
102
|
+
* 3. recovery.location is a single-line content-free pointer;
|
|
103
|
+
* 4. activity_event_id matches the deterministic `act-<24 hex>` shape.
|
|
104
|
+
*/
|
|
105
|
+
export declare function validateActivityEvent(value: unknown): ActivityEventValidation;
|
|
106
|
+
export declare function buildMeasureOnlyActivityEvent(event: CrossSurfaceEvent, recovery: ActivityRecovery): ActivityEvent;
|
|
107
|
+
export {};
|