pi-harness-runtime 1.1.95 → 1.1.97

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.
Files changed (226) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/harness/loop-runtime.ts +3 -0
  3. package/index.ts +130 -29
  4. package/package.json +2 -1
  5. package/packages/a2a-adapter/package.json +1 -1
  6. package/packages/architecture-generator/package.json +1 -1
  7. package/packages/auth/package.json +1 -1
  8. package/packages/autonomous-refactor/package.json +1 -1
  9. package/packages/autonomous-runtime/package.json +1 -1
  10. package/packages/cache-strategy/package.json +1 -1
  11. package/packages/capability-registry/package.json +1 -1
  12. package/packages/checkpoint/package.json +1 -1
  13. package/packages/cli-plugin-sdk/package.json +1 -1
  14. package/packages/clipboard/package.json +1 -1
  15. package/packages/clipboard-plugin/package.json +1 -1
  16. package/packages/code-generation/package.json +1 -1
  17. package/packages/code-review/package.json +1 -1
  18. package/packages/codex-adapter/package.json +1 -1
  19. package/packages/config-capture/package.json +1 -1
  20. package/packages/context-compiler/package.json +1 -1
  21. package/packages/context-discovery/package.json +1 -1
  22. package/packages/context-manager/package.json +1 -1
  23. package/packages/cookie-sanitizer/package.json +1 -1
  24. package/packages/cost-optimizer/package.json +1 -1
  25. package/packages/dependency-analyzer/package.json +1 -1
  26. package/packages/django-plugin/package.json +1 -1
  27. package/packages/doc-generator/package.json +1 -1
  28. package/packages/evaluation-engine/package.json +1 -1
  29. package/packages/evaluation-runner/package.json +1 -1
  30. package/packages/event-bus/package.json +1 -1
  31. package/packages/event-store/package.json +1 -1
  32. package/packages/experience-replay/package.json +1 -1
  33. package/packages/feedback-collector/package.json +1 -1
  34. package/packages/file-copy-helper/package.json +1 -1
  35. package/packages/framework-detector/package.json +1 -1
  36. package/packages/framework-plugin-sdk/package.json +1 -1
  37. package/packages/frappe-plugin/package.json +1 -1
  38. package/packages/generic-web-plugin/package.json +1 -1
  39. package/packages/health-monitor/package.json +1 -1
  40. package/packages/intent-analyzer/package.json +1 -1
  41. package/packages/jev-judge/package.json +1 -1
  42. package/packages/knowledge-graph/package.json +1 -1
  43. package/packages/knowledge-retrieval/package.json +1 -1
  44. package/packages/laravel-plugin/package.json +1 -1
  45. package/packages/learning-engine/package.json +1 -1
  46. package/packages/mcp-adapter/package.json +1 -1
  47. package/packages/memory-engine/package.json +1 -1
  48. package/packages/milestone-manager/package.json +1 -1
  49. package/packages/model-registry/package.json +1 -1
  50. package/packages/nextjs-plugin/package.json +1 -1
  51. package/packages/notification/package.json +1 -1
  52. package/packages/observability/package.json +1 -1
  53. package/packages/okf-indexer/package.json +1 -1
  54. package/packages/performance-optimizer/package.json +1 -1
  55. package/packages/privilege-broker/package.json +1 -1
  56. package/packages/project-analyzer/package.json +1 -1
  57. package/packages/project-bootstrap/package.json +1 -1
  58. package/packages/projection-engine/package.json +1 -1
  59. package/packages/prompt-compiler/package.json +1 -1
  60. package/packages/prompt-versioning/package.json +1 -1
  61. package/packages/provider-adapter-sdk/package.json +1 -1
  62. package/packages/provider-router/package.json +1 -1
  63. package/packages/provider-selector/package.json +1 -1
  64. package/packages/providers/package.json +1 -1
  65. package/packages/qdrant-skills/dist/client.d.ts +51 -0
  66. package/packages/qdrant-skills/dist/client.d.ts.map +1 -0
  67. package/packages/qdrant-skills/dist/client.js +105 -0
  68. package/packages/qdrant-skills/dist/client.js.map +1 -0
  69. package/packages/qdrant-skills/dist/embedder.d.ts +39 -0
  70. package/packages/qdrant-skills/dist/embedder.d.ts.map +1 -0
  71. package/packages/qdrant-skills/dist/embedder.js +101 -0
  72. package/packages/qdrant-skills/dist/embedder.js.map +1 -0
  73. package/packages/qdrant-skills/dist/index.d.ts +25 -0
  74. package/packages/qdrant-skills/dist/index.d.ts.map +1 -0
  75. package/packages/qdrant-skills/dist/index.js +25 -0
  76. package/packages/qdrant-skills/dist/index.js.map +1 -0
  77. package/packages/qdrant-skills/package.json +27 -0
  78. package/packages/qdrant-skills/src/client.ts +178 -0
  79. package/packages/qdrant-skills/src/embedder.ts +137 -0
  80. package/packages/qdrant-skills/src/index.ts +42 -0
  81. package/packages/quota-manager/package.json +1 -1
  82. package/packages/rate-limiter/package.json +1 -1
  83. package/packages/react-vite-plugin/package.json +1 -1
  84. package/packages/release-manager/package.json +1 -1
  85. package/packages/requirement-compiler/package.json +1 -1
  86. package/packages/runtime/package.json +1 -1
  87. package/packages/scheduler/package.json +1 -1
  88. package/packages/scheduler-adapter/package.json +1 -1
  89. package/packages/session/package.json +1 -1
  90. package/packages/session-api/package.json +1 -1
  91. package/packages/session-export/package.json +1 -1
  92. package/packages/shared-context/package.json +1 -1
  93. package/packages/skill-mcp-client/package.json +1 -1
  94. package/packages/skill-registry/package.json +1 -1
  95. package/packages/skills/dist/index.d.ts +40 -0
  96. package/packages/skills/dist/index.d.ts.map +1 -0
  97. package/packages/skills/dist/index.js +84 -0
  98. package/packages/skills/dist/index.js.map +1 -0
  99. package/packages/skills/dist/linter.d.ts +38 -0
  100. package/packages/skills/dist/linter.d.ts.map +1 -0
  101. package/packages/skills/dist/linter.js +323 -0
  102. package/packages/skills/dist/linter.js.map +1 -0
  103. package/packages/skills/dist/loader.d.ts +74 -0
  104. package/packages/skills/dist/loader.d.ts.map +1 -0
  105. package/packages/skills/dist/loader.js +280 -0
  106. package/packages/skills/dist/loader.js.map +1 -0
  107. package/packages/skills/dist/parser.d.ts +32 -0
  108. package/packages/skills/dist/parser.d.ts.map +1 -0
  109. package/packages/skills/dist/parser.js +459 -0
  110. package/packages/skills/dist/parser.js.map +1 -0
  111. package/packages/skills/dist/scanner.d.ts +33 -0
  112. package/packages/skills/dist/scanner.d.ts.map +1 -0
  113. package/packages/skills/dist/scanner.js +257 -0
  114. package/packages/skills/dist/scanner.js.map +1 -0
  115. package/packages/skills/dist/skill-commands.d.ts +33 -0
  116. package/packages/skills/dist/skill-commands.d.ts.map +1 -0
  117. package/packages/skills/dist/skill-commands.js +239 -0
  118. package/packages/skills/dist/skill-commands.js.map +1 -0
  119. package/packages/skills/dist/skill-tool.d.ts +120 -0
  120. package/packages/skills/dist/skill-tool.d.ts.map +1 -0
  121. package/packages/skills/dist/skill-tool.js +239 -0
  122. package/packages/skills/dist/skill-tool.js.map +1 -0
  123. package/packages/skills/dist/skill-versioning.d.ts +123 -0
  124. package/packages/skills/dist/skill-versioning.d.ts.map +1 -0
  125. package/packages/skills/dist/skill-versioning.js +240 -0
  126. package/packages/skills/dist/skill-versioning.js.map +1 -0
  127. package/packages/skills/dist/types.d.ts +226 -0
  128. package/packages/skills/dist/types.d.ts.map +1 -0
  129. package/packages/skills/dist/types.js +21 -0
  130. package/packages/skills/dist/types.js.map +1 -0
  131. package/packages/skills/package.json +46 -0
  132. package/packages/skills/src/index.ts +95 -0
  133. package/packages/skills/src/linter.ts +371 -0
  134. package/packages/skills/src/loader.ts +335 -0
  135. package/packages/skills/src/parser.ts +548 -0
  136. package/packages/skills/src/scanner.ts +322 -0
  137. package/packages/skills/src/skill-commands.ts +318 -0
  138. package/packages/skills/src/skill-tool.ts +324 -0
  139. package/packages/skills/src/skill-versioning.ts +345 -0
  140. package/packages/skills/src/types.ts +259 -0
  141. package/packages/skills/test/init-skills.test.ts +118 -0
  142. package/packages/sprint-planner/package.json +1 -1
  143. package/packages/subscription-engine/package.json +1 -1
  144. package/packages/task-compiler/package.json +1 -1
  145. package/packages/tencentdb-memory/package.json +1 -1
  146. package/packages/tencentdb-sync/package.json +1 -1
  147. package/packages/test-data-generator/package.json +1 -1
  148. package/packages/test-generator/package.json +1 -1
  149. package/packages/todo-bd-sync/package.json +1 -1
  150. package/packages/token-estimation/package.json +1 -1
  151. package/packages/token-optimizer/package.json +1 -1
  152. package/packages/trajectory/dist/src/curator.d.ts +189 -0
  153. package/packages/trajectory/dist/src/curator.d.ts.map +1 -0
  154. package/packages/trajectory/dist/src/curator.js +340 -0
  155. package/packages/trajectory/dist/src/curator.js.map +1 -0
  156. package/packages/trajectory/dist/src/journey-renderer.d.ts +53 -0
  157. package/packages/trajectory/dist/src/journey-renderer.d.ts.map +1 -0
  158. package/packages/trajectory/dist/src/journey-renderer.js +324 -0
  159. package/packages/trajectory/dist/src/journey-renderer.js.map +1 -0
  160. package/packages/trajectory/dist/src/learning-graph.d.ts +159 -0
  161. package/packages/trajectory/dist/src/learning-graph.d.ts.map +1 -0
  162. package/packages/trajectory/dist/src/learning-graph.js +258 -0
  163. package/packages/trajectory/dist/src/learning-graph.js.map +1 -0
  164. package/packages/trajectory/dist/src/memory-store.d.ts +146 -0
  165. package/packages/trajectory/dist/src/memory-store.d.ts.map +1 -0
  166. package/packages/trajectory/dist/src/memory-store.js +472 -0
  167. package/packages/trajectory/dist/src/memory-store.js.map +1 -0
  168. package/packages/trajectory/dist/src/review-fork.d.ts +164 -0
  169. package/packages/trajectory/dist/src/review-fork.d.ts.map +1 -0
  170. package/packages/trajectory/dist/src/review-fork.js +332 -0
  171. package/packages/trajectory/dist/src/review-fork.js.map +1 -0
  172. package/packages/trajectory/dist/src/write-approval.d.ts +136 -0
  173. package/packages/trajectory/dist/src/write-approval.d.ts.map +1 -0
  174. package/packages/trajectory/dist/src/write-approval.js +281 -0
  175. package/packages/trajectory/dist/src/write-approval.js.map +1 -0
  176. package/packages/trajectory/package.json +1 -1
  177. package/packages/trajectory/src/curator.ts +485 -0
  178. package/packages/trajectory/src/journey-renderer.ts +399 -0
  179. package/packages/trajectory/src/learning-graph.ts +363 -0
  180. package/packages/trajectory/src/memory-store.ts +578 -0
  181. package/packages/trajectory/src/review-fork.ts +450 -0
  182. package/packages/trajectory/src/write-approval.ts +372 -0
  183. package/packages/tui/package.json +1 -1
  184. package/packages/types/package.json +1 -1
  185. package/packages/workflow-events/package.json +1 -1
  186. package/packages/workspace-scanner/package.json +1 -1
  187. package/packages/worktree/package.json +1 -1
  188. package/packages/write-review/dist/blackboard.d.ts +98 -0
  189. package/packages/write-review/dist/blackboard.d.ts.map +1 -0
  190. package/packages/write-review/dist/blackboard.js +289 -0
  191. package/packages/write-review/dist/blackboard.js.map +1 -0
  192. package/packages/write-review/dist/event-bus.d.ts +106 -0
  193. package/packages/write-review/dist/event-bus.d.ts.map +1 -0
  194. package/packages/write-review/dist/event-bus.js +294 -0
  195. package/packages/write-review/dist/event-bus.js.map +1 -0
  196. package/packages/write-review/dist/gate.d.ts +37 -0
  197. package/packages/write-review/dist/gate.d.ts.map +1 -0
  198. package/packages/write-review/dist/gate.js +138 -0
  199. package/packages/write-review/dist/gate.js.map +1 -0
  200. package/packages/write-review/dist/index.d.ts +22 -0
  201. package/packages/write-review/dist/index.d.ts.map +1 -0
  202. package/packages/write-review/dist/index.js +60 -0
  203. package/packages/write-review/dist/index.js.map +1 -0
  204. package/packages/write-review/dist/injection.d.ts +40 -0
  205. package/packages/write-review/dist/injection.d.ts.map +1 -0
  206. package/packages/write-review/dist/injection.js +179 -0
  207. package/packages/write-review/dist/injection.js.map +1 -0
  208. package/packages/write-review/dist/review.d.ts +54 -0
  209. package/packages/write-review/dist/review.d.ts.map +1 -0
  210. package/packages/write-review/dist/review.js +154 -0
  211. package/packages/write-review/dist/review.js.map +1 -0
  212. package/packages/write-review/dist/trigger.d.ts +39 -0
  213. package/packages/write-review/dist/trigger.d.ts.map +1 -0
  214. package/packages/write-review/dist/trigger.js +107 -0
  215. package/packages/write-review/dist/trigger.js.map +1 -0
  216. package/packages/write-review/dist/types.d.ts +78 -0
  217. package/packages/write-review/dist/types.d.ts.map +1 -0
  218. package/packages/write-review/dist/types.js +26 -0
  219. package/packages/write-review/dist/types.js.map +1 -0
  220. package/packages/write-review/package.json +1 -1
  221. package/packages/write-review/src/event-bus.ts +351 -0
  222. package/packages/write-review/src/index.ts +1 -0
  223. package/packages/write-review/src/injection.ts +25 -3
  224. package/proactive-compact.ts +51 -7
  225. package/scripts/sync-skills.ts +275 -0
  226. package/scripts/sync-to-qdrant.ts +398 -0
