avorelo 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +23 -16
- package/README.md +90 -51
- package/bin/avorelo.mjs +7 -0
- package/dist/avorelo.mjs +19741 -0
- package/package.json +135 -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,789 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
// Run Improvements: local-first next-run preparation based on evidence from the previous run.
|
|
4
|
-
// Generates a canonical artifact with improvement categories and next-run defaults.
|
|
5
|
-
// No cloud calls, no LLM, no daemon, no hidden destructive actions.
|
|
6
|
-
|
|
7
|
-
const fs = require("fs");
|
|
8
|
-
const path = require("path");
|
|
9
|
-
const crypto = require("crypto");
|
|
10
|
-
|
|
11
|
-
const RUN_IMPROVEMENTS_REL = ".claude/cco/state/run-improvements.json";
|
|
12
|
-
const SCHEMA_VERSION = "avorelo.runImprovements.v1";
|
|
13
|
-
const TTL_MS = 24 * 60 * 60 * 1000; // 24 hours
|
|
14
|
-
|
|
15
|
-
const IMPROVEMENT_CATEGORIES = [
|
|
16
|
-
"stale_context",
|
|
17
|
-
"missing_validation",
|
|
18
|
-
"rework_loop",
|
|
19
|
-
"instruction_noise",
|
|
20
|
-
"risky_action",
|
|
21
|
-
"unclear_continuation",
|
|
22
|
-
"oversized_scope",
|
|
23
|
-
"missing_proof",
|
|
24
|
-
"cost_or_token_waste",
|
|
25
|
-
"repo_state_risk",
|
|
26
|
-
];
|
|
27
|
-
|
|
28
|
-
const STATUSES = [
|
|
29
|
-
"not_available",
|
|
30
|
-
"insufficient_evidence",
|
|
31
|
-
"prepared",
|
|
32
|
-
"consumed",
|
|
33
|
-
"applied",
|
|
34
|
-
"expired",
|
|
35
|
-
"stale",
|
|
36
|
-
"skipped",
|
|
37
|
-
"error",
|
|
38
|
-
];
|
|
39
|
-
|
|
40
|
-
const MODES = ["observe", "prepare", "enforce"];
|
|
41
|
-
|
|
42
|
-
function nowIso() {
|
|
43
|
-
return new Date().toISOString();
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
function expiresAtFromNow(fromIso) {
|
|
47
|
-
const base = fromIso ? new Date(fromIso) : new Date();
|
|
48
|
-
return new Date(base.getTime() + TTL_MS).toISOString();
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
function isExpired(artifact) {
|
|
52
|
-
if (!artifact || !artifact.expiresAt) return true;
|
|
53
|
-
return Date.now() > new Date(artifact.expiresAt).getTime();
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// Stable fingerprint from the key signals that determine improvements.
|
|
57
|
-
// Same evidence → same fingerprint → idempotent artifact.
|
|
58
|
-
function buildSourceFingerprint(signals) {
|
|
59
|
-
const stable = JSON.stringify({
|
|
60
|
-
budgetStatus: signals?.contextBudget?.status || "unknown",
|
|
61
|
-
budgetPercent: Math.round((signals?.contextBudget?.usedPercent || 0) / 10) * 10,
|
|
62
|
-
reentryIntervention: signals?.reentryState?.lastInterventionType || "none",
|
|
63
|
-
unresolvedRisk: Boolean(signals?.reentryState?.unresolvedRisk),
|
|
64
|
-
weeklyEventCount: signals?.outcomeEvents?.weeklyEventCount || 0,
|
|
65
|
-
loopDetected: Boolean(signals?.outcomeEvents?.loopDetected),
|
|
66
|
-
riskySkillCount: signals?.outcomeEvents?.riskySkillCount || 0,
|
|
67
|
-
validationState: signals?.validationState || "missing",
|
|
68
|
-
carryForwardAvailable: Boolean(signals?.carryForward?.available),
|
|
69
|
-
hasProofReceipt: Boolean(signals?.latestProofReceipt?.available),
|
|
70
|
-
proofStatus: signals?.latestProofReceipt?.completionStatus || "unknown",
|
|
71
|
-
});
|
|
72
|
-
return crypto.createHash("sha256").update(stable).digest("hex").slice(0, 16);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
// Load the latest proof receipt to detect validation/completion signals.
|
|
76
|
-
function loadLatestProofReceipt(cwd) {
|
|
77
|
-
try {
|
|
78
|
-
const receiptsDir = path.join(cwd, ".claude", "cco", "receipts");
|
|
79
|
-
if (!fs.existsSync(receiptsDir)) return null;
|
|
80
|
-
const files = fs.readdirSync(receiptsDir).filter((f) => f.endsWith(".json"));
|
|
81
|
-
if (!files.length) return null;
|
|
82
|
-
const latest = files
|
|
83
|
-
.map((name) => ({ name, mtimeMs: fs.statSync(path.join(receiptsDir, name)).mtimeMs }))
|
|
84
|
-
.sort((a, b) => b.mtimeMs - a.mtimeMs)[0];
|
|
85
|
-
const raw = JSON.parse(fs.readFileSync(path.join(receiptsDir, latest.name), "utf8"));
|
|
86
|
-
return {
|
|
87
|
-
available: true,
|
|
88
|
-
completionStatus: raw.result?.status || "unknown",
|
|
89
|
-
material: raw.material || false,
|
|
90
|
-
improvements: raw.improvements || [],
|
|
91
|
-
antiGamingValid: raw.anti_gaming?.valid !== false,
|
|
92
|
-
};
|
|
93
|
-
} catch {
|
|
94
|
-
return null;
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
// Safe read-only repo state check. Fails open to "unknown".
|
|
99
|
-
// No write, no stage, no commit, no network, no config mutation.
|
|
100
|
-
function collectRepoState(cwd) {
|
|
101
|
-
try {
|
|
102
|
-
const { spawnSync } = require("child_process");
|
|
103
|
-
const result = spawnSync("git", ["status", "--porcelain"], {
|
|
104
|
-
cwd,
|
|
105
|
-
encoding: "utf8",
|
|
106
|
-
timeout: 3000,
|
|
107
|
-
});
|
|
108
|
-
if (result.status !== 0 || result.error) return "unknown";
|
|
109
|
-
const output = (result.stdout || "").trim();
|
|
110
|
-
return output.length > 0 ? "dirty" : "clean";
|
|
111
|
-
} catch {
|
|
112
|
-
return "unknown";
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
function collectSignals(cwd) {
|
|
117
|
-
const signals = {
|
|
118
|
-
contextBudget: null,
|
|
119
|
-
reentryState: null,
|
|
120
|
-
carryForward: null,
|
|
121
|
-
outcomeEvents: null,
|
|
122
|
-
workflowDiscipline: null,
|
|
123
|
-
latestProofReceipt: null,
|
|
124
|
-
validationState: "missing",
|
|
125
|
-
riskLevel: "low",
|
|
126
|
-
repoState: "unknown",
|
|
127
|
-
};
|
|
128
|
-
|
|
129
|
-
// Context budget
|
|
130
|
-
try {
|
|
131
|
-
const { loadBudgetState } = require("./context-budget-guard");
|
|
132
|
-
const budgetState = loadBudgetState(cwd);
|
|
133
|
-
if (budgetState) {
|
|
134
|
-
signals.contextBudget = {
|
|
135
|
-
status: budgetState.status || "ok",
|
|
136
|
-
usedPercent: budgetState.usedPercent || 0,
|
|
137
|
-
usedChars: budgetState.usedChars || 0,
|
|
138
|
-
};
|
|
139
|
-
}
|
|
140
|
-
} catch {}
|
|
141
|
-
|
|
142
|
-
// Reentry state
|
|
143
|
-
try {
|
|
144
|
-
const { loadReentryState } = require("./reentry-state");
|
|
145
|
-
const rs = loadReentryState(cwd);
|
|
146
|
-
if (rs) {
|
|
147
|
-
signals.reentryState = {
|
|
148
|
-
lastInterventionType: rs.lastInterventionType || "none",
|
|
149
|
-
unresolvedRisk: Boolean(rs.unresolvedRisk),
|
|
150
|
-
nextAction: rs.nextAction || null,
|
|
151
|
-
};
|
|
152
|
-
if (rs.unresolvedRisk) {
|
|
153
|
-
signals.riskLevel = "high";
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
} catch {}
|
|
157
|
-
|
|
158
|
-
// Carry-forward
|
|
159
|
-
try {
|
|
160
|
-
const { loadCarryForward } = require("./carry-forward-surfacing");
|
|
161
|
-
const cf = loadCarryForward(cwd);
|
|
162
|
-
signals.carryForward = {
|
|
163
|
-
available: cf !== null,
|
|
164
|
-
sessionId: cf?.sessionId || null,
|
|
165
|
-
toolHistoryDepth: cf?.toolHistory?.toolNames?.length || 0,
|
|
166
|
-
};
|
|
167
|
-
} catch {}
|
|
168
|
-
|
|
169
|
-
// Latest proof receipt
|
|
170
|
-
signals.latestProofReceipt = loadLatestProofReceipt(cwd);
|
|
171
|
-
if (signals.latestProofReceipt?.completionStatus === "completed") {
|
|
172
|
-
signals.validationState = "passed";
|
|
173
|
-
} else if (signals.latestProofReceipt?.available) {
|
|
174
|
-
signals.validationState = "partial";
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
// Outcome events (last 7 days)
|
|
178
|
-
try {
|
|
179
|
-
const { readOutcomeEvents, aggregateOutcomeEvents } = require("./unified-events");
|
|
180
|
-
const rawEvents = readOutcomeEvents(cwd);
|
|
181
|
-
// Exclude run_improvements audit events from signal calculation to preserve idempotency
|
|
182
|
-
const events = rawEvents.filter((e) => e.category !== "run_improvements");
|
|
183
|
-
if (events.length > 0) {
|
|
184
|
-
const agg = aggregateOutcomeEvents(events, { days: 7 });
|
|
185
|
-
const weekly = agg.weeklyRepoSummary || {};
|
|
186
|
-
const byCategory = weekly.byCategory || {};
|
|
187
|
-
signals.outcomeEvents = {
|
|
188
|
-
weeklyEventCount: weekly.events || 0,
|
|
189
|
-
loopDetected: (byCategory.loop_detected || 0) > 0,
|
|
190
|
-
loopCount: byCategory.loop_detected || 0,
|
|
191
|
-
riskySkillCount: byCategory.risky_skill_flagged || 0,
|
|
192
|
-
outputTrimmedCount: byCategory.output_trimmed || 0,
|
|
193
|
-
tokenUsageTotal: weekly.tokenUsageTotal || 0,
|
|
194
|
-
measuredCostTotal: weekly.measuredCostTotal || 0,
|
|
195
|
-
topReasonCodes: agg.sessionSummary?.topReasonCodes || [],
|
|
196
|
-
};
|
|
197
|
-
}
|
|
198
|
-
} catch {}
|
|
199
|
-
|
|
200
|
-
// Safe read-only repo state
|
|
201
|
-
signals.repoState = collectRepoState(cwd);
|
|
202
|
-
|
|
203
|
-
// Workflow discipline — inferred from available signals
|
|
204
|
-
try {
|
|
205
|
-
const { buildWorkflowDisciplineStatus } = require("./workflow-discipline");
|
|
206
|
-
const budgetStatus = signals.contextBudget?.status || "ok";
|
|
207
|
-
const contextPressure =
|
|
208
|
-
budgetStatus === "critical" ? "critical" : budgetStatus === "warn" ? "warn" : "ok";
|
|
209
|
-
const reentryAvailable = signals.carryForward?.available ? "available" : "missing";
|
|
210
|
-
const loopDetected = signals.outcomeEvents?.loopDetected || false;
|
|
211
|
-
|
|
212
|
-
const wdInput = {
|
|
213
|
-
taskType: "unknown",
|
|
214
|
-
riskLevel: signals.riskLevel,
|
|
215
|
-
repoState: signals.repoState === "dirty" ? "modified" : signals.repoState === "clean" ? "clean" : "unknown",
|
|
216
|
-
contextPressure,
|
|
217
|
-
reentryState: reentryAvailable,
|
|
218
|
-
validationState: signals.validationState,
|
|
219
|
-
agentSecurityState: signals.reentryState?.unresolvedRisk ? "warn" : "off",
|
|
220
|
-
ambiguous: false,
|
|
221
|
-
repetitiveAgent: loopDetected,
|
|
222
|
-
};
|
|
223
|
-
signals.workflowDiscipline = buildWorkflowDisciplineStatus(wdInput, {});
|
|
224
|
-
} catch {}
|
|
225
|
-
|
|
226
|
-
// Learning summary (compact influence on next-run defaults)
|
|
227
|
-
try {
|
|
228
|
-
const { loadLearningSummary } = require("./learning-memory");
|
|
229
|
-
signals.learningSummary = loadLearningSummary(cwd);
|
|
230
|
-
} catch {
|
|
231
|
-
signals.learningSummary = null;
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
return signals;
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
function generateImprovements(signals) {
|
|
238
|
-
const improvements = [];
|
|
239
|
-
let idx = 0;
|
|
240
|
-
|
|
241
|
-
const budgetStatus = signals.contextBudget?.status;
|
|
242
|
-
|
|
243
|
-
// stale_context: context window was under pressure
|
|
244
|
-
if (budgetStatus === "critical" || budgetStatus === "warn") {
|
|
245
|
-
improvements.push({
|
|
246
|
-
id: `imp_${++idx}_stale_context`,
|
|
247
|
-
category: "stale_context",
|
|
248
|
-
severity: budgetStatus === "critical" ? "critical" : "warn",
|
|
249
|
-
title: "Context window was under pressure",
|
|
250
|
-
evidence: `Context usage at ${signals.contextBudget.usedPercent}%`,
|
|
251
|
-
recommendedDefault: "prefer carry-forward summary over full stale context",
|
|
252
|
-
reasonCodes: [`CTX_PRESSURE_${budgetStatus.toUpperCase()}`],
|
|
253
|
-
confidence: budgetStatus === "critical" ? 0.92 : 0.75,
|
|
254
|
-
source: "contextBudget",
|
|
255
|
-
});
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
// rework_loop: repeated tool loops detected
|
|
259
|
-
if (signals.outcomeEvents?.loopDetected) {
|
|
260
|
-
improvements.push({
|
|
261
|
-
id: `imp_${++idx}_rework_loop`,
|
|
262
|
-
category: "rework_loop",
|
|
263
|
-
severity: "warn",
|
|
264
|
-
title: "Repeated tool loops detected",
|
|
265
|
-
evidence: `${signals.outcomeEvents.loopCount} loop event(s) in last 7 days`,
|
|
266
|
-
recommendedDefault: "ask for a plan or options before re-executing the same approach",
|
|
267
|
-
reasonCodes: ["LOOP_REPEATED_TOOL"],
|
|
268
|
-
confidence: 0.81,
|
|
269
|
-
source: "outcomeEvents",
|
|
270
|
-
});
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
// risky_action: unresolved risk from reentry
|
|
274
|
-
if (signals.reentryState?.unresolvedRisk) {
|
|
275
|
-
const interventionCode = String(signals.reentryState.lastInterventionType || "unknown")
|
|
276
|
-
.toUpperCase()
|
|
277
|
-
.replace(/-/g, "_");
|
|
278
|
-
improvements.push({
|
|
279
|
-
id: `imp_${++idx}_risky_action`,
|
|
280
|
-
category: "risky_action",
|
|
281
|
-
severity: "critical",
|
|
282
|
-
title: "Unresolved risk from previous run",
|
|
283
|
-
evidence: `Last intervention: ${signals.reentryState.lastInterventionType}`,
|
|
284
|
-
recommendedDefault: "ask for confirmation before risky or destructive actions",
|
|
285
|
-
reasonCodes: ["UNRESOLVED_RISK", `INTERVENTION_${interventionCode}`],
|
|
286
|
-
confidence: 0.90,
|
|
287
|
-
source: "reentryState",
|
|
288
|
-
});
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
// risky_action from security events (only if not already from reentry)
|
|
292
|
-
if (
|
|
293
|
-
(signals.outcomeEvents?.riskySkillCount || 0) > 0 &&
|
|
294
|
-
!improvements.find((i) => i.category === "risky_action")
|
|
295
|
-
) {
|
|
296
|
-
improvements.push({
|
|
297
|
-
id: `imp_${++idx}_risky_action_events`,
|
|
298
|
-
category: "risky_action",
|
|
299
|
-
severity: "warn",
|
|
300
|
-
title: "Risky tool actions detected in session events",
|
|
301
|
-
evidence: `${signals.outcomeEvents.riskySkillCount} risky skill event(s) in last 7 days`,
|
|
302
|
-
recommendedDefault: "ask for confirmation before risky or destructive actions",
|
|
303
|
-
reasonCodes: ["RISKY_SKILL_FLAGGED"],
|
|
304
|
-
confidence: 0.83,
|
|
305
|
-
source: "outcomeEvents",
|
|
306
|
-
});
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
// missing_validation: no completed proof receipt
|
|
310
|
-
if (signals.validationState === "missing" || signals.validationState === "partial") {
|
|
311
|
-
const isPartial = signals.validationState === "partial";
|
|
312
|
-
improvements.push({
|
|
313
|
-
id: `imp_${++idx}_missing_validation`,
|
|
314
|
-
category: "missing_validation",
|
|
315
|
-
severity: isPartial ? "info" : "warn",
|
|
316
|
-
title: isPartial ? "Validation proof incomplete from previous run" : "No validation proof from previous run",
|
|
317
|
-
evidence: isPartial
|
|
318
|
-
? "Proof receipt exists but completion status is not 'completed'"
|
|
319
|
-
: "No proof receipt found for last run",
|
|
320
|
-
recommendedDefault: "require validation proof before claiming done",
|
|
321
|
-
reasonCodes: [isPartial ? "VALIDATION_PARTIAL" : "VALIDATION_MISSING"],
|
|
322
|
-
confidence: isPartial ? 0.68 : 0.72,
|
|
323
|
-
source: "latestProofReceipt",
|
|
324
|
-
});
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
// missing_proof: no receipt at all and there was activity
|
|
328
|
-
if (
|
|
329
|
-
!signals.latestProofReceipt?.available &&
|
|
330
|
-
(signals.outcomeEvents?.weeklyEventCount || 0) > 0
|
|
331
|
-
) {
|
|
332
|
-
if (!improvements.find((i) => i.category === "missing_proof")) {
|
|
333
|
-
improvements.push({
|
|
334
|
-
id: `imp_${++idx}_missing_proof`,
|
|
335
|
-
category: "missing_proof",
|
|
336
|
-
severity: "info",
|
|
337
|
-
title: "No proof receipt found for recent sessions",
|
|
338
|
-
evidence: `${signals.outcomeEvents.weeklyEventCount} events logged but no receipt written`,
|
|
339
|
-
recommendedDefault: "require proof/receipt output at end of run",
|
|
340
|
-
reasonCodes: ["NO_PROOF_RECEIPT", "EVENTS_WITHOUT_RECEIPT"],
|
|
341
|
-
confidence: 0.65,
|
|
342
|
-
source: "outcomeEvents",
|
|
343
|
-
});
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
// cost_or_token_waste: high token usage with loop signals
|
|
348
|
-
if (
|
|
349
|
-
(signals.outcomeEvents?.tokenUsageTotal || 0) > 50000 &&
|
|
350
|
-
signals.outcomeEvents?.loopDetected
|
|
351
|
-
) {
|
|
352
|
-
improvements.push({
|
|
353
|
-
id: `imp_${++idx}_cost_or_token_waste`,
|
|
354
|
-
category: "cost_or_token_waste",
|
|
355
|
-
severity: "info",
|
|
356
|
-
title: "High token usage with loop signals",
|
|
357
|
-
evidence: `${signals.outcomeEvents.tokenUsageTotal} tokens used with loop detection active`,
|
|
358
|
-
recommendedDefault: "run targeted tests before full suite to reduce redundant token spend",
|
|
359
|
-
reasonCodes: ["HIGH_TOKEN_USAGE", "LOOP_REPEATED_TOOL"],
|
|
360
|
-
confidence: 0.65,
|
|
361
|
-
source: "outcomeEvents",
|
|
362
|
-
});
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
// repo_state_risk: unresolved risk with unknown repo state
|
|
366
|
-
if (signals.reentryState?.unresolvedRisk && signals.repoState === "unknown") {
|
|
367
|
-
improvements.push({
|
|
368
|
-
id: `imp_${++idx}_repo_state_risk`,
|
|
369
|
-
category: "repo_state_risk",
|
|
370
|
-
severity: "warn",
|
|
371
|
-
title: "Repo state unknown with unresolved risk",
|
|
372
|
-
evidence: "Unresolved risk detected and repo state not verified",
|
|
373
|
-
recommendedDefault: "preserve rollback or undo note before continuing",
|
|
374
|
-
reasonCodes: ["UNRESOLVED_RISK", "REPO_STATE_UNKNOWN"],
|
|
375
|
-
confidence: 0.70,
|
|
376
|
-
source: "reentryState",
|
|
377
|
-
});
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
// unclear_continuation: no carry-forward + past intervention
|
|
381
|
-
if (
|
|
382
|
-
!signals.carryForward?.available &&
|
|
383
|
-
signals.reentryState?.lastInterventionType &&
|
|
384
|
-
signals.reentryState.lastInterventionType !== "none"
|
|
385
|
-
) {
|
|
386
|
-
improvements.push({
|
|
387
|
-
id: `imp_${++idx}_unclear_continuation`,
|
|
388
|
-
category: "unclear_continuation",
|
|
389
|
-
severity: "info",
|
|
390
|
-
title: "No carry-forward context for continuation",
|
|
391
|
-
evidence: "Previous run ended without carry-forward state capture",
|
|
392
|
-
recommendedDefault: "prefer carry-forward summary for context continuity",
|
|
393
|
-
reasonCodes: ["NO_CARRY_FORWARD", "REENTRY_MISSING"],
|
|
394
|
-
confidence: 0.63,
|
|
395
|
-
source: "carryForward",
|
|
396
|
-
});
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
// instruction_noise: signal-backed from context pressure + carry-forward depth
|
|
400
|
-
// Only generated when concrete signals support it; otherwise remains insufficient_evidence.
|
|
401
|
-
const carryForwardDepth = signals.carryForward?.toolHistoryDepth || 0;
|
|
402
|
-
const ctxCritical = budgetStatus === "critical";
|
|
403
|
-
const ctxWarn = budgetStatus === "warn";
|
|
404
|
-
const heavyCarryForward = carryForwardDepth >= 3;
|
|
405
|
-
const wdRecommendations = signals.workflowDiscipline?.recommendations || [];
|
|
406
|
-
const wdHandoff = wdRecommendations.some((r) => r.id === "WF_HANDOFF_COMPRESS");
|
|
407
|
-
if (ctxCritical && (heavyCarryForward || wdHandoff)) {
|
|
408
|
-
improvements.push({
|
|
409
|
-
id: `imp_${++idx}_instruction_noise`,
|
|
410
|
-
category: "instruction_noise",
|
|
411
|
-
severity: "warn",
|
|
412
|
-
title: "Context pressure with heavy carry-forward suggests instruction noise",
|
|
413
|
-
evidence:
|
|
414
|
-
`Context at ${signals.contextBudget.usedPercent}% (critical)` +
|
|
415
|
-
(heavyCarryForward ? `, carry-forward depth ${carryForwardDepth}` : "") +
|
|
416
|
-
(wdHandoff ? ", workflow recommends compress/handoff" : ""),
|
|
417
|
-
recommendedDefault: "reduce stale context and clarify scope before next run",
|
|
418
|
-
reasonCodes: [
|
|
419
|
-
"CTX_PRESSURE_CRITICAL",
|
|
420
|
-
heavyCarryForward ? "HEAVY_CARRY_FORWARD" : null,
|
|
421
|
-
wdHandoff ? "WF_HANDOFF_COMPRESS" : null,
|
|
422
|
-
].filter(Boolean),
|
|
423
|
-
confidence: 0.70,
|
|
424
|
-
source: "contextBudget",
|
|
425
|
-
});
|
|
426
|
-
} else if (ctxWarn && heavyCarryForward) {
|
|
427
|
-
improvements.push({
|
|
428
|
-
id: `imp_${++idx}_instruction_noise`,
|
|
429
|
-
category: "instruction_noise",
|
|
430
|
-
severity: "info",
|
|
431
|
-
title: "Context pressure with deep carry-forward may introduce noise",
|
|
432
|
-
evidence: `Context at ${signals.contextBudget.usedPercent}% (warn), carry-forward depth ${carryForwardDepth}`,
|
|
433
|
-
recommendedDefault: "prefer fresh compact context over full carry-forward when context is under pressure",
|
|
434
|
-
reasonCodes: ["CTX_PRESSURE_WARN", "HEAVY_CARRY_FORWARD"],
|
|
435
|
-
confidence: 0.60,
|
|
436
|
-
source: "contextBudget",
|
|
437
|
-
});
|
|
438
|
-
}
|
|
439
|
-
// If no signal: instruction_noise remains undefined (insufficient_evidence) — do not generate it.
|
|
440
|
-
|
|
441
|
-
// oversized_scope: signal-backed from output trimming, token waste without loop, or WF_PLAN_FIRST
|
|
442
|
-
const outputTrimmedCount = signals.outcomeEvents?.outputTrimmedCount || 0;
|
|
443
|
-
const wdPlanFirst = wdRecommendations.some((r) => r.id === "WF_PLAN_FIRST");
|
|
444
|
-
const highTokenNoLoop =
|
|
445
|
-
(signals.outcomeEvents?.tokenUsageTotal || 0) > 100000 &&
|
|
446
|
-
!signals.outcomeEvents?.loopDetected;
|
|
447
|
-
if (outputTrimmedCount > 0 || wdPlanFirst || highTokenNoLoop) {
|
|
448
|
-
const evidenceParts = [];
|
|
449
|
-
if (outputTrimmedCount > 0) evidenceParts.push(`${outputTrimmedCount} output(s) trimmed`);
|
|
450
|
-
if (wdPlanFirst) evidenceParts.push("workflow recommends plan-first");
|
|
451
|
-
if (highTokenNoLoop)
|
|
452
|
-
evidenceParts.push(`${signals.outcomeEvents.tokenUsageTotal} tokens without loop`);
|
|
453
|
-
improvements.push({
|
|
454
|
-
id: `imp_${++idx}_oversized_scope`,
|
|
455
|
-
category: "oversized_scope",
|
|
456
|
-
severity: "warn",
|
|
457
|
-
title: "Scope may have been too broad for clean single-run completion",
|
|
458
|
-
evidence: evidenceParts.join("; "),
|
|
459
|
-
recommendedDefault: "define a clear scope boundary and acceptance criteria before next run",
|
|
460
|
-
reasonCodes: [
|
|
461
|
-
outputTrimmedCount > 0 ? "OUTPUT_TRIMMED" : null,
|
|
462
|
-
wdPlanFirst ? "WF_PLAN_FIRST" : null,
|
|
463
|
-
highTokenNoLoop ? "HIGH_TOKEN_NO_LOOP" : null,
|
|
464
|
-
].filter(Boolean),
|
|
465
|
-
confidence: wdPlanFirst ? 0.72 : 0.65,
|
|
466
|
-
source: "outcomeEvents",
|
|
467
|
-
});
|
|
468
|
-
}
|
|
469
|
-
// If no signal: oversized_scope remains undefined (insufficient_evidence) — do not generate it.
|
|
470
|
-
|
|
471
|
-
// Deduplicate by category (keep highest confidence)
|
|
472
|
-
const byCat = new Map();
|
|
473
|
-
for (const imp of improvements) {
|
|
474
|
-
const existing = byCat.get(imp.category);
|
|
475
|
-
if (!existing || imp.confidence > existing.confidence) {
|
|
476
|
-
byCat.set(imp.category, imp);
|
|
477
|
-
}
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
const deduped = [...byCat.values()];
|
|
481
|
-
|
|
482
|
-
// Sort: confidence desc, then severity rank
|
|
483
|
-
const severityRank = { critical: 3, warn: 2, info: 1 };
|
|
484
|
-
deduped.sort((a, b) => {
|
|
485
|
-
const confDiff = b.confidence - a.confidence;
|
|
486
|
-
if (Math.abs(confDiff) > 0.05) return confDiff;
|
|
487
|
-
return (severityRank[b.severity] || 0) - (severityRank[a.severity] || 0);
|
|
488
|
-
});
|
|
489
|
-
|
|
490
|
-
return deduped.slice(0, 5);
|
|
491
|
-
}
|
|
492
|
-
|
|
493
|
-
function generateNextRunDefaults(improvements, learningSummary) {
|
|
494
|
-
const defaults = [];
|
|
495
|
-
const seen = new Set();
|
|
496
|
-
|
|
497
|
-
for (const imp of improvements) {
|
|
498
|
-
const text = imp.recommendedDefault;
|
|
499
|
-
if (!text || seen.has(text)) continue;
|
|
500
|
-
seen.add(text);
|
|
501
|
-
defaults.push({
|
|
502
|
-
id: `def_${imp.category}`,
|
|
503
|
-
text,
|
|
504
|
-
reasonCodes: imp.reasonCodes,
|
|
505
|
-
source: imp.category,
|
|
506
|
-
});
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
// Learning influence: append bounded, reason-coded defaults from learning summary.
|
|
510
|
-
// Learning may recommend but never silently overrides user instructions.
|
|
511
|
-
// Only include influence that is not already covered by evidence-based defaults.
|
|
512
|
-
if (learningSummary && Array.isArray(learningSummary.nextRunInfluence)) {
|
|
513
|
-
for (const influence of learningSummary.nextRunInfluence) {
|
|
514
|
-
if (!influence.text || seen.has(influence.text)) continue;
|
|
515
|
-
seen.add(influence.text);
|
|
516
|
-
defaults.push({
|
|
517
|
-
id: `def_learning_${influence.type}`,
|
|
518
|
-
text: influence.text,
|
|
519
|
-
reasonCodes: influence.reasonCodes || [],
|
|
520
|
-
source: "learning",
|
|
521
|
-
});
|
|
522
|
-
}
|
|
523
|
-
}
|
|
524
|
-
|
|
525
|
-
return defaults;
|
|
526
|
-
}
|
|
527
|
-
|
|
528
|
-
function buildPublicSummary(status, topImprovements, nextRunDefaults) {
|
|
529
|
-
if (status === "not_available") {
|
|
530
|
-
return "Run Improvements: not available. No prior run evidence found.";
|
|
531
|
-
}
|
|
532
|
-
if (status === "insufficient_evidence") {
|
|
533
|
-
return "Run Improvements: insufficient evidence. No improvements generated.";
|
|
534
|
-
}
|
|
535
|
-
if (status === "expired") {
|
|
536
|
-
return "Run Improvements: expired. Run again to refresh.";
|
|
537
|
-
}
|
|
538
|
-
if (status === "error") {
|
|
539
|
-
return "Run Improvements: error generating improvements.";
|
|
540
|
-
}
|
|
541
|
-
if (status === "skipped") {
|
|
542
|
-
return "Run Improvements: skipped.";
|
|
543
|
-
}
|
|
544
|
-
|
|
545
|
-
const topDefault = nextRunDefaults[0];
|
|
546
|
-
const improvementNote = topDefault
|
|
547
|
-
? `Next run: ${topDefault.text}.`
|
|
548
|
-
: "No improvements needed.";
|
|
549
|
-
|
|
550
|
-
const topCategories = [...new Set(topImprovements.map((i) => i.category))].slice(0, 2);
|
|
551
|
-
const whyNote =
|
|
552
|
-
topCategories.length > 0
|
|
553
|
-
? `Why: ${topCategories.map((c) => c.replace(/_/g, " ")).join(" and ")}.`
|
|
554
|
-
: "";
|
|
555
|
-
|
|
556
|
-
return [`Run Improvements: ${status}.`, improvementNote, whyNote].filter(Boolean).join(" ");
|
|
557
|
-
}
|
|
558
|
-
|
|
559
|
-
function buildRunImprovements(cwd, options = {}) {
|
|
560
|
-
const mode = MODES.includes(options.mode) ? options.mode : "prepare";
|
|
561
|
-
const generatedAt = nowIso();
|
|
562
|
-
|
|
563
|
-
let signals;
|
|
564
|
-
try {
|
|
565
|
-
signals = collectSignals(cwd);
|
|
566
|
-
} catch (err) {
|
|
567
|
-
return {
|
|
568
|
-
schemaVersion: SCHEMA_VERSION,
|
|
569
|
-
generatedAt,
|
|
570
|
-
expiresAt: expiresAtFromNow(generatedAt),
|
|
571
|
-
sourceRunFingerprint: "error",
|
|
572
|
-
status: "error",
|
|
573
|
-
mode,
|
|
574
|
-
applied: false,
|
|
575
|
-
appliedAt: null,
|
|
576
|
-
sourceSignals: {},
|
|
577
|
-
topImprovements: [],
|
|
578
|
-
nextRunDefaults: [],
|
|
579
|
-
publicSummary: "Run Improvements: error collecting signals.",
|
|
580
|
-
reasonCodes: ["SIGNAL_COLLECTION_ERROR"],
|
|
581
|
-
limitations: [String(err.message)],
|
|
582
|
-
};
|
|
583
|
-
}
|
|
584
|
-
|
|
585
|
-
const fingerprint = buildSourceFingerprint(signals);
|
|
586
|
-
|
|
587
|
-
const hasAnySignal =
|
|
588
|
-
signals.contextBudget !== null ||
|
|
589
|
-
signals.reentryState !== null ||
|
|
590
|
-
signals.outcomeEvents !== null ||
|
|
591
|
-
signals.latestProofReceipt !== null;
|
|
592
|
-
|
|
593
|
-
if (!hasAnySignal) {
|
|
594
|
-
return {
|
|
595
|
-
schemaVersion: SCHEMA_VERSION,
|
|
596
|
-
generatedAt,
|
|
597
|
-
expiresAt: expiresAtFromNow(generatedAt),
|
|
598
|
-
sourceRunFingerprint: fingerprint,
|
|
599
|
-
status: "not_available",
|
|
600
|
-
mode,
|
|
601
|
-
applied: false,
|
|
602
|
-
appliedAt: null,
|
|
603
|
-
sourceSignals: signals,
|
|
604
|
-
topImprovements: [],
|
|
605
|
-
nextRunDefaults: [],
|
|
606
|
-
publicSummary: "Run Improvements: not available. No prior run evidence found.",
|
|
607
|
-
reasonCodes: ["NO_EVIDENCE"],
|
|
608
|
-
limitations: ["No prior run artifacts found. Run an Avorelo session first."],
|
|
609
|
-
};
|
|
610
|
-
}
|
|
611
|
-
|
|
612
|
-
const topImprovements = generateImprovements(signals);
|
|
613
|
-
|
|
614
|
-
if (topImprovements.length === 0) {
|
|
615
|
-
return {
|
|
616
|
-
schemaVersion: SCHEMA_VERSION,
|
|
617
|
-
generatedAt,
|
|
618
|
-
expiresAt: expiresAtFromNow(generatedAt),
|
|
619
|
-
sourceRunFingerprint: fingerprint,
|
|
620
|
-
status: "insufficient_evidence",
|
|
621
|
-
mode,
|
|
622
|
-
applied: false,
|
|
623
|
-
appliedAt: null,
|
|
624
|
-
sourceSignals: signals,
|
|
625
|
-
topImprovements: [],
|
|
626
|
-
nextRunDefaults: [],
|
|
627
|
-
publicSummary: "Run Improvements: insufficient evidence. No improvements generated.",
|
|
628
|
-
reasonCodes: ["INSUFFICIENT_EVIDENCE"],
|
|
629
|
-
limitations: ["Signal sources present but no actionable improvements derived."],
|
|
630
|
-
};
|
|
631
|
-
}
|
|
632
|
-
|
|
633
|
-
const nextRunDefaults = generateNextRunDefaults(topImprovements, signals.learningSummary);
|
|
634
|
-
const reasonCodes = [...new Set(topImprovements.flatMap((i) => i.reasonCodes))];
|
|
635
|
-
const publicSummary = buildPublicSummary("prepared", topImprovements, nextRunDefaults);
|
|
636
|
-
|
|
637
|
-
return {
|
|
638
|
-
schemaVersion: SCHEMA_VERSION,
|
|
639
|
-
generatedAt,
|
|
640
|
-
expiresAt: expiresAtFromNow(generatedAt),
|
|
641
|
-
sourceRunFingerprint: fingerprint,
|
|
642
|
-
status: "prepared",
|
|
643
|
-
mode,
|
|
644
|
-
applied: false,
|
|
645
|
-
appliedAt: null,
|
|
646
|
-
sourceSignals: signals,
|
|
647
|
-
topImprovements,
|
|
648
|
-
nextRunDefaults,
|
|
649
|
-
publicSummary,
|
|
650
|
-
reasonCodes,
|
|
651
|
-
limitations: [
|
|
652
|
-
"Defaults are prepared and visible in status/dashboard output.",
|
|
653
|
-
"Applied state requires explicit consume/apply via a supported surface.",
|
|
654
|
-
"No cloud calls, no LLM, no daemon — purely evidence-based.",
|
|
655
|
-
"instruction_noise and oversized_scope require specific signal combinations.",
|
|
656
|
-
],
|
|
657
|
-
};
|
|
658
|
-
}
|
|
659
|
-
|
|
660
|
-
// Write artifact. Idempotent: same fingerprint + not expired → skip rewrite.
|
|
661
|
-
function generateRunImprovementsArtifact(cwd, options = {}) {
|
|
662
|
-
const artifact = buildRunImprovements(cwd, options);
|
|
663
|
-
|
|
664
|
-
const existing = loadRunImprovements(cwd);
|
|
665
|
-
if (
|
|
666
|
-
existing &&
|
|
667
|
-
!isExpired(existing) &&
|
|
668
|
-
existing.sourceRunFingerprint === artifact.sourceRunFingerprint &&
|
|
669
|
-
existing.status === artifact.status
|
|
670
|
-
) {
|
|
671
|
-
return { artifact: existing, written: false, reason: "same_fingerprint_not_expired" };
|
|
672
|
-
}
|
|
673
|
-
|
|
674
|
-
const absPath = path.join(cwd, RUN_IMPROVEMENTS_REL);
|
|
675
|
-
fs.mkdirSync(path.dirname(absPath), { recursive: true });
|
|
676
|
-
fs.writeFileSync(absPath, JSON.stringify(artifact, null, 2), "utf8");
|
|
677
|
-
|
|
678
|
-
try {
|
|
679
|
-
_emitAuditEvent(cwd, artifact);
|
|
680
|
-
} catch {}
|
|
681
|
-
|
|
682
|
-
return { artifact, written: true, reason: "generated" };
|
|
683
|
-
}
|
|
684
|
-
|
|
685
|
-
function loadRunImprovements(cwd) {
|
|
686
|
-
try {
|
|
687
|
-
const absPath = path.join(cwd, RUN_IMPROVEMENTS_REL);
|
|
688
|
-
const raw = JSON.parse(fs.readFileSync(absPath, "utf8"));
|
|
689
|
-
if (raw.schemaVersion !== SCHEMA_VERSION) return null;
|
|
690
|
-
if (isExpired(raw)) {
|
|
691
|
-
raw.status = "expired";
|
|
692
|
-
}
|
|
693
|
-
return raw;
|
|
694
|
-
} catch {
|
|
695
|
-
return null;
|
|
696
|
-
}
|
|
697
|
-
}
|
|
698
|
-
|
|
699
|
-
function formatRunImprovementsText(cwd) {
|
|
700
|
-
const artifact = loadRunImprovements(cwd);
|
|
701
|
-
if (!artifact || artifact.status === "not_available" || artifact.status === "expired") {
|
|
702
|
-
return null;
|
|
703
|
-
}
|
|
704
|
-
const lines = [artifact.publicSummary];
|
|
705
|
-
if (
|
|
706
|
-
(artifact.status === "prepared" || artifact.status === "applied") &&
|
|
707
|
-
artifact.nextRunDefaults.length > 0
|
|
708
|
-
) {
|
|
709
|
-
const top = artifact.nextRunDefaults[0];
|
|
710
|
-
lines.push(` Next: ${top.text}`);
|
|
711
|
-
}
|
|
712
|
-
return lines.join("\n");
|
|
713
|
-
}
|
|
714
|
-
|
|
715
|
-
function formatRunImprovementsStatusLine(cwd) {
|
|
716
|
-
const artifact = loadRunImprovements(cwd);
|
|
717
|
-
if (!artifact || artifact.status === "not_available") return null;
|
|
718
|
-
if (artifact.status === "expired") {
|
|
719
|
-
return "Run Improvements: expired";
|
|
720
|
-
}
|
|
721
|
-
if (artifact.status === "insufficient_evidence") {
|
|
722
|
-
return "Run Improvements: no actionable improvements from last run";
|
|
723
|
-
}
|
|
724
|
-
if (artifact.status === "prepared" || artifact.status === "applied") {
|
|
725
|
-
const topCats = [...new Set(artifact.topImprovements.map((i) => i.category))].slice(0, 2);
|
|
726
|
-
const catText = topCats.map((c) => c.replace(/_/g, " ")).join(", ");
|
|
727
|
-
return `Run Improvements: ${artifact.status} · ${artifact.topImprovements.length} improvement(s) · focus: ${catText || "general"}`;
|
|
728
|
-
}
|
|
729
|
-
return null;
|
|
730
|
-
}
|
|
731
|
-
|
|
732
|
-
function buildRunImprovementsSurface(cwd) {
|
|
733
|
-
const artifact = loadRunImprovements(cwd);
|
|
734
|
-
if (!artifact) {
|
|
735
|
-
return { showInStatus: false, statusLine: null, artifact: null };
|
|
736
|
-
}
|
|
737
|
-
const statusLine = formatRunImprovementsStatusLine(cwd);
|
|
738
|
-
return {
|
|
739
|
-
showInStatus: statusLine !== null,
|
|
740
|
-
statusLine,
|
|
741
|
-
artifact,
|
|
742
|
-
};
|
|
743
|
-
}
|
|
744
|
-
|
|
745
|
-
function _emitAuditEvent(cwd, artifact) {
|
|
746
|
-
const eventsPath = path.join(cwd, ".claude/cco/events/outcome-events.jsonl");
|
|
747
|
-
fs.mkdirSync(path.dirname(eventsPath), { recursive: true });
|
|
748
|
-
const event = JSON.stringify({
|
|
749
|
-
event_id: `run_imp_${artifact.sourceRunFingerprint}`,
|
|
750
|
-
session_id: "avorelo-run-improvements",
|
|
751
|
-
timestamp: artifact.generatedAt,
|
|
752
|
-
category: "run_improvements",
|
|
753
|
-
event_name: "RunImprovementsGenerated",
|
|
754
|
-
reason_code: "RUN_IMPROVEMENTS_PREPARED",
|
|
755
|
-
confidence_score: 1.0,
|
|
756
|
-
platform: "avorelo",
|
|
757
|
-
metadata: {
|
|
758
|
-
schemaVersion: artifact.schemaVersion,
|
|
759
|
-
status: artifact.status,
|
|
760
|
-
improvementCount: artifact.topImprovements.length,
|
|
761
|
-
topCategories: [...new Set(artifact.topImprovements.map((i) => i.category))].slice(0, 3),
|
|
762
|
-
sourceRunFingerprint: artifact.sourceRunFingerprint,
|
|
763
|
-
redacted: true,
|
|
764
|
-
},
|
|
765
|
-
});
|
|
766
|
-
fs.appendFileSync(eventsPath, event + "\n", "utf8");
|
|
767
|
-
}
|
|
768
|
-
|
|
769
|
-
module.exports = {
|
|
770
|
-
SCHEMA_VERSION,
|
|
771
|
-
IMPROVEMENT_CATEGORIES,
|
|
772
|
-
STATUSES,
|
|
773
|
-
MODES,
|
|
774
|
-
TTL_MS,
|
|
775
|
-
RUN_IMPROVEMENTS_REL,
|
|
776
|
-
buildSourceFingerprint,
|
|
777
|
-
collectRepoState,
|
|
778
|
-
collectSignals,
|
|
779
|
-
generateImprovements,
|
|
780
|
-
generateNextRunDefaults,
|
|
781
|
-
buildPublicSummary,
|
|
782
|
-
buildRunImprovements,
|
|
783
|
-
generateRunImprovementsArtifact,
|
|
784
|
-
loadRunImprovements,
|
|
785
|
-
formatRunImprovementsText,
|
|
786
|
-
formatRunImprovementsStatusLine,
|
|
787
|
-
buildRunImprovementsSurface,
|
|
788
|
-
isExpired,
|
|
789
|
-
};
|