avorelo 0.1.0 → 0.2.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 +23 -16
- package/README.md +91 -51
- package/bin/avorelo.mjs +7 -0
- package/dist/avorelo.mjs +14337 -0
- package/package.json +106 -120
- package/bin/avorelo +0 -9
- package/scripts/README.md +0 -40
- package/scripts/cco-dashboard.js +0 -252
- package/scripts/cco-status.js +0 -430
- package/scripts/lib/activation/account-state.js +0 -37
- package/scripts/lib/activation/activation-runner.js +0 -546
- package/scripts/lib/activation/activation-self-healing.js +0 -480
- package/scripts/lib/activation/activation-state.js +0 -83
- package/scripts/lib/activation/activation-summary.js +0 -191
- package/scripts/lib/activation/adapters/claude-code.js +0 -77
- package/scripts/lib/activation/adapters/codex-cli.js +0 -52
- package/scripts/lib/activation/adapters/cursor.js +0 -37
- package/scripts/lib/activation/adapters/github-agent.js +0 -39
- package/scripts/lib/activation/adapters/terminal.js +0 -42
- package/scripts/lib/activation/adapters/vscode.js +0 -39
- package/scripts/lib/activation/adapters/windsurf.js +0 -37
- package/scripts/lib/activation/ai-surface-detector.js +0 -151
- package/scripts/lib/activation/connect-account.js +0 -145
- package/scripts/lib/activation/detect-environment.js +0 -75
- package/scripts/lib/activation/detect-hosts.js +0 -62
- package/scripts/lib/activation/format-activation-output.js +0 -109
- package/scripts/lib/activation/next-action.js +0 -43
- package/scripts/lib/activation/repair-engine.js +0 -219
- package/scripts/lib/activation-distribution-readiness.js +0 -507
- package/scripts/lib/adapter-conformance.js +0 -176
- package/scripts/lib/adapter-readiness.js +0 -417
- package/scripts/lib/adapter-safety-boundaries.js +0 -335
- package/scripts/lib/adapter-technical-readiness-gate.js +0 -205
- package/scripts/lib/agent-access-governance.js +0 -455
- package/scripts/lib/agent-enforcement.js +0 -765
- package/scripts/lib/agent-policy-profile.js +0 -210
- package/scripts/lib/agent-security/action-evaluator.js +0 -507
- package/scripts/lib/agent-security/adapter-registry.js +0 -98
- package/scripts/lib/agent-security/auto-policy.js +0 -139
- package/scripts/lib/agent-security/bounded-scan.js +0 -93
- package/scripts/lib/agent-security/enforcement-adapter.js +0 -174
- package/scripts/lib/agent-security/enforcement-engine.js +0 -1129
- package/scripts/lib/agent-security/file-write-adapter.js +0 -183
- package/scripts/lib/agent-security/file-write-rules.js +0 -178
- package/scripts/lib/agent-security/index.js +0 -3342
- package/scripts/lib/agent-security/instruction-risk.js +0 -181
- package/scripts/lib/agent-security/mcp-action-adapter.js +0 -185
- package/scripts/lib/agent-security/mcp-action-rules.js +0 -184
- package/scripts/lib/agent-security/package-action-adapter.js +0 -175
- package/scripts/lib/agent-security/package-action-rules.js +0 -233
- package/scripts/lib/agent-security/performance.js +0 -148
- package/scripts/lib/agent-security/permission-minimizer.js +0 -403
- package/scripts/lib/agent-security/scan-cache.js +0 -74
- package/scripts/lib/agent-security/source-trust.js +0 -146
- package/scripts/lib/ai-install-prompt.js +0 -288
- package/scripts/lib/ai-workspace-hygiene.js +0 -1499
- package/scripts/lib/alpha-activation.js +0 -520
- package/scripts/lib/alpha-feedback.js +0 -263
- package/scripts/lib/alpha-readiness-gate.js +0 -332
- package/scripts/lib/anti-gaming.js +0 -169
- package/scripts/lib/artifact-health.js +0 -431
- package/scripts/lib/attribution.js +0 -180
- package/scripts/lib/audit.js +0 -289
- package/scripts/lib/avorelo-skill-registry.js +0 -810
- package/scripts/lib/batch-jobs.js +0 -71
- package/scripts/lib/brain-pack.js +0 -578
- package/scripts/lib/brand-boundary.js +0 -424
- package/scripts/lib/brand.js +0 -74
- package/scripts/lib/browser-capability.js +0 -1048
- package/scripts/lib/browser-proof-preflight.js +0 -321
- package/scripts/lib/cache-readiness.js +0 -187
- package/scripts/lib/canonical-reentry.js +0 -162
- package/scripts/lib/capability-packs.js +0 -314
- package/scripts/lib/capability-recommender.js +0 -512
- package/scripts/lib/capability-registry.js +0 -1059
- package/scripts/lib/carry-forward-surfacing.js +0 -194
- package/scripts/lib/ccusage-adapter.js +0 -188
- package/scripts/lib/company-loop.js +0 -1149
- package/scripts/lib/config.js +0 -637
- package/scripts/lib/context-acquisition-plan.js +0 -287
- package/scripts/lib/context-budget-guard.js +0 -170
- package/scripts/lib/context-budget-scanner.js +0 -257
- package/scripts/lib/context-optimizer.js +0 -715
- package/scripts/lib/context-reduction-plan.js +0 -178
- package/scripts/lib/context-safety.js +0 -88
- package/scripts/lib/context-savings-engine.js +0 -158
- package/scripts/lib/cost-evidence.js +0 -254
- package/scripts/lib/cross-host-install-plan.js +0 -308
- package/scripts/lib/cross-host-install-readiness.js +0 -237
- package/scripts/lib/cross-host-value-flow.js +0 -268
- package/scripts/lib/dashboard.js +0 -900
- package/scripts/lib/design-partner-feedback.js +0 -346
- package/scripts/lib/entitlements.js +0 -100
- package/scripts/lib/execution-packet.js +0 -559
- package/scripts/lib/experimentation-events.js +0 -547
- package/scripts/lib/external-capability-compliance.js +0 -107
- package/scripts/lib/external-user-simulation.js +0 -166
- package/scripts/lib/failure-recovery-readiness.js +0 -81
- package/scripts/lib/failure-recovery.js +0 -419
- package/scripts/lib/feedback-intelligence.js +0 -537
- package/scripts/lib/feedback-signals.js +0 -205
- package/scripts/lib/file-integrity.js +0 -68
- package/scripts/lib/fsx.js +0 -127
- package/scripts/lib/full-readiness-gate.js +0 -451
- package/scripts/lib/guidance-builder.js +0 -174
- package/scripts/lib/hook-apply.js +0 -1019
- package/scripts/lib/hook-baseline.js +0 -310
- package/scripts/lib/hook-config-preview.js +0 -275
- package/scripts/lib/hook-contracts.js +0 -290
- package/scripts/lib/hook-safety-boundary-readiness.js +0 -80
- package/scripts/lib/host-capability-matrix.js +0 -351
- package/scripts/lib/host-support-context.js +0 -254
- package/scripts/lib/http-hook-action.js +0 -538
- package/scripts/lib/install-ai-readiness.js +0 -84
- package/scripts/lib/install-intake-risk.js +0 -1037
- package/scripts/lib/install-journey-intelligence.js +0 -329
- package/scripts/lib/intervention-guidance.js +0 -57
- package/scripts/lib/known-limitations.js +0 -115
- package/scripts/lib/l8-path-truth.js +0 -146
- package/scripts/lib/launch-hardening-gate.js +0 -436
- package/scripts/lib/launch-readiness.js +0 -628
- package/scripts/lib/learning-memory.js +0 -686
- package/scripts/lib/lifecycle-hooks.js +0 -802
- package/scripts/lib/local-package-smoke.js +0 -423
- package/scripts/lib/local-pricing.js +0 -299
- package/scripts/lib/mcp-enforcement.js +0 -311
- package/scripts/lib/mcp-least-privilege-policy.js +0 -303
- package/scripts/lib/mcp-tool-inventory.js +0 -388
- package/scripts/lib/mcp-tool-risk.js +0 -0
- package/scripts/lib/memory.js +0 -335
- package/scripts/lib/metrics.js +0 -699
- package/scripts/lib/micro-proof.js +0 -133
- package/scripts/lib/next-run-context.js +0 -436
- package/scripts/lib/operating-value.js +0 -1648
- package/scripts/lib/optimization-v3.js +0 -122
- package/scripts/lib/orchestration/adapters/_shared.js +0 -49
- package/scripts/lib/orchestration/adapters/aider.js +0 -18
- package/scripts/lib/orchestration/adapters/claude-code.js +0 -35
- package/scripts/lib/orchestration/adapters/codex.js +0 -35
- package/scripts/lib/orchestration/adapters/gemini-cli.js +0 -18
- package/scripts/lib/orchestration/adapters/git.js +0 -25
- package/scripts/lib/orchestration/adapters/index.js +0 -31
- package/scripts/lib/orchestration/adapters/lm-studio.js +0 -18
- package/scripts/lib/orchestration/adapters/ollama.js +0 -18
- package/scripts/lib/orchestration/adapters/opencode.js +0 -18
- package/scripts/lib/orchestration/adapters/openrouter.js +0 -18
- package/scripts/lib/orchestration/adapters/test-runner.js +0 -25
- package/scripts/lib/orchestration/cli.js +0 -438
- package/scripts/lib/orchestration/execution-manager.js +0 -279
- package/scripts/lib/orchestration/handoff.js +0 -314
- package/scripts/lib/orchestration/index.js +0 -456
- package/scripts/lib/orchestration/inventory.js +0 -47
- package/scripts/lib/orchestration/model-discovery.js +0 -498
- package/scripts/lib/orchestration/model-profiler.js +0 -170
- package/scripts/lib/orchestration/model-profiles.js +0 -252
- package/scripts/lib/orchestration/model-refresh-policy.js +0 -72
- package/scripts/lib/orchestration/proof-writer.js +0 -349
- package/scripts/lib/orchestration/provider-discovery/aider.js +0 -49
- package/scripts/lib/orchestration/provider-discovery/claude-code.js +0 -56
- package/scripts/lib/orchestration/provider-discovery/codex.js +0 -49
- package/scripts/lib/orchestration/provider-discovery/common.js +0 -186
- package/scripts/lib/orchestration/provider-discovery/gemini.js +0 -106
- package/scripts/lib/orchestration/provider-discovery/lm-studio.js +0 -118
- package/scripts/lib/orchestration/provider-discovery/models-dev.js +0 -12
- package/scripts/lib/orchestration/provider-discovery/ollama.js +0 -100
- package/scripts/lib/orchestration/provider-discovery/opencode.js +0 -47
- package/scripts/lib/orchestration/provider-discovery/openrouter.js +0 -44
- package/scripts/lib/orchestration/risk-classifier.js +0 -130
- package/scripts/lib/orchestration/routing-policy.js +0 -486
- package/scripts/lib/orchestration/settings.js +0 -112
- package/scripts/lib/orchestration/state.js +0 -165
- package/scripts/lib/orchestration/verification-manager.js +0 -138
- package/scripts/lib/output-profiles.js +0 -146
- package/scripts/lib/package-content-audit.js +0 -368
- package/scripts/lib/package-runtime.js +0 -278
- package/scripts/lib/plan-surface.js +0 -53
- package/scripts/lib/plans.js +0 -2318
- package/scripts/lib/policy-provider.js +0 -27
- package/scripts/lib/prelaunch-activation-readiness.js +0 -409
- package/scripts/lib/prelaunch-evidence-store.js +0 -816
- package/scripts/lib/prelaunch-intelligence.js +0 -869
- package/scripts/lib/pricing-experiment.js +0 -118
- package/scripts/lib/pro-moment-events.js +0 -77
- package/scripts/lib/pro-moment-state.js +0 -227
- package/scripts/lib/pro-moments.js +0 -1216
- package/scripts/lib/product-learning-events.js +0 -629
- package/scripts/lib/project-profile.js +0 -555
- package/scripts/lib/prompt-compiler.js +0 -280
- package/scripts/lib/prompt-lint.js +0 -32
- package/scripts/lib/prompt-suggestions.js +0 -52
- package/scripts/lib/proof-canonical.js +0 -398
- package/scripts/lib/proof-drilldown.js +0 -383
- package/scripts/lib/proof-events.js +0 -342
- package/scripts/lib/proof-history.js +0 -243
- package/scripts/lib/proof-metrics.js +0 -296
- package/scripts/lib/proof-outcome-evidence.js +0 -134
- package/scripts/lib/proof-receipt.js +0 -335
- package/scripts/lib/proof-record.js +0 -461
- package/scripts/lib/public-activation-distribution-gate.js +0 -258
- package/scripts/lib/public-cli.js +0 -3891
- package/scripts/lib/public-distribution-truth.js +0 -211
- package/scripts/lib/public-install-claim-checker.js +0 -294
- package/scripts/lib/publish-provenance-readiness.js +0 -283
- package/scripts/lib/readiness-delta.js +0 -218
- package/scripts/lib/readiness-evidence-closure.js +0 -196
- package/scripts/lib/reentry-memory-capture.js +0 -241
- package/scripts/lib/reentry-memory-retrieval.js +0 -302
- package/scripts/lib/reentry-memory-status.js +0 -146
- package/scripts/lib/reentry-memory-store.js +0 -178
- package/scripts/lib/reentry-state.js +0 -66
- package/scripts/lib/release-candidate-bundle.js +0 -166
- package/scripts/lib/remediation.js +0 -81
- package/scripts/lib/repo-map.js +0 -391
- package/scripts/lib/run-improvements-lifecycle.js +0 -330
- package/scripts/lib/run-improvements.js +0 -789
- package/scripts/lib/runtime-decision-policy.js +0 -387
- package/scripts/lib/safe-path-engine.js +0 -705
- package/scripts/lib/safe-run-controller.js +0 -887
- package/scripts/lib/score.js +0 -262
- package/scripts/lib/seamless-enforcement.js +0 -329
- package/scripts/lib/seamless-outcome.js +0 -689
- package/scripts/lib/seamless-reality-gate.js +0 -5043
- package/scripts/lib/security-risk-classifier.js +0 -511
- package/scripts/lib/security-scan.js +0 -384
- package/scripts/lib/session-context-optimizer.js +0 -1211
- package/scripts/lib/session-timing.js +0 -315
- package/scripts/lib/skill-hygiene.js +0 -805
- package/scripts/lib/skill-packs.js +0 -161
- package/scripts/lib/skills-operating-layer.js +0 -580
- package/scripts/lib/smart-work-routing.js +0 -768
- package/scripts/lib/source-catalog.js +0 -700
- package/scripts/lib/status-value-summary.js +0 -32
- package/scripts/lib/support-bundle.js +0 -578
- package/scripts/lib/task-continuation.js +0 -440
- package/scripts/lib/test-helpers.js +0 -15
- package/scripts/lib/tier.js +0 -38
- package/scripts/lib/token-context-quality-gate.js +0 -370
- package/scripts/lib/token-cost-capture.js +0 -187
- package/scripts/lib/token-cost-intelligence.js +0 -358
- package/scripts/lib/token-efficiency-evidence.js +0 -213
- package/scripts/lib/token-evidence.js +0 -699
- package/scripts/lib/tokenish.js +0 -17
- package/scripts/lib/tool-output-sandbox.js +0 -304
- package/scripts/lib/trust-audit.js +0 -136
- package/scripts/lib/unified-events.js +0 -396
- package/scripts/lib/upgrade-interruption-recovery.js +0 -407
- package/scripts/lib/usage-ledger.js +0 -201
- package/scripts/lib/value-ledger.js +0 -130
- package/scripts/lib/value-proof-calibration.js +0 -531
- package/scripts/lib/visual-qa.js +0 -231
- package/scripts/lib/voice-alpha.js +0 -29
- package/scripts/lib/work-aware-orchestration.js +0 -976
- package/scripts/lib/work-control-receipts.js +0 -577
- package/scripts/lib/work-ledger.js +0 -1123
- package/scripts/lib/work-panel-preview.js +0 -352
- package/scripts/lib/workflow-discipline.js +0 -280
- package/scripts/lib/workflow-signals.js +0 -419
- package/scripts/lib/workspace-map.js +0 -281
- package/scripts/lib/workspace-registry.js +0 -1367
- package/scripts/lib/workspace-resolver.js +0 -480
|
@@ -1,816 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
const fs = require("fs");
|
|
4
|
-
const path = require("path");
|
|
5
|
-
const crypto = require("crypto");
|
|
6
|
-
|
|
7
|
-
const { ensureCcoDirs, nowIso } = require("./fsx");
|
|
8
|
-
const { redactPayload, redactString } = require("./product-learning-events");
|
|
9
|
-
|
|
10
|
-
const FEEDBACK_EVIDENCE_DIR_REL = ".claude/cco/evidence/feedback";
|
|
11
|
-
const FEEDBACK_EVIDENCE_JSONL_REL = `${FEEDBACK_EVIDENCE_DIR_REL}/feedback.jsonl`;
|
|
12
|
-
const FEEDBACK_IMPORT_RECEIPT_REL = `${FEEDBACK_EVIDENCE_DIR_REL}/latest-import.json`;
|
|
13
|
-
const FEEDBACK_INTAKE_PACK_DIR_REL = `${FEEDBACK_EVIDENCE_DIR_REL}/intake-pack`;
|
|
14
|
-
const FEEDBACK_INTAKE_PACK_RECEIPT_REL = `${FEEDBACK_INTAKE_PACK_DIR_REL}/latest-pack.json`;
|
|
15
|
-
const FEEDBACK_INTAKE_PACK_README_REL = `${FEEDBACK_INTAKE_PACK_DIR_REL}/README.md`;
|
|
16
|
-
const FEEDBACK_INTAKE_PACK_TEMPLATE_REL = `${FEEDBACK_INTAKE_PACK_DIR_REL}/design-partner-feedback-template.md`;
|
|
17
|
-
const FEEDBACK_INTAKE_PACK_CHECKLIST_REL = `${FEEDBACK_INTAKE_PACK_DIR_REL}/redaction-checklist.md`;
|
|
18
|
-
|
|
19
|
-
const TOKEN_COST_EVIDENCE_DIR_REL = ".claude/cco/evidence/token-cost";
|
|
20
|
-
const TOKEN_COST_EVIDENCE_JSONL_REL = `${TOKEN_COST_EVIDENCE_DIR_REL}/token-cost.jsonl`;
|
|
21
|
-
const TOKEN_COST_CAPTURE_JSONL_REL = `${TOKEN_COST_EVIDENCE_DIR_REL}/capture.jsonl`;
|
|
22
|
-
const TOKEN_COST_IMPORT_RECEIPT_REL = `${TOKEN_COST_EVIDENCE_DIR_REL}/latest-import.json`;
|
|
23
|
-
const TOKEN_COST_CAPTURE_RECEIPT_REL = `${TOKEN_COST_EVIDENCE_DIR_REL}/latest-capture.json`;
|
|
24
|
-
const TOKEN_COST_SUMMARY_REL = `${TOKEN_COST_EVIDENCE_DIR_REL}/summary.json`;
|
|
25
|
-
|
|
26
|
-
const FEEDBACK_ITEM_CONTRACT = "avorelo.feedbackEvidenceItem.v1";
|
|
27
|
-
const FEEDBACK_VALIDATION_CONTRACT = "avorelo.feedbackEvidenceValidation.v1";
|
|
28
|
-
const FEEDBACK_INTAKE_PACK_CONTRACT = "avorelo.designPartnerFeedbackIntakePack.v1";
|
|
29
|
-
const TOKEN_COST_ITEM_CONTRACT = "avorelo.tokenCostEvidenceItem.v1";
|
|
30
|
-
const TOKEN_COST_VALIDATION_CONTRACT = "avorelo.tokenCostEvidenceValidation.v1";
|
|
31
|
-
const TOKEN_COST_SUMMARY_CONTRACT = "avorelo.tokenCostEvidence.v1";
|
|
32
|
-
|
|
33
|
-
const FEEDBACK_ALLOWED_KEYS = new Set([
|
|
34
|
-
"sourceType",
|
|
35
|
-
"date",
|
|
36
|
-
"persona",
|
|
37
|
-
"segment",
|
|
38
|
-
"theme",
|
|
39
|
-
"severity",
|
|
40
|
-
"quoteSummary",
|
|
41
|
-
"issueCategory",
|
|
42
|
-
"activationStage",
|
|
43
|
-
"trustConcern",
|
|
44
|
-
"pricingConcern",
|
|
45
|
-
"simulated",
|
|
46
|
-
"redacted",
|
|
47
|
-
]);
|
|
48
|
-
|
|
49
|
-
const TOKEN_COST_ALLOWED_KEYS = new Set([
|
|
50
|
-
"sourceType",
|
|
51
|
-
"capturedAt",
|
|
52
|
-
"runId",
|
|
53
|
-
"tool",
|
|
54
|
-
"taskType",
|
|
55
|
-
"modelProvider",
|
|
56
|
-
"modelName",
|
|
57
|
-
"provider",
|
|
58
|
-
"modelFamily",
|
|
59
|
-
"inputTokens",
|
|
60
|
-
"outputTokens",
|
|
61
|
-
"promptTokens",
|
|
62
|
-
"completionTokens",
|
|
63
|
-
"totalTokens",
|
|
64
|
-
"estimatedCostUsd",
|
|
65
|
-
"measuredCostUsd",
|
|
66
|
-
"costMicros",
|
|
67
|
-
"currency",
|
|
68
|
-
"evidenceMode",
|
|
69
|
-
"confidence",
|
|
70
|
-
"notesCategory",
|
|
71
|
-
"cacheHit",
|
|
72
|
-
"estimatedOnly",
|
|
73
|
-
"heuristic",
|
|
74
|
-
"redacted",
|
|
75
|
-
]);
|
|
76
|
-
|
|
77
|
-
const FEEDBACK_FORBIDDEN_KEYS = [
|
|
78
|
-
"prompt",
|
|
79
|
-
"promptText",
|
|
80
|
-
"rawPrompt",
|
|
81
|
-
"quote",
|
|
82
|
-
"rawQuote",
|
|
83
|
-
"transcript",
|
|
84
|
-
"code",
|
|
85
|
-
"rawCode",
|
|
86
|
-
"commandOutput",
|
|
87
|
-
"stack",
|
|
88
|
-
"path",
|
|
89
|
-
"filePath",
|
|
90
|
-
"repoContent",
|
|
91
|
-
"secret",
|
|
92
|
-
"apiKey",
|
|
93
|
-
"token",
|
|
94
|
-
];
|
|
95
|
-
|
|
96
|
-
const TOKEN_COST_FORBIDDEN_KEYS = [
|
|
97
|
-
"prompt",
|
|
98
|
-
"promptText",
|
|
99
|
-
"rawPrompt",
|
|
100
|
-
"completion",
|
|
101
|
-
"completionText",
|
|
102
|
-
"code",
|
|
103
|
-
"rawCode",
|
|
104
|
-
"commandOutput",
|
|
105
|
-
"stack",
|
|
106
|
-
"path",
|
|
107
|
-
"filePath",
|
|
108
|
-
"repoContent",
|
|
109
|
-
"secret",
|
|
110
|
-
"apiKey",
|
|
111
|
-
"accessToken",
|
|
112
|
-
"authorization",
|
|
113
|
-
];
|
|
114
|
-
|
|
115
|
-
function sha256(value) {
|
|
116
|
-
return crypto.createHash("sha256").update(String(value || "")).digest("hex");
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
function safeReadJson(absPath) {
|
|
120
|
-
try {
|
|
121
|
-
if (!fs.existsSync(absPath)) return null;
|
|
122
|
-
return JSON.parse(fs.readFileSync(absPath, "utf8").replace(/^\uFEFF/, ""));
|
|
123
|
-
} catch {
|
|
124
|
-
return null;
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
function safeReadJsonl(absPath) {
|
|
129
|
-
try {
|
|
130
|
-
if (!fs.existsSync(absPath)) return [];
|
|
131
|
-
return fs
|
|
132
|
-
.readFileSync(absPath, "utf8")
|
|
133
|
-
.split("\n")
|
|
134
|
-
.map((line) => line.trim())
|
|
135
|
-
.filter(Boolean)
|
|
136
|
-
.map((line) => {
|
|
137
|
-
try {
|
|
138
|
-
return JSON.parse(line);
|
|
139
|
-
} catch {
|
|
140
|
-
return null;
|
|
141
|
-
}
|
|
142
|
-
})
|
|
143
|
-
.filter(Boolean);
|
|
144
|
-
} catch {
|
|
145
|
-
return [];
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
function ensureDir(cwd, rel) {
|
|
150
|
-
ensureCcoDirs(cwd);
|
|
151
|
-
const abs = path.join(cwd, rel);
|
|
152
|
-
fs.mkdirSync(abs, { recursive: true });
|
|
153
|
-
return abs;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
function appendJsonl(absPath, items) {
|
|
157
|
-
if (!items.length) {
|
|
158
|
-
if (!fs.existsSync(absPath)) fs.writeFileSync(absPath, "", "utf8");
|
|
159
|
-
return;
|
|
160
|
-
}
|
|
161
|
-
const lines = items.map((item) => JSON.stringify(item)).join("\n") + "\n";
|
|
162
|
-
fs.appendFileSync(absPath, lines, "utf8");
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
function readImportInput(absPath) {
|
|
166
|
-
const raw = fs.readFileSync(absPath, "utf8").replace(/^\uFEFF/, "").trim();
|
|
167
|
-
if (!raw) return [];
|
|
168
|
-
if (raw.startsWith("[")) {
|
|
169
|
-
const parsed = JSON.parse(raw);
|
|
170
|
-
return Array.isArray(parsed) ? parsed : [parsed];
|
|
171
|
-
}
|
|
172
|
-
if (raw.startsWith("{")) {
|
|
173
|
-
return [JSON.parse(raw)];
|
|
174
|
-
}
|
|
175
|
-
return raw
|
|
176
|
-
.split("\n")
|
|
177
|
-
.map((line) => line.trim())
|
|
178
|
-
.filter(Boolean)
|
|
179
|
-
.map((line) => JSON.parse(line));
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
function summarizeRejectedRows(rejected) {
|
|
183
|
-
const counts = {};
|
|
184
|
-
rejected.forEach((item) => {
|
|
185
|
-
item.reasons.forEach((reason) => {
|
|
186
|
-
counts[reason] = (counts[reason] || 0) + 1;
|
|
187
|
-
});
|
|
188
|
-
});
|
|
189
|
-
return Object.entries(counts).map(([reason, count]) => ({ reason, count }));
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
function redactPathValue(value) {
|
|
193
|
-
const redacted = redactPayload({ filePath: value });
|
|
194
|
-
return redacted.filePath || "[redacted-path]";
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
function sanitizeText(value, max = 240) {
|
|
198
|
-
return redactString(String(value || "").slice(0, max).replace(/[\x00-\x08\x0b\x0c\x0e-\x1f]/g, "")).trim();
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
function sanitizeBoolean(value) {
|
|
202
|
-
return value === true;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
function sanitizeNumber(value) {
|
|
206
|
-
if (value === null || value === undefined || value === "") return null;
|
|
207
|
-
const num = Number(value);
|
|
208
|
-
return Number.isFinite(num) ? num : null;
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
function sanitizeEnum(value, allowed, fallback = null) {
|
|
212
|
-
const normalized = sanitizeText(value || "", 64).toLowerCase();
|
|
213
|
-
if (!normalized) return fallback;
|
|
214
|
-
return allowed.has(normalized) ? normalized : fallback;
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
function findForbiddenKeys(row, forbiddenKeys) {
|
|
218
|
-
return Object.keys(row || {}).filter((key) => {
|
|
219
|
-
if (!forbiddenKeys.includes(key)) return false;
|
|
220
|
-
const value = row[key];
|
|
221
|
-
return value !== null && value !== undefined && String(value).trim() !== "";
|
|
222
|
-
});
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
function findUnknownKeys(row, allowedKeys) {
|
|
226
|
-
return Object.keys(row || {}).filter((key) => !allowedKeys.has(key));
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
function baseImportReceipt(contract, sourceFile, accepted, rejected, outputRel, itemContract) {
|
|
230
|
-
return {
|
|
231
|
-
contract,
|
|
232
|
-
schemaVersion: 1,
|
|
233
|
-
createdAt: nowIso(),
|
|
234
|
-
sourceFile: redactPathValue(sourceFile),
|
|
235
|
-
sourceFileHash: sha256(sourceFile),
|
|
236
|
-
acceptedCount: accepted.length,
|
|
237
|
-
rejectedCount: rejected.length,
|
|
238
|
-
rejectedReasonSummary: summarizeRejectedRows(rejected),
|
|
239
|
-
outputPath: outputRel,
|
|
240
|
-
itemContract,
|
|
241
|
-
redacted: true,
|
|
242
|
-
};
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
function normalizeFeedbackRow(row, index) {
|
|
246
|
-
const rejected = [];
|
|
247
|
-
if (!row || typeof row !== "object" || Array.isArray(row)) {
|
|
248
|
-
return { ok: false, reasons: ["row_not_object"], index };
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
const forbidden = findForbiddenKeys(row, FEEDBACK_FORBIDDEN_KEYS);
|
|
252
|
-
if (forbidden.length) rejected.push("forbidden_feedback_field");
|
|
253
|
-
|
|
254
|
-
const unknown = findUnknownKeys(row, FEEDBACK_ALLOWED_KEYS);
|
|
255
|
-
if (unknown.length) rejected.push("unknown_feedback_field");
|
|
256
|
-
|
|
257
|
-
const sourceType = sanitizeText(row.sourceType || "manual_import", 48);
|
|
258
|
-
const severity = sanitizeText(row.severity || "medium", 16).toLowerCase();
|
|
259
|
-
const quoteSummary = sanitizeText(row.quoteSummary || "", 240);
|
|
260
|
-
const theme = sanitizeText(row.theme || row.issueCategory || "", 64);
|
|
261
|
-
const issueCategory = sanitizeText(row.issueCategory || row.theme || "other", 64);
|
|
262
|
-
|
|
263
|
-
if (!quoteSummary) rejected.push("quote_summary_required");
|
|
264
|
-
if (!theme) rejected.push("theme_required");
|
|
265
|
-
if (!["low", "medium", "high", "blocker"].includes(severity)) rejected.push("invalid_severity");
|
|
266
|
-
|
|
267
|
-
if (rejected.length) {
|
|
268
|
-
return { ok: false, reasons: rejected, index };
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
const simulated = sanitizeBoolean(row.simulated) || sourceType.toLowerCase().includes("sim");
|
|
272
|
-
|
|
273
|
-
return {
|
|
274
|
-
ok: true,
|
|
275
|
-
value: {
|
|
276
|
-
contract: FEEDBACK_ITEM_CONTRACT,
|
|
277
|
-
schemaVersion: 1,
|
|
278
|
-
importedAt: nowIso(),
|
|
279
|
-
sourceType,
|
|
280
|
-
date: sanitizeText(row.date || nowIso(), 40),
|
|
281
|
-
persona: sanitizeText(row.persona || "unknown", 48) || "unknown",
|
|
282
|
-
segment: sanitizeText(row.segment || "unknown", 64) || "unknown",
|
|
283
|
-
theme,
|
|
284
|
-
severity,
|
|
285
|
-
quoteSummary,
|
|
286
|
-
issueCategory,
|
|
287
|
-
activationStage: sanitizeText(row.activationStage || "unknown", 48) || "unknown",
|
|
288
|
-
trustConcern: sanitizeBoolean(row.trustConcern),
|
|
289
|
-
pricingConcern: sanitizeBoolean(row.pricingConcern),
|
|
290
|
-
simulated,
|
|
291
|
-
redacted: true,
|
|
292
|
-
},
|
|
293
|
-
};
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
function normalizeTokenCostRow(row, index) {
|
|
297
|
-
const rejected = [];
|
|
298
|
-
if (!row || typeof row !== "object" || Array.isArray(row)) {
|
|
299
|
-
return { ok: false, reasons: ["row_not_object"], index };
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
const forbidden = findForbiddenKeys(row, TOKEN_COST_FORBIDDEN_KEYS);
|
|
303
|
-
if (forbidden.length) rejected.push("forbidden_token_cost_field");
|
|
304
|
-
|
|
305
|
-
const unknown = findUnknownKeys(row, TOKEN_COST_ALLOWED_KEYS);
|
|
306
|
-
if (unknown.length) rejected.push("unknown_token_cost_field");
|
|
307
|
-
|
|
308
|
-
const sourceType = sanitizeText(row.sourceType || "manual_import", 48);
|
|
309
|
-
const capturedAt = sanitizeText(row.capturedAt || nowIso(), 40);
|
|
310
|
-
const inputTokens = sanitizeNumber(row.inputTokens != null ? row.inputTokens : row.promptTokens);
|
|
311
|
-
const outputTokens = sanitizeNumber(row.outputTokens != null ? row.outputTokens : row.completionTokens);
|
|
312
|
-
const totalTokens = sanitizeNumber(row.totalTokens != null ? row.totalTokens : ((inputTokens || 0) + (outputTokens || 0)));
|
|
313
|
-
const estimatedCostUsd = sanitizeNumber(row.estimatedCostUsd);
|
|
314
|
-
const measuredCostUsd = sanitizeNumber(row.measuredCostUsd);
|
|
315
|
-
const costMicros = sanitizeNumber(row.costMicros);
|
|
316
|
-
const currency = sanitizeText(row.currency || (estimatedCostUsd != null || measuredCostUsd != null || costMicros != null ? "USD" : ""), 8);
|
|
317
|
-
const tool = sanitizeText(row.tool || "unknown", 48) || "unknown";
|
|
318
|
-
const taskType = sanitizeText(row.taskType || "unknown", 48) || "unknown";
|
|
319
|
-
const provider = sanitizeText(row.provider || row.modelProvider || "unknown", 24) || "unknown";
|
|
320
|
-
const modelFamily = sanitizeText(row.modelFamily || row.modelName || "unknown", 48) || "unknown";
|
|
321
|
-
const notesCategory = sanitizeText(row.notesCategory || "general", 32) || "general";
|
|
322
|
-
const explicitMode = sanitizeEnum(row.evidenceMode, new Set(["measured", "estimated", "heuristic", "missing"]), null);
|
|
323
|
-
const explicitConfidence = sanitizeEnum(row.confidence, new Set(["measured", "estimated", "heuristic", "missing"]), null);
|
|
324
|
-
const estimatedOnly = sanitizeBoolean(row.estimatedOnly);
|
|
325
|
-
const heuristic = sanitizeBoolean(row.heuristic);
|
|
326
|
-
const hasMeasuredCost = measuredCostUsd !== null || costMicros !== null;
|
|
327
|
-
const hasEstimatedCost = estimatedCostUsd !== null;
|
|
328
|
-
const hasTokenTotals = totalTokens !== null;
|
|
329
|
-
|
|
330
|
-
if (totalTokens === null) rejected.push("token_fields_required");
|
|
331
|
-
if (!hasMeasuredCost && !hasEstimatedCost) rejected.push("cost_fields_missing");
|
|
332
|
-
|
|
333
|
-
let evidenceMode = explicitMode;
|
|
334
|
-
if (!evidenceMode) {
|
|
335
|
-
if (heuristic) evidenceMode = "heuristic";
|
|
336
|
-
else if (hasMeasuredCost && hasTokenTotals && !estimatedOnly) evidenceMode = "measured";
|
|
337
|
-
else if (hasEstimatedCost && hasTokenTotals) evidenceMode = "estimated";
|
|
338
|
-
else if (hasTokenTotals) evidenceMode = "heuristic";
|
|
339
|
-
else evidenceMode = "missing";
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
if (evidenceMode === "measured" && !hasMeasuredCost) rejected.push("measured_cost_required");
|
|
343
|
-
if (evidenceMode === "estimated" && !hasMeasuredCost && !hasEstimatedCost) rejected.push("estimated_cost_required");
|
|
344
|
-
|
|
345
|
-
const hardRejectReasons = rejected.filter((reason) => reason !== "cost_fields_missing");
|
|
346
|
-
if (hardRejectReasons.length) {
|
|
347
|
-
return { ok: false, reasons: rejected, index };
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
let confidence = explicitConfidence;
|
|
351
|
-
if (!confidence) {
|
|
352
|
-
if (evidenceMode === "measured") confidence = "measured";
|
|
353
|
-
else if (evidenceMode === "estimated") confidence = "estimated";
|
|
354
|
-
else if (evidenceMode === "heuristic") confidence = "heuristic";
|
|
355
|
-
else confidence = "missing";
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
return {
|
|
359
|
-
ok: true,
|
|
360
|
-
value: {
|
|
361
|
-
contract: TOKEN_COST_ITEM_CONTRACT,
|
|
362
|
-
schemaVersion: 1,
|
|
363
|
-
importedAt: nowIso(),
|
|
364
|
-
sourceType,
|
|
365
|
-
capturedAt,
|
|
366
|
-
runIdHash: row.runId ? sha256(row.runId) : null,
|
|
367
|
-
tool,
|
|
368
|
-
taskType,
|
|
369
|
-
provider,
|
|
370
|
-
modelFamily,
|
|
371
|
-
modelProvider: provider,
|
|
372
|
-
modelName: modelFamily,
|
|
373
|
-
inputTokens,
|
|
374
|
-
outputTokens,
|
|
375
|
-
promptTokens: inputTokens,
|
|
376
|
-
completionTokens: outputTokens,
|
|
377
|
-
totalTokens,
|
|
378
|
-
estimatedCostUsd,
|
|
379
|
-
measuredCostUsd,
|
|
380
|
-
costMicros,
|
|
381
|
-
currency: currency || null,
|
|
382
|
-
evidenceMode,
|
|
383
|
-
confidence,
|
|
384
|
-
notesCategory,
|
|
385
|
-
cacheHit: sanitizeBoolean(row.cacheHit),
|
|
386
|
-
estimatedOnly,
|
|
387
|
-
heuristic: heuristic || evidenceMode === "heuristic",
|
|
388
|
-
redacted: true,
|
|
389
|
-
},
|
|
390
|
-
warnings: rejected,
|
|
391
|
-
};
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
function importFeedbackEvidence(cwd, sourceFile) {
|
|
395
|
-
const sourceAbs = path.resolve(sourceFile);
|
|
396
|
-
const evaluated = evaluateFeedbackRows(sourceAbs);
|
|
397
|
-
const accepted = evaluated.accepted;
|
|
398
|
-
const rejected = evaluated.rejected;
|
|
399
|
-
|
|
400
|
-
ensureDir(cwd, FEEDBACK_EVIDENCE_DIR_REL);
|
|
401
|
-
appendJsonl(path.join(cwd, FEEDBACK_EVIDENCE_JSONL_REL), accepted);
|
|
402
|
-
|
|
403
|
-
const receipt = {
|
|
404
|
-
...baseImportReceipt(
|
|
405
|
-
"avorelo.feedbackEvidenceImport.v1",
|
|
406
|
-
sourceAbs,
|
|
407
|
-
accepted,
|
|
408
|
-
rejected,
|
|
409
|
-
FEEDBACK_EVIDENCE_JSONL_REL,
|
|
410
|
-
FEEDBACK_ITEM_CONTRACT
|
|
411
|
-
),
|
|
412
|
-
safeNextActions: accepted.length
|
|
413
|
-
? ["Run: node bin/avorelo feedback insights --json"]
|
|
414
|
-
: ["Fix rejected rows, then rerun: node bin/avorelo feedback import --file <path> --json"],
|
|
415
|
-
};
|
|
416
|
-
fs.writeFileSync(path.join(cwd, FEEDBACK_IMPORT_RECEIPT_REL), JSON.stringify(receipt, null, 2), "utf8");
|
|
417
|
-
return receipt;
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
function evaluateFeedbackRows(sourceAbs) {
|
|
421
|
-
const rows = readImportInput(sourceAbs);
|
|
422
|
-
const accepted = [];
|
|
423
|
-
const rejected = [];
|
|
424
|
-
rows.forEach((row, index) => {
|
|
425
|
-
const normalized = normalizeFeedbackRow(row, index);
|
|
426
|
-
if (normalized.ok) accepted.push(normalized.value);
|
|
427
|
-
else rejected.push({ index, reasons: normalized.reasons });
|
|
428
|
-
});
|
|
429
|
-
return { rows, accepted, rejected };
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
function validateFeedbackEvidence(cwd, sourceFile) {
|
|
433
|
-
const sourceAbs = path.resolve(sourceFile);
|
|
434
|
-
const evaluated = evaluateFeedbackRows(sourceAbs);
|
|
435
|
-
return {
|
|
436
|
-
contract: FEEDBACK_VALIDATION_CONTRACT,
|
|
437
|
-
schemaVersion: 1,
|
|
438
|
-
createdAt: nowIso(),
|
|
439
|
-
sourceFile: redactPathValue(sourceAbs),
|
|
440
|
-
sourceFileHash: sha256(sourceAbs),
|
|
441
|
-
acceptedCount: evaluated.accepted.length,
|
|
442
|
-
rejectedCount: evaluated.rejected.length,
|
|
443
|
-
rejectedReasonSummary: summarizeRejectedRows(evaluated.rejected),
|
|
444
|
-
outputPath: FEEDBACK_EVIDENCE_JSONL_REL,
|
|
445
|
-
writesPerformed: false,
|
|
446
|
-
itemContract: FEEDBACK_ITEM_CONTRACT,
|
|
447
|
-
safeNextActions: evaluated.accepted.length > 0 && evaluated.rejected.length === 0
|
|
448
|
-
? [
|
|
449
|
-
"Run: node bin/avorelo feedback import --file <redacted-json-or-jsonl> --json",
|
|
450
|
-
"Run: node bin/avorelo feedback insights --json",
|
|
451
|
-
]
|
|
452
|
-
: [
|
|
453
|
-
"Run: node bin/avorelo feedback intake-pack --json",
|
|
454
|
-
"Fix rejected rows, then rerun: node bin/avorelo feedback validate --file <path> --json",
|
|
455
|
-
],
|
|
456
|
-
redacted: true,
|
|
457
|
-
};
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
function buildFeedbackIntakePackReadme() {
|
|
461
|
-
return [
|
|
462
|
-
"# Design Partner Feedback Intake Pack",
|
|
463
|
-
"",
|
|
464
|
-
"Use this pack to collect redacted design-partner feedback without storing raw transcripts, raw prompts, raw code, secrets, or sensitive paths.",
|
|
465
|
-
"",
|
|
466
|
-
"## Safe flow",
|
|
467
|
-
"",
|
|
468
|
-
"1. Capture short redacted summaries only.",
|
|
469
|
-
"2. Use the template in `design-partner-feedback-template.md` to structure each row.",
|
|
470
|
-
"3. Validate your prepared file:",
|
|
471
|
-
" `node bin/avorelo feedback validate --file [redacted-json-or-jsonl] --json`",
|
|
472
|
-
"4. Import only after validation is clean:",
|
|
473
|
-
" `node bin/avorelo feedback import --file [redacted-json-or-jsonl] --json`",
|
|
474
|
-
"5. Rebuild readiness summaries:",
|
|
475
|
-
" `node bin/avorelo feedback insights --json`",
|
|
476
|
-
"",
|
|
477
|
-
"## What counts",
|
|
478
|
-
"",
|
|
479
|
-
"- real dogfood or design-partner observations",
|
|
480
|
-
"- redacted issue summaries",
|
|
481
|
-
"- activation stage, trust concern, and pricing concern metadata",
|
|
482
|
-
"",
|
|
483
|
-
"## What does not count",
|
|
484
|
-
"",
|
|
485
|
-
"- invented feedback",
|
|
486
|
-
"- simulated rows for readiness scoring",
|
|
487
|
-
"- raw interview transcripts",
|
|
488
|
-
"- raw customer quotes with sensitive data",
|
|
489
|
-
].join("\n");
|
|
490
|
-
}
|
|
491
|
-
|
|
492
|
-
function buildFeedbackIntakeTemplate() {
|
|
493
|
-
return [
|
|
494
|
-
"# Design Partner Feedback Template",
|
|
495
|
-
"",
|
|
496
|
-
"Create a JSON or JSONL file using rows like this:",
|
|
497
|
-
"",
|
|
498
|
-
"```json",
|
|
499
|
-
"{",
|
|
500
|
-
' "sourceType": "design_partner",',
|
|
501
|
-
' "date": "2026-05-18",',
|
|
502
|
-
' "persona": "developer",',
|
|
503
|
-
' "segment": "agency",',
|
|
504
|
-
' "theme": "install_confusion",',
|
|
505
|
-
' "severity": "high",',
|
|
506
|
-
' "quoteSummary": "Needed a clearer first-run install path after the initial setup.",',
|
|
507
|
-
' "issueCategory": "activation",',
|
|
508
|
-
' "activationStage": "first_run",',
|
|
509
|
-
' "trustConcern": true,',
|
|
510
|
-
' "pricingConcern": false,',
|
|
511
|
-
' "simulated": false',
|
|
512
|
-
"}",
|
|
513
|
-
"```",
|
|
514
|
-
"",
|
|
515
|
-
"Required fields:",
|
|
516
|
-
"",
|
|
517
|
-
"- `sourceType`",
|
|
518
|
-
"- `theme`",
|
|
519
|
-
"- `severity`",
|
|
520
|
-
"- `quoteSummary`",
|
|
521
|
-
"",
|
|
522
|
-
"Recommended fields:",
|
|
523
|
-
"",
|
|
524
|
-
"- `segment`",
|
|
525
|
-
"- `issueCategory`",
|
|
526
|
-
"- `activationStage`",
|
|
527
|
-
"- `trustConcern`",
|
|
528
|
-
"- `pricingConcern`",
|
|
529
|
-
"",
|
|
530
|
-
"Never include raw transcripts, file paths, code, prompts, secrets, or command output.",
|
|
531
|
-
].join("\n");
|
|
532
|
-
}
|
|
533
|
-
|
|
534
|
-
function buildFeedbackIntakeChecklist() {
|
|
535
|
-
return [
|
|
536
|
-
"# Redaction Checklist",
|
|
537
|
-
"",
|
|
538
|
-
"Before importing any feedback file, confirm:",
|
|
539
|
-
"",
|
|
540
|
-
"- no raw partner names or emails",
|
|
541
|
-
"- no raw company-private text",
|
|
542
|
-
"- no raw prompts",
|
|
543
|
-
"- no raw code",
|
|
544
|
-
"- no secrets or API keys",
|
|
545
|
-
"- no command output",
|
|
546
|
-
"- no Windows, Unix, or repo-local file paths",
|
|
547
|
-
"- no stack traces",
|
|
548
|
-
"- only short redacted quote summaries",
|
|
549
|
-
"",
|
|
550
|
-
"If you cannot safely summarize a note, leave it out until it can be redacted.",
|
|
551
|
-
].join("\n");
|
|
552
|
-
}
|
|
553
|
-
|
|
554
|
-
function generateFeedbackIntakePack(cwd) {
|
|
555
|
-
ensureDir(cwd, FEEDBACK_INTAKE_PACK_DIR_REL);
|
|
556
|
-
fs.writeFileSync(path.join(cwd, FEEDBACK_INTAKE_PACK_README_REL), buildFeedbackIntakePackReadme(), "utf8");
|
|
557
|
-
fs.writeFileSync(path.join(cwd, FEEDBACK_INTAKE_PACK_TEMPLATE_REL), buildFeedbackIntakeTemplate(), "utf8");
|
|
558
|
-
fs.writeFileSync(path.join(cwd, FEEDBACK_INTAKE_PACK_CHECKLIST_REL), buildFeedbackIntakeChecklist(), "utf8");
|
|
559
|
-
|
|
560
|
-
const receipt = {
|
|
561
|
-
contract: FEEDBACK_INTAKE_PACK_CONTRACT,
|
|
562
|
-
schemaVersion: 1,
|
|
563
|
-
createdAt: nowIso(),
|
|
564
|
-
status: "ready",
|
|
565
|
-
outputDir: FEEDBACK_INTAKE_PACK_DIR_REL,
|
|
566
|
-
files: [
|
|
567
|
-
{ id: "readme", path: FEEDBACK_INTAKE_PACK_README_REL, purpose: "safe intake steps" },
|
|
568
|
-
{ id: "template", path: FEEDBACK_INTAKE_PACK_TEMPLATE_REL, purpose: "structured field template" },
|
|
569
|
-
{ id: "checklist", path: FEEDBACK_INTAKE_PACK_CHECKLIST_REL, purpose: "redaction checklist" },
|
|
570
|
-
],
|
|
571
|
-
safeNextActions: [
|
|
572
|
-
"Run: node bin/avorelo feedback validate --file <redacted-json-or-jsonl> --json",
|
|
573
|
-
"Run: node bin/avorelo feedback import --file <redacted-json-or-jsonl> --json",
|
|
574
|
-
"Run: node bin/avorelo feedback insights --json",
|
|
575
|
-
],
|
|
576
|
-
noRawFeedbackRequested: true,
|
|
577
|
-
noPublicLaunchClaim: true,
|
|
578
|
-
redacted: true,
|
|
579
|
-
};
|
|
580
|
-
fs.writeFileSync(path.join(cwd, FEEDBACK_INTAKE_PACK_RECEIPT_REL), JSON.stringify(receipt, null, 2), "utf8");
|
|
581
|
-
return receipt;
|
|
582
|
-
}
|
|
583
|
-
|
|
584
|
-
function importTokenCostEvidence(cwd, sourceFile) {
|
|
585
|
-
const sourceAbs = path.resolve(sourceFile);
|
|
586
|
-
const evaluated = evaluateTokenCostRows(sourceAbs);
|
|
587
|
-
const accepted = evaluated.accepted;
|
|
588
|
-
const rejected = evaluated.rejected;
|
|
589
|
-
const warnings = evaluated.warnings;
|
|
590
|
-
|
|
591
|
-
ensureDir(cwd, TOKEN_COST_EVIDENCE_DIR_REL);
|
|
592
|
-
appendJsonl(path.join(cwd, TOKEN_COST_EVIDENCE_JSONL_REL), accepted);
|
|
593
|
-
const summary = writeTokenCostEvidenceSummary(cwd, buildTokenCostEvidenceSummary(cwd));
|
|
594
|
-
|
|
595
|
-
const receipt = {
|
|
596
|
-
...baseImportReceipt(
|
|
597
|
-
"avorelo.tokenCostEvidenceImport.v1",
|
|
598
|
-
sourceAbs,
|
|
599
|
-
accepted,
|
|
600
|
-
rejected,
|
|
601
|
-
TOKEN_COST_EVIDENCE_JSONL_REL,
|
|
602
|
-
TOKEN_COST_ITEM_CONTRACT
|
|
603
|
-
),
|
|
604
|
-
warningCount: warnings.length,
|
|
605
|
-
warningReasonSummary: summarizeRejectedRows(warnings),
|
|
606
|
-
summary,
|
|
607
|
-
safeNextActions: accepted.length
|
|
608
|
-
? ["Run: node bin/avorelo token-cost summary --json", "Run: node bin/avorelo token-cost --json"]
|
|
609
|
-
: ["Provide token totals and cost fields, then rerun: node bin/avorelo token-cost import --file <path> --json"],
|
|
610
|
-
redacted: true,
|
|
611
|
-
};
|
|
612
|
-
fs.writeFileSync(path.join(cwd, TOKEN_COST_IMPORT_RECEIPT_REL), JSON.stringify(receipt, null, 2), "utf8");
|
|
613
|
-
return receipt;
|
|
614
|
-
}
|
|
615
|
-
|
|
616
|
-
function evaluateTokenCostRows(sourceAbs) {
|
|
617
|
-
const rows = readImportInput(sourceAbs);
|
|
618
|
-
const accepted = [];
|
|
619
|
-
const rejected = [];
|
|
620
|
-
const warnings = [];
|
|
621
|
-
rows.forEach((row, index) => {
|
|
622
|
-
const normalized = normalizeTokenCostRow(row, index);
|
|
623
|
-
if (normalized.ok) {
|
|
624
|
-
accepted.push(normalized.value);
|
|
625
|
-
if (normalized.warnings && normalized.warnings.length) {
|
|
626
|
-
warnings.push({ index, reasons: normalized.warnings });
|
|
627
|
-
}
|
|
628
|
-
} else {
|
|
629
|
-
rejected.push({ index, reasons: normalized.reasons });
|
|
630
|
-
}
|
|
631
|
-
});
|
|
632
|
-
return { rows, accepted, rejected, warnings };
|
|
633
|
-
}
|
|
634
|
-
|
|
635
|
-
function validateTokenCostEvidence(cwd, sourceFile) {
|
|
636
|
-
const sourceAbs = path.resolve(sourceFile);
|
|
637
|
-
const evaluated = evaluateTokenCostRows(sourceAbs);
|
|
638
|
-
return {
|
|
639
|
-
contract: TOKEN_COST_VALIDATION_CONTRACT,
|
|
640
|
-
schemaVersion: 1,
|
|
641
|
-
createdAt: nowIso(),
|
|
642
|
-
sourceFile: redactPathValue(sourceAbs),
|
|
643
|
-
sourceFileHash: sha256(sourceAbs),
|
|
644
|
-
acceptedCount: evaluated.accepted.length,
|
|
645
|
-
rejectedCount: evaluated.rejected.length,
|
|
646
|
-
warningCount: evaluated.warnings.length,
|
|
647
|
-
rejectedReasonSummary: summarizeRejectedRows(evaluated.rejected),
|
|
648
|
-
warningReasonSummary: summarizeRejectedRows(evaluated.warnings),
|
|
649
|
-
outputPath: TOKEN_COST_EVIDENCE_JSONL_REL,
|
|
650
|
-
writesPerformed: false,
|
|
651
|
-
itemContract: TOKEN_COST_ITEM_CONTRACT,
|
|
652
|
-
safeNextActions: evaluated.accepted.length > 0 && evaluated.rejected.length === 0
|
|
653
|
-
? [
|
|
654
|
-
"Run: node bin/avorelo token-cost import --file <redacted-json-or-jsonl> --json",
|
|
655
|
-
"Run: node bin/avorelo token-cost summary --json",
|
|
656
|
-
]
|
|
657
|
-
: [
|
|
658
|
-
"Fix rejected rows, then rerun: node bin/avorelo token-cost validate --file <path> --json",
|
|
659
|
-
"Run: node bin/avorelo token-cost summary --json after importing clean rows",
|
|
660
|
-
],
|
|
661
|
-
redacted: true,
|
|
662
|
-
};
|
|
663
|
-
}
|
|
664
|
-
|
|
665
|
-
function summarizeAvailableFields(rows, fields) {
|
|
666
|
-
return fields.filter((field) => rows.some((row) => row[field] !== null && row[field] !== undefined && row[field] !== ""));
|
|
667
|
-
}
|
|
668
|
-
|
|
669
|
-
function deriveStoredTokenCostEvidenceMode(row) {
|
|
670
|
-
if (!row || typeof row !== "object") return "missing";
|
|
671
|
-
if (row.evidenceMode) return row.evidenceMode;
|
|
672
|
-
const totalTokens = row.totalTokens;
|
|
673
|
-
const hasMeasuredCost = typeof row.measuredCostUsd === "number" || typeof row.costMicros === "number";
|
|
674
|
-
const hasEstimatedCost = typeof row.estimatedCostUsd === "number";
|
|
675
|
-
if (row.heuristic === true) return "heuristic";
|
|
676
|
-
if (typeof totalTokens === "number" && hasMeasuredCost && row.estimatedOnly !== true) return "measured";
|
|
677
|
-
if (typeof totalTokens === "number" && (hasEstimatedCost || hasMeasuredCost)) return "estimated";
|
|
678
|
-
if (typeof totalTokens === "number") return "heuristic";
|
|
679
|
-
return "missing";
|
|
680
|
-
}
|
|
681
|
-
|
|
682
|
-
function buildTokenCostEvidenceSummary(cwd) {
|
|
683
|
-
const importedRows = readImportedTokenCostEvidence(cwd);
|
|
684
|
-
const capturedRows = readCapturedTokenCostEvidence(cwd);
|
|
685
|
-
const rows = [...capturedRows, ...importedRows];
|
|
686
|
-
const measuredRows = rows.filter((row) =>
|
|
687
|
-
row &&
|
|
688
|
-
row.redacted === true &&
|
|
689
|
-
deriveStoredTokenCostEvidenceMode(row) === "measured" &&
|
|
690
|
-
typeof row.totalTokens === "number" &&
|
|
691
|
-
(typeof row.measuredCostUsd === "number" || typeof row.costMicros === "number")
|
|
692
|
-
);
|
|
693
|
-
const estimatedRows = rows.filter((row) =>
|
|
694
|
-
row &&
|
|
695
|
-
row.redacted === true &&
|
|
696
|
-
deriveStoredTokenCostEvidenceMode(row) === "estimated" &&
|
|
697
|
-
typeof row.totalTokens === "number" &&
|
|
698
|
-
(typeof row.estimatedCostUsd === "number" || typeof row.measuredCostUsd === "number" || typeof row.costMicros === "number")
|
|
699
|
-
);
|
|
700
|
-
const heuristicRows = rows.filter((row) =>
|
|
701
|
-
row &&
|
|
702
|
-
row.redacted === true &&
|
|
703
|
-
(deriveStoredTokenCostEvidenceMode(row) === "heuristic" || (typeof row.totalTokens === "number" && typeof row.measuredCostUsd !== "number" && typeof row.costMicros !== "number" && typeof row.estimatedCostUsd !== "number"))
|
|
704
|
-
);
|
|
705
|
-
|
|
706
|
-
let evidenceMode = "missing";
|
|
707
|
-
if (measuredRows.length > 0) evidenceMode = "measured";
|
|
708
|
-
else if (estimatedRows.length > 0) evidenceMode = "estimated";
|
|
709
|
-
else if (heuristicRows.length > 0) evidenceMode = "heuristic";
|
|
710
|
-
|
|
711
|
-
const tokenFieldsAvailable = summarizeAvailableFields(rows, ["inputTokens", "outputTokens", "promptTokens", "completionTokens", "totalTokens"]);
|
|
712
|
-
const costFieldsAvailable = summarizeAvailableFields(rows, ["estimatedCostUsd", "measuredCostUsd", "costMicros", "currency"]);
|
|
713
|
-
const sourceTypes = Array.from(new Set(rows.map((row) => row && row.sourceType).filter(Boolean)));
|
|
714
|
-
const tools = Array.from(new Set(rows.map((row) => row && row.tool).filter(Boolean)));
|
|
715
|
-
|
|
716
|
-
const missingEvidence = [];
|
|
717
|
-
if (rows.length === 0) missingEvidence.push("No local token/cost evidence rows have been captured or imported.");
|
|
718
|
-
if (measuredRows.length === 0) missingEvidence.push("No redacted measured token/cost usage samples are available.");
|
|
719
|
-
if (tokenFieldsAvailable.length === 0) missingEvidence.push("No token fields are available in token/cost evidence.");
|
|
720
|
-
if (costFieldsAvailable.length === 0) missingEvidence.push("No cost fields are available in token/cost evidence.");
|
|
721
|
-
|
|
722
|
-
const safeNextActions = [];
|
|
723
|
-
if (rows.length === 0) {
|
|
724
|
-
safeNextActions.push("Run: node bin/avorelo token-cost capture --json");
|
|
725
|
-
safeNextActions.push("Run: node bin/avorelo token-cost validate --file <redacted-json-or-jsonl> --json");
|
|
726
|
-
safeNextActions.push("Run: node bin/avorelo token-cost import --file <redacted-json-or-jsonl> --json");
|
|
727
|
-
} else if (measuredRows.length === 0) {
|
|
728
|
-
safeNextActions.push("Run: node bin/avorelo token-cost capture --json after a real local task with runtime attribution.");
|
|
729
|
-
safeNextActions.push("Import measured token/cost usage rows with token totals and measured cost fields.");
|
|
730
|
-
safeNextActions.push("Run: node bin/avorelo token-cost import --file <redacted-json-or-jsonl> --json");
|
|
731
|
-
}
|
|
732
|
-
safeNextActions.push("Run: node bin/avorelo token-cost summary --json");
|
|
733
|
-
|
|
734
|
-
return {
|
|
735
|
-
contract: TOKEN_COST_SUMMARY_CONTRACT,
|
|
736
|
-
schemaVersion: 1,
|
|
737
|
-
createdAt: nowIso(),
|
|
738
|
-
status: evidenceMode === "measured" ? "pass" : evidenceMode === "missing" ? "warn" : "warn",
|
|
739
|
-
evidenceAvailable: rows.length > 0,
|
|
740
|
-
evidenceMode,
|
|
741
|
-
realUsageSamplesCount: measuredRows.length,
|
|
742
|
-
capturedUsageSamplesCount: capturedRows.filter((row) => deriveStoredTokenCostEvidenceMode(row) === "measured").length,
|
|
743
|
-
importedUsageSamplesCount: importedRows.filter((row) => deriveStoredTokenCostEvidenceMode(row) === "measured").length,
|
|
744
|
-
source: {
|
|
745
|
-
sourceTypes,
|
|
746
|
-
tools,
|
|
747
|
-
importedEvidencePath: TOKEN_COST_EVIDENCE_JSONL_REL,
|
|
748
|
-
captureEvidencePath: TOKEN_COST_CAPTURE_JSONL_REL,
|
|
749
|
-
importReceiptPath: TOKEN_COST_IMPORT_RECEIPT_REL,
|
|
750
|
-
captureReceiptPath: TOKEN_COST_CAPTURE_RECEIPT_REL,
|
|
751
|
-
},
|
|
752
|
-
costFieldsAvailable,
|
|
753
|
-
tokenFieldsAvailable,
|
|
754
|
-
confidence: evidenceMode === "measured" ? "measured" : evidenceMode === "estimated" ? "estimated" : evidenceMode === "heuristic" ? "heuristic" : "missing",
|
|
755
|
-
missingEvidence,
|
|
756
|
-
safeNextActions,
|
|
757
|
-
noSavingsClaimUnlessMeasured: true,
|
|
758
|
-
redacted: true,
|
|
759
|
-
};
|
|
760
|
-
}
|
|
761
|
-
|
|
762
|
-
function writeTokenCostEvidenceSummary(cwd, summary) {
|
|
763
|
-
ensureDir(cwd, TOKEN_COST_EVIDENCE_DIR_REL);
|
|
764
|
-
fs.writeFileSync(path.join(cwd, TOKEN_COST_SUMMARY_REL), JSON.stringify(summary, null, 2), "utf8");
|
|
765
|
-
return summary;
|
|
766
|
-
}
|
|
767
|
-
|
|
768
|
-
function readTokenCostEvidenceSummary(cwd) {
|
|
769
|
-
return safeReadJson(path.join(cwd, TOKEN_COST_SUMMARY_REL));
|
|
770
|
-
}
|
|
771
|
-
|
|
772
|
-
function readImportedFeedbackEvidence(cwd) {
|
|
773
|
-
return safeReadJsonl(path.join(cwd, FEEDBACK_EVIDENCE_JSONL_REL));
|
|
774
|
-
}
|
|
775
|
-
|
|
776
|
-
function readImportedTokenCostEvidence(cwd) {
|
|
777
|
-
return safeReadJsonl(path.join(cwd, TOKEN_COST_EVIDENCE_JSONL_REL));
|
|
778
|
-
}
|
|
779
|
-
|
|
780
|
-
function readCapturedTokenCostEvidence(cwd) {
|
|
781
|
-
return safeReadJsonl(path.join(cwd, TOKEN_COST_CAPTURE_JSONL_REL));
|
|
782
|
-
}
|
|
783
|
-
|
|
784
|
-
module.exports = {
|
|
785
|
-
FEEDBACK_EVIDENCE_DIR_REL,
|
|
786
|
-
FEEDBACK_EVIDENCE_JSONL_REL,
|
|
787
|
-
FEEDBACK_IMPORT_RECEIPT_REL,
|
|
788
|
-
FEEDBACK_INTAKE_PACK_DIR_REL,
|
|
789
|
-
FEEDBACK_INTAKE_PACK_RECEIPT_REL,
|
|
790
|
-
FEEDBACK_INTAKE_PACK_README_REL,
|
|
791
|
-
FEEDBACK_INTAKE_PACK_TEMPLATE_REL,
|
|
792
|
-
FEEDBACK_INTAKE_PACK_CHECKLIST_REL,
|
|
793
|
-
TOKEN_COST_EVIDENCE_DIR_REL,
|
|
794
|
-
TOKEN_COST_EVIDENCE_JSONL_REL,
|
|
795
|
-
TOKEN_COST_CAPTURE_JSONL_REL,
|
|
796
|
-
TOKEN_COST_IMPORT_RECEIPT_REL,
|
|
797
|
-
TOKEN_COST_CAPTURE_RECEIPT_REL,
|
|
798
|
-
TOKEN_COST_SUMMARY_REL,
|
|
799
|
-
FEEDBACK_ITEM_CONTRACT,
|
|
800
|
-
FEEDBACK_VALIDATION_CONTRACT,
|
|
801
|
-
FEEDBACK_INTAKE_PACK_CONTRACT,
|
|
802
|
-
TOKEN_COST_ITEM_CONTRACT,
|
|
803
|
-
TOKEN_COST_VALIDATION_CONTRACT,
|
|
804
|
-
TOKEN_COST_SUMMARY_CONTRACT,
|
|
805
|
-
readImportedFeedbackEvidence,
|
|
806
|
-
readImportedTokenCostEvidence,
|
|
807
|
-
readCapturedTokenCostEvidence,
|
|
808
|
-
readTokenCostEvidenceSummary,
|
|
809
|
-
validateFeedbackEvidence,
|
|
810
|
-
generateFeedbackIntakePack,
|
|
811
|
-
importFeedbackEvidence,
|
|
812
|
-
importTokenCostEvidence,
|
|
813
|
-
validateTokenCostEvidence,
|
|
814
|
-
buildTokenCostEvidenceSummary,
|
|
815
|
-
writeTokenCostEvidenceSummary,
|
|
816
|
-
};
|