@@ -0,0 +1,450 @@
1
+ /**
2
+ * Background Review Fork
3
+ *
4
+ * Background review that analyzes trajectories and suggests:
5
+ * - Memory entries to persist
6
+ * - Skills to create/update
7
+ * - User preferences to learn
8
+ *
9
+ * Based on Hermes Agent's closed learning loop.
10
+ */
11
+
12
+ import type { Trajectory, TrajectoryClassification } from "./types.js";
13
+ import type { MemoryEntry, UserProfileEntry } from "./memory-store.js";
14
+
15
+ /**
16
+ * Background review configuration
17
+ */
18
+ export interface BackgroundReviewConfig {
19
+ /** Enable background review */
20
+ enabled: boolean;
21
+ /** Cycles between reviews (1 = every cycle) */
22
+ nudgeInterval: number;
23
+ /** Reasoning effort for review */
24
+ reasoningEffort: "low" | "medium" | "high";
25
+ /** Route to cheaper model for review */
26
+ routeToCheaperModel: boolean;
27
+ /** Cheaper model to use */
28
+ cheaperModel?: string;
29
+ /** Require approval before writes */
30
+ writeApproval: boolean;
31
+ /** Defer review when GPU busy */
32
+ deferWhenGpuBusy: boolean;
33
+ /** Max age in seconds before running queued review */
34
+ deferMaxAgeSeconds: number;
35
+ }
36
+
37
+ /**
38
+ * Default background review configuration
39
+ */
40
+ export const DEFAULT_REVIEW_CONFIG: BackgroundReviewConfig = {
41
+ enabled: true,
42
+ nudgeInterval: 5,
43
+ reasoningEffort: "medium",
44
+ routeToCheaperModel: true,
45
+ writeApproval: false,
46
+ deferWhenGpuBusy: true,
47
+ deferMaxAgeSeconds: 1800,
48
+ };
49
+
50
+ /**
51
+ * Review suggestion types
52
+ */
53
+ export type SuggestionType =
54
+ | "memory"
55
+ | "skill_create"
56
+ | "skill_patch"
57
+ | "user_profile"
58
+ | "pattern";
59
+
60
+ /**
61
+ * Review suggestion
62
+ */
63
+ export interface ReviewSuggestion {
64
+ id: string;
65
+ type: SuggestionType;
66
+ priority: "low" | "medium" | "high";
67
+ content: string;
68
+ reason: string;
69
+ trajectoryId?: string;
70
+ metadata?: Record<string, unknown>;
71
+ }
72
+
73
+ /**
74
+ * Review result
75
+ */
76
+ export interface ReviewResult {
77
+ trajectoryId: string;
78
+ suggestions: ReviewSuggestion[];
79
+ patterns: string[];
80
+ corrections: string[];
81
+ timestamp: number;
82
+ }
83
+
84
+ /**
85
+ * Review event types
86
+ */
87
+ export type ReviewEvent =
88
+ | { type: "review.started"; trajectoryId: string }
89
+ | { type: "review.completed"; result: ReviewResult }
90
+ | { type: "review.error"; error: string; trajectoryId: string }
91
+ | { type: "suggestion.created"; suggestion: ReviewSuggestion }
92
+ | { type: "suggestion.approved"; suggestion: ReviewSuggestion }
93
+ | { type: "suggestion.rejected"; suggestion: ReviewSuggestion };
94
+
95
+ /**
96
+ * Review event handler
97
+ */
98
+ export type ReviewEventHandler = (event: ReviewEvent) => void;
99
+
100
+ /**
101
+ * Background Review Fork
102
+ */
103
+ export class BackgroundReviewFork {
104
+ private config: BackgroundReviewConfig;
105
+ private cycleCount = 0;
106
+ private queuedReview: Trajectory | null = null;
107
+ private handlers: Set<ReviewEventHandler> = new Set();
108
+ private pendingSuggestions: ReviewSuggestion[] = [];
109
+
110
+ constructor(config?: Partial<BackgroundReviewConfig>) {
111
+ this.config = { ...DEFAULT_REVIEW_CONFIG, ...config };
112
+ }
113
+
114
+ /**
115
+ * Update configuration
116
+ */
117
+ updateConfig(config: Partial<BackgroundReviewConfig>): void {
118
+ this.config = { ...this.config, ...config };
119
+ }
120
+
121
+ /**
122
+ * Register event handler
123
+ */
124
+ on(handler: ReviewEventHandler): () => void {
125
+ this.handlers.add(handler);
126
+ return () => this.handlers.delete(handler);
127
+ }
128
+
129
+ /**
130
+ * Emit event to all handlers
131
+ */
132
+ private emit(event: ReviewEvent): void {
133
+ for (const handler of this.handlers) {
134
+ try {
135
+ handler(event);
136
+ } catch (err) {
137
+ console.error("[BackgroundReviewFork] Handler error:", err);
138
+ }
139
+ }
140
+ }
141
+
142
+ /**
143
+ * Process cycle end - check if review should run
144
+ */
145
+ onCycleEnd(trajectory: Trajectory): void {
146
+ if (!this.config.enabled) return;
147
+
148
+ this.cycleCount++;
149
+
150
+ // Check if we should run review now
151
+ if (this.cycleCount >= this.config.nudgeInterval) {
152
+ this.cycleCount = 0;
153
+ this.runReview(trajectory);
154
+ } else {
155
+ // Queue for later
156
+ this.queuedReview = trajectory;
157
+ }
158
+ }
159
+
160
+ /**
161
+ * Run review on trajectory
162
+ */
163
+ async runReview(trajectory: Trajectory): Promise<ReviewResult> {
164
+ this.emit({ type: "review.started", trajectoryId: trajectory.id });
165
+
166
+ try {
167
+ const result = await this.analyzeTrajectory(trajectory);
168
+
169
+ // Emit completion
170
+ this.emit({ type: "review.completed", result });
171
+
172
+ // Create suggestions
173
+ for (const suggestion of result.suggestions) {
174
+ this.emit({ type: "suggestion.created", suggestion });
175
+ this.pendingSuggestions.push(suggestion);
176
+ }
177
+
178
+ // Clear queued review
179
+ this.queuedReview = null;
180
+
181
+ return result;
182
+ } catch (err) {
183
+ const errorMsg = err instanceof Error ? err.message : String(err);
184
+ this.emit({ type: "review.error", error: errorMsg, trajectoryId: trajectory.id });
185
+ throw err;
186
+ }
187
+ }
188
+
189
+ /**
190
+ * Analyze trajectory and generate suggestions
191
+ */
192
+ private async analyzeTrajectory(trajectory: Trajectory): Promise<ReviewResult> {
193
+ const suggestions: ReviewSuggestion[] = [];
194
+ const patterns: string[] = [];
195
+ const corrections: string[] = [];
196
+
197
+ // Analyze verdict
198
+ if (trajectory.verdict === "blocked") {
199
+ // Blocked cycles might need memory about blockers
200
+ suggestions.push({
201
+ id: `mem_blocked_${Date.now()}`,
202
+ type: "memory",
203
+ priority: "high",
204
+ content: `Blocked cycle: ${trajectory.taskRequest}. Reason: ${trajectory.reason}`,
205
+ reason: "Remember what caused blocks to avoid them",
206
+ trajectoryId: trajectory.id,
207
+ });
208
+ }
209
+
210
+ // Analyze iterations
211
+ if (trajectory.iterations > 5) {
212
+ // High iteration count might indicate pattern to optimize
213
+ suggestions.push({
214
+ id: `pat_high_iter_${Date.now()}`,
215
+ type: "pattern",
216
+ priority: "medium",
217
+ content: `High iteration pattern: ${trajectory.taskRequest.slice(0, 100)}...`,
218
+ reason: "Investigate why this task took many iterations",
219
+ trajectoryId: trajectory.id,
220
+ });
221
+ }
222
+
223
+ // Analyze files
224
+ if (trajectory.files.length > 0) {
225
+ // Check for repeated files across iterations
226
+ const fileCount: Record<string, number> = {};
227
+ for (const file of trajectory.files) {
228
+ fileCount[file] = (fileCount[file] || 0) + 1;
229
+ }
230
+
231
+ // Files with high counts might need conventions
232
+ for (const [file, count] of Object.entries(fileCount)) {
233
+ if (count > 3) {
234
+ suggestions.push({
235
+ id: `conv_${Date.now()}`,
236
+ type: "memory",
237
+ priority: "low",
238
+ content: `Conventions for ${file}: Review patterns established in recent cycles`,
239
+ reason: `File ${file} appears frequently (${count}x)`,
240
+ trajectoryId: trajectory.id,
241
+ });
242
+ }
243
+ }
244
+ }
245
+
246
+ // Analyze comments for patterns
247
+ for (const comment of trajectory.comments) {
248
+ // Detect corrections (repeated comments)
249
+ const commentText = comment.comment.toLowerCase();
250
+
251
+ if (commentText.includes("same") || commentText.includes("again") || commentText.includes("repeated")) {
252
+ corrections.push(comment.comment);
253
+ }
254
+
255
+ // Detect severity patterns
256
+ if (comment.severity === "major" || comment.severity === "critical") {
257
+ patterns.push(`high-severity: ${comment.comment.slice(0, 100)}`);
258
+ }
259
+ }
260
+
261
+ // Generate skill suggestion for complex tasks
262
+ if (trajectory.iterations >= 3 && trajectory.verdict === "approved") {
263
+ suggestions.push({
264
+ id: `skill_${Date.now()}`,
265
+ type: "skill_create",
266
+ priority: "medium",
267
+ content: this.generateSkillFromTrajectory(trajectory),
268
+ reason: "Complex task that succeeded - capture the pattern",
269
+ trajectoryId: trajectory.id,
270
+ });
271
+ }
272
+
273
+ // Analyze for user preferences
274
+ if (trajectory.summary) {
275
+ const userPrefs = this.extractUserPreferences(trajectory.summary);
276
+ for (const pref of userPrefs) {
277
+ suggestions.push({
278
+ id: `user_${Date.now()}`,
279
+ type: "user_profile",
280
+ priority: "low",
281
+ content: pref,
282
+ reason: "Detected from cycle summary",
283
+ trajectoryId: trajectory.id,
284
+ });
285
+ }
286
+ }
287
+
288
+ return {
289
+ trajectoryId: trajectory.id,
290
+ suggestions,
291
+ patterns,
292
+ corrections,
293
+ timestamp: Date.now(),
294
+ };
295
+ }
296
+
297
+ /**
298
+ * Generate skill content from trajectory
299
+ */
300
+ private generateSkillFromTrajectory(trajectory: Trajectory): string {
301
+ const lines: string[] = [];
302
+
303
+ // Extract task type from request
304
+ const taskType = this.extractTaskType(trajectory.taskRequest);
305
+
306
+ lines.push(`---\n`);
307
+ lines.push(`name: ${taskType}-pattern\n`);
308
+ lines.push(`description: ${trajectory.taskRequest.slice(0, 200)}\n`);
309
+ lines.push(`author: curator\n`);
310
+ lines.push(`confidence: 0.7\n`);
311
+ lines.push(`triggers:\n`);
312
+ lines.push(` - "${taskType}"\n`);
313
+ lines.push(` - "${trajectory.taskRequest.slice(0, 50)}"\n`);
314
+ lines.push(`---\n\n`);
315
+
316
+ lines.push(`# ${taskType} Pattern\n\n`);
317
+ lines.push(`## When to Use\n`);
318
+ lines.push(`Task: ${trajectory.taskRequest}\n\n`);
319
+
320
+ lines.push(`## Procedure\n`);
321
+ lines.push(`1. ${trajectory.plan.split("\n")[0] || "Plan based on task analysis"}\n\n`);
322
+
323
+ lines.push(`## Key Files\n`);
324
+ for (const file of trajectory.files.slice(0, 5)) {
325
+ lines.push(`- ${file}\n`);
326
+ }
327
+ lines.push(`\n`);
328
+
329
+ lines.push(`## Notes\n`);
330
+ lines.push(`Iterations: ${trajectory.iterations}\n`);
331
+ lines.push(`Duration: ${Math.round(trajectory.durationMs / 1000 / 60)} minutes\n\n`);
332
+
333
+ if (trajectory.comments.length > 0) {
334
+ lines.push(`## Common Issues\n`);
335
+ for (const comment of trajectory.comments.slice(0, 3)) {
336
+ lines.push(`- ${comment.comment}\n`);
337
+ }
338
+ }
339
+
340
+ return lines.join("");
341
+ }
342
+
343
+ /**
344
+ * Extract task type from request
345
+ */
346
+ private extractTaskType(request: string): string {
347
+ const lower = request.toLowerCase();
348
+
349
+ if (lower.includes("test")) return "testing";
350
+ if (lower.includes("fix") || lower.includes("bug")) return "bugfix";
351
+ if (lower.includes("refactor")) return "refactoring";
352
+ if (lower.includes("api")) return "api-development";
353
+ if (lower.includes("config") || lower.includes("setup")) return "configuration";
354
+ if (lower.includes("deploy")) return "deployment";
355
+
356
+ return "general-task";
357
+ }
358
+
359
+ /**
360
+ * Extract user preferences from summary
361
+ */
362
+ private extractUserPreferences(summary: string): string[] {
363
+ const prefs: string[] = [];
364
+ const lower = summary.toLowerCase();
365
+
366
+ // Detection patterns
367
+ if (lower.includes("prefer") || lower.includes("like") || lower.includes("want")) {
368
+ prefs.push(`Prefers concise responses where possible`);
369
+ }
370
+ if (lower.includes("style") || lower.includes("format")) {
371
+ prefs.push(`Has specific code style preferences`);
372
+ }
373
+ if (lower.includes("error") || lower.includes("fix")) {
374
+ prefs.push(`Focuses on fixing issues thoroughly`);
375
+ }
376
+
377
+ return prefs;
378
+ }
379
+
380
+ /**
381
+ * Get pending suggestions
382
+ */
383
+ getPendingSuggestions(): ReviewSuggestion[] {
384
+ return [...this.pendingSuggestions];
385
+ }
386
+
387
+ /**
388
+ * Approve suggestion
389
+ */
390
+ approveSuggestion(suggestionId: string): ReviewSuggestion | null {
391
+ const index = this.pendingSuggestions.findIndex((s) => s.id === suggestionId);
392
+ if (index < 0) return null;
393
+
394
+ const suggestion = this.pendingSuggestions[index];
395
+ this.pendingSuggestions.splice(index, 1);
396
+ this.emit({ type: "suggestion.approved", suggestion });
397
+ return suggestion;
398
+ }
399
+
400
+ /**
401
+ * Reject suggestion
402
+ */
403
+ rejectSuggestion(suggestionId: string): ReviewSuggestion | null {
404
+ const index = this.pendingSuggestions.findIndex((s) => s.id === suggestionId);
405
+ if (index < 0) return null;
406
+
407
+ const suggestion = this.pendingSuggestions[index];
408
+ this.pendingSuggestions.splice(index, 1);
409
+ this.emit({ type: "suggestion.rejected", suggestion });
410
+ return suggestion;
411
+ }
412
+
413
+ /**
414
+ * Clear all pending suggestions
415
+ */
416
+ clearSuggestions(): void {
417
+ this.pendingSuggestions = [];
418
+ }
419
+
420
+ /**
421
+ * Get review stats
422
+ */
423
+ getStats(): {
424
+ cycleCount: number;
425
+ pendingCount: number;
426
+ enabled: boolean;
427
+ nudgeInterval: number;
428
+ } {
429
+ return {
430
+ cycleCount: this.cycleCount,
431
+ pendingCount: this.pendingSuggestions.length,
432
+ enabled: this.config.enabled,
433
+ nudgeInterval: this.config.nudgeInterval,
434
+ };
435
+ }
436
+ }
437
+
438
+ // Global instance
439
+ let globalReviewFork: BackgroundReviewFork | null = null;
440
+
441
+ export function getGlobalReviewFork(): BackgroundReviewFork {
442
+ if (!globalReviewFork) {
443
+ globalReviewFork = new BackgroundReviewFork();
444
+ }
445
+ return globalReviewFork;
446
+ }
447
+
448
+ export function createReviewFork(config?: Partial<BackgroundReviewConfig>): BackgroundReviewFork {
449
+ return new BackgroundReviewFork(config);
450
+ }