@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
|
@@ -1,8 +1,110 @@
|
|
|
1
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
1
3
|
import chalk from "chalk";
|
|
2
4
|
import { captureOpenAIAgentsCommand, captureOpenAIAgentsExport } from "../../core/openai-agents-capture.js";
|
|
3
|
-
import {
|
|
5
|
+
import { captureCodexCommand, captureCodexExport } from "../../core/codex-capture.js";
|
|
6
|
+
import { captureCursorCommand, captureCursorExport } from "../../core/cursor-capture.js";
|
|
7
|
+
import { gateCursorLiveRun } from "../cursor-live-preflight.js";
|
|
8
|
+
import { readCursorExportFile } from "../cursor-export-read.js";
|
|
9
|
+
import { buildRunFlowTokenReport, formatRunFlowTokenReport } from "../../core/run-flow-report.js";
|
|
10
|
+
import { recordCaptureContentFree, captureTokenSource } from "../../core/capture-record.js";
|
|
11
|
+
import { attachOutputShapingToCommand } from "../../core/output-shaping-attach.js";
|
|
12
|
+
import { OUTPUT_SHAPING_HONESTY_NOTE } from "../../core/output-shaping.js";
|
|
13
|
+
import { buildCaptureUsageSidecar } from "../../core/output-shaping-ab.js";
|
|
14
|
+
import { resolveApiConfig } from "../../core/api-client/index.js";
|
|
15
|
+
import { hostedConfigured } from "./optimize-hosted.js";
|
|
16
|
+
import { describeTokenMetadata } from "../../core/usage-metadata.js";
|
|
17
|
+
import { captureClaudeCodeCommand, captureClaudeCodeFromHook, captureClaudeCodeFromPromptHook, discoverClaudeCodeCommand } from "./capture-claude-code.js";
|
|
4
18
|
import { captureProviderUsageCommand } from "./capture-provider-usage.js";
|
|
19
|
+
import { bridgeCodexShimActivity, bridgeCursorShimActivity } from "../../core/shim-capture-bridge.js";
|
|
5
20
|
import { DEFAULT_CREDENTIAL_ENV_VAR } from "../../core/provider-usage/provider-usage-adapter.js";
|
|
21
|
+
/**
|
|
22
|
+
* Shared content-free `--from-shim` handler (the PATH-shim always-on bridge — charter 2026-07-04-run-9).
|
|
23
|
+
* Reads the shim's temp copy of the tool's OWN stdout, appends ONE metrics-only activity event, writes
|
|
24
|
+
* NO trace artifact and NO content. Best-effort + fail-open: a bad/missing file is a non-fatal skip so
|
|
25
|
+
* the transparent shim can never break the wrapped command. `commandParts` (Cursor only) carries the
|
|
26
|
+
* ORIGINAL invocation so input can be locally estimated (counted, never stored).
|
|
27
|
+
*/
|
|
28
|
+
async function handleCaptureFromShim(tool, fromShimPath, commandParts) {
|
|
29
|
+
let rawOutput;
|
|
30
|
+
try {
|
|
31
|
+
rawOutput = await readFile(fromShimPath, "utf8");
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
35
|
+
console.log(`compaction shim: skipped (non-fatal: could not read the captured output — ${message}).`);
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
try {
|
|
39
|
+
if (tool === "codex") {
|
|
40
|
+
const { result, tokenMetadataStatus } = await bridgeCodexShimActivity({ rawOutput, cwd: process.cwd() });
|
|
41
|
+
const label = tokenMetadataStatus === "present" ? "provider-reported" : "usage unavailable (not invented)";
|
|
42
|
+
console.log(result.appended
|
|
43
|
+
? `compaction shim: recorded metrics-only activity (surface=codex, ${label}, id ${result.activity_event_id.slice(0, 12)}…) — see 'compaction activity'.`
|
|
44
|
+
: `compaction shim: activity not appended (${result.reason}).`);
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
const { result, outputStatus } = await bridgeCursorShimActivity({
|
|
48
|
+
rawOutput,
|
|
49
|
+
commandParts: commandParts.length > 0 ? commandParts : undefined,
|
|
50
|
+
cwd: process.cwd()
|
|
51
|
+
});
|
|
52
|
+
const label = `local-estimate; output ${outputStatus === "present" ? "local-estimate" : "unavailable"}`;
|
|
53
|
+
console.log(result.appended
|
|
54
|
+
? `compaction shim: recorded metrics-only activity (surface=cursor, ${label}, id ${result.activity_event_id.slice(0, 12)}…) — see 'compaction activity'.`
|
|
55
|
+
: `compaction shim: activity not appended (${result.reason}).`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
60
|
+
console.log(`compaction shim: skipped (non-fatal: ${message}).`);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Apply the opt-in output-shaping flag to a wrapped command BEFORE generation (increment 3). Returns the
|
|
65
|
+
* (possibly modified) commandParts + console lines. Surfaces NO output-savings number — a savings figure
|
|
66
|
+
* requires the private measured-A/B + short-but-sufficient eval gate. Original command is never mutated.
|
|
67
|
+
*/
|
|
68
|
+
function applyOutputShapingFlag(commandParts, options) {
|
|
69
|
+
if (!options.outputShaping)
|
|
70
|
+
return { commandParts, lines: [], policyNames: [] };
|
|
71
|
+
const budget = options.verbosityBudget !== undefined ? Number.parseInt(options.verbosityBudget, 10) : undefined;
|
|
72
|
+
const policies = options.outputShapingPolicies
|
|
73
|
+
? options.outputShapingPolicies.split(",").map((s) => s.trim()).filter(Boolean)
|
|
74
|
+
: undefined;
|
|
75
|
+
const att = attachOutputShapingToCommand(commandParts, {
|
|
76
|
+
...(budget !== undefined && Number.isFinite(budget) ? { verbosityBudgetTokens: budget } : {}),
|
|
77
|
+
...(policies ? { policies } : {})
|
|
78
|
+
});
|
|
79
|
+
const lines = att.attached
|
|
80
|
+
? [
|
|
81
|
+
chalk.green(` Attached output-shaping policy to the prompt BEFORE generation: ${att.applied.map((a) => a.policy_name).join(", ")}`),
|
|
82
|
+
chalk.gray(` ${OUTPUT_SHAPING_HONESTY_NOTE}`)
|
|
83
|
+
]
|
|
84
|
+
: [chalk.yellow(` Output-shaping NOT attached: ${att.reason}.`)];
|
|
85
|
+
return { commandParts: att.commandParts, lines, policyNames: att.applied.map((a) => a.policy_name) };
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Write a content-free `capture-usage.json` sidecar next to the capture artifact (operator-side evidence).
|
|
89
|
+
* It carries provider-reported token counts + honest source + (treatment) output-shaping policy names so a
|
|
90
|
+
* later `compaction output-shaping-ab add` can link this run into an A/B arm. NO content is written.
|
|
91
|
+
*/
|
|
92
|
+
async function writeCaptureUsageSidecar(outDir, tool, usage, policyNames) {
|
|
93
|
+
const sidecar = buildCaptureUsageSidecar({
|
|
94
|
+
tool,
|
|
95
|
+
...(usage.provider ? { provider: usage.provider } : {}),
|
|
96
|
+
...(usage.model ? { model: usage.model } : {}),
|
|
97
|
+
...(typeof usage.input_tokens === "number" ? { inputTokens: usage.input_tokens } : {}),
|
|
98
|
+
...(typeof usage.output_tokens === "number" ? { outputTokens: usage.output_tokens } : {}),
|
|
99
|
+
providerReported: usage.provider_reported_tokens === true,
|
|
100
|
+
tokenSource: captureTokenSource(usage),
|
|
101
|
+
tokenMetadataStatus: usage.provider_reported_tokens === true ? "present" : "missing",
|
|
102
|
+
...(policyNames.length > 0 ? { policyNames } : {})
|
|
103
|
+
});
|
|
104
|
+
const sidecarPath = path.join(outDir, "capture-usage.json");
|
|
105
|
+
await writeFile(sidecarPath, JSON.stringify(sidecar, null, 2), "utf8");
|
|
106
|
+
return sidecarPath;
|
|
107
|
+
}
|
|
6
108
|
export function registerCaptureCommand(program) {
|
|
7
109
|
const capture = program.command("capture").description("Capture local integration traces into compaction.dev AgentTrace format.");
|
|
8
110
|
capture
|
|
@@ -26,6 +128,175 @@ export function registerCaptureCommand(program) {
|
|
|
26
128
|
process.exitCode = 1;
|
|
27
129
|
}
|
|
28
130
|
});
|
|
131
|
+
capture
|
|
132
|
+
.command("codex")
|
|
133
|
+
.description("Capture a LIVE `codex exec --json` run (or a saved export) into AgentTrace — no manual import. " +
|
|
134
|
+
"Provider-reported tokens from turn.completed.usage; local only, no upload, no proxying.")
|
|
135
|
+
.option("--out <dir>", "Output directory for capture artifacts")
|
|
136
|
+
.option("--export <file>", "Read a saved `codex exec --json` JSONL export instead of running a command")
|
|
137
|
+
.option("--from-shim <file>", "INTERNAL (used by the connect-once PATH shim): read a captured `codex exec --json` output copy and append ONE metrics-only, CONTENT-FREE activity event (no trace artifact, no content). Fail-open.")
|
|
138
|
+
.option("--output-shaping", "Attach the output-shaping policy to the prompt BEFORE generation (opt-in; no savings claimed)")
|
|
139
|
+
.option("--verbosity-budget <tokens>", "Soft output-token budget for the output-shaping policy")
|
|
140
|
+
.option("--output-shaping-policies <names>", "Comma-separated output-shaping policy names (default: the default-on set)")
|
|
141
|
+
.argument("[commandParts...]", 'Command and args to execute after -- (e.g. -- codex exec --json "do X")')
|
|
142
|
+
.allowUnknownOption(true)
|
|
143
|
+
.action(async (commandPartsRaw, options) => {
|
|
144
|
+
// Always-on shim bridge: content-free, writes only a metrics-only activity event. Handled first,
|
|
145
|
+
// before any artifact-writing path, and before the "provide a command" guard.
|
|
146
|
+
if (options.fromShim) {
|
|
147
|
+
await handleCaptureFromShim("codex", options.fromShim, commandPartsRaw);
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
console.log(chalk.cyan("compaction capture codex"));
|
|
151
|
+
console.log("Capturing a local codex exec --json run. No upload, no proxying. Review the artifact before sharing (it may contain code/output).");
|
|
152
|
+
if (!options.out) {
|
|
153
|
+
console.error("error: --out <dir> is required (except with --from-shim).");
|
|
154
|
+
process.exitCode = 1;
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
if (!options.export && commandPartsRaw.length === 0) {
|
|
158
|
+
console.error('error: provide a command after -- (e.g. -- codex exec --json "do X") or use --export <file>.');
|
|
159
|
+
process.exitCode = 1;
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
const outDir = options.out;
|
|
163
|
+
// Opt-in: attach the output-shaping policy to the prompt BEFORE generation (no savings claimed).
|
|
164
|
+
const shaped = applyOutputShapingFlag(commandPartsRaw, options);
|
|
165
|
+
for (const line of shaped.lines)
|
|
166
|
+
console.log(line);
|
|
167
|
+
const result = options.export
|
|
168
|
+
? captureCodexExport(await readFile(options.export, "utf8"))
|
|
169
|
+
: await captureCodexCommand(shaped.commandParts);
|
|
170
|
+
await mkdir(outDir, { recursive: true });
|
|
171
|
+
const tracePath = path.join(outDir, "captured-trace.json");
|
|
172
|
+
await writeFile(tracePath, JSON.stringify(result.trace, null, 2), "utf8");
|
|
173
|
+
// Honest token labels: provider-reported (from turn.completed.usage) or honest missing — never invented.
|
|
174
|
+
for (const line of describeTokenMetadata(result.usageMetadata))
|
|
175
|
+
console.log(` ${line}`);
|
|
176
|
+
for (const warning of result.warnings)
|
|
177
|
+
console.log(chalk.yellow(` ! ${warning}`));
|
|
178
|
+
console.log(chalk.green(`Wrote ${tracePath}`));
|
|
179
|
+
// Content-free A/B evidence sidecar (provider-reported counts + policy names) for output-shaping-ab.
|
|
180
|
+
const usagePath = await writeCaptureUsageSidecar(outDir, "codex", result.usageMetadata, shaped.policyNames);
|
|
181
|
+
console.log(chalk.green(`Wrote ${usagePath}`));
|
|
182
|
+
// Unified flow: content-free record (input/output separate + honest source) when hosted-configured.
|
|
183
|
+
// No default network call — only when the user has set COMPACTION_API_URL + COMPACTION_API_KEY.
|
|
184
|
+
if (hostedConfigured()) {
|
|
185
|
+
const rec = await recordCaptureContentFree(resolveApiConfig(), { usage: result.usageMetadata, tool: "codex", reference: tracePath });
|
|
186
|
+
console.log(rec.recorded ? chalk.green(` Recorded content-free usage (tool=codex, source=${rec.source}).`) : chalk.yellow(` Not recorded: ${rec.reason}.`));
|
|
187
|
+
}
|
|
188
|
+
else {
|
|
189
|
+
console.log(" Not recorded (set COMPACTION_API_URL + COMPACTION_API_KEY to record content-free usage).");
|
|
190
|
+
}
|
|
191
|
+
console.log(` Next: compaction compact ${tracePath} --eval --out <dir>`);
|
|
192
|
+
const exitCode = result.commandRun?.exitCode;
|
|
193
|
+
if (typeof exitCode === "number" && exitCode !== 0)
|
|
194
|
+
process.exitCode = exitCode;
|
|
195
|
+
});
|
|
196
|
+
capture
|
|
197
|
+
.command("cursor")
|
|
198
|
+
.description("Capture a LIVE Cursor headless CLI run (or saved output) into AgentTrace — no manual import. " +
|
|
199
|
+
"LOCAL-ESTIMATE tokens only (Cursor emits no usage); output counted from the result field where " +
|
|
200
|
+
"separable (use --output-format json), else marked unavailable. Local only, no upload, no SQLite.")
|
|
201
|
+
.option("--out <dir>", "Output directory for capture artifacts")
|
|
202
|
+
.option("--export <file>", "Read saved Cursor headless output (json / stream-json) instead of running a command")
|
|
203
|
+
.option("--from-shim <file>", "INTERNAL (used by the connect-once PATH shim): read a captured Cursor headless output copy and append ONE metrics-only, CONTENT-FREE activity event (local-estimate only, no trace artifact, no content). Fail-open.")
|
|
204
|
+
.option("--output-shaping", "Attach the output-shaping policy to the prompt BEFORE generation (opt-in; Cursor output is local-estimate, no savings)")
|
|
205
|
+
.option("--verbosity-budget <tokens>", "Soft output-token budget for the output-shaping policy")
|
|
206
|
+
.option("--output-shaping-policies <names>", "Comma-separated output-shaping policy names (default: the default-on set)")
|
|
207
|
+
.argument("[commandParts...]", 'Command and args after -- (e.g. -- cursor agent -p "do X" --output-format json)')
|
|
208
|
+
.allowUnknownOption(true)
|
|
209
|
+
.action(async (commandPartsRaw, options) => {
|
|
210
|
+
// Always-on shim bridge: content-free, writes only a metrics-only activity event (local-estimate).
|
|
211
|
+
// Handled first; the ORIGINAL invocation after -- lets input be locally estimated (counted, not stored).
|
|
212
|
+
if (options.fromShim) {
|
|
213
|
+
await handleCaptureFromShim("cursor", options.fromShim, commandPartsRaw);
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
console.log(chalk.cyan("compaction capture cursor"));
|
|
217
|
+
console.log("Capturing a local Cursor headless run. LOCAL-ESTIMATE tokens only (Cursor emits no provider usage). No upload, no SQLite. Review the artifact before sharing.");
|
|
218
|
+
if (!options.out) {
|
|
219
|
+
console.error("error: --out <dir> is required (except with --from-shim).");
|
|
220
|
+
process.exitCode = 1;
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
if (!options.export && commandPartsRaw.length === 0) {
|
|
224
|
+
console.error('error: provide a command after -- (e.g. -- cursor agent -p "do X" --output-format json) or use --export <file>.');
|
|
225
|
+
process.exitCode = 1;
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
// LIVE path (no --export): run the SAFE preflight FIRST (CLI-presence + capability only; never a
|
|
229
|
+
// real prompt, never `cursor agent login`, never a CURSOR_API_KEY read). If the CLI is missing or
|
|
230
|
+
// not capable, print exact guidance and STOP before spawning — no opaque failure, no crash.
|
|
231
|
+
if (!options.export) {
|
|
232
|
+
const ready = await gateCursorLiveRun();
|
|
233
|
+
if (!ready) {
|
|
234
|
+
process.exitCode = 1;
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
// Opt-in: attach the output-shaping policy to the prompt BEFORE generation. Cursor output stays
|
|
239
|
+
// local-estimate (no provider usage) → shaping never yields a savings number for Cursor.
|
|
240
|
+
const shaped = applyOutputShapingFlag(commandPartsRaw, options);
|
|
241
|
+
for (const line of shaped.lines)
|
|
242
|
+
console.log(line);
|
|
243
|
+
// Export path: read the saved output HONESTLY (a missing/unreadable file is an actionable error,
|
|
244
|
+
// never a raw errno, never a fabricated capture). Pass the RAW declared command (if the operator
|
|
245
|
+
// provided one after --) so the LOCAL-ESTIMATE input count matches `run cursor --export` exactly;
|
|
246
|
+
// shaped parts are NOT used here — nothing was executed, so no shaping was actually attached.
|
|
247
|
+
let result;
|
|
248
|
+
if (options.export) {
|
|
249
|
+
const exportRead = await readCursorExportFile(options.export);
|
|
250
|
+
if (!exportRead.ok) {
|
|
251
|
+
for (const line of exportRead.errorLines)
|
|
252
|
+
console.error(line);
|
|
253
|
+
process.exitCode = 1;
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
result = captureCursorExport(exportRead.rawOutput, commandPartsRaw.length > 0 ? commandPartsRaw : undefined);
|
|
257
|
+
}
|
|
258
|
+
else {
|
|
259
|
+
result = await captureCursorCommand(shaped.commandParts);
|
|
260
|
+
}
|
|
261
|
+
const outDir = options.out;
|
|
262
|
+
await mkdir(outDir, { recursive: true });
|
|
263
|
+
const tracePath = path.join(outDir, "captured-trace.json");
|
|
264
|
+
await writeFile(tracePath, JSON.stringify(result.trace, null, 2), "utf8");
|
|
265
|
+
// Print the SAME honest per-field token block `run cursor` prints (input/output SEPARATE, source
|
|
266
|
+
// explicit, an unavailable axis carries its TRUE per-run reason) — never a bare
|
|
267
|
+
// "input tokens: unknown" with no reason, never a fabricated count, never provider-reported.
|
|
268
|
+
const cursorTokenReport = buildRunFlowTokenReport({
|
|
269
|
+
tool: "cursor",
|
|
270
|
+
usage: result.usageMetadata,
|
|
271
|
+
outputStatus: result.outputStatus
|
|
272
|
+
});
|
|
273
|
+
const cursorReasons = { input: result.inputUnavailableReason, output: result.outputUnavailableReason };
|
|
274
|
+
// `capture` does not compact — no input-reduction figures follow, so that line is omitted.
|
|
275
|
+
const cursorTokenLines = formatRunFlowTokenReport(cursorTokenReport, {
|
|
276
|
+
reasons: cursorReasons,
|
|
277
|
+
inputReductionFollows: false
|
|
278
|
+
});
|
|
279
|
+
for (const line of cursorTokenLines)
|
|
280
|
+
console.log(` ${line}`);
|
|
281
|
+
for (const warning of result.warnings)
|
|
282
|
+
console.log(chalk.yellow(` ! ${warning}`));
|
|
283
|
+
console.log(chalk.green(`Wrote ${tracePath}`));
|
|
284
|
+
// Content-free sidecar. Cursor is local-estimate (providerReported=false) → A/B treats it as
|
|
285
|
+
// unavailable for a provider-reported savings number; it can never produce a confirmed claim.
|
|
286
|
+
const usagePath = await writeCaptureUsageSidecar(outDir, "cursor", result.usageMetadata, shaped.policyNames);
|
|
287
|
+
console.log(chalk.green(`Wrote ${usagePath}`));
|
|
288
|
+
if (hostedConfigured()) {
|
|
289
|
+
const rec = await recordCaptureContentFree(resolveApiConfig(), { usage: result.usageMetadata, tool: "cursor", reference: tracePath });
|
|
290
|
+
console.log(rec.recorded ? chalk.green(` Recorded content-free usage (tool=cursor, source=${rec.source}).`) : chalk.yellow(` Not recorded: ${rec.reason}.`));
|
|
291
|
+
}
|
|
292
|
+
else {
|
|
293
|
+
console.log(" Not recorded (set COMPACTION_API_URL + COMPACTION_API_KEY to record content-free usage).");
|
|
294
|
+
}
|
|
295
|
+
console.log(` Next: compaction compact ${tracePath} --eval --out <dir>`);
|
|
296
|
+
const exitCode = result.commandRun?.exitCode;
|
|
297
|
+
if (typeof exitCode === "number" && exitCode !== 0)
|
|
298
|
+
process.exitCode = exitCode;
|
|
299
|
+
});
|
|
29
300
|
capture
|
|
30
301
|
.command("claude-code")
|
|
31
302
|
.description("Capture a Claude Code session JSONL file into compaction.dev AgentTrace format (source: real_captured). Local only — no network calls, no upload.")
|
|
@@ -35,7 +306,18 @@ export function registerCaptureCommand(program) {
|
|
|
35
306
|
.option("--out <dir>", "Output directory for captured artifacts (default: .compaction/runs/<session-id-prefix>/)")
|
|
36
307
|
.option("--max-tool-result-chars <N>", "Maximum characters to extract from each tool result before truncation (default: 32000)")
|
|
37
308
|
.option("--include-subagents", "Include subagent JSONL files from <session-id>/subagents/ directory, merging their messages and usage into the captured trace")
|
|
309
|
+
.option("--from-hook", "Read a Claude Code Stop payload from stdin and record CONTENT-FREE usage via its transcript_path (used by `compaction hooks install`). Fail-open, idempotent.")
|
|
310
|
+
.option("--from-prompt-hook", "BEFORE-CALL (run-13): read a Claude Code UserPromptSubmit payload from stdin and record a CONTENT-FREE before-call RECOMMENDATION (used by the UserPromptSubmit hook). Recommendation-only (apply is a proven blocker on this surface); the prompt runs unchanged. Fail-open, silent (no stdout).")
|
|
311
|
+
.option("--dry-run", "With --from-hook: print what would be recorded without writing anything.")
|
|
38
312
|
.action(async (options) => {
|
|
313
|
+
if (options.fromPromptHook) {
|
|
314
|
+
await captureClaudeCodeFromPromptHook();
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
if (options.fromHook) {
|
|
318
|
+
await captureClaudeCodeFromHook({ dryRun: options.dryRun });
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
39
321
|
if (options.discover) {
|
|
40
322
|
await discoverClaudeCodeCommand({ projectsDir: options.projectsDir });
|
|
41
323
|
return;
|
|
@@ -2,7 +2,7 @@ import path from "node:path";
|
|
|
2
2
|
import chalk from "chalk";
|
|
3
3
|
import { Option } from "commander";
|
|
4
4
|
import { writeJsonArtifact, writeTextArtifact } from "../../core/artifact-writer.js";
|
|
5
|
-
import { withTraceFingerprint } from "../../core/report-generator.js";
|
|
5
|
+
import { formatCompactionMarkdownReport, withSavingsEvidence, withTraceFingerprint } from "../../core/report-generator.js";
|
|
6
6
|
import { describeTokenAccounting } from "../../core/token-accounting.js";
|
|
7
7
|
import { parseTraceFile } from "../../core/trace-parser.js";
|
|
8
8
|
import { buildRunLabelsFile, hasAnyLabel } from "../../core/run-labels.js";
|
|
@@ -109,11 +109,12 @@ export function registerCompactCommand(program) {
|
|
|
109
109
|
.description("Compact a trace and write local artifacts.")
|
|
110
110
|
.action(async (traceFile, options) => {
|
|
111
111
|
await runEngineCommand(async () => {
|
|
112
|
-
//
|
|
113
|
-
//
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
const {
|
|
112
|
+
// Basic deterministic compaction is PUBLIC (src/core): the transform + policy application +
|
|
113
|
+
// artifact writing ship in the npm package, so `compact` works with no private engine build.
|
|
114
|
+
// Only `--eval` (deterministic recoverability/strong eval) lazy-loads the private engine below;
|
|
115
|
+
// when the engine is absent, runEngineCommand prints the boundary message and exits cleanly.
|
|
116
|
+
const { writeCompactionArtifacts } = await import("../../core/compaction-artifacts.js");
|
|
117
|
+
const { applyCompactionPolicy } = await import("../../core/policy-middleware.js");
|
|
117
118
|
const trace = await parseTraceFile(traceFile);
|
|
118
119
|
const reviewerType = options.reviewer;
|
|
119
120
|
const reviewSummaryPresent = typeof options.reviewSummary === "string" && options.reviewSummary.length > 0;
|
|
@@ -124,11 +125,20 @@ export function registerCompactCommand(program) {
|
|
|
124
125
|
// hand-assembled bundle — the eval consumes the identical PolicyMiddlewareResult.
|
|
125
126
|
const policyResult = applyCompactionPolicy({ trace, compactSkillInjections: approveSkillInjectionPolicy });
|
|
126
127
|
const artifacts = await writeCompactionArtifacts(trace, options.out, runId, policyResult, undefined, { reviewerType, reviewSummaryPresent, approveSkillInjectionPolicy });
|
|
127
|
-
// Attribution/integrity (V0.2 savings-evidence): re-persist
|
|
128
|
-
// content-addressed trace fingerprint so `aggregate`/`summary` can
|
|
129
|
-
// verifiable run and de-duplicate
|
|
130
|
-
//
|
|
131
|
-
|
|
128
|
+
// Attribution/integrity + per-run evidence label (V0.2 savings-evidence): re-persist
|
|
129
|
+
// report.json with (1) the content-addressed trace fingerprint so `aggregate`/`summary` can
|
|
130
|
+
// attribute each saving to a verifiable run and de-duplicate a run rolled up twice, and
|
|
131
|
+
// (2) the composed `savings_evidence` record stating the per-run label explicitly. The
|
|
132
|
+
// compact path's figures are local estimates (chars/4) — `local_estimate` rung 1; never
|
|
133
|
+
// billing-confirmed, never semantic. Additive, backward-compatible; changes no existing field.
|
|
134
|
+
const evidenceReport = withSavingsEvidence(withTraceFingerprint(artifacts.report, trace), {
|
|
135
|
+
costSource: "local_estimate"
|
|
136
|
+
});
|
|
137
|
+
await writeJsonArtifact(options.out, "report.json", evidenceReport);
|
|
138
|
+
// Re-render report.md from the ENRICHED report so the per-run savings_evidence record
|
|
139
|
+
// appears in the human-readable artifact too (the engine rendered report.md from the base
|
|
140
|
+
// report before the CLI added the public-layer fingerprint/evidence enrichment).
|
|
141
|
+
await writeTextArtifact(options.out, "report.md", formatCompactionMarkdownReport(evidenceReport, artifacts.policy));
|
|
132
142
|
console.log(chalk.cyan("compaction compact"));
|
|
133
143
|
console.log(artifacts.consoleReport);
|
|
134
144
|
// Operator-visible only when the approval gesture was given; default output is unchanged.
|
|
@@ -180,6 +190,9 @@ export function registerCompactCommand(program) {
|
|
|
180
190
|
// (no disk round-trip, no hand-assembled bundle) and print the combined summary. Fail closed:
|
|
181
191
|
// a failing recoverability verdict exits non-zero, identical to standalone `compaction eval`.
|
|
182
192
|
if (options.eval === true) {
|
|
193
|
+
// The recoverability/strong eval stays PRIVATE (src/engine): lazy-loaded only when --eval is
|
|
194
|
+
// requested, so basic compaction above never needs the engine. Absent engine ⇒ clean degrade.
|
|
195
|
+
const { evaluateCompactionResult, evaluateStrongCompactionResult, formatStrongEvalMarkdownReport } = await import("../../engine/eval-harness.js");
|
|
183
196
|
const evalResult = evaluateCompactionResult(trace, policyResult, runId);
|
|
184
197
|
printCombinedEvalSummary(evalResult);
|
|
185
198
|
// Strong eval (Tracks B/C/D): commitment-preservation recoverability + fixture task-check +
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
import chalk from "chalk";
|
|
4
|
+
import { assembleContext, contextItemsFromTrace, retrieveContextItems } from "../../core/context-store.js";
|
|
5
|
+
import { appendContextItems, loadContextStore } from "../../core/context-store-fs.js";
|
|
6
|
+
/**
|
|
7
|
+
* V0.4 `compaction context` — a LOCAL memory + retrieval surface over the user's own captured
|
|
8
|
+
* traces (design: docs/design/v0.4-context-command.md, accepted 2026-06-24).
|
|
9
|
+
*
|
|
10
|
+
* HARD RAILS (load-bearing): local-only — no network, no model, no embeddings, no engine. It
|
|
11
|
+
* makes NO savings/cost claim (cost lives in `spend`/`summary`) and NO quality/recall/correctness
|
|
12
|
+
* verdict on user data (the four-axis sufficiency harness stays internal — there is no ground
|
|
13
|
+
* truth for an arbitrary user query). `get` prints local retrieval DIAGNOSTICS only.
|
|
14
|
+
*/
|
|
15
|
+
const DEFAULT_STORE_DIR = ".compaction/context-store";
|
|
16
|
+
function readTrace(path) {
|
|
17
|
+
if (!existsSync(path)) {
|
|
18
|
+
throw new Error(`File not found: ${path}`);
|
|
19
|
+
}
|
|
20
|
+
let parsed;
|
|
21
|
+
try {
|
|
22
|
+
parsed = JSON.parse(readFileSync(path, "utf8"));
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
throw new Error(`Not valid JSON: ${path}`);
|
|
26
|
+
}
|
|
27
|
+
const trace = parsed;
|
|
28
|
+
if (!trace || typeof trace.id !== "string" || !Array.isArray(trace.messages)) {
|
|
29
|
+
throw new Error("Not a normalized AgentTrace (expected { id, messages: [...] }). " +
|
|
30
|
+
"Produce one with `compaction capture` or `compaction import`.");
|
|
31
|
+
}
|
|
32
|
+
for (const message of trace.messages) {
|
|
33
|
+
const m = message;
|
|
34
|
+
if (!m || typeof m.id !== "string" || typeof m.content !== "string") {
|
|
35
|
+
throw new Error("Malformed trace: every message needs a string `id` and `content`. " +
|
|
36
|
+
"Produce a trace with `compaction capture` or `compaction import`.");
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return parsed;
|
|
40
|
+
}
|
|
41
|
+
function collect(value, previous) {
|
|
42
|
+
return [...previous, value];
|
|
43
|
+
}
|
|
44
|
+
export function registerContextCommand(program) {
|
|
45
|
+
const context = program
|
|
46
|
+
.command("context")
|
|
47
|
+
.description("Local memory: build a durable context store from your own captured/imported traces and " +
|
|
48
|
+
"retrieve the active context for a next step (local-only; no model, no network, no savings claim).");
|
|
49
|
+
context
|
|
50
|
+
.command("add")
|
|
51
|
+
.argument("<artifact>", "Path to a local normalized AgentTrace JSON (from `compaction capture`/`import`)")
|
|
52
|
+
.option("--store-dir <dir>", "Context store directory (local, gitignored)", DEFAULT_STORE_DIR)
|
|
53
|
+
.description("Append context items derived from a local trace into the local context store (size-cap enforced).")
|
|
54
|
+
.action(async (artifact, options) => {
|
|
55
|
+
const storeDir = resolve(options.storeDir ?? DEFAULT_STORE_DIR);
|
|
56
|
+
const trace = readTrace(resolve(artifact));
|
|
57
|
+
const items = contextItemsFromTrace(trace, { created_at: new Date().toISOString() });
|
|
58
|
+
const result = await appendContextItems(storeDir, items);
|
|
59
|
+
console.log(chalk.cyan("compaction context add"));
|
|
60
|
+
console.log(`Source: ${artifact}`);
|
|
61
|
+
console.log(`Store: ${storeDir}`);
|
|
62
|
+
console.log(`Items added: ${result.appended.length} skipped (duplicate): ${result.skipped.length} ` +
|
|
63
|
+
`evicted (size cap): ${result.evicted.length}`);
|
|
64
|
+
console.log(`Store now holds: ${result.total} items.`);
|
|
65
|
+
console.log("Local-only: nothing was uploaded. This makes no savings claim (see `compaction spend`/`summary` for cost).");
|
|
66
|
+
console.log(chalk.bold('Next: compaction context get "<your query>"'));
|
|
67
|
+
});
|
|
68
|
+
context
|
|
69
|
+
.command("get")
|
|
70
|
+
.argument("<query>", "Free-text description of the current step")
|
|
71
|
+
.option("--store-dir <dir>", "Context store directory (local, gitignored)", DEFAULT_STORE_DIR)
|
|
72
|
+
.option("--budget <tokens>", "Token budget for the assembled context (local estimate)", "4000")
|
|
73
|
+
.option("--source <pointer>", "Required source pointer for coverage diagnostics (repeatable)", collect, [])
|
|
74
|
+
.option("--limit <n>", "Max candidate items to consider after ranking")
|
|
75
|
+
.description("Retrieve + assemble the active context for a query from the local store (deterministic, local). " +
|
|
76
|
+
"Prints the assembled context WITH source pointers + local retrieval diagnostics — not a quality score.")
|
|
77
|
+
.action(async (query, options) => {
|
|
78
|
+
const storeDir = resolve(options.storeDir ?? DEFAULT_STORE_DIR);
|
|
79
|
+
const budget = Number.parseInt(options.budget ?? "4000", 10);
|
|
80
|
+
if (Number.isNaN(budget) || budget < 0) {
|
|
81
|
+
console.error("--budget must be a non-negative integer number of tokens.");
|
|
82
|
+
process.exitCode = 1;
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
let limit;
|
|
86
|
+
if (options.limit !== undefined) {
|
|
87
|
+
limit = Number.parseInt(options.limit, 10);
|
|
88
|
+
if (Number.isNaN(limit) || limit < 0) {
|
|
89
|
+
console.error("--limit must be a non-negative integer.");
|
|
90
|
+
process.exitCode = 1;
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
const items = await loadContextStore(storeDir);
|
|
95
|
+
const retrievalOptions = limit !== undefined ? { limit } : {};
|
|
96
|
+
const start = performance.now();
|
|
97
|
+
const ranked = retrieveContextItems(items, { text: query, source_pointers: options.source && options.source.length > 0 ? options.source : undefined }, retrievalOptions);
|
|
98
|
+
const assembled = assembleContext(ranked, { tokenBudget: budget });
|
|
99
|
+
const latencyMs = performance.now() - start;
|
|
100
|
+
console.log(chalk.cyan("compaction context get"));
|
|
101
|
+
console.log(`Query: ${JSON.stringify(query)}`);
|
|
102
|
+
console.log(`Store: ${storeDir} (${items.length} items)`);
|
|
103
|
+
if (assembled.included.length === 0) {
|
|
104
|
+
console.log("Assembled context: (no matching context in the store for this query)");
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
console.log(`Assembled context (~${assembled.estimated_tokens} tokens, local estimate; budget ${budget}):`);
|
|
108
|
+
for (const item of assembled.included) {
|
|
109
|
+
const pointer = item.source_pointer ?? "(no source pointer)";
|
|
110
|
+
const oneLine = item.content.replace(/\s+/g, " ");
|
|
111
|
+
console.log(` [${pointer}] ${oneLine}`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
const recoverable = assembled.included.filter((i) => i.recoverability === true && i.source_pointer).length;
|
|
115
|
+
console.log("Diagnostics (local retrieval, not a quality score):");
|
|
116
|
+
console.log(` considered: ${ranked.length} included: ${assembled.included.length} dropped: ${assembled.dropped.length}`);
|
|
117
|
+
console.log(` recoverable (has source pointer): ${recoverable}/${assembled.included.length}`);
|
|
118
|
+
if (options.source && options.source.length > 0) {
|
|
119
|
+
const includedPointers = new Set(assembled.included.map((i) => i.source_pointer).filter((p) => Boolean(p)));
|
|
120
|
+
const covered = options.source.filter((s) => includedPointers.has(s)).length;
|
|
121
|
+
console.log(` source coverage: ${covered}/${options.source.length}`);
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
console.log(" source coverage: n/a (no --source given)");
|
|
125
|
+
}
|
|
126
|
+
console.log(` latency: ${latencyMs.toFixed(1)} ms`);
|
|
127
|
+
console.log("No model, no network. Local memory/retrieval view — it makes no savings claim and no quality/correctness claim.");
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
//# sourceMappingURL=context.js.map
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
export interface RunThroughGatewayOptions {
|
|
3
|
+
provider?: string;
|
|
4
|
+
upstream?: string;
|
|
5
|
+
listen?: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Run `command` through the local Compaction Gateway. Shared by `gateway run` (the public gateway-native
|
|
9
|
+
* form) and the hidden `dev` compatibility alias — `label` only changes the message prefix + usage hint.
|
|
10
|
+
* Calls `process.exit(code)` with the child's exit code (so it is a terminal action).
|
|
11
|
+
*/
|
|
12
|
+
export declare function runThroughGateway(command: string[], options: RunThroughGatewayOptions, label?: string): Promise<void>;
|
|
13
|
+
/**
|
|
14
|
+
* Register the hidden `dev` compatibility alias. The PUBLIC gateway-native form is `gateway run`
|
|
15
|
+
* (registered in gateway.ts); `dev` is kept for backward compatibility and hidden from top-level help.
|
|
16
|
+
*/
|
|
17
|
+
export declare function registerDevCommand(program: Command): void;
|