@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.
Files changed (170) hide show
  1. package/README.md +51 -12
  2. package/dist/cli/commands/activity.d.ts +8 -0
  3. package/dist/cli/commands/activity.js +35 -0
  4. package/dist/cli/commands/apply-context.js +68 -0
  5. package/dist/cli/commands/billing-delta.js +12 -1
  6. package/dist/cli/commands/capture-claude-code.d.ts +44 -0
  7. package/dist/cli/commands/capture-claude-code.js +206 -0
  8. package/dist/cli/commands/capture.js +283 -1
  9. package/dist/cli/commands/compact.js +24 -11
  10. package/dist/cli/commands/context.d.ts +2 -0
  11. package/dist/cli/commands/context.js +130 -0
  12. package/dist/cli/commands/dev.d.ts +17 -0
  13. package/dist/cli/commands/dev.js +131 -0
  14. package/dist/cli/commands/gateway.d.ts +31 -0
  15. package/dist/cli/commands/gateway.js +312 -0
  16. package/dist/cli/commands/hooks.d.ts +5 -0
  17. package/dist/cli/commands/hooks.js +181 -0
  18. package/dist/cli/commands/import.js +3 -1
  19. package/dist/cli/commands/init.js +422 -17
  20. package/dist/cli/commands/input-compaction-ab.d.ts +2 -0
  21. package/dist/cli/commands/input-compaction-ab.js +125 -0
  22. package/dist/cli/commands/optimize-hosted.d.ts +54 -0
  23. package/dist/cli/commands/optimize-hosted.js +123 -0
  24. package/dist/cli/commands/optimize.js +8 -0
  25. package/dist/cli/commands/output-shaping-ab.d.ts +2 -0
  26. package/dist/cli/commands/output-shaping-ab.js +132 -0
  27. package/dist/cli/commands/output-shaping.d.ts +7 -0
  28. package/dist/cli/commands/output-shaping.js +43 -0
  29. package/dist/cli/commands/policies.d.ts +2 -0
  30. package/dist/cli/commands/policies.js +80 -0
  31. package/dist/cli/commands/precall.d.ts +19 -0
  32. package/dist/cli/commands/precall.js +436 -0
  33. package/dist/cli/commands/recommend.js +1 -1
  34. package/dist/cli/commands/run.js +310 -18
  35. package/dist/cli/commands/upgrade-status.d.ts +42 -0
  36. package/dist/cli/commands/upgrade-status.js +152 -0
  37. package/dist/cli/cursor-export-read.d.ts +13 -0
  38. package/dist/cli/cursor-export-read.js +53 -0
  39. package/dist/cli/cursor-live-preflight.d.ts +19 -0
  40. package/dist/cli/cursor-live-preflight.js +46 -0
  41. package/dist/cli/index.js +39 -2
  42. package/dist/cli/onboarding/GatewayTui.d.ts +33 -0
  43. package/dist/cli/onboarding/GatewayTui.js +113 -0
  44. package/dist/cli/onboarding/model.d.ts +32 -1
  45. package/dist/cli/onboarding/model.js +27 -2
  46. package/dist/cli/terminal-logo.d.ts +27 -0
  47. package/dist/cli/terminal-logo.js +49 -0
  48. package/dist/core/activity-event.d.ts +107 -0
  49. package/dist/core/activity-event.js +182 -0
  50. package/dist/core/activity-store.d.ts +63 -0
  51. package/dist/core/activity-store.js +254 -0
  52. package/dist/core/activity-view.d.ts +76 -0
  53. package/dist/core/activity-view.js +120 -0
  54. package/dist/core/api-client/index.d.ts +3 -1
  55. package/dist/core/api-client/index.js +4 -0
  56. package/dist/core/api-client/payload.d.ts +5 -1
  57. package/dist/core/api-client/payload.js +8 -6
  58. package/dist/core/api-client/persisted-config.d.ts +57 -0
  59. package/dist/core/api-client/persisted-config.js +156 -0
  60. package/dist/core/api-client/tool.d.ts +29 -0
  61. package/dist/core/api-client/tool.js +50 -0
  62. package/dist/core/api-client/types.d.ts +15 -4
  63. package/dist/core/auto-apply-ask.d.ts +58 -0
  64. package/dist/core/auto-apply-ask.js +105 -0
  65. package/dist/core/auto-apply-gates.d.ts +76 -0
  66. package/dist/core/auto-apply-gates.js +113 -0
  67. package/dist/core/before-call-activity.d.ts +35 -0
  68. package/dist/core/before-call-activity.js +103 -0
  69. package/dist/core/before-call-recovery.d.ts +19 -0
  70. package/dist/core/before-call-recovery.js +46 -0
  71. package/dist/core/before-call-stdin.d.ts +59 -0
  72. package/dist/core/before-call-stdin.js +78 -0
  73. package/dist/core/before-call.d.ts +149 -0
  74. package/dist/core/before-call.js +358 -0
  75. package/dist/core/billing-delta/billing-delta-record.d.ts +28 -0
  76. package/dist/core/billing-delta/billing-delta-record.js +26 -0
  77. package/dist/core/capture-record.d.ts +40 -0
  78. package/dist/core/capture-record.js +55 -0
  79. package/dist/core/claude-code-before-call.d.ts +37 -0
  80. package/dist/core/claude-code-before-call.js +120 -0
  81. package/dist/core/claude-code-connect.d.ts +31 -0
  82. package/dist/core/claude-code-connect.js +87 -0
  83. package/dist/core/claude-code-hook-record.d.ts +71 -0
  84. package/dist/core/claude-code-hook-record.js +0 -0
  85. package/dist/core/claude-code-hooks.d.ts +77 -0
  86. package/dist/core/claude-code-hooks.js +141 -0
  87. package/dist/core/codex-capture.d.ts +45 -0
  88. package/dist/core/codex-capture.js +204 -0
  89. package/dist/core/command-runner.js +5 -1
  90. package/dist/core/compaction-artifacts.d.ts +51 -0
  91. package/dist/core/compaction-artifacts.js +242 -0
  92. package/dist/core/compactor.d.ts +9 -0
  93. package/dist/core/compactor.js +95 -0
  94. package/dist/core/context-store-eval-cases.d.ts +6 -0
  95. package/dist/core/context-store-eval-cases.js +331 -0
  96. package/dist/core/context-store-eval.d.ts +140 -0
  97. package/dist/core/context-store-eval.js +138 -0
  98. package/dist/core/context-store-fs.d.ts +73 -0
  99. package/dist/core/context-store-fs.js +157 -0
  100. package/dist/core/context-store-sufficiency.d.ts +98 -0
  101. package/dist/core/context-store-sufficiency.js +135 -0
  102. package/dist/core/context-store.d.ts +155 -0
  103. package/dist/core/context-store.js +228 -0
  104. package/dist/core/cross-surface-event.d.ts +306 -0
  105. package/dist/core/cross-surface-event.js +330 -0
  106. package/dist/core/cursor-capture.d.ts +54 -0
  107. package/dist/core/cursor-capture.js +215 -0
  108. package/dist/core/cursor-preflight-probe.d.ts +8 -0
  109. package/dist/core/cursor-preflight-probe.js +88 -0
  110. package/dist/core/cursor-preflight.d.ts +86 -0
  111. package/dist/core/cursor-preflight.js +126 -0
  112. package/dist/core/gateway/apply-activation.d.ts +39 -0
  113. package/dist/core/gateway/apply-activation.js +84 -0
  114. package/dist/core/gateway/apply-policy.d.ts +64 -0
  115. package/dist/core/gateway/apply-policy.js +221 -0
  116. package/dist/core/gateway/apply-receipt.d.ts +36 -0
  117. package/dist/core/gateway/apply-receipt.js +75 -0
  118. package/dist/core/gateway/cache-proof.d.ts +45 -0
  119. package/dist/core/gateway/cache-proof.js +65 -0
  120. package/dist/core/gateway/configure.d.ts +50 -0
  121. package/dist/core/gateway/configure.js +169 -0
  122. package/dist/core/gateway/openai-usage.d.ts +56 -0
  123. package/dist/core/gateway/openai-usage.js +128 -0
  124. package/dist/core/gateway/receipt.d.ts +138 -0
  125. package/dist/core/gateway/receipt.js +120 -0
  126. package/dist/core/gateway/recovery.d.ts +23 -0
  127. package/dist/core/gateway/recovery.js +68 -0
  128. package/dist/core/gateway/server.d.ts +51 -0
  129. package/dist/core/gateway/server.js +276 -0
  130. package/dist/core/gateway/status.d.ts +45 -0
  131. package/dist/core/gateway/status.js +109 -0
  132. package/dist/core/hook-usage-aggregate.d.ts +47 -0
  133. package/dist/core/hook-usage-aggregate.js +161 -0
  134. package/dist/core/input-compaction-ab.d.ts +111 -0
  135. package/dist/core/input-compaction-ab.js +158 -0
  136. package/dist/core/local-run-record.d.ts +109 -0
  137. package/dist/core/local-run-record.js +223 -0
  138. package/dist/core/output-shaping-ab.d.ts +140 -0
  139. package/dist/core/output-shaping-ab.js +146 -0
  140. package/dist/core/output-shaping-attach.d.ts +31 -0
  141. package/dist/core/output-shaping-attach.js +57 -0
  142. package/dist/core/output-shaping.d.ts +56 -0
  143. package/dist/core/output-shaping.js +89 -0
  144. package/dist/core/policy-middleware.d.ts +121 -0
  145. package/dist/core/policy-middleware.js +919 -0
  146. package/dist/core/policy-preferences.d.ts +99 -0
  147. package/dist/core/policy-preferences.js +232 -0
  148. package/dist/core/report-generator.d.ts +19 -1
  149. package/dist/core/report-generator.js +51 -0
  150. package/dist/core/run-aggregator.d.ts +56 -1
  151. package/dist/core/run-aggregator.js +93 -2
  152. package/dist/core/run-flow-report.d.ts +82 -0
  153. package/dist/core/run-flow-report.js +71 -0
  154. package/dist/core/safety-report.js +8 -1
  155. package/dist/core/shim-capture-bridge.d.ts +32 -0
  156. package/dist/core/shim-capture-bridge.js +88 -0
  157. package/dist/core/skill-injection-policy.d.ts +72 -0
  158. package/dist/core/skill-injection-policy.js +183 -0
  159. package/dist/core/spend-attribution.js +1 -1
  160. package/dist/core/token-accounting.d.ts +1 -1
  161. package/dist/core/tool-shim.d.ts +129 -0
  162. package/dist/core/tool-shim.js +447 -0
  163. package/dist/core/trace-adapters.d.ts +8 -0
  164. package/dist/core/trace-adapters.js +4 -0
  165. package/dist/core/trace-parser.d.ts +13 -13
  166. package/dist/core/trace-parser.js +6 -6
  167. package/dist/core/types.d.ts +45 -2
  168. package/dist/core/waste-detector.d.ts +20 -0
  169. package/dist/core/waste-detector.js +160 -6
  170. 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.1.4");
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
- /** All workflow cards, primary first — the order shown in the TUI chooser. */
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
- /** All workflow cards, primary first — the order shown in the TUI chooser. */
51
- export const WORKFLOW_CARDS = [PRIMARY, ...SECONDARY];
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 {};