pi-harness-runtime 1.1.37 → 1.1.39

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 (94) hide show
  1. package/harness/langchain/daemon.ts +91 -15
  2. package/harness/langchain/graph.ts +3 -0
  3. package/harness/langchain/widget.test.ts +244 -0
  4. package/harness/langchain/widget.ts +463 -0
  5. package/package.json +1 -1
  6. package/packages/a2a-adapter/package.json +1 -1
  7. package/packages/architecture-generator/package.json +1 -1
  8. package/packages/auth/package.json +1 -1
  9. package/packages/autonomous-refactor/package.json +1 -1
  10. package/packages/autonomous-runtime/package.json +1 -1
  11. package/packages/cache-strategy/package.json +1 -1
  12. package/packages/capability-registry/package.json +1 -1
  13. package/packages/checkpoint/package.json +1 -1
  14. package/packages/cli-plugin-sdk/package.json +1 -1
  15. package/packages/clipboard/package.json +1 -1
  16. package/packages/clipboard-plugin/package.json +1 -1
  17. package/packages/code-generation/package.json +1 -1
  18. package/packages/code-review/package.json +1 -1
  19. package/packages/codex-adapter/package.json +1 -1
  20. package/packages/config-capture/package.json +1 -1
  21. package/packages/context-compiler/package.json +1 -1
  22. package/packages/context-discovery/package.json +1 -1
  23. package/packages/context-manager/package.json +1 -1
  24. package/packages/cookie-sanitizer/package.json +1 -1
  25. package/packages/cost-optimizer/package.json +1 -1
  26. package/packages/dependency-analyzer/package.json +1 -1
  27. package/packages/django-plugin/package.json +1 -1
  28. package/packages/doc-generator/package.json +1 -1
  29. package/packages/evaluation-engine/package.json +1 -1
  30. package/packages/evaluation-runner/package.json +1 -1
  31. package/packages/event-bus/package.json +1 -1
  32. package/packages/event-store/package.json +1 -1
  33. package/packages/experience-replay/package.json +1 -1
  34. package/packages/feedback-collector/package.json +1 -1
  35. package/packages/file-copy-helper/package.json +1 -1
  36. package/packages/framework-detector/package.json +1 -1
  37. package/packages/framework-plugin-sdk/package.json +1 -1
  38. package/packages/frappe-plugin/package.json +1 -1
  39. package/packages/generic-web-plugin/package.json +1 -1
  40. package/packages/health-monitor/package.json +1 -1
  41. package/packages/intent-analyzer/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/quota-manager/package.json +1 -1
  66. package/packages/rate-limiter/package.json +1 -1
  67. package/packages/react-vite-plugin/package.json +1 -1
  68. package/packages/release-manager/package.json +1 -1
  69. package/packages/requirement-compiler/package.json +1 -1
  70. package/packages/runtime/package.json +1 -1
  71. package/packages/scheduler/package.json +1 -1
  72. package/packages/scheduler-adapter/package.json +1 -1
  73. package/packages/session/package.json +1 -1
  74. package/packages/session-api/package.json +1 -1
  75. package/packages/session-export/package.json +1 -1
  76. package/packages/shared-context/package.json +1 -1
  77. package/packages/skill-mcp-client/package.json +1 -1
  78. package/packages/skill-registry/package.json +1 -1
  79. package/packages/sprint-planner/package.json +1 -1
  80. package/packages/subscription-engine/package.json +1 -1
  81. package/packages/task-compiler/package.json +1 -1
  82. package/packages/tencentdb-memory/package.json +1 -1
  83. package/packages/tencentdb-sync/package.json +1 -1
  84. package/packages/test-data-generator/package.json +1 -1
  85. package/packages/test-generator/package.json +1 -1
  86. package/packages/todo-bd-sync/package.json +1 -1
  87. package/packages/token-estimation/package.json +1 -1
  88. package/packages/token-optimizer/package.json +1 -1
  89. package/packages/tui/package.json +1 -1
  90. package/packages/types/package.json +1 -1
  91. package/packages/workflow-events/package.json +1 -1
  92. package/packages/workspace-scanner/package.json +1 -1
  93. package/packages/worktree/package.json +1 -1
  94. package/packages/write-review/package.json +1 -1
