@compaction/cli 0.1.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/LICENSE +663 -0
- package/README.md +319 -0
- package/dist/cli/commands/adapter.d.ts +2 -0
- package/dist/cli/commands/adapter.js +49 -0
- package/dist/cli/commands/aggregate.d.ts +2 -0
- package/dist/cli/commands/aggregate.js +60 -0
- package/dist/cli/commands/analyze.d.ts +2 -0
- package/dist/cli/commands/analyze.js +55 -0
- package/dist/cli/commands/apply-context.d.ts +12 -0
- package/dist/cli/commands/apply-context.js +80 -0
- package/dist/cli/commands/apply.d.ts +2 -0
- package/dist/cli/commands/apply.js +65 -0
- package/dist/cli/commands/approve.d.ts +2 -0
- package/dist/cli/commands/approve.js +55 -0
- package/dist/cli/commands/audit.d.ts +2 -0
- package/dist/cli/commands/audit.js +63 -0
- package/dist/cli/commands/billing-delta.d.ts +2 -0
- package/dist/cli/commands/billing-delta.js +246 -0
- package/dist/cli/commands/capture-claude-code.d.ts +19 -0
- package/dist/cli/commands/capture-claude-code.js +198 -0
- package/dist/cli/commands/capture-provider-usage.d.ts +35 -0
- package/dist/cli/commands/capture-provider-usage.js +113 -0
- package/dist/cli/commands/capture.d.ts +2 -0
- package/dist/cli/commands/capture.js +76 -0
- package/dist/cli/commands/compact.d.ts +2 -0
- package/dist/cli/commands/compact.js +206 -0
- package/dist/cli/commands/eval.d.ts +2 -0
- package/dist/cli/commands/eval.js +66 -0
- package/dist/cli/commands/export-session-seed.d.ts +11 -0
- package/dist/cli/commands/export-session-seed.js +42 -0
- package/dist/cli/commands/feedback.d.ts +2 -0
- package/dist/cli/commands/feedback.js +233 -0
- package/dist/cli/commands/import.d.ts +2 -0
- package/dist/cli/commands/import.js +60 -0
- package/dist/cli/commands/init.d.ts +2 -0
- package/dist/cli/commands/init.js +216 -0
- package/dist/cli/commands/integrations.d.ts +2 -0
- package/dist/cli/commands/integrations.js +29 -0
- package/dist/cli/commands/launch-treatment-session.d.ts +14 -0
- package/dist/cli/commands/launch-treatment-session.js +50 -0
- package/dist/cli/commands/optimize.d.ts +2 -0
- package/dist/cli/commands/optimize.js +33 -0
- package/dist/cli/commands/recommend.d.ts +4 -0
- package/dist/cli/commands/recommend.js +66 -0
- package/dist/cli/commands/review.d.ts +2 -0
- package/dist/cli/commands/review.js +60 -0
- package/dist/cli/commands/run.d.ts +2 -0
- package/dist/cli/commands/run.js +49 -0
- package/dist/cli/commands/spend.d.ts +2 -0
- package/dist/cli/commands/spend.js +24 -0
- package/dist/cli/commands/summary.d.ts +2 -0
- package/dist/cli/commands/summary.js +19 -0
- package/dist/cli/engine-degrade.d.ts +40 -0
- package/dist/cli/engine-degrade.js +59 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +59 -0
- package/dist/core/adapter-validation.d.ts +32 -0
- package/dist/core/adapter-validation.js +185 -0
- package/dist/core/adapters/claude-code-adapter.d.ts +51 -0
- package/dist/core/adapters/claude-code-adapter.js +539 -0
- package/dist/core/adapters/claude-code-discovery.d.ts +40 -0
- package/dist/core/adapters/claude-code-discovery.js +100 -0
- package/dist/core/aggregate-format.d.ts +62 -0
- package/dist/core/aggregate-format.js +349 -0
- package/dist/core/api-client/client.d.ts +43 -0
- package/dist/core/api-client/client.js +143 -0
- package/dist/core/api-client/config.d.ts +36 -0
- package/dist/core/api-client/config.js +44 -0
- package/dist/core/api-client/index.d.ts +13 -0
- package/dist/core/api-client/index.js +14 -0
- package/dist/core/api-client/payload.d.ts +93 -0
- package/dist/core/api-client/payload.js +180 -0
- package/dist/core/api-client/types.d.ts +95 -0
- package/dist/core/api-client/types.js +21 -0
- package/dist/core/artifact-writer.d.ts +2 -0
- package/dist/core/artifact-writer.js +14 -0
- package/dist/core/audit-report.d.ts +91 -0
- package/dist/core/audit-report.js +422 -0
- package/dist/core/billing-delta/billing-delta-record.d.ts +290 -0
- package/dist/core/billing-delta/billing-delta-record.js +394 -0
- package/dist/core/capture-adapter.d.ts +74 -0
- package/dist/core/capture-adapter.js +2 -0
- package/dist/core/command-runner.d.ts +29 -0
- package/dist/core/command-runner.js +96 -0
- package/dist/core/content-hash.d.ts +1 -0
- package/dist/core/content-hash.js +5 -0
- package/dist/core/cost-calculator.d.ts +6 -0
- package/dist/core/cost-calculator.js +20 -0
- package/dist/core/feedback-bundle.d.ts +159 -0
- package/dist/core/feedback-bundle.js +406 -0
- package/dist/core/openai-agents-capture.d.ts +66 -0
- package/dist/core/openai-agents-capture.js +475 -0
- package/dist/core/policy-types.d.ts +85 -0
- package/dist/core/policy-types.js +29 -0
- package/dist/core/pricing.d.ts +23 -0
- package/dist/core/pricing.js +55 -0
- package/dist/core/provider-usage/credential-redaction.d.ts +23 -0
- package/dist/core/provider-usage/credential-redaction.js +60 -0
- package/dist/core/provider-usage/provider-usage-adapter.d.ts +65 -0
- package/dist/core/provider-usage/provider-usage-adapter.js +147 -0
- package/dist/core/provider-usage/provider-usage-client.d.ts +89 -0
- package/dist/core/provider-usage/provider-usage-client.js +96 -0
- package/dist/core/report-generator.d.ts +7 -0
- package/dist/core/report-generator.js +275 -0
- package/dist/core/run-aggregator.d.ts +50 -0
- package/dist/core/run-aggregator.js +251 -0
- package/dist/core/run-labels.d.ts +52 -0
- package/dist/core/run-labels.js +80 -0
- package/dist/core/run-trace-converter.d.ts +3 -0
- package/dist/core/run-trace-converter.js +94 -0
- package/dist/core/safety-report.d.ts +52 -0
- package/dist/core/safety-report.js +440 -0
- package/dist/core/savings.d.ts +22 -0
- package/dist/core/savings.js +36 -0
- package/dist/core/session-aggregate.d.ts +211 -0
- package/dist/core/session-aggregate.js +490 -0
- package/dist/core/skill-injection-detector.d.ts +51 -0
- package/dist/core/skill-injection-detector.js +146 -0
- package/dist/core/spend-attribution.d.ts +169 -0
- package/dist/core/spend-attribution.js +611 -0
- package/dist/core/standalone-capsule-provenance.d.ts +4 -0
- package/dist/core/standalone-capsule-provenance.js +62 -0
- package/dist/core/state-capsule.d.ts +3 -0
- package/dist/core/state-capsule.js +147 -0
- package/dist/core/token-accounting.d.ts +62 -0
- package/dist/core/token-accounting.js +81 -0
- package/dist/core/token-estimator.d.ts +3 -0
- package/dist/core/token-estimator.js +18 -0
- package/dist/core/trace-adapters.d.ts +53 -0
- package/dist/core/trace-adapters.js +714 -0
- package/dist/core/trace-fingerprint.d.ts +79 -0
- package/dist/core/trace-fingerprint.js +102 -0
- package/dist/core/trace-intake.d.ts +41 -0
- package/dist/core/trace-intake.js +164 -0
- package/dist/core/trace-parser.d.ts +203 -0
- package/dist/core/trace-parser.js +143 -0
- package/dist/core/types.d.ts +238 -0
- package/dist/core/types.js +2 -0
- package/dist/core/usage-metadata.d.ts +51 -0
- package/dist/core/usage-metadata.js +122 -0
- package/dist/core/waste-detector.d.ts +8 -0
- package/dist/core/waste-detector.js +58 -0
- package/package.json +90 -0
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Privacy-safe feedback bundle for the beta learning loop.
|
|
3
|
+
*
|
|
4
|
+
* This module BUILDS a redacted feedback bundle that a beta tester may OPTIONALLY
|
|
5
|
+
* send to the maintainers. It does NOT write files and does NOT touch the network —
|
|
6
|
+
* the CLI command (src/cli/commands/feedback.ts) owns the local write and the
|
|
7
|
+
* explicit-confirm gate. Keeping the builders pure makes the privacy guarantees
|
|
8
|
+
* unit-testable.
|
|
9
|
+
*
|
|
10
|
+
* PRIVACY MODEL — exclude-by-default (whitelist construction):
|
|
11
|
+
* The bundle is ASSEMBLED FIELD-BY-FIELD from a small allowed set of non-sensitive,
|
|
12
|
+
* aggregate signals. Forbidden categories (raw trace messages, prompts, completions,
|
|
13
|
+
* tool outputs, source code, file contents, environment variables,
|
|
14
|
+
* credentials/tokens, customer data) are NEVER collected in the first place — they
|
|
15
|
+
* have no field to land in. The redaction pass below is defense-in-depth for the one
|
|
16
|
+
* free-text channel we do include (error/log diagnostics), NOT the primary control.
|
|
17
|
+
*
|
|
18
|
+
* REDACTION IS BEST-EFFORT, NOT PERFECT. It is a conservative shape matcher, not a DLP
|
|
19
|
+
* classifier. The tester chooses whether to send the bundle and can inspect it first.
|
|
20
|
+
*
|
|
21
|
+
* EVIDENCE HONESTY: every figure carries the weakest label the evidence supports.
|
|
22
|
+
* workflow_confirmed is NOT billing_confirmed. There is no billing-confirmed savings
|
|
23
|
+
* claim, no semantic/commitment-preservation claim, and no output-token-reduction
|
|
24
|
+
* claim anywhere in this bundle.
|
|
25
|
+
*/
|
|
26
|
+
/** Bundle schema version (additive changes bump the minor; field removals bump major). */
|
|
27
|
+
export declare const FEEDBACK_BUNDLE_VERSION = "1.0.0";
|
|
28
|
+
/** Marker used wherever a value is not available rather than guessed. */
|
|
29
|
+
export declare const UNKNOWN: "unknown";
|
|
30
|
+
export type TriState = "yes" | "no" | "unknown";
|
|
31
|
+
export type WorkflowOutcome = "succeeded" | "failed" | "partial" | "unknown";
|
|
32
|
+
/**
|
|
33
|
+
* Evidence ladder for this bundle, ordered weakest-to-strongest. The bundle labels
|
|
34
|
+
* each run at the WEAKEST rung the supplied evidence supports. Critically,
|
|
35
|
+
* `workflow_confirmed` is its OWN rung and is NOT `billing_confirmed` — observing that
|
|
36
|
+
* a workflow succeeded does not confirm a billed cost delta. `billing_confirmed` is
|
|
37
|
+
* only ever reachable with real billing/invoice/export evidence (none is collected by
|
|
38
|
+
* this command), so the bundle never emits it.
|
|
39
|
+
*/
|
|
40
|
+
export declare const EVIDENCE_LADDER: readonly ["measured_input_token_reduction", "output_token_delta_observed", "recoverability_verified", "applied_context", "workflow_confirmed", "usage_confirmed", "billing_confirmed"];
|
|
41
|
+
export type EvidenceLevel = (typeof EVIDENCE_LADDER)[number] | "unknown";
|
|
42
|
+
/** The exact non-sensitive categories the bundle INCLUDES (for the preview + README). */
|
|
43
|
+
export declare const INCLUDED_FIELDS: readonly string[];
|
|
44
|
+
/** The categories the bundle EXCLUDES BY DEFAULT — these must NEVER appear. */
|
|
45
|
+
export declare const EXCLUDED_CATEGORIES: readonly string[];
|
|
46
|
+
export declare const BEST_EFFORT_REDACTION_NOTE: string;
|
|
47
|
+
/**
|
|
48
|
+
* ALLOWLIST of non-sensitive usage-metadata keys.
|
|
49
|
+
*
|
|
50
|
+
* Provider usage exports can carry request/response bodies, user IDs, emails, and
|
|
51
|
+
* prompt fragments alongside token counts. So usage metadata is NOT copied verbatim:
|
|
52
|
+
* we KEEP ONLY these known non-sensitive keys (numeric token counts + the model /
|
|
53
|
+
* provider identifiers) and DROP every other key — allowlist, not blocklist. An
|
|
54
|
+
* unrecognized key is always dropped, never copied. This is applied identically to
|
|
55
|
+
* the written bundle and to the preview.
|
|
56
|
+
*/
|
|
57
|
+
export declare const USAGE_METADATA_ALLOWLIST: readonly string[];
|
|
58
|
+
export declare const USAGE_METADATA_ALLOWLIST_NOTE: string;
|
|
59
|
+
/** Result of allowlist-filtering supplied usage metadata: kept fields + count of dropped keys. */
|
|
60
|
+
export interface FilteredUsageMetadata {
|
|
61
|
+
kept: Record<string, unknown>;
|
|
62
|
+
dropped_key_count: number;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Apply the usage-metadata allowlist. Keeps ONLY recognized non-sensitive keys, and
|
|
66
|
+
* only when their value is the expected primitive type (numeric token counts; string
|
|
67
|
+
* model/provider). Every other key — including unknown keys and allowlisted keys with
|
|
68
|
+
* an unexpected (e.g. object/array) value — is DROPPED. Never records dropped VALUES,
|
|
69
|
+
* only a count. Returns `undefined` if nothing survives, so absent ≡ unknown.
|
|
70
|
+
*/
|
|
71
|
+
export declare function filterUsageMetadata(raw: Record<string, unknown> | undefined): FilteredUsageMetadata | undefined;
|
|
72
|
+
export declare const NO_UPLOAD_NOTE: string;
|
|
73
|
+
/** Aggregate token figures collected from local run reports (input tokens only by default). */
|
|
74
|
+
export interface AggregateRunSignals {
|
|
75
|
+
run_count: number;
|
|
76
|
+
total_original_input_tokens: number;
|
|
77
|
+
total_compacted_input_tokens: number;
|
|
78
|
+
total_input_tokens_saved: number;
|
|
79
|
+
/** Output-token delta only where the source actually carried output tokens; else unknown. */
|
|
80
|
+
output_token_delta: number | typeof UNKNOWN;
|
|
81
|
+
/** Estimated cost delta in USD — labeled estimated, NEVER billing-confirmed; unknown if unestimated. */
|
|
82
|
+
estimated_cost_delta_usd: number | typeof UNKNOWN;
|
|
83
|
+
}
|
|
84
|
+
export interface EnvironmentSignals {
|
|
85
|
+
cli_version: string;
|
|
86
|
+
os: string;
|
|
87
|
+
node_version: string;
|
|
88
|
+
package_version: string;
|
|
89
|
+
install_method: string;
|
|
90
|
+
}
|
|
91
|
+
/** Optional, operator-SUPPLIED signals. Absent → recorded as unknown, never inferred. */
|
|
92
|
+
export interface SuppliedSignals {
|
|
93
|
+
command_path?: string;
|
|
94
|
+
evidence_level?: EvidenceLevel;
|
|
95
|
+
recoverability_status?: string;
|
|
96
|
+
applied_context?: TriState;
|
|
97
|
+
workflow_outcome?: WorkflowOutcome;
|
|
98
|
+
missing_context?: TriState;
|
|
99
|
+
provider?: string;
|
|
100
|
+
model?: string;
|
|
101
|
+
/** Free-form usage metadata (e.g. provider-reported token counts) the tester supplies. */
|
|
102
|
+
usage_metadata?: Record<string, unknown>;
|
|
103
|
+
/** Raw error/log text to be REDACTED (best-effort) before inclusion. */
|
|
104
|
+
diagnostic_text?: string;
|
|
105
|
+
}
|
|
106
|
+
export interface FeedbackBundleInput {
|
|
107
|
+
environment: EnvironmentSignals;
|
|
108
|
+
aggregate: AggregateRunSignals;
|
|
109
|
+
supplied?: SuppliedSignals;
|
|
110
|
+
}
|
|
111
|
+
export interface FeedbackBundle {
|
|
112
|
+
bundle_version: string;
|
|
113
|
+
generated_at: string;
|
|
114
|
+
privacy: {
|
|
115
|
+
includes: readonly string[];
|
|
116
|
+
excludes_by_default: readonly string[];
|
|
117
|
+
redaction: string;
|
|
118
|
+
upload: string;
|
|
119
|
+
};
|
|
120
|
+
environment: EnvironmentSignals;
|
|
121
|
+
command_path: string | typeof UNKNOWN;
|
|
122
|
+
evidence_level: EvidenceLevel;
|
|
123
|
+
tokens: {
|
|
124
|
+
aggregate_original_input_tokens: number;
|
|
125
|
+
aggregate_compacted_input_tokens: number;
|
|
126
|
+
aggregate_input_tokens_saved: number;
|
|
127
|
+
/** Output-token delta where observable; otherwise unknown. NOT a reduction claim. */
|
|
128
|
+
output_token_delta: number | typeof UNKNOWN;
|
|
129
|
+
note: string;
|
|
130
|
+
};
|
|
131
|
+
cost: {
|
|
132
|
+
estimated_cost_delta_usd: number | typeof UNKNOWN;
|
|
133
|
+
label: string;
|
|
134
|
+
};
|
|
135
|
+
recoverability_status: string | typeof UNKNOWN;
|
|
136
|
+
applied_context: TriState;
|
|
137
|
+
workflow_outcome: WorkflowOutcome;
|
|
138
|
+
missing_context: TriState;
|
|
139
|
+
provider: string | typeof UNKNOWN;
|
|
140
|
+
model: string | typeof UNKNOWN;
|
|
141
|
+
/** Allowlist-filtered usage metadata (numeric token counts + model/provider only), or unknown. */
|
|
142
|
+
usage_metadata: Record<string, unknown> | typeof UNKNOWN;
|
|
143
|
+
/** Count of usage-metadata keys DROPPED by the allowlist (values never recorded). */
|
|
144
|
+
usage_metadata_dropped_key_count: number;
|
|
145
|
+
/** Best-effort REDACTED diagnostics. Free-text channel; redaction defense-in-depth applies. */
|
|
146
|
+
redacted_diagnostics: string | typeof UNKNOWN;
|
|
147
|
+
run_count: number;
|
|
148
|
+
}
|
|
149
|
+
export declare function redactDiagnostic(text: string): string;
|
|
150
|
+
/**
|
|
151
|
+
* Assemble the bundle from the allowed signal set. Whitelist construction: there is no
|
|
152
|
+
* code path here that copies raw messages, prompts, completions, tool outputs, source,
|
|
153
|
+
* file contents, env vars, credentials, or customer data into the result.
|
|
154
|
+
*/
|
|
155
|
+
export declare function buildFeedbackBundle(input: FeedbackBundleInput, generatedAt?: string): FeedbackBundle;
|
|
156
|
+
/** Human-readable preview: EXACTLY what will be written, field-by-field. */
|
|
157
|
+
export declare function formatBundlePreview(bundle: FeedbackBundle): string;
|
|
158
|
+
/** README written INSIDE the bundle directory. */
|
|
159
|
+
export declare function renderBundleReadme(bundle: FeedbackBundle): string;
|
|
@@ -0,0 +1,406 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Privacy-safe feedback bundle for the beta learning loop.
|
|
3
|
+
*
|
|
4
|
+
* This module BUILDS a redacted feedback bundle that a beta tester may OPTIONALLY
|
|
5
|
+
* send to the maintainers. It does NOT write files and does NOT touch the network —
|
|
6
|
+
* the CLI command (src/cli/commands/feedback.ts) owns the local write and the
|
|
7
|
+
* explicit-confirm gate. Keeping the builders pure makes the privacy guarantees
|
|
8
|
+
* unit-testable.
|
|
9
|
+
*
|
|
10
|
+
* PRIVACY MODEL — exclude-by-default (whitelist construction):
|
|
11
|
+
* The bundle is ASSEMBLED FIELD-BY-FIELD from a small allowed set of non-sensitive,
|
|
12
|
+
* aggregate signals. Forbidden categories (raw trace messages, prompts, completions,
|
|
13
|
+
* tool outputs, source code, file contents, environment variables,
|
|
14
|
+
* credentials/tokens, customer data) are NEVER collected in the first place — they
|
|
15
|
+
* have no field to land in. The redaction pass below is defense-in-depth for the one
|
|
16
|
+
* free-text channel we do include (error/log diagnostics), NOT the primary control.
|
|
17
|
+
*
|
|
18
|
+
* REDACTION IS BEST-EFFORT, NOT PERFECT. It is a conservative shape matcher, not a DLP
|
|
19
|
+
* classifier. The tester chooses whether to send the bundle and can inspect it first.
|
|
20
|
+
*
|
|
21
|
+
* EVIDENCE HONESTY: every figure carries the weakest label the evidence supports.
|
|
22
|
+
* workflow_confirmed is NOT billing_confirmed. There is no billing-confirmed savings
|
|
23
|
+
* claim, no semantic/commitment-preservation claim, and no output-token-reduction
|
|
24
|
+
* claim anywhere in this bundle.
|
|
25
|
+
*/
|
|
26
|
+
import { redactSecrets } from "./provider-usage/credential-redaction.js";
|
|
27
|
+
/** Bundle schema version (additive changes bump the minor; field removals bump major). */
|
|
28
|
+
export const FEEDBACK_BUNDLE_VERSION = "1.0.0";
|
|
29
|
+
/** Marker used wherever a value is not available rather than guessed. */
|
|
30
|
+
export const UNKNOWN = "unknown";
|
|
31
|
+
/**
|
|
32
|
+
* Evidence ladder for this bundle, ordered weakest-to-strongest. The bundle labels
|
|
33
|
+
* each run at the WEAKEST rung the supplied evidence supports. Critically,
|
|
34
|
+
* `workflow_confirmed` is its OWN rung and is NOT `billing_confirmed` — observing that
|
|
35
|
+
* a workflow succeeded does not confirm a billed cost delta. `billing_confirmed` is
|
|
36
|
+
* only ever reachable with real billing/invoice/export evidence (none is collected by
|
|
37
|
+
* this command), so the bundle never emits it.
|
|
38
|
+
*/
|
|
39
|
+
export const EVIDENCE_LADDER = [
|
|
40
|
+
"measured_input_token_reduction",
|
|
41
|
+
"output_token_delta_observed",
|
|
42
|
+
"recoverability_verified",
|
|
43
|
+
"applied_context",
|
|
44
|
+
"workflow_confirmed",
|
|
45
|
+
"usage_confirmed",
|
|
46
|
+
"billing_confirmed"
|
|
47
|
+
];
|
|
48
|
+
/** The exact non-sensitive categories the bundle INCLUDES (for the preview + README). */
|
|
49
|
+
export const INCLUDED_FIELDS = [
|
|
50
|
+
"CLI version, OS, node version, package version",
|
|
51
|
+
"command path used (which compaction command produced the run)",
|
|
52
|
+
"evidence level (weakest-supported label)",
|
|
53
|
+
"aggregate original/compacted INPUT tokens",
|
|
54
|
+
"output-token delta WHERE OBSERVABLE (else unknown)",
|
|
55
|
+
"estimated cost delta (labeled estimated — never billing-confirmed)",
|
|
56
|
+
"recoverability status",
|
|
57
|
+
"applied_context (yes/no)",
|
|
58
|
+
"workflow_outcome (succeeded/failed/partial/unknown)",
|
|
59
|
+
"missing_context (yes/no/unknown)",
|
|
60
|
+
"provider/model IF supplied",
|
|
61
|
+
"usage metadata IF supplied (allowlisted non-sensitive fields only: numeric token counts + model/provider)",
|
|
62
|
+
"install method",
|
|
63
|
+
"REDACTED errors/logs (best-effort)"
|
|
64
|
+
];
|
|
65
|
+
/** The categories the bundle EXCLUDES BY DEFAULT — these must NEVER appear. */
|
|
66
|
+
export const EXCLUDED_CATEGORIES = [
|
|
67
|
+
"raw trace messages",
|
|
68
|
+
"prompts",
|
|
69
|
+
"completions",
|
|
70
|
+
"tool outputs",
|
|
71
|
+
"source code",
|
|
72
|
+
"file contents",
|
|
73
|
+
"environment variables",
|
|
74
|
+
"credentials / tokens",
|
|
75
|
+
"customer data"
|
|
76
|
+
];
|
|
77
|
+
export const BEST_EFFORT_REDACTION_NOTE = "Redaction is BEST-EFFORT, not perfect: it is a conservative shape matcher, not a guaranteed scrubber. " +
|
|
78
|
+
"Inspect this bundle before you choose to send it.";
|
|
79
|
+
/**
|
|
80
|
+
* ALLOWLIST of non-sensitive usage-metadata keys.
|
|
81
|
+
*
|
|
82
|
+
* Provider usage exports can carry request/response bodies, user IDs, emails, and
|
|
83
|
+
* prompt fragments alongside token counts. So usage metadata is NOT copied verbatim:
|
|
84
|
+
* we KEEP ONLY these known non-sensitive keys (numeric token counts + the model /
|
|
85
|
+
* provider identifiers) and DROP every other key — allowlist, not blocklist. An
|
|
86
|
+
* unrecognized key is always dropped, never copied. This is applied identically to
|
|
87
|
+
* the written bundle and to the preview.
|
|
88
|
+
*/
|
|
89
|
+
export const USAGE_METADATA_ALLOWLIST = [
|
|
90
|
+
"input_tokens",
|
|
91
|
+
"prompt_tokens",
|
|
92
|
+
"output_tokens",
|
|
93
|
+
"completion_tokens",
|
|
94
|
+
"total_tokens",
|
|
95
|
+
"cache_read_input_tokens",
|
|
96
|
+
"cache_creation_input_tokens",
|
|
97
|
+
"cache_read_tokens",
|
|
98
|
+
"cache_creation_tokens",
|
|
99
|
+
"cached_tokens",
|
|
100
|
+
"model",
|
|
101
|
+
"provider"
|
|
102
|
+
];
|
|
103
|
+
const USAGE_METADATA_ALLOWED_SET = new Set(USAGE_METADATA_ALLOWLIST);
|
|
104
|
+
/** These allowlisted keys carry string identifiers; all other allowlisted keys are numeric. */
|
|
105
|
+
const USAGE_METADATA_STRING_KEYS = new Set(["model", "provider"]);
|
|
106
|
+
export const USAGE_METADATA_ALLOWLIST_NOTE = "usage metadata IF supplied (ALLOWLISTED non-sensitive fields only: numeric token counts + model/provider; " +
|
|
107
|
+
"all unrecognized keys are DROPPED, best-effort)";
|
|
108
|
+
/**
|
|
109
|
+
* Apply the usage-metadata allowlist. Keeps ONLY recognized non-sensitive keys, and
|
|
110
|
+
* only when their value is the expected primitive type (numeric token counts; string
|
|
111
|
+
* model/provider). Every other key — including unknown keys and allowlisted keys with
|
|
112
|
+
* an unexpected (e.g. object/array) value — is DROPPED. Never records dropped VALUES,
|
|
113
|
+
* only a count. Returns `undefined` if nothing survives, so absent ≡ unknown.
|
|
114
|
+
*/
|
|
115
|
+
export function filterUsageMetadata(raw) {
|
|
116
|
+
if (!raw || typeof raw !== "object")
|
|
117
|
+
return undefined;
|
|
118
|
+
const kept = {};
|
|
119
|
+
let droppedKeyCount = 0;
|
|
120
|
+
for (const [key, value] of Object.entries(raw)) {
|
|
121
|
+
if (!USAGE_METADATA_ALLOWED_SET.has(key)) {
|
|
122
|
+
droppedKeyCount += 1;
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
if (USAGE_METADATA_STRING_KEYS.has(key)) {
|
|
126
|
+
if (typeof value === "string" && value.length > 0) {
|
|
127
|
+
kept[key] = value;
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
droppedKeyCount += 1;
|
|
131
|
+
}
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
// Token-count keys: keep only finite numbers (drop strings/objects/NaN/etc.).
|
|
135
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
136
|
+
kept[key] = value;
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
droppedKeyCount += 1;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
if (Object.keys(kept).length === 0 && droppedKeyCount === 0)
|
|
143
|
+
return undefined;
|
|
144
|
+
return { kept, dropped_key_count: droppedKeyCount };
|
|
145
|
+
}
|
|
146
|
+
export const NO_UPLOAD_NOTE = "This command writes a LOCAL bundle only. It performs NO network call, NO upload, and NO telemetry. " +
|
|
147
|
+
"Whether to send this bundle is entirely your choice.";
|
|
148
|
+
const COST_LABEL = "estimated (token-estimated cost / local estimate) — NOT billing-confirmed, NOT realized savings";
|
|
149
|
+
const OUTPUT_TOKEN_NOTE = "Input-token figures are measured aggregates. Output-token delta is shown only where the " +
|
|
150
|
+
"source carried output tokens (else unknown); this bundle makes NO output-token-reduction claim.";
|
|
151
|
+
/**
|
|
152
|
+
* Best-effort redaction for the ONE free-text channel (error/log diagnostics).
|
|
153
|
+
*
|
|
154
|
+
* Two-stage, FAIL-CLOSED design — because shape redaction alone cannot catch
|
|
155
|
+
* arbitrary natural-language content (a leaked prompt/completion/customer record is
|
|
156
|
+
* just prose). So:
|
|
157
|
+
*
|
|
158
|
+
* Stage 1 (shape redaction): mask credential shapes (shared backstop), env-var
|
|
159
|
+
* assignments, absolute-ish file paths, emails, and long quoted strings.
|
|
160
|
+
* Stage 2 (line allowlist, fail-closed): KEEP only lines that match recognizable
|
|
161
|
+
* diagnostic STRUCTURE — a stack frame (`at fn (file:line:col)`), an error/exception
|
|
162
|
+
* header (`TypeError: ...`), a Node error code (`Error [ERR_...]`, `code: 'E...'`),
|
|
163
|
+
* a leading compiler/HTTP code, or a line that is itself only redaction markers.
|
|
164
|
+
* A line is NOT kept merely because it contains a word like "trace" or "stack":
|
|
165
|
+
* `trace: <raw prompt>` has no diagnostic structure and is DROPPED — replaced by a
|
|
166
|
+
* `[dropped: non-error-shaped line]` marker. Arbitrary prose (prompts, completions,
|
|
167
|
+
* customer data) is therefore absent by construction, not by hoping a regex caught it.
|
|
168
|
+
*
|
|
169
|
+
* Still explicitly BEST-EFFORT: a secret embedded inside an error-shaped line in a
|
|
170
|
+
* shape we do not recognize could survive. The exclude-by-default model and the
|
|
171
|
+
* tester's own review are the real guarantees; this is defense in depth.
|
|
172
|
+
*/
|
|
173
|
+
function redactLineShapes(line) {
|
|
174
|
+
let out = redactSecrets(line);
|
|
175
|
+
// export KEY=... shell forms (before bare KEY=VALUE so the keyword is kept).
|
|
176
|
+
out = out.replace(/\b(export\s+[A-Z][A-Z0-9_]{2,})\s*=\s*("[^"]*"|'[^']*'|[^\s]+)/gi, "$1=***REDACTED***");
|
|
177
|
+
// KEY=VALUE env-var-style assignments (mask the value; keep the key name).
|
|
178
|
+
out = out.replace(/\b([A-Z][A-Z0-9_]{2,})\s*=\s*("[^"]*"|'[^']*'|[^\s]+)/g, "$1=***REDACTED***");
|
|
179
|
+
// Absolute-ish filesystem paths (POSIX + Windows) — may reveal usernames/dirs.
|
|
180
|
+
out = out.replace(/(?:\/[\w.\-]+){2,}\/?/g, "***REDACTED_PATH***");
|
|
181
|
+
out = out.replace(/[A-Za-z]:\\(?:[\w.\- ]+\\?)+/g, "***REDACTED_PATH***");
|
|
182
|
+
// Email addresses.
|
|
183
|
+
out = out.replace(/\b[\w.+-]+@[\w-]+\.[\w.-]+\b/g, "***REDACTED_EMAIL***");
|
|
184
|
+
// Long quoted strings — likely prompt/completion/content fragments, not error shape.
|
|
185
|
+
out = out.replace(/"[^"]{40,}"/g, '"***REDACTED_CONTENT***"');
|
|
186
|
+
out = out.replace(/'[^']{40,}'/g, "'***REDACTED_CONTENT***'");
|
|
187
|
+
return out;
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Does a (already shape-redacted) line look like a REAL error/diagnostic, vs arbitrary
|
|
191
|
+
* prose? Fail-closed: a line is kept ONLY if it matches recognizable diagnostic
|
|
192
|
+
* STRUCTURE, never merely because it contains a word like "trace" or "stack". A bare
|
|
193
|
+
* `trace: <raw prompt>` line carries no stack-frame / error-header structure and is
|
|
194
|
+
* therefore DROPPED — its content (a prompt, completion, or customer record) would
|
|
195
|
+
* otherwise survive.
|
|
196
|
+
*/
|
|
197
|
+
function isErrorShapedLine(line) {
|
|
198
|
+
const trimmed = line.trim();
|
|
199
|
+
if (trimmed.length === 0)
|
|
200
|
+
return true; // blank lines are harmless
|
|
201
|
+
// Stack frames: "at fn (file:line:col)" / "at file:line:col".
|
|
202
|
+
if (/^\s*at\s+.+\(.+:\d+:\d+\)\s*$/.test(line))
|
|
203
|
+
return true;
|
|
204
|
+
if (/^\s*at\s+.+:\d+:\d+\)?\s*$/.test(line))
|
|
205
|
+
return true;
|
|
206
|
+
// Node-style "at async fn ..." frames are covered by the two patterns above.
|
|
207
|
+
// Error/exception HEADER: "TypeError: ...", "Error: ...", "SomethingException: ...".
|
|
208
|
+
if (/^\s*[\w.$]*(?:Error|Exception|Warning):\s/.test(line))
|
|
209
|
+
return true;
|
|
210
|
+
// Node error codes: "Error [ERR_FOO]" or a `code: 'ERR_FOO'` / `errno: -2` line.
|
|
211
|
+
if (/\b(?:Error|Exception)\s*\[(?:ERR_[A-Z0-9_]+|E[A-Z]{2,})\]/.test(line))
|
|
212
|
+
return true;
|
|
213
|
+
if (/^\s*(?:code|errno):\s*['"]?(?:E[A-Z]{2,}|ERR_[A-Z0-9_]+|-?\d+)['"]?\s*$/.test(line))
|
|
214
|
+
return true;
|
|
215
|
+
// Bare Node error codes on their own / leading the line (ENOENT, EACCES, ECONNRESET).
|
|
216
|
+
if (/^\s*(?:E[A-Z]{2,}|ERR_[A-Z0-9_]+)\b/.test(line))
|
|
217
|
+
return true;
|
|
218
|
+
// Compiler/HTTP diagnostic codes leading the line: "TS2345: ...", "error TS2345", "HTTP 500".
|
|
219
|
+
if (/^\s*(?:error\s+)?[A-Z]{2}\d{3,5}\b/.test(line))
|
|
220
|
+
return true;
|
|
221
|
+
if (/^\s*(?:HTTP\s+|status\s+)[1-5]\d{2}\b/i.test(line))
|
|
222
|
+
return true;
|
|
223
|
+
// Lines that are now ENTIRELY redaction markers (plus tiny glue) are safe to keep.
|
|
224
|
+
if (/\*\*\*REDACTED/.test(line) && trimmed.replace(/\*\*\*REDACTED[A-Z_]*\*\*\*/g, "").trim().length < 20) {
|
|
225
|
+
return true;
|
|
226
|
+
}
|
|
227
|
+
return false;
|
|
228
|
+
}
|
|
229
|
+
export function redactDiagnostic(text) {
|
|
230
|
+
if (text.length === 0)
|
|
231
|
+
return text;
|
|
232
|
+
const lines = text.split(/\r?\n/);
|
|
233
|
+
const kept = lines.map((line) => {
|
|
234
|
+
const shaped = redactLineShapes(line);
|
|
235
|
+
return isErrorShapedLine(shaped) ? shaped : "[dropped: non-error-shaped line]";
|
|
236
|
+
});
|
|
237
|
+
return kept.join("\n");
|
|
238
|
+
}
|
|
239
|
+
function triOrUnknown(value) {
|
|
240
|
+
return value ?? "unknown";
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Assemble the bundle from the allowed signal set. Whitelist construction: there is no
|
|
244
|
+
* code path here that copies raw messages, prompts, completions, tool outputs, source,
|
|
245
|
+
* file contents, env vars, credentials, or customer data into the result.
|
|
246
|
+
*/
|
|
247
|
+
export function buildFeedbackBundle(input, generatedAt = new Date().toISOString()) {
|
|
248
|
+
const supplied = input.supplied ?? {};
|
|
249
|
+
const redactedDiagnostics = typeof supplied.diagnostic_text === "string" && supplied.diagnostic_text.length > 0
|
|
250
|
+
? redactDiagnostic(supplied.diagnostic_text)
|
|
251
|
+
: UNKNOWN;
|
|
252
|
+
// Usage metadata is NEVER copied verbatim: apply the allowlist, keep only recognized
|
|
253
|
+
// non-sensitive fields, drop everything else (and only record a dropped-key COUNT).
|
|
254
|
+
const filteredUsage = filterUsageMetadata(supplied.usage_metadata);
|
|
255
|
+
const usageMetadata = filteredUsage && Object.keys(filteredUsage.kept).length > 0 ? filteredUsage.kept : UNKNOWN;
|
|
256
|
+
const usageMetadataDroppedKeyCount = filteredUsage ? filteredUsage.dropped_key_count : 0;
|
|
257
|
+
return {
|
|
258
|
+
bundle_version: FEEDBACK_BUNDLE_VERSION,
|
|
259
|
+
generated_at: generatedAt,
|
|
260
|
+
privacy: {
|
|
261
|
+
includes: INCLUDED_FIELDS,
|
|
262
|
+
excludes_by_default: EXCLUDED_CATEGORIES,
|
|
263
|
+
redaction: BEST_EFFORT_REDACTION_NOTE,
|
|
264
|
+
upload: NO_UPLOAD_NOTE
|
|
265
|
+
},
|
|
266
|
+
environment: input.environment,
|
|
267
|
+
command_path: supplied.command_path ?? UNKNOWN,
|
|
268
|
+
evidence_level: supplied.evidence_level ?? UNKNOWN,
|
|
269
|
+
tokens: {
|
|
270
|
+
aggregate_original_input_tokens: input.aggregate.total_original_input_tokens,
|
|
271
|
+
aggregate_compacted_input_tokens: input.aggregate.total_compacted_input_tokens,
|
|
272
|
+
aggregate_input_tokens_saved: input.aggregate.total_input_tokens_saved,
|
|
273
|
+
output_token_delta: input.aggregate.output_token_delta,
|
|
274
|
+
note: OUTPUT_TOKEN_NOTE
|
|
275
|
+
},
|
|
276
|
+
cost: {
|
|
277
|
+
estimated_cost_delta_usd: input.aggregate.estimated_cost_delta_usd,
|
|
278
|
+
label: COST_LABEL
|
|
279
|
+
},
|
|
280
|
+
recoverability_status: supplied.recoverability_status ?? UNKNOWN,
|
|
281
|
+
applied_context: triOrUnknown(supplied.applied_context),
|
|
282
|
+
workflow_outcome: supplied.workflow_outcome ?? "unknown",
|
|
283
|
+
missing_context: triOrUnknown(supplied.missing_context),
|
|
284
|
+
provider: supplied.provider ?? UNKNOWN,
|
|
285
|
+
model: supplied.model ?? UNKNOWN,
|
|
286
|
+
usage_metadata: usageMetadata,
|
|
287
|
+
usage_metadata_dropped_key_count: usageMetadataDroppedKeyCount,
|
|
288
|
+
redacted_diagnostics: redactedDiagnostics,
|
|
289
|
+
run_count: input.aggregate.run_count
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
/** Human-readable preview: EXACTLY what will be written, field-by-field. */
|
|
293
|
+
export function formatBundlePreview(bundle) {
|
|
294
|
+
const lines = [];
|
|
295
|
+
lines.push("Feedback bundle preview — EXACTLY these fields will be written (local file only):");
|
|
296
|
+
lines.push("");
|
|
297
|
+
lines.push(` bundle_version: ${bundle.bundle_version}`);
|
|
298
|
+
lines.push(` generated_at: ${bundle.generated_at}`);
|
|
299
|
+
lines.push(` run_count: ${bundle.run_count}`);
|
|
300
|
+
lines.push("");
|
|
301
|
+
lines.push(" environment:");
|
|
302
|
+
lines.push(` cli_version: ${bundle.environment.cli_version}`);
|
|
303
|
+
lines.push(` os: ${bundle.environment.os}`);
|
|
304
|
+
lines.push(` node_version: ${bundle.environment.node_version}`);
|
|
305
|
+
lines.push(` package_version: ${bundle.environment.package_version}`);
|
|
306
|
+
lines.push(` install_method: ${bundle.environment.install_method}`);
|
|
307
|
+
lines.push("");
|
|
308
|
+
lines.push(` command_path: ${String(bundle.command_path)}`);
|
|
309
|
+
lines.push(` evidence_level: ${bundle.evidence_level}`);
|
|
310
|
+
lines.push("");
|
|
311
|
+
lines.push(" tokens (aggregate, INPUT measured):");
|
|
312
|
+
lines.push(` original_input_tokens: ${bundle.tokens.aggregate_original_input_tokens}`);
|
|
313
|
+
lines.push(` compacted_input_tokens: ${bundle.tokens.aggregate_compacted_input_tokens}`);
|
|
314
|
+
lines.push(` input_tokens_saved: ${bundle.tokens.aggregate_input_tokens_saved}`);
|
|
315
|
+
lines.push(` output_token_delta: ${String(bundle.tokens.output_token_delta)} (where observable; else unknown)`);
|
|
316
|
+
lines.push("");
|
|
317
|
+
lines.push(` estimated_cost_delta_usd: ${String(bundle.cost.estimated_cost_delta_usd)}`);
|
|
318
|
+
lines.push(` cost label: ${bundle.cost.label}`);
|
|
319
|
+
lines.push("");
|
|
320
|
+
lines.push(` recoverability_status: ${String(bundle.recoverability_status)}`);
|
|
321
|
+
lines.push(` applied_context: ${bundle.applied_context}`);
|
|
322
|
+
lines.push(` workflow_outcome: ${bundle.workflow_outcome}`);
|
|
323
|
+
lines.push(` missing_context: ${bundle.missing_context}`);
|
|
324
|
+
lines.push(` provider: ${String(bundle.provider)}`);
|
|
325
|
+
lines.push(` model: ${String(bundle.model)}`);
|
|
326
|
+
lines.push(` usage_metadata: ${bundle.usage_metadata === UNKNOWN ? UNKNOWN : JSON.stringify(bundle.usage_metadata)}`);
|
|
327
|
+
lines.push(` (allowlisted fields only; ${bundle.usage_metadata_dropped_key_count} unrecognized key(s) dropped)`);
|
|
328
|
+
lines.push(` redacted_diagnostics: ${bundle.redacted_diagnostics === UNKNOWN ? UNKNOWN : "(best-effort redacted text — see bundle)"}`);
|
|
329
|
+
lines.push("");
|
|
330
|
+
lines.push("EXCLUDED BY DEFAULT (never collected, never written):");
|
|
331
|
+
for (const category of EXCLUDED_CATEGORIES) {
|
|
332
|
+
lines.push(` - ${category}`);
|
|
333
|
+
}
|
|
334
|
+
lines.push("");
|
|
335
|
+
lines.push(BEST_EFFORT_REDACTION_NOTE);
|
|
336
|
+
lines.push(NO_UPLOAD_NOTE);
|
|
337
|
+
return lines.join("\n");
|
|
338
|
+
}
|
|
339
|
+
/** README written INSIDE the bundle directory. */
|
|
340
|
+
export function renderBundleReadme(bundle) {
|
|
341
|
+
const lines = [];
|
|
342
|
+
lines.push("# compaction feedback bundle");
|
|
343
|
+
lines.push("");
|
|
344
|
+
lines.push(`Generated: ${bundle.generated_at}`);
|
|
345
|
+
lines.push(`Bundle version: ${bundle.bundle_version}`);
|
|
346
|
+
lines.push("");
|
|
347
|
+
lines.push("## What this is");
|
|
348
|
+
lines.push("");
|
|
349
|
+
lines.push("A privacy-safe feedback bundle for the compaction beta learning loop. It contains a small set of");
|
|
350
|
+
lines.push("NON-SENSITIVE, aggregate signals about a compaction run so the maintainers can learn whether the");
|
|
351
|
+
lines.push("tool helped — WITHOUT seeing your traces, prompts, code, or data.");
|
|
352
|
+
lines.push("");
|
|
353
|
+
lines.push("## What it INCLUDES (by default — non-sensitive only)");
|
|
354
|
+
lines.push("");
|
|
355
|
+
for (const field of INCLUDED_FIELDS) {
|
|
356
|
+
lines.push(`- ${field}`);
|
|
357
|
+
}
|
|
358
|
+
lines.push("");
|
|
359
|
+
lines.push("## What it EXCLUDES by default (never collected, never written)");
|
|
360
|
+
lines.push("");
|
|
361
|
+
for (const category of EXCLUDED_CATEGORIES) {
|
|
362
|
+
lines.push(`- ${category}`);
|
|
363
|
+
}
|
|
364
|
+
lines.push("");
|
|
365
|
+
lines.push("## Usage metadata is allowlist-filtered (best-effort)");
|
|
366
|
+
lines.push("");
|
|
367
|
+
lines.push("Provider usage exports can carry request/response bodies, user IDs, emails, or prompt fragments " +
|
|
368
|
+
"alongside token counts. So supplied usage metadata is NOT copied verbatim: only an allowlist of " +
|
|
369
|
+
"non-sensitive fields is kept (numeric token counts plus model/provider), and every unrecognized " +
|
|
370
|
+
"key is DROPPED — allowlist, not blocklist. This is best-effort; inspect the kept fields below.");
|
|
371
|
+
lines.push("");
|
|
372
|
+
lines.push("Allowlisted usage-metadata keys (kept when present, with the expected value type):");
|
|
373
|
+
for (const key of USAGE_METADATA_ALLOWLIST) {
|
|
374
|
+
lines.push(`- \`${key}\``);
|
|
375
|
+
}
|
|
376
|
+
lines.push("");
|
|
377
|
+
if (bundle.usage_metadata !== UNKNOWN || bundle.usage_metadata_dropped_key_count > 0) {
|
|
378
|
+
lines.push(`${bundle.usage_metadata_dropped_key_count} unrecognized usage-metadata key(s) were dropped ` +
|
|
379
|
+
"from this bundle (their values were never recorded).");
|
|
380
|
+
lines.push("");
|
|
381
|
+
}
|
|
382
|
+
lines.push("## Redaction is best-effort");
|
|
383
|
+
lines.push("");
|
|
384
|
+
lines.push(BEST_EFFORT_REDACTION_NOTE);
|
|
385
|
+
lines.push("");
|
|
386
|
+
lines.push("## You choose whether to send");
|
|
387
|
+
lines.push("");
|
|
388
|
+
lines.push(NO_UPLOAD_NOTE);
|
|
389
|
+
lines.push("");
|
|
390
|
+
lines.push("## Evidence honesty");
|
|
391
|
+
lines.push("");
|
|
392
|
+
lines.push("Each figure carries the weakest label the evidence supports. The estimated cost delta is a " +
|
|
393
|
+
"token-estimated / local estimate — it is NOT billing-confirmed and NOT realized savings.");
|
|
394
|
+
lines.push("`workflow_outcome: succeeded` means a workflow ran to completion; it is NOT a billing confirmation. " +
|
|
395
|
+
"workflow_confirmed is NOT billing_confirmed.");
|
|
396
|
+
lines.push("This bundle makes no output-token-reduction claim and no semantic/commitment-preservation claim. " +
|
|
397
|
+
"Output-token delta is shown only where observable, otherwise unknown.");
|
|
398
|
+
lines.push("");
|
|
399
|
+
lines.push("## Files");
|
|
400
|
+
lines.push("");
|
|
401
|
+
lines.push("- `feedback-bundle.json` — the bundle data (the fields listed above).");
|
|
402
|
+
lines.push("- `README.md` — this file.");
|
|
403
|
+
lines.push("");
|
|
404
|
+
return lines.join("\n");
|
|
405
|
+
}
|
|
406
|
+
//# sourceMappingURL=feedback-bundle.js.map
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { type LocalCommandRun } from "./command-runner.js";
|
|
2
|
+
import { type UsageMetadata } from "./usage-metadata.js";
|
|
3
|
+
import type { AgentTrace } from "./types.js";
|
|
4
|
+
export type OpenAIAgentsCaptureMode = "command wrapper" | "local export" | "fixture";
|
|
5
|
+
export type CaptureStatus = "pass" | "warn" | "fail";
|
|
6
|
+
export type MetadataStatus = "present" | "partial" | "synthetic-demo" | "missing" | "unknown";
|
|
7
|
+
export interface OpenAIAgentsCaptureReport {
|
|
8
|
+
capture_id: string;
|
|
9
|
+
generated_at: string;
|
|
10
|
+
integration: "openai-agents";
|
|
11
|
+
capture_mode: OpenAIAgentsCaptureMode;
|
|
12
|
+
status: CaptureStatus;
|
|
13
|
+
command_run?: {
|
|
14
|
+
command: string;
|
|
15
|
+
args: string[];
|
|
16
|
+
exit_code: number;
|
|
17
|
+
duration_ms: number;
|
|
18
|
+
};
|
|
19
|
+
output_trace_id: string | null;
|
|
20
|
+
events_captured: number;
|
|
21
|
+
messages_captured: number;
|
|
22
|
+
tool_outputs_captured: number;
|
|
23
|
+
token_metadata_status: MetadataStatus;
|
|
24
|
+
cost_metadata_status: MetadataStatus;
|
|
25
|
+
usage_metadata: UsageMetadata;
|
|
26
|
+
spend_confidence: UsageMetadata["cost_confidence"];
|
|
27
|
+
pricing_assumptions: string[];
|
|
28
|
+
warnings: string[];
|
|
29
|
+
failures: string[];
|
|
30
|
+
limitations: string[];
|
|
31
|
+
recommended_next_command: string | null;
|
|
32
|
+
}
|
|
33
|
+
export interface OpenAIAgentsCaptureArtifacts {
|
|
34
|
+
report: OpenAIAgentsCaptureReport;
|
|
35
|
+
trace: AgentTrace | null;
|
|
36
|
+
outputDirectory: string;
|
|
37
|
+
paths: {
|
|
38
|
+
capturedTracePath: string;
|
|
39
|
+
captureReportJsonPath: string;
|
|
40
|
+
captureReportMarkdownPath: string;
|
|
41
|
+
};
|
|
42
|
+
terminalSummary: string;
|
|
43
|
+
}
|
|
44
|
+
interface NormalizationResult {
|
|
45
|
+
trace: AgentTrace;
|
|
46
|
+
eventsCaptured: number;
|
|
47
|
+
messagesCaptured: number;
|
|
48
|
+
toolOutputsCaptured: number;
|
|
49
|
+
tokenMetadataStatus: MetadataStatus;
|
|
50
|
+
costMetadataStatus: MetadataStatus;
|
|
51
|
+
usageMetadata: UsageMetadata;
|
|
52
|
+
spendConfidence: UsageMetadata["cost_confidence"];
|
|
53
|
+
pricingAssumptions: string[];
|
|
54
|
+
warnings: string[];
|
|
55
|
+
limitations: string[];
|
|
56
|
+
}
|
|
57
|
+
export declare function createOpenAIAgentsCaptureId(now?: Date): string;
|
|
58
|
+
export declare function normalizeOpenAIAgentsEvents(params: {
|
|
59
|
+
captureId: string;
|
|
60
|
+
commandRun?: LocalCommandRun;
|
|
61
|
+
rawOutput: string;
|
|
62
|
+
generatedAt?: string;
|
|
63
|
+
}): NormalizationResult;
|
|
64
|
+
export declare function captureOpenAIAgentsCommand(commandParts: string[], outRoot: string): Promise<OpenAIAgentsCaptureArtifacts>;
|
|
65
|
+
export declare function captureOpenAIAgentsExport(inputPath: string, outRoot: string): Promise<OpenAIAgentsCaptureArtifacts>;
|
|
66
|
+
export {};
|