pi-harness-runtime 0.10.0 → 1.1.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.
Files changed (109) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/README.md +122 -0
  3. package/harness/e2e/minimax-quota-scraper.ts +4 -4
  4. package/harness/e2e/openai-quota-scraper.ts +13 -8
  5. package/index.ts +93 -2
  6. package/package.json +1 -1
  7. package/packages/a2a-adapter/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/dist/src/copy-sync.d.ts +27 -0
  16. package/packages/clipboard/dist/src/copy-sync.d.ts.map +1 -0
  17. package/packages/clipboard/dist/src/copy-sync.js +170 -0
  18. package/packages/clipboard/dist/src/copy-sync.js.map +1 -0
  19. package/packages/clipboard/dist/src/gist-relay.d.ts +48 -0
  20. package/packages/clipboard/dist/src/gist-relay.d.ts.map +1 -0
  21. package/packages/clipboard/dist/src/gist-relay.js +186 -0
  22. package/packages/clipboard/dist/src/gist-relay.js.map +1 -0
  23. package/packages/clipboard/dist/src/github-login.d.ts +16 -0
  24. package/packages/clipboard/dist/src/github-login.d.ts.map +1 -0
  25. package/packages/clipboard/dist/src/github-login.js +69 -0
  26. package/packages/clipboard/dist/src/github-login.js.map +1 -0
  27. package/packages/clipboard/dist/src/index.d.ts +2 -0
  28. package/packages/clipboard/dist/src/index.d.ts.map +1 -1
  29. package/packages/clipboard/dist/src/index.js +2 -1
  30. package/packages/clipboard/dist/src/index.js.map +1 -1
  31. package/packages/clipboard/package.json +1 -1
  32. package/packages/clipboard/src/copy-sync.ts +201 -0
  33. package/packages/clipboard/src/gist-relay.ts +240 -0
  34. package/packages/clipboard/src/github-login.ts +107 -0
  35. package/packages/clipboard/src/index.ts +2 -0
  36. package/packages/clipboard/test/mojibake.test.mjs +143 -0
  37. package/packages/code-generation/package.json +1 -1
  38. package/packages/code-review/package.json +1 -1
  39. package/packages/codex-adapter/package.json +1 -1
  40. package/packages/context-compiler/package.json +1 -1
  41. package/packages/context-discovery/package.json +1 -1
  42. package/packages/context-manager/package.json +1 -1
  43. package/packages/cookie-sanitizer/package.json +1 -1
  44. package/packages/cost-optimizer/package.json +1 -1
  45. package/packages/dependency-analyzer/package.json +1 -1
  46. package/packages/django-plugin/package.json +1 -1
  47. package/packages/doc-generator/package.json +1 -1
  48. package/packages/evaluation-engine/package.json +1 -1
  49. package/packages/evaluation-runner/package.json +1 -1
  50. package/packages/event-bus/package.json +1 -1
  51. package/packages/event-store/package.json +1 -1
  52. package/packages/experience-replay/package.json +1 -1
  53. package/packages/feedback-collector/package.json +1 -1
  54. package/packages/framework-detector/package.json +1 -1
  55. package/packages/framework-plugin-sdk/package.json +1 -1
  56. package/packages/frappe-plugin/package.json +1 -1
  57. package/packages/generic-web-plugin/package.json +1 -1
  58. package/packages/health-monitor/package.json +1 -1
  59. package/packages/intent-analyzer/package.json +1 -1
  60. package/packages/laravel-plugin/package.json +1 -1
  61. package/packages/learning-engine/package.json +1 -1
  62. package/packages/mcp-adapter/package.json +1 -1
  63. package/packages/memory-engine/package.json +1 -1
  64. package/packages/model-registry/package.json +1 -1
  65. package/packages/nextjs-plugin/package.json +1 -1
  66. package/packages/notification/package.json +1 -1
  67. package/packages/observability/package.json +1 -1
  68. package/packages/performance-optimizer/package.json +1 -1
  69. package/packages/privilege-broker/package.json +1 -1
  70. package/packages/project-analyzer/package.json +1 -1
  71. package/packages/projection-engine/package.json +1 -1
  72. package/packages/prompt-compiler/package.json +1 -1
  73. package/packages/prompt-versioning/package.json +1 -1
  74. package/packages/provider-adapter-sdk/package.json +1 -1
  75. package/packages/provider-router/package.json +1 -1
  76. package/packages/provider-selector/package.json +1 -1
  77. package/packages/providers/package.json +1 -1
  78. package/packages/quota-manager/package.json +1 -1
  79. package/packages/rate-limiter/package.json +1 -1
  80. package/packages/react-vite-plugin/package.json +1 -1
  81. package/packages/release-manager/package.json +1 -1
  82. package/packages/requirement-compiler/package.json +1 -1
  83. package/packages/runtime/package.json +1 -1
  84. package/packages/scheduler/package.json +1 -1
  85. package/packages/scheduler-adapter/package.json +1 -1
  86. package/packages/session/package.json +1 -1
  87. package/packages/session-api/package.json +1 -1
  88. package/packages/session-export/package.json +1 -1
  89. package/packages/shared-context/package.json +1 -1
  90. package/packages/skill-registry/package.json +1 -1
  91. package/packages/sprint-planner/package.json +1 -1
  92. package/packages/subscription-engine/package.json +1 -1
  93. package/packages/task-compiler/package.json +1 -1
  94. package/packages/test-data-generator/package.json +1 -1
  95. package/packages/test-generator/package.json +1 -1
  96. package/packages/todo-bd-sync/package.json +22 -0
  97. package/packages/todo-bd-sync/src/detector.ts +150 -0
  98. package/packages/todo-bd-sync/src/extension.ts +101 -0
  99. package/packages/todo-bd-sync/src/index.ts +401 -0
  100. package/packages/todo-bd-sync/src/sync.ts +322 -0
  101. package/packages/todo-bd-sync/src/todo-reminder.ts +418 -0
  102. package/packages/todo-bd-sync/src/types.ts +137 -0
  103. package/packages/token-estimation/package.json +1 -1
  104. package/packages/token-optimizer/package.json +1 -1
  105. package/packages/tui/package.json +1 -1
  106. package/packages/types/package.json +1 -1
  107. package/packages/workflow-events/package.json +1 -1
  108. package/packages/workspace-scanner/package.json +1 -1
  109. package/packages/worktree/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -2,6 +2,28 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4