@@ -0,0 +1,463 @@
1
+ /**
2
+ * LoopWidget — harness progress display for the pi host status line.
3
+ *
4
+ * Architecture mirrors pi-lens's `clients/widget-state.ts` + `renderWidget()`:
5
+ * - State store: per-file step counts, iteration, phase
6
+ * - Render function: builds the `!NW ●ME` style summary line
7
+ * - Pi host integration: wired via ExtensionUIContext.setWidget() when available
8
+ *
9
+ * The widget is designed as a dependency injected into LoopDaemon/LoopRuntime,
10
+ * so it works in two modes:
11
+ * 1. Standalone (console): logs human-readable progress to stderr
12
+ * 2. Pi host: calls ui.setWidget("harness-loop", renderFn) for TUI display
13
+ *
14
+ * Wiki: wiki/multi-agent-langchain.md
15
+ */
16
+
17
+ import type { TUI } from "@earendil-works/pi-tui";
18
+ import type { Theme } from "@earendil-works/pi-coding-agent";
19
+
20
+ /** Valid theme color keys passed to `theme.fg()`.*/
21
+ type ColorKey = "dim" | "error" | "warning" | "success" | "accent";
22
+
23
+ /**
24
+ * Count visible terminal columns. ANSI CSI sequences (\x1b[...m) contribute 0 width.
25
+ * Terminal wide chars (emoji, CJK) contribute 2 columns.
26
+ */
27
+ function visibleWidth(s: string): number {
28
+ let w = 0;
29
+ let i = 0;
30
+ while (i < s.length) {
31
+ const cp = s.codePointAt(i)!;
32
+ if (cp === 0x1b) {
33
+ // Skip CSI sequences: \x1b[ <params> <final>
34
+ // Valid final bytes: m (SGR), H (CUP), J (ED), A/B/C/D (CUU/CUD/CUF/CUB)
35
+ i++;
36
+ while (i < s.length && !/[a-zA-Z@]/.test(s[i])) i++;
37
+ if (i < s.length) i++; // skip final byte
38
+ continue;
39
+ }
40
+ if (cp <= 0x1f || cp === 0x7f) { i++; continue; } // C0 + DEL = 0
41
+ w += cp > 0xffff ? 2 : 1;
42
+ i += cp > 0xffff ? 2 : 1; // advance by code point, not UTF-16 code unit
43
+ }
44
+ return w;
45
+ }
46
+
47
+ // ─── Types ────────────────────────────────────────────────────────────────────
48
+
49
+ export type LoopPhase =
50
+ | "idle"
51
+ | "planning"
52
+ | "writing"
53
+ | "reviewing"
54
+ | "fixing"
55
+ | "approving"
56
+ | "blocked"
57
+ | "surge-pause"
58
+ | "complete"
59
+ | "error";
60
+
61
+ export interface LoopWidgetOptions {
62
+ /** Called with the rendered lines each time the widget updates. */
63
+ onRender?: (lines: string[]) => void;
64
+ }
65
+
66
+ /** Shaped like the pi-lens FileRecord tier system. */
67
+ interface FileStepRecord {
68
+ filePath: string;
69
+ /** Write steps touching this file in current iteration. */
70
+ writeSteps: number;
71
+ /** Review cycles passed (no blocking issues). */
72
+ reviewsPassed: number;
73
+ /** Blocking issues found by reviewer. */
74
+ blockers: number;
75
+ lastPhase: LoopPhase;
76
+ touchedAt: number;
77
+ }
78
+
79
+ // ─── Widget State ─────────────────────────────────────────────────────────────
80
+
81
+ export class LoopWidget {
82
+ private files = new Map<string, FileStepRecord>();
83
+ private phase: LoopPhase = "idle";
84
+ private iteration = 0;
85
+ private maxIterations: number;
86
+ private stepLabel: string = "";
87
+ private errors = 0;
88
+ private warnings = 0;
89
+ private readonly onRender?: (lines: string[]) => void;
90
+
91
+ constructor(options: LoopWidgetOptions = {}) {
92
+ this.maxIterations = 10;
93
+ this.onRender = options.onRender;
94
+ }
95
+
96
+ // ─── Mutation API ───────────────────────────────────────────────────────────
97
+
98
+ /** Called when the loop starts a new iteration. */
99
+ startIteration(iter: number, max: number): void {
100
+ this.iteration = iter;
101
+ this.maxIterations = max;
102
+ // Clear per-iteration counts; keep file records for history
103
+ for (const rec of this.files.values()) {
104
+ rec.writeSteps = 0;
105
+ rec.reviewsPassed = 0;
106
+ rec.blockers = 0;
107
+ }
108
+ this.errors = 0;
109
+ this.warnings = 0;
110
+ this.render();
111
+ }
112
+
113
+ /** Called when the loop transitions to a new phase. */
114
+ setPhase(phase: LoopPhase, label?: string): void {
115
+ this.phase = phase;
116
+ this.stepLabel = label ?? this.phaseLabel(phase);
117
+ this.render();
118
+ }
119
+
120
+ /** Called when the coder writes to a file. */
121
+ recordWrite(filePath: string): void {
122
+ const rec = this.getOrCreate(filePath);
123
+ rec.writeSteps++;
124
+ rec.lastPhase = "writing";
125
+ rec.touchedAt = Date.now();
126
+ this.render();
127
+ }
128
+
129
+ /** Called when the reviewer reports blockers for a file. */
130
+ recordBlockers(filePath: string, count: number): void {
131
+ const rec = this.getOrCreate(filePath);
132
+ rec.blockers = count;
133
+ rec.lastPhase = count > 0 ? "blocked" : "reviewing";
134
+ rec.touchedAt = Date.now();
135
+ if (count > 0) {
136
+ this.errors += count;
137
+ }
138
+ this.render();
139
+ }
140
+
141
+ /** Called when the reviewer passes a file (no blockers). */
142
+ recordReviewPass(filePath: string): void {
143
+ const rec = this.getOrCreate(filePath);
144
+ rec.reviewsPassed++;
145
+ rec.blockers = 0;
146
+ rec.lastPhase = "reviewing";
147
+ rec.touchedAt = Date.now();
148
+ this.render();
149
+ }
150
+
151
+ /** Called on surge-pause / quota-wait events. */
152
+ setSurgePause(resetAt?: Date): void {
153
+ this.phase = "surge-pause";
154
+ this.stepLabel = resetAt
155
+ ? `surge (${this.formatResetTime(resetAt)})`
156
+ : "surge pause";
157
+ this.render();
158
+ }
159
+
160
+ /** Called on unrecoverable error. */
161
+ setError(message: string): void {
162
+ this.phase = "error";
163
+ this.stepLabel = `error: ${message}`;
164
+ this.render();
165
+ }
166
+
167
+ /** Called when the loop completes with a verdict. */
168
+ setComplete(verdict: "approved" | "rejected" | "max_iterations"): void {
169
+ this.phase = "complete";
170
+ const labels = {
171
+ approved: "✓ loop complete",
172
+ rejected: "✗ loop rejected",
173
+ "max_iterations": `⚠ max iterations (${this.maxIterations})`,
174
+ };
175
+ this.stepLabel = labels[verdict];
176
+ this.render();
177
+ }
178
+
179
+ /** Reset to idle state. */
180
+ reset(): void {
181
+ this.phase = "idle";
182
+ this.iteration = 0;
183
+ this.errors = 0;
184
+ this.warnings = 0;
185
+ this.stepLabel = "";
186
+ this.files.clear();
187
+ this.render();
188
+ }
189
+
190
+ // ─── Render (pi host + standalone) ────────────────────────────────────────
191
+
192
+ /**
193
+ * Build widget lines for the pi host's `setWidget()` renderer.
194
+ *
195
+ * Returns 0-3 lines:
196
+ * Line 1: `harness [iter 2/5] ✍ coder !2W` — header + summary
197
+ * Line 2: ` surge pause — resets 19:17` — surge detail (when applicable)
198
+ * Line 3: ` ●surge.ts ✍2 🔍3 !1` — file rows (up to 5)
199
+ */
200
+ renderWidget(width: number, theme: { fg: (color: ColorKey, s: string) => string }): string[] {
201
+ const dim = (s: string) => theme.fg("dim", s);
202
+ const red = (s: string) => theme.fg("error", s);
203
+ const yellow = (s: string) => theme.fg("warning", s);
204
+ const green = (s: string) => theme.fg("success", s);
205
+ const cyan = (s: string) => theme.fg("accent", s);
206
+ const w = Math.max(1, width || 80);
207
+
208
+ const lines: string[] = [];
209
+
210
+ // ── Header ──────────────────────────────────────────────────────────────
211
+ const iterStr = this.iteration > 0
212
+ ? dim(`iter ${this.iteration}/${this.maxIterations}`)
213
+ : "";
214
+ // Use stepLabel if set (custom phase label, surge detail, error message)
215
+ const phaseStr = this.stepLabel
216
+ ? this.phaseIcon(this.phase) + " " + this.stepLabel
217
+ : this.phaseIcon(this.phase) + " " + this.phaseLabel(this.phase);
218
+
219
+ // Summary chunks (matches pi-lens style: !NW ●ME)
220
+ const errorChunk = this.errors > 0
221
+ ? red(`●${this.errors}E`)
222
+ : "";
223
+ const warningChunk = this.warnings > 0
224
+ ? yellow(`!${this.warnings}W`)
225
+ : "";
226
+ const summary = errorChunk
227
+ ? errorChunk + (warningChunk ? " " + warningChunk : "")
228
+ : warningChunk
229
+ ? warningChunk
230
+ : this.phase === "idle" || this.phase === "complete"
231
+ ? green("✓")
232
+ : dim("…");
233
+
234
+ const parts = [
235
+ cyan("harness"),
236
+ iterStr,
237
+ phaseStr,
238
+ summary,
239
+ ].filter(Boolean).join(" ");
240
+
241
+ lines.push(this.fitLine(` ${parts}`, w));
242
+
243
+ // ── Surge detail ───────────────────────────────────────────────────────
244
+ if (this.phase === "surge-pause" && this.stepLabel) {
245
+ lines.push(this.fitLine(` ${yellow("▸")} ${dim(this.stepLabel)}`, w));
246
+ }
247
+
248
+ // ── Error detail ───────────────────────────────────────────────────────
249
+ if (this.phase === "error" && this.stepLabel) {
250
+ lines.push(this.fitLine(` ${red("✗")} ${this.stepLabel}`, w));
251
+ }
252
+
253
+ // ── File rows ─────────────────────────────────────────────────────────
254
+ const sorted = this.fileRecords()
255
+ .sort((a, b) => b.touchedAt - a.touchedAt)
256
+ .slice(0, 5);
257
+
258
+ for (const rec of sorted) {
259
+ const tier = this.classifyFileTier(rec);
260
+ const dot = tier === "blocking"
261
+ ? red("●")
262
+ : tier === "warning"
263
+ ? yellow("!")
264
+ : dim("·");
265
+ const base = this.fileBasename(rec.filePath);
266
+ const steps = rec.writeSteps > 0 ? dim(` ✍${rec.writeSteps}`) : "";
267
+ const reviews = rec.reviewsPassed > 0 ? dim(` 🔍${rec.reviewsPassed}`) : "";
268
+ const blockers = rec.blockers > 0 ? red(` !${rec.blockers}`) : "";
269
+ const line = ` ${dot} ${base}${steps}${reviews}${blockers}`;
270
+ lines.push(this.fitLine(line, w));
271
+ }
272
+
273
+ return lines;
274
+ }
275
+
276
+ /** Console fallback (standalone mode). */
277
+ toConsoleString(): string {
278
+ const phase = this.phaseIcon(this.phase) + " " + this.stepLabel;
279
+ const iter = this.iteration > 0 ? ` [iter ${this.iteration}/${this.maxIterations}]` : "";
280
+ const err = this.errors > 0 ? ` ●${this.errors}E` : "";
281
+ const warn = this.warnings > 0 ? ` !${this.warnings}W` : "";
282
+ const files = [...this.files.values()]
283
+ .filter(r => r.writeSteps > 0 || r.blockers > 0)
284
+ .sort((a, b) => b.touchedAt - a.touchedAt)
285
+ .slice(0, 3)
286
+ .map(r => `${this.fileBasename(r.filePath)}(${r.writeSteps}w/${r.blockers}b)`)
287
+ .join(", ");
288
+
289
+ const parts = [
290
+ `harness${iter}`,
291
+ phase,
292
+ ].filter(Boolean).join(" ");
293
+
294
+ return [
295
+ parts + err + warn,
296
+ files ? ` files: ${files}` : "",
297
+ ].filter(Boolean).join("\n");
298
+ }
299
+
300
+ // ─── Pi host widget factory (used by index.ts / ExtensionUIContext) ────────
301
+
302
+ /**
303
+ * Returns a pi-tui Component factory for use with `ui.setWidget("harness-loop", factory)`.
304
+ * The caller (pi host integration) owns the `setWidget` call — this factory is just
305
+ * the render function.
306
+ *
307
+ * Usage in pi host:
308
+ * ```
309
+ * setWidget("harness-loop", makeWidgetRenderer(widget, theme), { placement: "belowEditor" });
310
+ * ```
311
+ */
312
+ /**
313
+ * Returns a factory suitable for `ui.setWidget("harness-loop", factory)` in the
314
+ * pi host. The factory's `render(width)` is called by the pi-tui render loop
315
+ * on every frame; `invalidate` is called by the harness to trigger a re-render.
316
+ */
317
+ makeRenderer(): {
318
+ factory: (tui: TUI, theme: Theme) => {
319
+ render: (width: number) => string[];
320
+ invalidate: () => void;
321
+ dispose: () => void;
322
+ };
323
+ invalidate: () => void;
324
+ } {
325
+ // Shared invalidate trigger — both the harness and the pi-tui component call this
326
+ const invalidate = () => { /* mark dirty for next frame */ };
327
+
328
+ const factory = (_tui: TUI, theme: Theme) => {
329
+ type ColorKey = "dim" | "error" | "warning" | "success" | "accent";
330
+ const fg = (color: ColorKey, s: string): string => theme.fg(color, s);
331
+
332
+ const render = (width: number): string[] => {
333
+ return this.renderWidget(width, { fg });
334
+ };
335
+
336
+ // Called by harness to signal the widget needs to re-render
337
+ const widgetInvalidate = () => { /* trigger invalidate */ };
338
+
339
+ return {
340
+ render,
341
+ invalidate: widgetInvalidate,
342
+ dispose: () => { /* clean up */ },
343
+ };
344
+ };
345
+
346
+ return { factory, invalidate };
347
+ }
348
+
349
+ // ─── Internals ─────────────────────────────────────────────────────────────
350
+
351
+ private getOrCreate(filePath: string): FileStepRecord {
352
+ if (!this.files.has(filePath)) {
353
+ this.files.set(filePath, {
354
+ filePath,
355
+ writeSteps: 0,
356
+ reviewsPassed: 0,
357
+ blockers: 0,
358
+ lastPhase: "idle",
359
+ touchedAt: Date.now(),
360
+ });
361
+ }
362
+ return this.files.get(filePath)!;
363
+ }
364
+
365
+ private fileRecords(): FileStepRecord[] {
366
+ return [...this.files.values()];
367
+ }
368
+
369
+ private fileBasename(filePath: string): string {
370
+ const segs = filePath.replace(/\\/g, "/").split("/");
371
+ return segs[segs.length - 1] ?? filePath;
372
+ }
373
+
374
+ private classifyFileTier(rec: FileStepRecord): "blocking" | "warning" | "clean" {
375
+ if (rec.blockers > 0) return "blocking";
376
+ if (rec.writeSteps > 0 || rec.reviewsPassed > 0) return "warning";
377
+ return "clean";
378
+ }
379
+
380
+ private phaseLabel(phase: LoopPhase): string {
381
+ const labels: Record<LoopPhase, string> = {
382
+ idle: "idle",
383
+ planning: "planning",
384
+ writing: "coding",
385
+ reviewing: "reviewing",
386
+ fixing: "fixing",
387
+ approving: "approving",
388
+ blocked: "blocked",
389
+ "surge-pause": "surge",
390
+ complete: "complete",
391
+ error: "error",
392
+ };
393
+ return labels[phase];
394
+ }
395
+
396
+ private phaseIcon(phase: LoopPhase): string {
397
+ const icons: Record<LoopPhase, string> = {
398
+ idle: "○",
399
+ planning: "🧭",
400
+ writing: "✍",
401
+ reviewing: "🔍",
402
+ fixing: "🔧",
403
+ approving: "✅",
404
+ blocked: "⛔",
405
+ "surge-pause": "⏸",
406
+ complete: "✓",
407
+ error: "✗",
408
+ };
409
+ return icons[phase];
410
+ }
411
+
412
+ private formatResetTime(date: Date): string {
413
+ const now = new Date();
414
+ const diff = date.getTime() - now.getTime();
415
+ if (diff <= 0) return "now";
416
+ const mins = Math.ceil(diff / 60_000);
417
+ if (mins < 60) return `in ${mins}m`;
418
+ const hrs = Math.floor(mins / 60);
419
+ const rem = mins % 60;
420
+ return rem > 0 ? `in ${hrs}h ${rem}m` : `in ${hrs}h`;
421
+ }
422
+
423
+ /**
424
+ * Truncate `line` to `width` visible columns.
425
+ * Uses `visibleWidth` (not raw char count) so ANSI codes don't cause
426
+ * false wrapping — matching how the terminal measures columns.
427
+ */
428
+ private fitLine(line: string, width: number): string {
429
+ if (visibleWidth(line) <= width) return line;
430
+ // Walk forward, stopping when adding the next character would exceed width
431
+ let w = 0;
432
+ let cut = 0;
433
+ for (let i = 0; i < line.length; i++) {
434
+ const cp = line.codePointAt(i)!;
435
+ if (cp === 0x1b) {
436
+ // Skip ANSI sequences (don't count toward width)
437
+ while (i < line.length && line[i] !== "m" && line[i] !== "H" && line[i] !== "J") i++;
438
+ continue;
439
+ }
440
+ const charW = cp > 0xffff ? 2 : 1;
441
+ if (w + charW > width - 1) break; // need room for the ellipsis
442
+ w += charW;
443
+ cut = i + (cp > 0xffff ? 2 : 1);
444
+ }
445
+ return line.slice(0, cut) + "…";
446
+ }
447
+
448
+ private render(): void {
449
+ const console = this.toConsoleString();
450
+ this.onRender?.(console.split("\n"));
451
+ }
452
+ }
453
+
454
+ // ─── Singleton factory ───────────────────────────────────────────────────────
455
+
456
+ let _instance: LoopWidget | undefined;
457
+
458
+ export function getLoopWidget(): LoopWidget {
459
+ if (!_instance) {
460
+ _instance = new LoopWidget();
461
+ }
462
+ return _instance;
463
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-harness-runtime",
3
- "version": "1.1.37",
3
+ "version": "1.1.39",
4
4
  "description": "[BETA] Codex-style /usage status + autonomous coding harness for pi. Not production ready — expect breaking changes.",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/a2a-adapter",
3
- "version": "1.1.37",
3
+ "version": "1.1.39",
4
4
  "type": "module",
5
5
  "description": "Google Agent-to-Agent (A2A) protocol adapter for pi-harness",
6
6
  "main": "dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/architecture-generator",
3
- "version": "1.1.37",
3
+ "version": "1.1.39",
4
4
  "description": "Generate ADR and Mermaid diagrams from project analysis",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/auth",
3
- "version": "1.1.37",
3
+ "version": "1.1.39",
4
4
  "description": "pi-harness-runtime — auth",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/autonomous-refactor",
3
- "version": "1.1.37",
3
+ "version": "1.1.39",
4
4
  "type": "module",
5
5
  "description": "Autonomous refactoring engine",
6
6
  "main": "dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/autonomous-runtime",
3
- "version": "1.1.37",
3
+ "version": "1.1.39",
4
4
  "description": "Autonomous Operations Runtime — task inbox, lease management, and worker lifecycle (RFC-0101)",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/cache-strategy",
3
- "version": "1.1.37",
3
+ "version": "1.1.39",
4
4
  "type": "module",
5
5
  "description": "Smart caching with TTL and invalidation strategies (RFC-0022)",
6
6
  "main": "dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/capability-registry",
3
- "version": "1.1.37",
3
+ "version": "1.1.39",
4
4
  "description": "Capability Registry for pi-harness-runtime — tracks model capabilities and enables capability-based routing",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/checkpoint",
3
- "version": "1.1.37",
3
+ "version": "1.1.39",
4
4
  "description": "Enhanced checkpoint system with incremental snapshots, diff-based storage, and recovery strategies",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/cli-plugin-sdk",
3
- "version": "1.1.37",
3
+ "version": "1.1.39",
4
4
  "type": "module",
5
5
  "description": "CLI Plugin SDK for pi-harness — install, list, remove, update, invoke plugins",
6
6
  "main": "dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/clipboard",
3
- "version": "1.1.37",
3
+ "version": "1.1.39",
4
4
  "type": "module",
5
5
  "main": "src/index.ts",
6
6
  "exports": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/clipboard-plugin",
3
- "version": "1.1.37",
3
+ "version": "1.1.39",
4
4
  "type": "module",
5
5
  "main": "src/index.ts",
6
6
  "exports": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/code-generation",
3
- "version": "1.1.37",
3
+ "version": "1.1.39",
4
4
  "description": "Code generation pipeline for pi-harness-runtime",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/code-review",
3
- "version": "1.1.37",
3
+ "version": "1.1.39",
4
4
  "description": "Automated code review engine for pi-harness-runtime",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/codex-adapter",
3
- "version": "1.1.37",
3
+ "version": "1.1.39",
4
4
  "type": "module",
5
5
  "description": "OpenAI Codex provider adapter for pi-harness",
6
6
  "main": "dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moocoding/config-capture",
3
- "version": "1.1.37",
3
+ "version": "1.1.39",
4
4
  "description": "Auto-capture API-fetched configuration values to AGENTS.md",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/context-compiler",
3
- "version": "1.1.37",
3
+ "version": "1.1.39",
4
4
  "description": "Bounded context selection engine for pi-harness-runtime",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/context-discovery",
3
- "version": "1.1.37",
3
+ "version": "1.1.39",
4
4
  "type": "module",
5
5
  "main": "src/index.ts",
6
6
  "exports": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/context-manager",
3
- "version": "1.1.37",
3
+ "version": "1.1.39",
4
4
  "description": "Context Window Manager — prevents model context overflow via compaction and resume prompts (RFC-0010)",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/cookie-sanitizer",
3
- "version": "1.1.37",
3
+ "version": "1.1.39",
4
4
  "description": "pi-harness-runtime — cookie sanitizer (provider-quota cookie file normaliser)",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/cost-optimizer",
3
- "version": "1.1.37",
3
+ "version": "1.1.39",
4
4
  "description": "Cost Optimizer for pi-harness-runtime — budget tracking, forecasting, and model selection optimization",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/dependency-analyzer",
3
- "version": "1.1.37",
3
+ "version": "1.1.39",
4
4
  "type": "module",
5
5
  "main": "src/index.ts",
6
6
  "exports": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/django-plugin",
3
- "version": "1.1.37",
3
+ "version": "1.1.39",
4
4
  "description": "Django framework analysis — models, management commands, settings",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",