bb-cc-lite 0.1.9 → 0.1.10

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.
@@ -0,0 +1,245 @@
1
+ const VALIDATION_PURPOSES = new Set(["tests", "lint", "typecheck", "build"]);
2
+ export function decideFeedback(input) {
3
+ if (input.mode === "observe") {
4
+ return { kind: "none" };
5
+ }
6
+ if (input.hookEventName === "Stop") {
7
+ return stopFeedback(input);
8
+ }
9
+ const coachRetryWarning = coachValidationRetryWarning(input);
10
+ if (coachRetryWarning) {
11
+ return coachRetryWarning;
12
+ }
13
+ if (input.mode === "guard" && input.hookEventName === "PreToolUse") {
14
+ const guard = guardFeedback(input);
15
+ if (guard.kind !== "none") {
16
+ return guard;
17
+ }
18
+ if (!isValidationTool(input.currentTool)) {
19
+ return { kind: "none" };
20
+ }
21
+ }
22
+ if (input.decision?.state === "Healthy" || hasFreshValidationSuccess(input.summary)) {
23
+ return { kind: "none" };
24
+ }
25
+ const risk = strongestRisk(input);
26
+ if (!risk) {
27
+ return { kind: "none" };
28
+ }
29
+ const cooldownKey = `coach:${risk.reasonCode}:${risk.safeCategory}`;
30
+ if (hasRecentCooldown(input.recentFeedback, cooldownKey)) {
31
+ return { kind: "none" };
32
+ }
33
+ return {
34
+ kind: "coach",
35
+ delivery: "additional_context",
36
+ reasonCode: risk.reasonCode,
37
+ safeCategory: risk.safeCategory,
38
+ confidence: risk.confidence,
39
+ messageKey: risk.messageKey,
40
+ cooldownKey,
41
+ message: messageFor(risk.messageKey)
42
+ };
43
+ }
44
+ function guardFeedback(input) {
45
+ const currentCategory = validationCategory(input.currentTool?.purpose);
46
+ if (!currentCategory || input.currentTool?.toolName !== "Bash") {
47
+ return { kind: "none" };
48
+ }
49
+ const blindRetry = input.summary.blindRetry;
50
+ const repeated = strongestRepeatedValidationFailure(input.summary);
51
+ const isHighConfidenceRetry = !input.summary.hasUnvalidatedEdits &&
52
+ ((blindRetry?.category === currentCategory && blindRetry.blindRetryFailureCount >= 3) ||
53
+ (repeated?.safeCategory === currentCategory && repeated.count >= 3));
54
+ if (!isHighConfidenceRetry) {
55
+ return { kind: "none" };
56
+ }
57
+ const cooldownKey = `guard:guard_validation_retry:${currentCategory}`;
58
+ return {
59
+ kind: "guard",
60
+ reasonCode: "guard_validation_retry",
61
+ safeCategory: currentCategory,
62
+ confidence: "high",
63
+ messageKey: "guard_validation_retry",
64
+ cooldownKey,
65
+ message: messageFor("guard_validation_retry")
66
+ };
67
+ }
68
+ function coachValidationRetryWarning(input) {
69
+ if (input.mode !== "coach" || input.hookEventName !== "PreToolUse" || !isValidationTool(input.currentTool)) {
70
+ return undefined;
71
+ }
72
+ const category = validationCategory(input.currentTool?.purpose);
73
+ if (!category || input.summary.hasUnvalidatedEdits) {
74
+ return undefined;
75
+ }
76
+ const blindRetry = input.summary.blindRetry;
77
+ const repeated = strongestRepeatedValidationFailure(input.summary);
78
+ const isRetryAfterFailure = (blindRetry?.category === category && blindRetry.blindRetryFailureCount >= 2) ||
79
+ (repeated?.safeCategory === category && repeated.count >= 2);
80
+ if (!isRetryAfterFailure) {
81
+ return undefined;
82
+ }
83
+ const priorCoachWasIgnored = input.recentFeedback.some((feedback) => feedback.action === "coach" &&
84
+ (feedback.cooldownKey === `coach:validation_repeated:${category}` ||
85
+ feedback.cooldownKey === `coach:blind_retry_loop:${category}` ||
86
+ feedback.cooldownKey === `coach:coach_validation_retry_after_feedback:${category}`));
87
+ if (!priorCoachWasIgnored) {
88
+ return undefined;
89
+ }
90
+ return {
91
+ kind: "coach",
92
+ delivery: "additional_context",
93
+ reasonCode: "coach_validation_retry_after_feedback",
94
+ safeCategory: category,
95
+ confidence: blindRetry && blindRetry.blindRetryFailureCount >= 3 ? "high" : "medium",
96
+ messageKey: "coach_validation_retry_after_feedback",
97
+ cooldownKey: `coach:coach_validation_retry_after_feedback:${category}`,
98
+ message: messageFor("coach_validation_retry_after_feedback")
99
+ };
100
+ }
101
+ function stopFeedback(input) {
102
+ if (input.stopHookActive || input.decision?.state === "Healthy") {
103
+ return { kind: "none" };
104
+ }
105
+ const hasUnresolvedRisk = input.decision?.state === "Stop" ||
106
+ input.decision?.reasonCode === "blind_retry" ||
107
+ input.decision?.reasonCode === "tool_failure_repeated" ||
108
+ input.summary.hasUnvalidatedEdits ||
109
+ Boolean(input.summary.blindRetry && input.summary.blindRetry.blindRetryFailureCount >= 2) ||
110
+ Boolean(strongestRepeatedValidationFailure(input.summary));
111
+ if (!hasUnresolvedRisk) {
112
+ return { kind: "none" };
113
+ }
114
+ const cooldownKey = "coach:finish_with_unresolved_risk:finish";
115
+ if (hasRecentCooldown(input.recentFeedback, cooldownKey)) {
116
+ return { kind: "none" };
117
+ }
118
+ return {
119
+ kind: "coach",
120
+ delivery: "stop_block",
121
+ reasonCode: "finish_with_unresolved_risk",
122
+ safeCategory: "finish",
123
+ confidence: "medium",
124
+ messageKey: "finish_with_unresolved_risk",
125
+ cooldownKey,
126
+ message: messageFor("finish_with_unresolved_risk")
127
+ };
128
+ }
129
+ function strongestRisk(input) {
130
+ const blindRetry = input.summary.blindRetry;
131
+ if (blindRetry && blindRetry.blindRetryFailureCount >= 3) {
132
+ return {
133
+ reasonCode: "blind_retry_loop",
134
+ safeCategory: safeCategoryForFailureCategory(blindRetry.category),
135
+ confidence: "high",
136
+ messageKey: "blind_retry_loop"
137
+ };
138
+ }
139
+ if (blindRetry && blindRetry.blindRetryFailureCount >= 2) {
140
+ return {
141
+ reasonCode: "validation_repeated",
142
+ safeCategory: safeCategoryForFailureCategory(blindRetry.category),
143
+ confidence: "medium",
144
+ messageKey: "validation_repeated"
145
+ };
146
+ }
147
+ const repeated = strongestRepeatedValidationFailure(input.summary);
148
+ if (repeated && repeated.count >= 2) {
149
+ return {
150
+ reasonCode: "validation_repeated",
151
+ safeCategory: repeated.safeCategory,
152
+ confidence: repeated.count >= 3 ? "high" : "medium",
153
+ messageKey: "validation_repeated"
154
+ };
155
+ }
156
+ if (input.summary.hasUnvalidatedEdits) {
157
+ return {
158
+ reasonCode: "edit_without_validation",
159
+ safeCategory: "edit",
160
+ confidence: "medium",
161
+ messageKey: "edit_without_validation"
162
+ };
163
+ }
164
+ if (input.decision?.reasonCode === "budget_busy_no_observed_progress") {
165
+ return {
166
+ reasonCode: "budget_busy_no_observed_progress",
167
+ safeCategory: "budget",
168
+ confidence: "medium",
169
+ messageKey: "budget_busy_no_observed_progress"
170
+ };
171
+ }
172
+ if (input.decision?.reasonCode === "cost_budget" || input.decision?.reasonCode === "duration_budget") {
173
+ return {
174
+ reasonCode: input.decision.reasonCode,
175
+ safeCategory: "budget",
176
+ confidence: "medium",
177
+ messageKey: "budget_summary"
178
+ };
179
+ }
180
+ if (input.decision?.reasonCode === "busy_no_observed_progress") {
181
+ return {
182
+ reasonCode: "busy_no_observed_progress",
183
+ safeCategory: "activity",
184
+ confidence: "medium",
185
+ messageKey: "busy_no_observed_progress"
186
+ };
187
+ }
188
+ return undefined;
189
+ }
190
+ function strongestRepeatedValidationFailure(summary) {
191
+ return summary.repeatedFailures
192
+ .flatMap((failure) => {
193
+ const purpose = validationCategory(failure.purpose);
194
+ return failure.toolName === "Bash" && purpose ? [{ safeCategory: purpose, count: failure.count }] : [];
195
+ })
196
+ .sort((left, right) => right.count - left.count)[0];
197
+ }
198
+ function hasFreshValidationSuccess(summary) {
199
+ return summary.validationRecovered || (summary.validationSuccesses || 0) > 0;
200
+ }
201
+ function isValidationTool(tool) {
202
+ return tool?.toolName === "Bash" && validationCategory(tool.purpose) !== undefined;
203
+ }
204
+ function validationCategory(value) {
205
+ return value && VALIDATION_PURPOSES.has(value)
206
+ ? value
207
+ : undefined;
208
+ }
209
+ function safeCategoryForFailureCategory(category) {
210
+ if (category === "tests" || category === "lint" || category === "typecheck" || category === "build") {
211
+ return category;
212
+ }
213
+ if (category === "mcp") {
214
+ return "mcp";
215
+ }
216
+ return "tool";
217
+ }
218
+ function hasRecentCooldown(recentFeedback, cooldownKey) {
219
+ return recentFeedback.some((feedback) => feedback.cooldownKey === cooldownKey);
220
+ }
221
+ function messageFor(messageKey) {
222
+ switch (messageKey) {
223
+ case "blind_retry_loop":
224
+ return "bb-cc-lite: the same safe validation category has failed repeatedly without a fix. Inspect the first failure and change approach before retrying.";
225
+ case "validation_repeated":
226
+ return "bb-cc-lite: validation has failed repeatedly without a passing check. Inspect the failure pattern, make one targeted fix, then run one focused check.";
227
+ case "coach_validation_retry_after_feedback":
228
+ return "bb-cc-lite: do not run the same validation check again yet. First inspect the failure, change the approach, or summarize the blocker; only rerun after a targeted fix.";
229
+ case "edit_without_validation":
230
+ return "bb-cc-lite: edits have not been validated yet; run one focused validation check before finishing or making more broad changes.";
231
+ case "budget_busy_no_observed_progress":
232
+ return "bb-cc-lite: budget is high and no safe progress signal was observed. Narrow the scope or summarize the blocker before continuing.";
233
+ case "budget_summary":
234
+ return "bb-cc-lite: budget is high for this session; summarize progress, name the next smallest check, and avoid broad retries.";
235
+ case "busy_no_observed_progress":
236
+ return "bb-cc-lite: many tool calls have run without a safe progress signal. Pause, state what changed, and choose one focused next step.";
237
+ case "guard_validation_retry":
238
+ return "bb-cc-lite denied this retry: the same validation category has failed repeatedly without an edit or passing check. Inspect before retrying.";
239
+ case "finish_with_unresolved_risk":
240
+ return "bb-cc-lite: unresolved validation risk remains. Run one focused check or summarize the blocker before finishing.";
241
+ default:
242
+ return "bb-cc-lite: inspect the latest safe risk signal before continuing.";
243
+ }
244
+ }
245
+ //# sourceMappingURL=feedback-policy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"feedback-policy.js","sourceRoot":"","sources":["../src/feedback-policy.ts"],"names":[],"mappings":"AAiDA,MAAM,mBAAmB,GAAG,IAAI,GAAG,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,OAAO,CAAC,CAAC,CAAC;AAE7E,MAAM,UAAU,cAAc,CAAC,KAA0B;IACvD,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC7B,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IAC1B,CAAC;IAED,IAAI,KAAK,CAAC,aAAa,KAAK,MAAM,EAAE,CAAC;QACnC,OAAO,YAAY,CAAC,KAAK,CAAC,CAAC;IAC7B,CAAC;IAED,MAAM,iBAAiB,GAAG,2BAA2B,CAAC,KAAK,CAAC,CAAC;IAC7D,IAAI,iBAAiB,EAAE,CAAC;QACtB,OAAO,iBAAiB,CAAC;IAC3B,CAAC;IAED,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,IAAI,KAAK,CAAC,aAAa,KAAK,YAAY,EAAE,CAAC;QACnE,MAAM,KAAK,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;QACnC,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YAC1B,OAAO,KAAK,CAAC;QACf,CAAC;QACD,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE,CAAC;YACzC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;QAC1B,CAAC;IACH,CAAC;IAED,IAAI,KAAK,CAAC,QAAQ,EAAE,KAAK,KAAK,SAAS,IAAI,yBAAyB,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;QACpF,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IAC1B,CAAC;IAED,MAAM,IAAI,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;IAClC,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IAC1B,CAAC;IACD,MAAM,WAAW,GAAG,SAAS,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;IACpE,IAAI,iBAAiB,CAAC,KAAK,CAAC,cAAc,EAAE,WAAW,CAAC,EAAE,CAAC;QACzD,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IAC1B,CAAC;IACD,OAAO;QACL,IAAI,EAAE,OAAO;QACb,QAAQ,EAAE,oBAAoB;QAC9B,UAAU,EAAE,IAAI,CAAC,UAAU;QAC3B,YAAY,EAAE,IAAI,CAAC,YAAY;QAC/B,UAAU,EAAE,IAAI,CAAC,UAAU;QAC3B,UAAU,EAAE,IAAI,CAAC,UAAU;QAC3B,WAAW;QACX,OAAO,EAAE,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC;KACrC,CAAC;AACJ,CAAC;AAED,SAAS,aAAa,CAAC,KAA0B;IAC/C,MAAM,eAAe,GAAG,kBAAkB,CAAC,KAAK,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;IACvE,IAAI,CAAC,eAAe,IAAI,KAAK,CAAC,WAAW,EAAE,QAAQ,KAAK,MAAM,EAAE,CAAC;QAC/D,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IAC1B,CAAC;IACD,MAAM,UAAU,GAAG,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC;IAC5C,MAAM,QAAQ,GAAG,kCAAkC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACnE,MAAM,qBAAqB,GACzB,CAAC,KAAK,CAAC,OAAO,CAAC,mBAAmB;QAClC,CAAC,CAAC,UAAU,EAAE,QAAQ,KAAK,eAAe,IAAI,UAAU,CAAC,sBAAsB,IAAI,CAAC,CAAC;YACnF,CAAC,QAAQ,EAAE,YAAY,KAAK,eAAe,IAAI,QAAQ,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC;IACzE,IAAI,CAAC,qBAAqB,EAAE,CAAC;QAC3B,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IAC1B,CAAC;IAED,MAAM,WAAW,GAAG,gCAAgC,eAAe,EAAE,CAAC;IACtE,OAAO;QACL,IAAI,EAAE,OAAO;QACb,UAAU,EAAE,wBAAwB;QACpC,YAAY,EAAE,eAAe;QAC7B,UAAU,EAAE,MAAM;QAClB,UAAU,EAAE,wBAAwB;QACpC,WAAW;QACX,OAAO,EAAE,UAAU,CAAC,wBAAwB,CAAC;KAC9C,CAAC;AACJ,CAAC;AAED,SAAS,2BAA2B,CAAC,KAA0B;IAC7D,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,IAAI,KAAK,CAAC,aAAa,KAAK,YAAY,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE,CAAC;QAC3G,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,MAAM,QAAQ,GAAG,kBAAkB,CAAC,KAAK,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;IAChE,IAAI,CAAC,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,mBAAmB,EAAE,CAAC;QACnD,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,MAAM,UAAU,GAAG,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC;IAC5C,MAAM,QAAQ,GAAG,kCAAkC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACnE,MAAM,mBAAmB,GACvB,CAAC,UAAU,EAAE,QAAQ,KAAK,QAAQ,IAAI,UAAU,CAAC,sBAAsB,IAAI,CAAC,CAAC;QAC7E,CAAC,QAAQ,EAAE,YAAY,KAAK,QAAQ,IAAI,QAAQ,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC;IAC/D,IAAI,CAAC,mBAAmB,EAAE,CAAC;QACzB,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,MAAM,oBAAoB,GAAG,KAAK,CAAC,cAAc,CAAC,IAAI,CACpD,CAAC,QAAQ,EAAE,EAAE,CACX,QAAQ,CAAC,MAAM,KAAK,OAAO;QAC3B,CAAC,QAAQ,CAAC,WAAW,KAAK,6BAA6B,QAAQ,EAAE;YAC/D,QAAQ,CAAC,WAAW,KAAK,0BAA0B,QAAQ,EAAE;YAC7D,QAAQ,CAAC,WAAW,KAAK,+CAA+C,QAAQ,EAAE,CAAC,CACxF,CAAC;IACF,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAC1B,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,OAAO;QACL,IAAI,EAAE,OAAO;QACb,QAAQ,EAAE,oBAAoB;QAC9B,UAAU,EAAE,uCAAuC;QACnD,YAAY,EAAE,QAAQ;QACtB,UAAU,EAAE,UAAU,IAAI,UAAU,CAAC,sBAAsB,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ;QACpF,UAAU,EAAE,uCAAuC;QACnD,WAAW,EAAE,+CAA+C,QAAQ,EAAE;QACtE,OAAO,EAAE,UAAU,CAAC,uCAAuC,CAAC;KAC7D,CAAC;AACJ,CAAC;AAED,SAAS,YAAY,CAAC,KAA0B;IAC9C,IAAI,KAAK,CAAC,cAAc,IAAI,KAAK,CAAC,QAAQ,EAAE,KAAK,KAAK,SAAS,EAAE,CAAC;QAChE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IAC1B,CAAC;IACD,MAAM,iBAAiB,GACrB,KAAK,CAAC,QAAQ,EAAE,KAAK,KAAK,MAAM;QAChC,KAAK,CAAC,QAAQ,EAAE,UAAU,KAAK,aAAa;QAC5C,KAAK,CAAC,QAAQ,EAAE,UAAU,KAAK,uBAAuB;QACtD,KAAK,CAAC,OAAO,CAAC,mBAAmB;QACjC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,IAAI,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,sBAAsB,IAAI,CAAC,CAAC;QACzF,OAAO,CAAC,kCAAkC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;IAC7D,IAAI,CAAC,iBAAiB,EAAE,CAAC;QACvB,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IAC1B,CAAC;IAED,MAAM,WAAW,GAAG,0CAA0C,CAAC;IAC/D,IAAI,iBAAiB,CAAC,KAAK,CAAC,cAAc,EAAE,WAAW,CAAC,EAAE,CAAC;QACzD,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IAC1B,CAAC;IACD,OAAO;QACL,IAAI,EAAE,OAAO;QACb,QAAQ,EAAE,YAAY;QACtB,UAAU,EAAE,6BAA6B;QACzC,YAAY,EAAE,QAAQ;QACtB,UAAU,EAAE,QAAQ;QACpB,UAAU,EAAE,6BAA6B;QACzC,WAAW;QACX,OAAO,EAAE,UAAU,CAAC,6BAA6B,CAAC;KACnD,CAAC;AACJ,CAAC;AAED,SAAS,aAAa,CAAC,KAA0B;IAQ/C,MAAM,UAAU,GAAG,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC;IAC5C,IAAI,UAAU,IAAI,UAAU,CAAC,sBAAsB,IAAI,CAAC,EAAE,CAAC;QACzD,OAAO;YACL,UAAU,EAAE,kBAAkB;YAC9B,YAAY,EAAE,8BAA8B,CAAC,UAAU,CAAC,QAAQ,CAAC;YACjE,UAAU,EAAE,MAAM;YAClB,UAAU,EAAE,kBAAkB;SAC/B,CAAC;IACJ,CAAC;IAED,IAAI,UAAU,IAAI,UAAU,CAAC,sBAAsB,IAAI,CAAC,EAAE,CAAC;QACzD,OAAO;YACL,UAAU,EAAE,qBAAqB;YACjC,YAAY,EAAE,8BAA8B,CAAC,UAAU,CAAC,QAAQ,CAAC;YACjE,UAAU,EAAE,QAAQ;YACpB,UAAU,EAAE,qBAAqB;SAClC,CAAC;IACJ,CAAC;IAED,MAAM,QAAQ,GAAG,kCAAkC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACnE,IAAI,QAAQ,IAAI,QAAQ,CAAC,KAAK,IAAI,CAAC,EAAE,CAAC;QACpC,OAAO;YACL,UAAU,EAAE,qBAAqB;YACjC,YAAY,EAAE,QAAQ,CAAC,YAAY;YACnC,UAAU,EAAE,QAAQ,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ;YACnD,UAAU,EAAE,qBAAqB;SAClC,CAAC;IACJ,CAAC;IAED,IAAI,KAAK,CAAC,OAAO,CAAC,mBAAmB,EAAE,CAAC;QACtC,OAAO;YACL,UAAU,EAAE,yBAAyB;YACrC,YAAY,EAAE,MAAM;YACpB,UAAU,EAAE,QAAQ;YACpB,UAAU,EAAE,yBAAyB;SACtC,CAAC;IACJ,CAAC;IAED,IAAI,KAAK,CAAC,QAAQ,EAAE,UAAU,KAAK,kCAAkC,EAAE,CAAC;QACtE,OAAO;YACL,UAAU,EAAE,kCAAkC;YAC9C,YAAY,EAAE,QAAQ;YACtB,UAAU,EAAE,QAAQ;YACpB,UAAU,EAAE,kCAAkC;SAC/C,CAAC;IACJ,CAAC;IACD,IAAI,KAAK,CAAC,QAAQ,EAAE,UAAU,KAAK,aAAa,IAAI,KAAK,CAAC,QAAQ,EAAE,UAAU,KAAK,iBAAiB,EAAE,CAAC;QACrG,OAAO;YACL,UAAU,EAAE,KAAK,CAAC,QAAQ,CAAC,UAAU;YACrC,YAAY,EAAE,QAAQ;YACtB,UAAU,EAAE,QAAQ;YACpB,UAAU,EAAE,gBAAgB;SAC7B,CAAC;IACJ,CAAC;IACD,IAAI,KAAK,CAAC,QAAQ,EAAE,UAAU,KAAK,2BAA2B,EAAE,CAAC;QAC/D,OAAO;YACL,UAAU,EAAE,2BAA2B;YACvC,YAAY,EAAE,UAAU;YACxB,UAAU,EAAE,QAAQ;YACpB,UAAU,EAAE,2BAA2B;SACxC,CAAC;IACJ,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,kCAAkC,CACzC,OAA0B;IAE1B,OAAO,OAAO,CAAC,gBAAgB;SAC5B,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QACnB,MAAM,OAAO,GAAG,kBAAkB,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QACpD,OAAO,OAAO,CAAC,QAAQ,KAAK,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACzG,CAAC,CAAC;SACD,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AACxD,CAAC;AAED,SAAS,yBAAyB,CAAC,OAA0B;IAC3D,OAAO,OAAO,CAAC,mBAAmB,IAAI,CAAC,OAAO,CAAC,mBAAmB,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;AAC/E,CAAC;AAED,SAAS,gBAAgB,CAAC,IAAiC;IACzD,OAAO,IAAI,EAAE,QAAQ,KAAK,MAAM,IAAI,kBAAkB,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,SAAS,CAAC;AACrF,CAAC;AAED,SAAS,kBAAkB,CAAC,KAAyB;IACnD,OAAO,KAAK,IAAI,mBAAmB,CAAC,GAAG,CAAC,KAAK,CAAC;QAC5C,CAAC,CAAE,KAAiF;QACpF,CAAC,CAAC,SAAS,CAAC;AAChB,CAAC;AAED,SAAS,8BAA8B,CAAC,QAAgB;IACtD,IAAI,QAAQ,KAAK,OAAO,IAAI,QAAQ,KAAK,MAAM,IAAI,QAAQ,KAAK,WAAW,IAAI,QAAQ,KAAK,OAAO,EAAE,CAAC;QACpG,OAAO,QAAQ,CAAC;IAClB,CAAC;IACD,IAAI,QAAQ,KAAK,KAAK,EAAE,CAAC;QACvB,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,iBAAiB,CAAC,cAAgC,EAAE,WAAmB;IAC9E,OAAO,cAAc,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,WAAW,KAAK,WAAW,CAAC,CAAC;AACjF,CAAC;AAED,SAAS,UAAU,CAAC,UAAkB;IACpC,QAAQ,UAAU,EAAE,CAAC;QACnB,KAAK,kBAAkB;YACrB,OAAO,mJAAmJ,CAAC;QAC7J,KAAK,qBAAqB;YACxB,OAAO,uJAAuJ,CAAC;QACjK,KAAK,uCAAuC;YAC1C,OAAO,wKAAwK,CAAC;QAClL,KAAK,yBAAyB;YAC5B,OAAO,gIAAgI,CAAC;QAC1I,KAAK,kCAAkC;YACrC,OAAO,mIAAmI,CAAC;QAC7I,KAAK,gBAAgB;YACnB,OAAO,yHAAyH,CAAC;QACnI,KAAK,2BAA2B;YAC9B,OAAO,mIAAmI,CAAC;QAC7I,KAAK,wBAAwB;YAC3B,OAAO,6IAA6I,CAAC;QACvJ,KAAK,6BAA6B;YAChC,OAAO,kHAAkH,CAAC;QAC5H;YACE,OAAO,oEAAoE,CAAC;IAChF,CAAC;AACH,CAAC"}
@@ -0,0 +1,11 @@
1
+ import { type FeedbackMode } from "./feedback-policy.js";
2
+ import { type HookResponse } from "./hook-response.js";
3
+ export interface HandleHookOptions {
4
+ fallbackEventName?: string;
5
+ mode?: FeedbackMode;
6
+ learn?: boolean;
7
+ storePath?: string;
8
+ homeDir?: string;
9
+ appHomePath?: string;
10
+ }
11
+ export declare function handleHook(raw: string, options?: HandleHookOptions): Promise<HookResponse | undefined>;
@@ -0,0 +1,122 @@
1
+ import { decideFeedback } from "./feedback-policy.js";
2
+ import { responseForFeedback } from "./hook-response.js";
3
+ import { parseHookPayload } from "./hook-payload.js";
4
+ import { lessonContextForProject, recordLessonFromSummary } from "./memory-lessons.js";
5
+ import { hashValue, projectKeyFromPath } from "./paths.js";
6
+ import { asRecord, stringField } from "./status-input.js";
7
+ import { classifyToolIdentity } from "./tool-metadata.js";
8
+ import { hookSummary, latestDecision, recentFeedbackEvents, recordFeedbackEvent, recordHookEvent } from "./store.js";
9
+ const EMPTY_TRANSCRIPT = {
10
+ pathReadable: true,
11
+ bytesRead: 0,
12
+ linesRead: 0,
13
+ malformedLines: 0,
14
+ toolCalls: 0,
15
+ readToolCalls: 0,
16
+ successfulEditResults: 0,
17
+ validationChecks: 0,
18
+ validationSuccesses: 0,
19
+ toolRecoveryEvents: 0,
20
+ failedToolResults: 0,
21
+ repeatedFailures: [],
22
+ editTestLoopFailures: 0,
23
+ hasUnvalidatedEdits: false,
24
+ validationRecovered: false,
25
+ observedProgress: false,
26
+ compactionEvents: 0,
27
+ postCompactionActivity: 0,
28
+ usage: {}
29
+ };
30
+ export async function handleHook(raw, options = {}) {
31
+ const root = parseRoot(raw);
32
+ if (!root) {
33
+ return undefined;
34
+ }
35
+ const hookEventName = stringField(root.hook_event_name) || stringField(root.event) || options.fallbackEventName || "unknown";
36
+ const sessionKey = hashValue(stringField(root.session_id) || stringField(root.sessionId));
37
+ const mode = options.mode || "coach";
38
+ const learn = options.learn !== false && process.env.BB_CC_LITE_LESSON_MEMORY !== "0";
39
+ const event = parseHookPayload(raw, hookEventName);
40
+ if (event && hookEventName !== "PreToolUse" && hookEventName !== "SessionStart") {
41
+ await recordHookEvent(event, options.storePath);
42
+ }
43
+ const summary = sessionKey ? await summaryForSession(sessionKey, options.storePath) : EMPTY_TRANSCRIPT;
44
+ if (hookEventName === "SessionEnd") {
45
+ if (learn) {
46
+ const projectKey = projectKeyFromHook(root);
47
+ if (projectKey) {
48
+ await recordLessonFromSummary({
49
+ projectKey,
50
+ summary,
51
+ homeDir: options.homeDir,
52
+ appHomePath: options.appHomePath
53
+ });
54
+ }
55
+ }
56
+ return undefined;
57
+ }
58
+ if (hookEventName === "SessionStart") {
59
+ if (mode === "observe" || !learn) {
60
+ return undefined;
61
+ }
62
+ const projectKey = projectKeyFromHook(root);
63
+ const lessonContext = projectKey
64
+ ? await lessonContextForProject({ projectKey, homeDir: options.homeDir, appHomePath: options.appHomePath })
65
+ : undefined;
66
+ return lessonContext
67
+ ? {
68
+ hookSpecificOutput: {
69
+ hookEventName,
70
+ additionalContext: lessonContext
71
+ }
72
+ }
73
+ : undefined;
74
+ }
75
+ const decision = sessionKey ? await latestDecision(sessionKey, options.storePath) : undefined;
76
+ const recentFeedback = await recentFeedbackEvents(sessionKey, options.storePath);
77
+ const feedback = decideFeedback({
78
+ mode,
79
+ hookEventName,
80
+ decision,
81
+ summary,
82
+ currentTool: currentTool(root),
83
+ recentFeedback,
84
+ stopHookActive: root.stop_hook_active === true || root.stopHookActive === true
85
+ });
86
+ if (feedback.kind !== "none") {
87
+ await recordFeedbackEvent({
88
+ sessionKey,
89
+ hookEventName,
90
+ feedbackAction: feedback.kind,
91
+ cooldownKey: feedback.cooldownKey
92
+ }, options.storePath);
93
+ }
94
+ return responseForFeedback(hookEventName, feedback);
95
+ }
96
+ async function summaryForSession(sessionKey, storePath) {
97
+ const summary = await hookSummary(sessionKey, storePath);
98
+ return {
99
+ ...EMPTY_TRANSCRIPT,
100
+ ...summary
101
+ };
102
+ }
103
+ function currentTool(root) {
104
+ const identity = classifyToolIdentity(stringField(root.tool_name) || stringField(root.toolName), root.tool_input ?? root.toolInput);
105
+ return {
106
+ toolName: identity.displayName,
107
+ purpose: identity.purpose
108
+ };
109
+ }
110
+ function parseRoot(raw) {
111
+ try {
112
+ return asRecord(JSON.parse(raw.trim() || "{}"));
113
+ }
114
+ catch {
115
+ return undefined;
116
+ }
117
+ }
118
+ function projectKeyFromHook(root) {
119
+ const cwd = stringField(root.cwd) || stringField(asRecord(root.workspace)?.current_dir) || stringField(asRecord(root.workspace)?.project_dir);
120
+ return cwd ? projectKeyFromPath(cwd) : undefined;
121
+ }
122
+ //# sourceMappingURL=hook-control.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hook-control.js","sourceRoot":"","sources":["../src/hook-control.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { FeedbackDecision } from "./feedback-policy.js";
2
+ export type HookResponse = Record<string, unknown>;
3
+ export declare function responseForFeedback(hookEventName: string, feedback: FeedbackDecision): HookResponse | undefined;
@@ -0,0 +1,27 @@
1
+ export function responseForFeedback(hookEventName, feedback) {
2
+ if (feedback.kind === "none") {
3
+ return undefined;
4
+ }
5
+ if (feedback.kind === "guard") {
6
+ return {
7
+ hookSpecificOutput: {
8
+ hookEventName,
9
+ permissionDecision: "deny",
10
+ permissionDecisionReason: feedback.message
11
+ }
12
+ };
13
+ }
14
+ if (feedback.delivery === "stop_block") {
15
+ return {
16
+ decision: "block",
17
+ reason: feedback.message
18
+ };
19
+ }
20
+ return {
21
+ hookSpecificOutput: {
22
+ hookEventName,
23
+ additionalContext: feedback.message
24
+ }
25
+ };
26
+ }
27
+ //# sourceMappingURL=hook-response.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hook-response.js","sourceRoot":"","sources":["../src/hook-response.ts"],"names":[],"mappings":"AAIA,MAAM,UAAU,mBAAmB,CAAC,aAAqB,EAAE,QAA0B;IACnF,IAAI,QAAQ,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QAC7B,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,IAAI,QAAQ,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;QAC9B,OAAO;YACL,kBAAkB,EAAE;gBAClB,aAAa;gBACb,kBAAkB,EAAE,MAAM;gBAC1B,wBAAwB,EAAE,QAAQ,CAAC,OAAO;aAC3C;SACF,CAAC;IACJ,CAAC;IAED,IAAI,QAAQ,CAAC,QAAQ,KAAK,YAAY,EAAE,CAAC;QACvC,OAAO;YACL,QAAQ,EAAE,OAAO;YACjB,MAAM,EAAE,QAAQ,CAAC,OAAO;SACzB,CAAC;IACJ,CAAC;IAED,OAAO;QACL,kBAAkB,EAAE;YAClB,aAAa;YACb,iBAAiB,EAAE,QAAQ,CAAC,OAAO;SACpC;KACF,CAAC;AACJ,CAAC"}
@@ -2,6 +2,13 @@ import type { TranscriptSummary } from "./types.js";
2
2
  export declare function mergeHookSummary(transcript: TranscriptSummary, hookData: {
3
3
  failedToolResults: number;
4
4
  toolCalls: number;
5
+ readToolCalls?: number;
6
+ successfulEditResults?: number;
7
+ validationChecks?: number;
8
+ validationSuccesses?: number;
9
+ validationRecovered?: boolean;
10
+ hasUnvalidatedEdits?: boolean;
11
+ unvalidatedEditToolSteps?: number;
5
12
  compactionEvents: number;
6
13
  postCompactionActivity: number;
7
14
  repeatedFailures: TranscriptSummary["repeatedFailures"];
@@ -10,9 +10,16 @@ export function mergeHookSummary(transcript, hookData) {
10
10
  return {
11
11
  ...transcript,
12
12
  toolCalls: Math.max(transcript.toolCalls, hookData.toolCalls),
13
+ readToolCalls: Math.max(transcript.readToolCalls, hookData.readToolCalls || 0),
14
+ successfulEditResults: Math.max(transcript.successfulEditResults || 0, hookData.successfulEditResults || 0),
15
+ validationChecks: Math.max(transcript.validationChecks || 0, hookData.validationChecks || 0),
16
+ validationSuccesses: Math.max(transcript.validationSuccesses || 0, hookData.validationSuccesses || 0),
13
17
  failedToolResults: Math.max(transcript.failedToolResults, hookData.failedToolResults),
14
18
  repeatedFailures: [...repeatedFailures.values()].filter((failure) => failure.count >= 2),
15
19
  blindRetry: strongestBlindRetry(transcript.blindRetry, hookData.blindRetry),
20
+ hasUnvalidatedEdits: transcript.hasUnvalidatedEdits || Boolean(hookData.hasUnvalidatedEdits),
21
+ unvalidatedEditToolSteps: Math.max(transcript.unvalidatedEditToolSteps || 0, hookData.unvalidatedEditToolSteps || 0) || undefined,
22
+ validationRecovered: transcript.validationRecovered || Boolean(hookData.validationRecovered),
16
23
  compactionEvents: Math.max(transcript.compactionEvents, hookData.compactionEvents),
17
24
  postCompactionActivity: mergedPostCompactionActivity(transcript, hookData, latestTimestamp, latestCompactionTimestamp),
18
25
  latestTimestamp,
@@ -1 +1 @@
1
- {"version":3,"file":"hook-summary.js","sourceRoot":"","sources":["../src/hook-summary.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"hook-summary.js","sourceRoot":"","sources":["../src/hook-summary.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,gBAAgB,CAC9B,UAA6B,EAC7B,QAgBC;IAED,MAAM,gBAAgB,GAAG,IAAI,GAAG,EAAyD,CAAC;IAC1F,KAAK,MAAM,OAAO,IAAI,CAAC,GAAG,UAAU,CAAC,gBAAgB,EAAE,GAAG,QAAQ,CAAC,gBAAgB,CAAC,EAAE,CAAC;QACrF,MAAM,GAAG,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;QAChC,MAAM,QAAQ,GAAG,gBAAgB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC3C,gBAAgB,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,GAAG,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,KAAK,IAAI,CAAC,EAAE,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAClG,CAAC;IAED,MAAM,eAAe,GAAG,kBAAkB,CAAC,UAAU,CAAC,eAAe,EAAE,QAAQ,CAAC,eAAe,CAAC,CAAC;IACjG,MAAM,yBAAyB,GAAG,kBAAkB,CAAC,UAAU,CAAC,yBAAyB,EAAE,QAAQ,CAAC,yBAAyB,CAAC,CAAC;IAE/H,OAAO;QACL,GAAG,UAAU;QACb,SAAS,EAAE,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,SAAS,EAAE,QAAQ,CAAC,SAAS,CAAC;QAC7D,aAAa,EAAE,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,aAAa,EAAE,QAAQ,CAAC,aAAa,IAAI,CAAC,CAAC;QAC9E,qBAAqB,EAAE,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,qBAAqB,IAAI,CAAC,EAAE,QAAQ,CAAC,qBAAqB,IAAI,CAAC,CAAC;QAC3G,gBAAgB,EAAE,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,gBAAgB,IAAI,CAAC,EAAE,QAAQ,CAAC,gBAAgB,IAAI,CAAC,CAAC;QAC5F,mBAAmB,EAAE,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,mBAAmB,IAAI,CAAC,EAAE,QAAQ,CAAC,mBAAmB,IAAI,CAAC,CAAC;QACrG,iBAAiB,EAAE,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,iBAAiB,EAAE,QAAQ,CAAC,iBAAiB,CAAC;QACrF,gBAAgB,EAAE,CAAC,GAAG,gBAAgB,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC,CAAC;QACxF,UAAU,EAAE,mBAAmB,CAAC,UAAU,CAAC,UAAU,EAAE,QAAQ,CAAC,UAAU,CAAC;QAC3E,mBAAmB,EAAE,UAAU,CAAC,mBAAmB,IAAI,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAC;QAC5F,wBAAwB,EAAE,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,wBAAwB,IAAI,CAAC,EAAE,QAAQ,CAAC,wBAAwB,IAAI,CAAC,CAAC,IAAI,SAAS;QACjI,mBAAmB,EAAE,UAAU,CAAC,mBAAmB,IAAI,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAC;QAC5F,gBAAgB,EAAE,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,gBAAgB,EAAE,QAAQ,CAAC,gBAAgB,CAAC;QAClF,sBAAsB,EAAE,4BAA4B,CAAC,UAAU,EAAE,QAAQ,EAAE,eAAe,EAAE,yBAAyB,CAAC;QACtH,eAAe;QACf,yBAAyB;KAC1B,CAAC;AACJ,CAAC;AAED,SAAS,mBAAmB,CAC1B,KAAsC,EACtC,MAAuC;IAEvC,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,MAAM,CAAC,sBAAsB,GAAG,KAAK,CAAC,sBAAsB,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC;AACvF,CAAC;AAED,SAAS,UAAU,CAAC,OAAsD;IACxE,OAAO,OAAO,CAAC,QAAQ,KAAK,KAAK,IAAI,OAAO,CAAC,YAAY;QACvD,CAAC,CAAC,OAAO,OAAO,CAAC,YAAY,EAAE;QAC/B,CAAC,CAAC,GAAG,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,OAAO,IAAI,EAAE,EAAE,CAAC;AACrD,CAAC;AAED,SAAS,kBAAkB,CAAC,KAAyB,EAAE,MAA0B;IAC/E,IAAI,KAAK,IAAI,MAAM,EAAE,CAAC;QACpB,OAAO,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC;IACzC,CAAC;IACD,OAAO,KAAK,IAAI,MAAM,CAAC;AACzB,CAAC;AAED,SAAS,4BAA4B,CACnC,UAA+G,EAC/G,QAIC,EACD,eAAmC,EACnC,yBAA6C;IAE7C,IAAI,CAAC,yBAAyB,EAAE,CAAC;QAC/B,OAAO,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,sBAAsB,EAAE,QAAQ,CAAC,sBAAsB,CAAC,CAAC;IACtF,CAAC;IAED,MAAM,kBAAkB,GACtB,UAAU,CAAC,yBAAyB,KAAK,yBAAyB,CAAC,CAAC,CAAC,UAAU,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7G,MAAM,YAAY,GAAG,QAAQ,CAAC,yBAAyB,KAAK,yBAAyB,CAAC,CAAC,CAAC,QAAQ,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5H,MAAM,iBAAiB,GAAG,eAAe,KAAK,SAAS,IAAI,eAAe,GAAG,yBAAyB,CAAC;IACvG,OAAO,IAAI,CAAC,GAAG,CAAC,kBAAkB,EAAE,YAAY,EAAE,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC/E,CAAC"}
@@ -0,0 +1,54 @@
1
+ import type { DecisionConfidence, TranscriptSummary } from "./types.js";
2
+ export declare const LESSON_MEMORY_DIR_NAME = "project-lessons";
3
+ export declare const LESSON_MEMORY_SCHEMA = "bb-cc-lite.lesson-memory.v1";
4
+ export declare const LESSON_CARD_SCHEMA = "bb-cc-lite.lesson-card.v1";
5
+ export declare const LESSON_MEMORY_VERSION = 1;
6
+ type LessonSafeCategory = "tests" | "lint" | "typecheck" | "build";
7
+ export interface LessonEvidenceCounts {
8
+ failures: number;
9
+ sessions: number;
10
+ }
11
+ export interface LessonCard {
12
+ schema: typeof LESSON_CARD_SCHEMA;
13
+ lessonId: string;
14
+ projectKey: string;
15
+ reasonCode: string;
16
+ safeCategory: LessonSafeCategory;
17
+ confidence: DecisionConfidence;
18
+ evidenceCounts: LessonEvidenceCounts;
19
+ createdAt: string;
20
+ updatedAt: string;
21
+ decayAt: string;
22
+ wordingKey: string;
23
+ }
24
+ export interface ProjectLessonMemory {
25
+ schema: typeof LESSON_MEMORY_SCHEMA;
26
+ version: typeof LESSON_MEMORY_VERSION;
27
+ projectKey: string;
28
+ updatedAt: string;
29
+ lessons: LessonCard[];
30
+ }
31
+ export interface LessonMemoryPathOptions {
32
+ projectKey: string;
33
+ homeDir?: string;
34
+ appHomePath?: string;
35
+ }
36
+ export declare function lessonMemoryPath(options: LessonMemoryPathOptions): string;
37
+ export declare function recordLessonFromSummary(options: {
38
+ projectKey: string;
39
+ summary: TranscriptSummary;
40
+ homeDir?: string;
41
+ appHomePath?: string;
42
+ now?: Date;
43
+ }): Promise<LessonCard | undefined>;
44
+ export declare function lessonContextForProject(options: {
45
+ projectKey: string;
46
+ homeDir?: string;
47
+ appHomePath?: string;
48
+ now?: Date;
49
+ }): Promise<string | undefined>;
50
+ export declare function clearLessonMemory(options?: {
51
+ homeDir?: string;
52
+ appHomePath?: string;
53
+ }): Promise<void>;
54
+ export {};