4
 
5
+ ### [0.10.1](https://github.com/ManotLuijiu/pi-harness-runtime/compare/v0.9.24...v0.10.1) (2026-07-31)
6
+
7
+
8
+ ### Features
9
+
10
+ * blackboard-coordinated loop controller with early exit ([f3cf3ea](https://github.com/ManotLuijiu/pi-harness-runtime/commit/f3cf3ea479170dd75b7e9a7c3515dde230bb0da7))
11
+ * herdr inter-agent event bus for autonomous code review ([1490cdd](https://github.com/ManotLuijiu/pi-harness-runtime/commit/1490cddec80dac812065c3c681984524ad3194e1))
12
+ * loop controller for write-review cycles with early exit ([95066ce](https://github.com/ManotLuijiu/pi-harness-runtime/commit/95066ce8cb58c55eaa14d69fd826b5aaff680c16))
13
+ * release adapters, stale reminder fix, tests, and bug fixes ([5fe5a26](https://github.com/ManotLuijiu/pi-harness-runtime/commit/5fe5a260e0d9a005965b43e4973cbe04a371b85e))
14
+
15
+
16
+ ### Bug Fixes
17
+
18
+ * **clipboard:** pass UTF-8 bytes directly to xclip via stdin, avoid pipeline corruption ([051ca18](https://github.com/ManotLuijiu/pi-harness-runtime/commit/051ca18fb1deb1169a8a4da16aa9314d2e6ec66d))
19
+ * disable todo-bd auto-reminder (Phase 1 containment) ([e1b16c1](https://github.com/ManotLuijiu/pi-harness-runtime/commit/e1b16c11e34cee8e35ec813081b17dd171671771))
20
+ * herdr-bus refactoring — rename publishers to *Simple variants ([d727591](https://github.com/ManotLuijiu/pi-harness-runtime/commit/d7275913a89deb56a6bcfdb912ea9d17e3a80ce1))
21
+ * import LoopConfig from index.js, remove unused LoopNextAction import ([1100a4e](https://github.com/ManotLuijiu/pi-harness-runtime/commit/1100a4e87433e54416259dfdad41bc5e0def19b3))
22
+ * periodic quota refresh every 15 minutes via setInterval ([f28e700](https://github.com/ManotLuijiu/pi-harness-runtime/commit/f28e7004d089aeada1659f4d55a35461baba76fc))
23
+ * replace all Unicode box-drawing characters with ASCII ([dd4223a](https://github.com/ManotLuijiu/pi-harness-runtime/commit/dd4223abb0e25f746ee09ced05f6b3e40a10eb85))
24
+ * replace Unicode dashes and arrows with ASCII equivalents ([e9027e6](https://github.com/ManotLuijiu/pi-harness-runtime/commit/e9027e689c06fdc1ca2ac4a6365ed6a6a0a384fd))
25
+ * trigger cookie sync on startup so pre-existing cookies aren't ignored ([2914299](https://github.com/ManotLuijiu/pi-harness-runtime/commit/2914299b8caa02acbb06620c7cb8e4870acfa40e))
26
+
5
27
  ## [0.10.0](https://github.com/ManotLuijiu/pi-harness-runtime/compare/v0.9.24...v0.10.0) (2026-07-30)
6
28
 
7
29
 
package/README.md CHANGED
@@ -27,6 +27,76 @@ pi install npm:pi-harness-runtime
27
27
 
28
28
  Requires Pi v0.37.3+.
29
29
 
30
+ ### Headless Server Setup (herdr clipboard bridge)
31
+
32
+ If running on a **headless server** via herdr SSH, install the clipboard bridge plugin to enable copy/paste between server and local machine:
33
+
34
+ ```bash
35
+ # 1. Link the plugin (already included in this package)
36
+ cd ~/.config/herdr/plugins
37
+ ln -s ~/.config/herdr/plugins/moocoding.clipboard-bridge moocoding.clipboard-bridge 2>/dev/null || true
38
+
39
+ # 2. Add keybinding to ~/.config/herdr/config.toml
40
+ cat >> ~/.config/herdr/config.toml << 'EOF'
41
+
42
+ [[keys.command]]
43
+ key = "prefix+y"
44
+ type = "plugin_action"
45
+ command = "moocoding.clipboard-bridge.copy"
46
+ description = "Copy selected text via bridge"
47
+ EOF
48
+
49
+ # 3. Reload herdr config
50
+ herdr server reload-config
51
+ ```
52
+
53
+ ### todo-bd-sync (Auto Task Tracker)
54
+
55
+ Automatic two-way sync between rpiv-todo overlay and bd issue tracker.
56
+
57
+ When you use `bd` for issue tracking, this feature automatically syncs tasks.
58
+
59
+ > **Important:** `bd` is **not** implemented or bundled by `pi-harness-runtime`.
60
+ > It is the external **Beads CLI** from the upstream project:
61
+ > `https://github.com/gastownhall/beads`
62
+ >
63
+ > Install it system-wide from upstream, then initialize it in your own project:
64
+
65
+ ```bash
66
+ # Install beads CLI (system-wide - don't clone this repo into your project)
67
+ curl -fsSL https://raw.githubusercontent.com/gastownhall/beads/main/scripts/install.sh | bash
68
+
69
+ # Initialize in YOUR project
70
+ cd your-project
71
+ bd init
72
+
73
+ # Optional: refresh or install richer instructions for your agent
74
+ bd setup codex # Codex CLI - installs skill, AGENTS.md guidance, and hooks
75
+ bd setup claude # Claude Code - installs hooks/settings
76
+ bd setup factory # Factory.ai Droid - creates/updates AGENTS.md
77
+ ```
78
+
79
+ - Install dependencies:
80
+
81
+ ```bash
82
+ # Install rpiv-todo overlay
83
+ pi install npm:@juicesharp/rpiv-todo
84
+
85
+ # Verify bd is available from your upstream beads install
86
+ bd --version
87
+ ```
88
+
89
+ - Works automatically: Just use prompts with multiple steps, and tasks sync to bd
90
+ - Manual commands:
91
+
92
+ ```bash
93
+ /bd-todo-sync # Force sync all mapped tasks
94
+ /bd-todo-status # Show sync status
95
+ ```
96
+
97
+ > **Note:** Auto-reminder is **disabled by default** (bug fix for transcript growth).
98
+ > See [docs/todo-bd-sync.md](docs/todo-bd-sync.md) for details.
99
+
30
100
  ## Usage Commands
31
101
 
32
102
  ```bash
@@ -35,6 +105,8 @@ Requires Pi v0.37.3+.
35
105
  /usage today # today's usage + 5h window
36
106
  /usage week # this week's usage + lifetime totals
37
107
  /usage reset # clear provider mirror
108
+ /bd-todo-sync # Force sync all mapped tasks (todo <-> bd)
109
+ /bd-todo-status # Show todo-bd sync status and dependencies
38
110
  ```
39
111
 
40
112
  ## Harness Commands
@@ -245,6 +317,56 @@ The runtime watches `~/.pi-harness-runtime/cookies/` for cookie files. Drop any
245
317
  **Override:** set `QUOTA_COOKIE_FILE=/path/to/your/cookies.txt` to bypass the sanitizer
246
318
  and read a specific file directly.
247
319
 
320
+ ## herdr Integration (Clipboard Bridge)
321
+
322
+ > **⚠️ This only applies when using herdr.dev**
323
+ >
324
+ > If you're using a normal terminal (iTerm2, Terminal.app, etc.), clipboard works fine — no special setup needed.
325
+
326
+ When running on a **headless server via herdr.dev**, clipboard operations need special setup because:
327
+
328
+ - herdr's `copy_on_select` uses OSC52 which fails in VS Code's integrated terminal PTY
329
+ - UTF-8 box-drawing characters (`┌─┐│└`) get corrupted to garbled text
330
+ - Server-side clipboard tools (`xclip`, `wl-copy`) don't exist
331
+
332
+ ### Quick Setup
333
+
334
+ ```bash
335
+ # Copy the example config (includes clipboard bridge keybinding)
336
+ cp config.toml.example ~/.config/herdr/config.toml
337
+
338
+ # Reload herdr config
339
+ herdr server reload-config
340
+ ```
341
+
342
+ ### Usage
343
+
344
+ 1. **Select text** with mouse in herdr terminal
345
+ 2. Press **`prefix+y`** (prefix is `ctrl+b` by default)
346
+ 3. Text is copied via the bridge to your local clipboard
347
+
348
+ ### How It Works
349
+
350
+ ```
351
+ Select text in herdr
352
+
353
+ Press prefix+y (plugin action)
354
+
355
+ ~/.herdr-clipboard (bridge file)
356
+
357
+ SSH reverse tunnel or tmux buffer
358
+
359
+ Your local machine clipboard
360
+ ```
361
+
362
+ ### Files
363
+
364
+ | File | Purpose |
365
+ |------|---------|
366
+ | `config.toml.example` | Template for `~/.config/herdr/config.toml` |
367
+ | `~/.herdr-clipboard` | Bridge file between herdr and clipboard |
368
+ | `~/.config/herdr/plugins/moocoding.clipboard-bridge/` | herdr plugin |
369
+
248
370
  ### Other Providers
249
371
 
250
372
  No setup needed. The runtime reads TUI messages and captures quota-exhaustion signals.
@@ -387,7 +387,8 @@ export class MiniMaxQuotaScraper {
387
387
  } catch {
388
388
  const msg =
389
389
  "Playwright not installed. Install with: bun add playwright\nThen install browsers: bunx playwright install chromium";
390
- if (!this.config.quiet) console.error("[MiniMaxQuotaScraper] " + msg);
390
+ if (!this.config.quiet)
391
+ console.error("[DEBUG MiniMaxQuotaScraper] " + msg);
391
392
  throw new Error(msg);
392
393
  }
393
394
 
@@ -399,8 +400,7 @@ export class MiniMaxQuotaScraper {
399
400
 
400
401
  if (cookies.length === 0) {
401
402
  const dropHint = join(homedir(), ".pi-harness-runtime", "cookies");
402
- const msg =
403
- `No cookies found.
403
+ const msg = `No cookies found.
404
404
  Drop your platform.minimax.io cookies (Netscape or EditThisCookie JSON) into:
405
405
  ${dropHint}
406
406
  …or run: bun packages/auth/src/run-minimax-auth.ts auth`;
@@ -550,7 +550,7 @@ MiniMax Quota Scraper Setup Instructions
550
550
  3. Use the scraper:
551
551
  const scraper = new MiniMaxQuotaScraper();
552
552
  const quota = await scraper.scrape();
553
- console.log("5h usage:", quota.h5UsedPct, "%");
553
+ console.log("[DEBUG MiniMaxQuotaScraper] 5h usage:", quota.h5UsedPct, "%");
554
554
  `;
555
555
  }
556
556
  }
@@ -205,13 +205,14 @@ export class OpenAIQuotaScraper {
205
205
  Drop your chatgpt.com cookies (Netscape or EditThisCookie JSON) into:
206
206
  ${dropHint}
207
207
  Then run: bun run packages/cookie-sanitizer/src/sync.ts`;
208
- if (!this.config.quiet) console.error(`[OpenAIQuotaScraper] ${msg}`);
208
+ if (!this.config.quiet)
209
+ console.error(`[DEBUG OpenAIQuotaScraper] ${msg}`);
209
210
  throw new Error(msg);
210
211
  }
211
212
 
212
213
  // Launch browser
213
214
  if (!this.config.quiet) {
214
- console.log("[OpenAIQuotaScraper] Launching browser...");
215
+ console.log("[DEBUG OpenAIQuotaScraper] Launching browser...");
215
216
  }
216
217
 
217
218
  const browser = await chromium.launch({
@@ -259,7 +260,9 @@ Then run: bun run packages/cookie-sanitizer/src/sync.ts`;
259
260
  try {
260
261
  // Navigate to analytics page
261
262
  if (!this.config.quiet) {
262
- console.log("[OpenAIQuotaScraper] Navigating to analytics page...");
263
+ console.log(
264
+ "[DEBUG OpenAIQuotaScraper] Navigating to analytics page...",
265
+ );
263
266
  }
264
267
 
265
268
  await page.goto(ANALYTICS_URL, {
@@ -282,14 +285,16 @@ Then run: bun run packages/cookie-sanitizer/src/sync.ts`;
282
285
  if (currentUrl.includes("login") || currentUrl.includes("auth")) {
283
286
  const msg =
284
287
  "OpenAI cookies are expired or insufficient. Please re-export cookies from chatgpt.com.";
285
- if (!this.config.quiet) console.error("[OpenAIQuotaScraper] " + msg);
288
+ if (!this.config.quiet)
289
+ console.error("[DEBUG OpenAIQuotaScraper] " + msg);
286
290
  throw new Error(msg);
287
291
  }
288
292
 
289
293
  // Parse the usage data from the captured API response
290
294
  if (!usageData) {
291
295
  const msg = "Failed to capture usage data from API";
292
- if (!this.config.quiet) console.error("[OpenAIQuotaScraper] " + msg);
296
+ if (!this.config.quiet)
297
+ console.error("[DEBUG OpenAIQuotaScraper] " + msg);
293
298
  throw new Error(msg);
294
299
  }
295
300
 
@@ -306,7 +311,7 @@ Then run: bun run packages/cookie-sanitizer/src/sync.ts`;
306
311
 
307
312
  if (!this.config.quiet) {
308
313
  console.log(
309
- `[OpenAIQuotaScraper] Weekly usage: ${weeklyUsedPct}%, resets in ${weeklyResetsAt}`,
314
+ `[DEBUG OpenAIQuotaScraper] Weekly usage: ${weeklyUsedPct}%, resets in ${weeklyResetsAt}`,
310
315
  );
311
316
  }
312
317
 
@@ -349,7 +354,7 @@ Then run: bun run packages/cookie-sanitizer/src/sync.ts`;
349
354
  if (!response.ok) {
350
355
  if (!this.config.quiet) {
351
356
  console.log(
352
- `[OpenAIQuotaScraper] Direct API failed: ${response.status}`,
357
+ `[DEBUG OpenAIQuotaScraper] Direct API failed: ${response.status}`,
353
358
  );
354
359
  }
355
360
  return null;
@@ -374,7 +379,7 @@ Then run: bun run packages/cookie-sanitizer/src/sync.ts`;
374
379
  } catch (error) {
375
380
  if (!this.config.quiet) {
376
381
  console.warn(
377
- "[OpenAIQuotaScraper] Direct API error:",
382
+ "[DEBUG OpenAIQuotaScraper] Direct API error:",
378
383
  error instanceof Error ? error.message : String(error),
379
384
  );
380
385
  }
package/index.ts CHANGED
@@ -13,6 +13,7 @@
13
13
  * Runs directly from Bun.
14
14
  */
15
15
 
16
+ import { Key } from "@earendil-works/pi-tui";
16
17
  import type {
17
18
  CompactOptions,
18
19
  ExtensionAPI,
@@ -39,6 +40,8 @@ import {
39
40
  } from "./packages/quota-manager/src/tui-usage-monitor.ts";
40
41
  import { QuotaManager } from "./packages/quota-manager/src/quota-manager.ts";
41
42
  import { buildFooterStatusValue } from "./footer-status.ts";
43
+ import { registerGithubLoginCommand } from "./packages/clipboard/src/github-login.js";
44
+ import { registerCopySyncShortcut } from "./packages/clipboard/src/copy-sync.js";
42
45
  import {
43
46
  MAX_PROACTIVE_COMPACT_FAILURES,
44
47
  OUTPUT_LIMIT_RESUME_PROMPT,
@@ -64,6 +67,17 @@ import {
64
67
  createBlackboard,
65
68
  } from "./harness/blackboard.ts";
66
69
  import { scheduleAutoResume, cancelAutoResume } from "./harness/index.js";
70
+
71
+ // --- todo-bd-sync: Two-way sync between rpiv-todo and bd --------------------
72
+ // Lazy import - only loads when packages/todo-bd-sync exists
73
+ async function initTodoBdSync(pi: ExtensionAPI): Promise<void> {
74
+ try {
75
+ const mod = await import("./packages/todo-bd-sync/src/extension.js");
76
+ mod.registerTodoBdSync(pi, { debug: false });
77
+ } catch {
78
+ // todo-bd-sync not available
79
+ }
80
+ }
67
81
  import { homedir } from "node:os";
68
82
  import { appendFileSync, existsSync, mkdirSync } from "node:fs";
69
83
  import { join } from "node:path";
@@ -211,6 +225,31 @@ export default function (pi: ExtensionAPI) {
211
225
  const mirrorStore = new MirrorStore();
212
226
  ensureHarnessDir();
213
227
 
228
+ // --- todo-bd-sync: Initialize two-way sync with bd ---------------
229
+ // Start async init but don't await - runs in background
230
+ void initTodoBdSync(pi);
231
+
232
+ // --- Auto-Invoke rpiv-todo via System Prompt ------------------------
233
+ // This makes the todo overlay ALWAYS activate at session start
234
+ const AUTO_TODO_INVOKE_HINT = `
235
+
236
+ You have access to a todo tool that shows a persistent task overlay.
237
+ ALWAYS use it at the START of every session to capture user requirements as tasks.
238
+ When the user gives you a multi-step task:
239
+ 1. Immediately create todo items for each step using the todo tool
240
+ 2. Keep tasks updated - mark in_progress when working, completed when done
241
+ 3. When a task is completed, continue to the next or ask the user
242
+
243
+ The todo overlay persists and helps track progress across your conversation.
244
+ `;
245
+ let firstAgentStart = true;
246
+ pi.on("before_agent_start", async (event) => {
247
+ if (firstAgentStart) {
248
+ event.systemPrompt += AUTO_TODO_INVOKE_HINT;
249
+ firstAgentStart = false;
250
+ }
251
+ });
252
+
214
253
  // --- Auto-track every assistant message ------------------------------
215
254
  pi.on("message_end", async (event, ctx) => {
216
255
  if (isOutputLimitResumePromptMessage(event.message)) {
@@ -288,7 +327,7 @@ export default function (pi: ExtensionAPI) {
288
327
 
289
328
  // --- Smart quota fetch for OpenAI status -------------------------
290
329
  const OPENAI_REFRESH_MIN_INTERVAL_MS = 5 * 60 * 1000; // 5 minutes
291
- const _openaiQuotaScraper = new OpenAIQuotaScraper();
330
+ const _openaiQuotaScraper = new OpenAIQuotaScraper({ quiet: true });
292
331
  let lastOpenAIQuotaFetchAt = 0;
293
332
 
294
333
  // --- Cookie sanitizer integration ------------------------------------
@@ -343,6 +382,8 @@ export default function (pi: ExtensionAPI) {
343
382
  }
344
383
  });
345
384
 
385
+ let lastQuotaAutoFetchAt = 0;
386
+
346
387
  // Live watcher — sanitises on every change in the drop folder.
347
388
  const cookieWatcher = new CookieWatcher({
348
389
  dropDir: cookieDropDir,
@@ -369,6 +410,7 @@ export default function (pi: ExtensionAPI) {
369
410
  }
370
411
  },
371
412
  });
413
+
372
414
  try {
373
415
  cookieWatcher.start();
374
416
  // Sync existing drop-folder cookies now (ignoreInitial: true means
@@ -396,7 +438,6 @@ export default function (pi: ExtensionAPI) {
396
438
  let footerStatusCtx: {
397
439
  ui: { setStatus: (key: string, value: string) => void };
398
440
  } | null = null;
399
- let lastQuotaAutoFetchAt = 0;
400
441
  let quotaAutoFetchInFlight = false;
401
442
  let proactiveCompactInFlight = false;
402
443
  let lastProactiveCompactAt = 0;
@@ -406,6 +447,49 @@ export default function (pi: ExtensionAPI) {
406
447
  let pendingOutputLimitResumeAfterCompact = false;
407
448
  let pendingOutputLimitResumeAfterSettled = false;
408
449
 
450
+ // --- Context-usage escalating warning tiers -----------------------------
451
+ // Amber at 75%, red at 85%. No notify above 90% (proactive compact handles it).
452
+ // Per-session dedup: only notify when crossing INTO a new higher tier.
453
+ const TIER_WARNING = 0.75; // amber
454
+ const TIER_ERROR = 0.85; // red
455
+ let lastNotifiedTier: "none" | "warning" | "error" = "none";
456
+
457
+ function maybeNotifyContextUsage(ctx: ExtensionContext): void {
458
+ const usage = ctx.getContextUsage();
459
+ const pct = usage?.percent;
460
+ if (pct === null || pct === undefined) return;
461
+ if (pct >= 0.9) return; // proactive compact handles 90%+
462
+
463
+ const tier: "none" | "warning" | "error" =
464
+ pct >= TIER_ERROR ? "error" : pct >= TIER_WARNING ? "warning" : "none";
465
+
466
+ // Only notify when crossing into a strictly higher tier
467
+ if (tier === "none") {
468
+ lastNotifiedTier = "none";
469
+ return;
470
+ }
471
+ if (
472
+ tier === "warning" &&
473
+ lastNotifiedTier !== "warning" &&
474
+ lastNotifiedTier !== "error"
475
+ ) {
476
+ lastNotifiedTier = "warning";
477
+ ctx.ui.notify(
478
+ `Context at ${Math.round(pct * 100)}% — consider condensing`,
479
+ "info",
480
+ );
481
+ return;
482
+ }
483
+ if (tier === "error" && lastNotifiedTier !== "error") {
484
+ lastNotifiedTier = "error";
485
+ ctx.ui.notify(
486
+ `Context at ${Math.round(pct * 100)}% — approaching limit`,
487
+ "warning",
488
+ );
489
+ return;
490
+ }
491
+ }
492
+
409
493
  function writeMirrorRecord(
410
494
  provider: ProviderId,
411
495
  record: Omit<import("./mirror.js").ProviderMirrorRecord, "provider">,
@@ -818,6 +902,12 @@ export default function (pi: ExtensionAPI) {
818
902
  },
819
903
  });
820
904
 
905
+ // --- /github-login — Connect GitHub Gist for clipboard sync ------------
906
+ registerGithubLoginCommand(pi);
907
+
908
+ // --- Ctrl+Shift+C — Copy to clipboard + sync to Gist ------------
909
+ registerCopySyncShortcut(pi, Key);
910
+
821
911
  // --- /harness start — Start a new harness job ----------------------
822
912
  pi.registerCommand("harness-start", {
823
913
  description: "Start a new harness job: /harness start <requirement>",
@@ -1117,6 +1207,7 @@ export default function (pi: ExtensionAPI) {
1117
1207
  );
1118
1208
  void maybeAutoFetchQuota(ctx.model?.id ?? null);
1119
1209
  maybeTriggerProactiveCompact(ctx);
1210
+ maybeNotifyContextUsage(ctx);
1120
1211
  });
1121
1212
 
1122
1213
  pi.on("agent_end", () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-harness-runtime",
3
- "version": "0.10.0",
3
+ "version": "1.1.0",
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": "0.9.25",
3
+ "version": "1.1.0",
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/auth",
3
- "version": "0.9.25",
3
+ "version": "1.1.0",
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": "0.9.25",
3
+ "version": "1.1.0",
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": "0.9.25",
3
+ "version": "1.1.0",
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": "0.9.25",
3
+ "version": "1.1.0",
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": "0.9.25",
3
+ "version": "1.1.0",
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": "0.9.25",
3
+ "version": "1.1.0",
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": "0.9.25",
3
+ "version": "1.1.0",
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",
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Copy + Sync — Ctrl+Shift+C shortcut for clipboard sync
3
+ *
4
+ * Registers a keyboard shortcut that:
5
+ * 1. Reads selected text from clipboard (Xvfb/X11 on headless server)
6
+ * 2. Writes to bridge file for terminal paste
7
+ * 3. POSTs to GitHub Gist for cross-device sync
8
+ *
9
+ * Only fires on explicit Ctrl+Shift+C — NOT on auto-select/highlight.
10
+ */
11
+ /**
12
+ * Read selected text, write to bridge, sync to Gist.
13
+ * Called by the Ctrl+Shift+C shortcut handler.
14
+ */
15
+ export declare function copyAndSync(ctx: {
16
+ ui: {
17
+ notify: (msg: string, type?: string) => void;
18
+ };
19
+ }): Promise<void>;
20
+ type AnyPi = any;
21
+ /**
22
+ * Register Ctrl+Shift+C as the copy+sync shortcut.
23
+ * The Key.ctrlShift("c") syntax comes from @earendil-works/pi-tui.
24
+ */
25
+ export declare function registerCopySyncShortcut(pi: AnyPi, Key: AnyPi): void;
26
+ export {};
27
+ //# sourceMappingURL=copy-sync.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"copy-sync.d.ts","sourceRoot":"","sources":["../../src/copy-sync.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AA6HH;;;GAGG;AACH,wBAAsB,WAAW,CAAC,GAAG,EAAE;IACtC,EAAE,EAAE;QAAE,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,KAAK,IAAI,CAAA;KAAE,CAAC;CACrD,GAAG,OAAO,CAAC,IAAI,CAAC,CAoChB;AAKD,KAAK,KAAK,GAAG,GAAG,CAAC;AAEjB;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,GAAG,IAAI,CAapE"}