pi-harness-runtime 1.1.250 → 1.1.254

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 (124) hide show
  1. package/index.ts +96 -48
  2. package/package.json +1 -1
  3. package/packages/a2a-adapter/package.json +1 -1
  4. package/packages/agent-policy/package.json +1 -1
  5. package/packages/architecture-generator/package.json +1 -1
  6. package/packages/auth/package.json +1 -1
  7. package/packages/autonomous-refactor/package.json +1 -1
  8. package/packages/autonomous-runtime/package.json +1 -1
  9. package/packages/cache-strategy/package.json +1 -1
  10. package/packages/capability-registry/package.json +1 -1
  11. package/packages/checkpoint/package.json +1 -1
  12. package/packages/cli-plugin-sdk/package.json +1 -1
  13. package/packages/clipboard/package.json +1 -1
  14. package/packages/clipboard-plugin/package.json +1 -1
  15. package/packages/code-generation/package.json +1 -1
  16. package/packages/code-review/package.json +1 -1
  17. package/packages/codex-adapter/package.json +1 -1
  18. package/packages/codex-watcher/dist/src/index.d.ts +1 -0
  19. package/packages/codex-watcher/dist/src/index.d.ts.map +1 -1
  20. package/packages/codex-watcher/dist/src/index.js +41 -17
  21. package/packages/codex-watcher/dist/src/index.js.map +1 -1
  22. package/packages/codex-watcher/dist/src/session.js +23 -29
  23. package/packages/codex-watcher/dist/src/session.js.map +1 -1
  24. package/packages/codex-watcher/package.json +1 -1
  25. package/packages/codex-watcher/src/index.ts +45 -19
  26. package/packages/codex-watcher/src/session.ts +20 -33
  27. package/packages/config-capture/package.json +1 -1
  28. package/packages/context-compiler/package.json +1 -1
  29. package/packages/context-discovery/package.json +1 -1
  30. package/packages/context-manager/package.json +1 -1
  31. package/packages/cookie-sanitizer/package.json +1 -1
  32. package/packages/cost-optimizer/package.json +1 -1
  33. package/packages/dependency-analyzer/package.json +1 -1
  34. package/packages/django-plugin/package.json +1 -1
  35. package/packages/doc-generator/package.json +1 -1
  36. package/packages/e2e-tester/package.json +1 -1
  37. package/packages/evaluation-engine/package.json +1 -1
  38. package/packages/evaluation-runner/package.json +1 -1
  39. package/packages/event-bus/package.json +1 -1
  40. package/packages/event-store/package.json +1 -1
  41. package/packages/experience-replay/package.json +1 -1
  42. package/packages/feedback-collector/package.json +1 -1
  43. package/packages/file-copy-helper/package.json +1 -1
  44. package/packages/framework-detector/package.json +1 -1
  45. package/packages/framework-plugin-sdk/package.json +1 -1
  46. package/packages/frappe-plugin/package.json +1 -1
  47. package/packages/generic-web-plugin/package.json +1 -1
  48. package/packages/health-monitor/package.json +1 -1
  49. package/packages/intent-analyzer/package.json +1 -1
  50. package/packages/jev-judge/package.json +1 -1
  51. package/packages/knowledge-graph/package.json +1 -1
  52. package/packages/knowledge-retrieval/package.json +1 -1
  53. package/packages/laravel-plugin/package.json +1 -1
  54. package/packages/learning-engine/package.json +1 -1
  55. package/packages/mcp-adapter/package.json +1 -1
  56. package/packages/memory-engine/package.json +1 -1
  57. package/packages/milestone-manager/package.json +1 -1
  58. package/packages/model-registry/package.json +1 -1
  59. package/packages/nextjs-plugin/package.json +1 -1
  60. package/packages/notification/dist/adapters/telegram-adapter.d.ts +10 -0
  61. package/packages/notification/dist/adapters/telegram-adapter.d.ts.map +1 -1
  62. package/packages/notification/dist/adapters/telegram-adapter.js +18 -1
  63. package/packages/notification/dist/adapters/telegram-adapter.js.map +1 -1
  64. package/packages/notification/dist/index.d.ts +1 -1
  65. package/packages/notification/dist/index.d.ts.map +1 -1
  66. package/packages/notification/dist/index.js +1 -1
  67. package/packages/notification/dist/index.js.map +1 -1
  68. package/packages/notification/dist/notification-center.d.ts +4 -0
  69. package/packages/notification/dist/notification-center.d.ts.map +1 -1
  70. package/packages/notification/dist/notification-center.js +10 -0
  71. package/packages/notification/dist/notification-center.js.map +1 -1
  72. package/packages/notification/package.json +1 -1
  73. package/packages/notification/src/adapters/telegram-adapter.ts +29 -2
  74. package/packages/notification/src/index.ts +1 -1
  75. package/packages/notification/src/notification-center.ts +11 -0
  76. package/packages/observability/package.json +1 -1
  77. package/packages/okf-indexer/package.json +1 -1
  78. package/packages/paperclip-integration/package.json +1 -1
  79. package/packages/performance-optimizer/package.json +1 -1
  80. package/packages/privilege-broker/package.json +1 -1
  81. package/packages/project-analyzer/package.json +1 -1
  82. package/packages/project-bootstrap/package.json +1 -1
  83. package/packages/projection-engine/package.json +1 -1
  84. package/packages/prompt-compiler/package.json +1 -1
  85. package/packages/prompt-versioning/package.json +1 -1
  86. package/packages/provider-adapter-sdk/package.json +1 -1
  87. package/packages/provider-router/package.json +1 -1
  88. package/packages/provider-selector/package.json +1 -1
  89. package/packages/providers/package.json +1 -1
  90. package/packages/qdrant-skills/package.json +1 -1
  91. package/packages/quota-manager/package.json +1 -1
  92. package/packages/rate-limiter/package.json +1 -1
  93. package/packages/react-vite-plugin/package.json +1 -1
  94. package/packages/release-manager/package.json +1 -1
  95. package/packages/requirement-compiler/package.json +1 -1
  96. package/packages/runtime/package.json +1 -1
  97. package/packages/scheduler/package.json +1 -1
  98. package/packages/scheduler-adapter/package.json +1 -1
  99. package/packages/session/package.json +1 -1
  100. package/packages/session-api/package.json +1 -1
  101. package/packages/session-export/package.json +1 -1
  102. package/packages/shared-context/package.json +1 -1
  103. package/packages/skill-mcp-client/package.json +1 -1
  104. package/packages/skill-registry/package.json +1 -1
  105. package/packages/skills/package.json +1 -1
  106. package/packages/sprint-planner/package.json +1 -1
  107. package/packages/subscription-engine/package.json +1 -1
  108. package/packages/task-compiler/package.json +1 -1
  109. package/packages/telegram/package.json +1 -1
  110. package/packages/tencentdb-memory/package.json +1 -1
  111. package/packages/tencentdb-sync/package.json +1 -1
  112. package/packages/test-data-generator/package.json +1 -1
  113. package/packages/test-generator/package.json +1 -1
  114. package/packages/todo-bd-sync/package.json +1 -1
  115. package/packages/token-estimation/package.json +1 -1
  116. package/packages/token-optimizer/package.json +1 -1
  117. package/packages/trajectory/package.json +1 -1
  118. package/packages/tui/package.json +1 -1
  119. package/packages/types/package.json +1 -1
  120. package/packages/webmcp-tester/package.json +1 -1
  121. package/packages/workflow-events/package.json +1 -1
  122. package/packages/workspace-scanner/package.json +1 -1
  123. package/packages/worktree/package.json +1 -1
  124. package/packages/write-review/package.json +1 -1
package/index.ts CHANGED
@@ -127,6 +127,14 @@ const startupStatus = new HarnessStartupStatus();
127
127
  const harnessMessages = startupStatus.messages;
128
128
  const addHarnessMessage = startupStatus.update.bind(startupStatus);
129
129
 
130
+ // Shared state for callback handlers (accessible across init functions)
131
+ const sharedState = {
132
+ waitingForUserSince: null as Date | null,
133
+ todoContinuationController: null as unknown,
134
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
135
+ updateAutoContinueStatus: null as any,
136
+ };
137
+
130
138
  async function initAutoContinue(pi: ExtensionAPI): Promise<void> {
131
139
  addHarnessMessage("Jev", "initializing", "wait");
132
140
  try {
@@ -190,6 +198,10 @@ async function initAutoContinue(pi: ExtensionAPI): Promise<void> {
190
198
  ERROR: "Auto-continue unavailable",
191
199
  } as const;
192
200
 
201
+ // Wire shared state for callback handlers
202
+ sharedState.waitingForUserSince = waitingForUserSince;
203
+ sharedState.updateAutoContinueStatus = updateAutoContinueStatus;
204
+
193
205
  // Update auto-continue status in TUI footer
194
206
  function updateAutoContinueStatus(state: keyof typeof AC_STATE_MESSAGES, requestId?: string): void {
195
207
  if (!_setAutoContinueStatus) return;
@@ -282,15 +294,26 @@ async function initAutoContinue(pi: ExtensionAPI): Promise<void> {
282
294
  return null;
283
295
  }
284
296
 
285
- // Detect routine continuation questions ("Should I continue?")
286
- // These should NOT block immediate continuation - let Jev/todo controller decide
287
297
  // Detect routine continuation questions ("Should I continue?")
288
298
  // These should NOT block immediate continuation - let Jev/todo controller decide
289
299
  function isRoutineContinuation(question: string): boolean {
290
300
  const lower = question.toLowerCase();
291
- // Match patterns like "should i continue?", "should we continue?", etc.
292
- return (/\b(should i|should we|should the|can i continue|can we continue)\b/.test(lower)
293
- && /\b(continue|proceed|with the next|to the next|move on)\b/.test(lower));
301
+ // Match ALL routine continuation patterns
302
+ const routinePatterns = [
303
+ /\b(should i|should we|should the|can i continue|can we continue)\b/,
304
+ /\b(would you like me to continue|shall i proceed)\b/,
305
+ /\b(can i proceed|may i continue)\b/,
306
+ /\b(continue|proceed)\s*(with|to|on|with the next|to the next)\b/,
307
+ /\bshall\s+(i|we)\s+(proceed|continue)\b/,
308
+ /\bshould\s+(i|we)\s+(continue|proceed|move on)\b/,
309
+ /\b(continue|proceed)\s+\?/,
310
+ ];
311
+ for (const pattern of routinePatterns) {
312
+ if (pattern.test(lower)) {
313
+ return true;
314
+ }
315
+ }
316
+ return false;
294
317
  }
295
318
 
296
319
  // Detect when agent asks for continuation
@@ -329,19 +352,24 @@ async function initAutoContinue(pi: ExtensionAPI): Promise<void> {
329
352
  // Build rich context message
330
353
  const waitMinutes = Math.round((Date.now() - waitingForUserSince!.getTime()) / 60000);
331
354
  const taskInfo = taskContext.total > 0
332
- ? ` | Tasks: ${taskContext.completed}/${taskContext.total} done`
333
- : "";
334
- const contextInfo = `Waiting: ${waitMinutes}m${taskInfo}`;
355
+ ? `Tasks: ${taskContext.completed}/${taskContext.total} done`
356
+ : "No active tasks";
357
+ const contextInfo = `Waiting: ${waitMinutes}m | ${taskInfo}`;
335
358
 
336
359
  // Emit WaitingForUserInput to Telegram with Yes/No buttons
337
360
  _nc?.notifyWithApproval("WaitingForUserInput", {
338
361
  jobId: `waiting-user-${questionHash}`,
339
362
  requirement: detectedQuestion,
340
- error: contextInfo,
341
363
  }, {
342
364
  approveLabel: "Continue",
343
365
  rejectLabel: "Not yet",
344
366
  });
367
+
368
+ // Also send context info as a follow-up message (not in error field)
369
+ _nc?.notify("Info", {
370
+ jobId: `info-${questionHash}`,
371
+ message: contextInfo,
372
+ });
345
373
  }
346
374
  });
347
375
 
@@ -665,7 +693,6 @@ async function initAutoContinue(pi: ExtensionAPI): Promise<void> {
665
693
  const result = await todoContinuationController.decide();
666
694
 
667
695
  if (result.action === "continue" && result.nextItemId) {
668
- _steerSentThisTurn = true;
669
696
  updateAutoContinueStatus("CONTINUING");
670
697
  await todoContinuationController.steerToContinue(result.nextItemId);
671
698
  // Queue remains set while agent processes, cleared on agent_end
@@ -863,7 +890,7 @@ async function initTelegram(pi: ExtensionAPI): Promise<void> {
863
890
 
864
891
  // Register callback handler for inline keyboard button clicks (approve/reject)
865
892
  const { parseCallbackData, CallbackActions } = await import(
866
- "./packages/notification/dist/telegram-webhook-handler.js"
893
+ "./packages/notification/dist/telegram-webhook-handler.js"
867
894
  );
868
895
  center.setCallbackHandler(async (data: string, _query: { id: string }) => {
869
896
  const parsed = parseCallbackData(data);
@@ -871,18 +898,31 @@ async function initTelegram(pi: ExtensionAPI): Promise<void> {
871
898
 
872
899
  switch (parsed.action) {
873
900
  case CallbackActions.APPROVE:
874
- // TODO: Resume auto-continue waiting state
875
- logToFile("[TelegramCallback] Approved - user clicked Continue");
901
+ // User clicked Continue - clear waiting state and resume continuation
902
+ logToFile("[TelegramCallback] Approved - user clicked Continue, resuming work");
903
+ sharedState.waitingForUserSince = null;
904
+ sharedState.updateAutoContinueStatus?.("IDLE");
905
+ // Also resume continuation controller
906
+ (sharedState.todoContinuationController as any)?.resume?.();
876
907
  break;
877
908
  case CallbackActions.REJECT:
878
- // TODO: Dismiss notification, don't resume
879
- logToFile("[TelegramCallback] Rejected - user clicked Not yet");
909
+ // User clicked Not yet - just dismiss, don't resume
910
+ logToFile("[TelegramCallback] Rejected - user clicked Not yet, pausing");
911
+ // Explicitly pause the continuation
912
+ (sharedState.todoContinuationController as any)?.explicitPause?.();
880
913
  break;
881
914
  default:
882
915
  logToFile("[TelegramCallback]", `Unknown action: ${parsed.action}`);
883
916
  }
884
917
  });
885
918
 
919
+ // Register message handler to forward Telegram messages to Pi
920
+ center.setMessageHandler(async (text: string, _chatId: string) => {
921
+ logToFile("[TelegramInbound]", `Forwarding message to Pi: "${text.slice(0, 50)}..."`);
922
+ // Forward the message to Pi as a user message
923
+ await pi.sendUserMessage(text, { deliverAs: "steer" });
924
+ });
925
+
886
926
  // Wire to singleton nc() helper so all event emitters can reach Telegram
887
927
  _nc = {
888
928
  center,
@@ -1937,22 +1977,35 @@ export default function (pi: ExtensionAPI) {
1937
1977
  // Collect promise so we can wait for initialization before showing startup notification
1938
1978
  asyncInitPromises.push(initTelegram(pi));
1939
1979
 
1940
- // --- codex-watcher: Inject Codex plans into pi.dev + Telegram --------------
1941
- // Lightweight: polls ~/.codex/sessions/ every 5s, no LangChain daemon.
1942
- // On plan detected: sends Telegram alert + steer message to pi.dev.
1943
- try {
1944
- let latestPlanOrdinal = 0;
1945
-
1946
- const codexHandle = startWatcher({
1947
- pollIntervalMs: 5000,
1948
- maxIdlePolls: Infinity,
1949
- onSessionChange: (session) => {
1980
+ // --- codex-watcher: Inject Codex plans into pi.dev + Telegram --------------
1981
+ // Lightweight: polls ~/.codex/sessions/ every 5s, no LangChain daemon.
1982
+ // On plan detected: sends Telegram alert + steer message to pi.dev.
1983
+ try {
1984
+ // Track accepted and delivered ordinals per session
1985
+ // Accepted: we've seen this ordinal and are trying to deliver
1986
+ // Delivered: successfully sent to destination
1987
+ const sessionAcceptedOrdinals = new Map<string, number>();
1988
+ const sessionDeliveredOrdinals = new Map<string, number>();
1989
+ let currentSessionId: string | null = null;
1990
+
1991
+ const codexHandle = startWatcher({
1992
+ pollIntervalMs: 5000,
1993
+ maxIdlePolls: Infinity,
1994
+ onSessionChange: (session) => {
1950
1995
  if (session) {
1951
1996
  logToFile("[codex]", `Session started: ${session.threadName}`);
1997
+ currentSessionId = session.id;
1998
+ // Initialize ordinal tracking for new session if not tracked yet
1999
+ if (!sessionAcceptedOrdinals.has(session.id)) {
2000
+ sessionAcceptedOrdinals.set(session.id, 0);
2001
+ sessionDeliveredOrdinals.set(session.id, 0);
2002
+ }
1952
2003
  nc("CodexSessionStarted", {
1953
2004
  requirement: session.threadName || "Codex session",
1954
2005
  taskTitle: session.id,
1955
2006
  });
2007
+ } else {
2008
+ currentSessionId = null;
1956
2009
  }
1957
2010
  },
1958
2011
  onMessages: (msgs) => {
@@ -1962,27 +2015,32 @@ export default function (pi: ExtensionAPI) {
1962
2015
 
1963
2016
  const classification = classifyMessage(msg.text);
1964
2017
  if (classification !== "plan" && classification !== "mixed") continue;
1965
- if (msg.ordinal <= latestPlanOrdinal) continue;
1966
2018
 
1967
- latestPlanOrdinal = msg.ordinal;
2019
+ // Get session-specific ordinal tracking (use currentSessionId from watcher)
2020
+ const sessionId = currentSessionId;
2021
+ if (!sessionId) continue;
2022
+
2023
+ // Check if we've already delivered this ordinal to this session
2024
+ const deliveredOrdinal = sessionDeliveredOrdinals.get(sessionId) ?? 0;
2025
+ if (msg.ordinal <= deliveredOrdinal) continue;
1968
2026
 
1969
- // Emit Telegram alert
2027
+ // Emit Telegram alert with preview (include more of the plan)
2028
+ const planPreview = msg.text.slice(0, 800) + (msg.text.length > 800 ? "\n... (full plan forwarded to Pi)" : "");
1970
2029
  nc("CodexPlanDetected", {
1971
- requirement: "Codex plan ready",
2030
+ requirement: planPreview,
1972
2031
  taskTitle: `Ordinal ${msg.ordinal}`,
1973
2032
  });
1974
2033
 
1975
- // Inject plan into pi.dev as a steer message
1976
- const planPreview = msg.text.slice(0, 500) + (msg.text.length > 500 ? "\n..." : "");
2034
+ // Inject full plan into pi.dev as a steer message
2035
+ const planContent = `[Codex plan detected — ordinal ${msg.ordinal}]\n\n${msg.text}`;
1977
2036
  try {
1978
- pi.sendUserMessage(
1979
- `[Codex plan detected — ordinal ${msg.ordinal}]
1980
-
1981
- ${planPreview}`,
1982
- { deliverAs: "steer" },
1983
- );
2037
+ pi.sendUserMessage(planContent, { deliverAs: "steer" });
2038
+ // Mark as delivered only if Pi send succeeds
2039
+ sessionDeliveredOrdinals.set(sessionId, msg.ordinal);
2040
+ logToFile("[codex]", `Delivered ordinal ${msg.ordinal} to Pi`);
1984
2041
  } catch {
1985
- // pi.dev may not be ready
2042
+ // pi.dev may not be ready - log failure, will retry on next poll
2043
+ logToFile("[codex]", `Delivery failed for ordinal ${msg.ordinal}, will retry on next poll`);
1986
2044
  }
1987
2045
  }
1988
2046
  },
@@ -2486,9 +2544,6 @@ Run \`bd ready\` to see current bd issues.
2486
2544
  let outputLimitResumeAttempts = 0;
2487
2545
  let pendingOutputLimitResumeAfterCompact = false;
2488
2546
  let pendingOutputLimitResumeAfterSettled = false;
2489
-
2490
- // Track if we sent a steer message - cleared when agent completes
2491
- let _steerSentThisTurn = false;
2492
2547
  let providerOverloadResumeAttempts = 0;
2493
2548
  let providerOverloadResumeTimer: ReturnType<typeof setTimeout> | null = null;
2494
2549
 
@@ -3552,13 +3607,6 @@ Run \`bd ready\` to see current bd issues.
3552
3607
 
3553
3608
  pi.on("agent_end", () => {
3554
3609
  setTimeout(() => {
3555
- // Clear steer queue when agent completes processing our steer message
3556
- if (_steerSentThisTurn) {
3557
- _steerSentThisTurn = false;
3558
- todoContinuationController?.clearQueue();
3559
- logToFile("[auto-continue]", "Agent turn complete, queue cleared");
3560
- }
3561
-
3562
3610
  if (!pendingOutputLimitResumeAfterSettled) {
3563
3611
  return;
3564
3612
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-harness-runtime",
3
- "version": "1.1.250",
3
+ "version": "1.1.254",
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.250",
3
+ "version": "1.1.254",
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/agent-policy",
3
- "version": "1.1.250",
3
+ "version": "1.1.254",
4
4
  "description": "Agent policy runtime for pi-harness - enforces mandatory rule delivery and mutation gating",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/architecture-generator",
3
- "version": "1.1.250",
3
+ "version": "1.1.254",
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.250",
3
+ "version": "1.1.254",
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.250",
3
+ "version": "1.1.254",
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.250",
3
+ "version": "1.1.254",
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.250",
3
+ "version": "1.1.254",
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.250",
3
+ "version": "1.1.254",
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.250",
3
+ "version": "1.1.254",
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.250",
3
+ "version": "1.1.254",
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.250",
3
+ "version": "1.1.254",
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.250",
3
+ "version": "1.1.254",
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.250",
3
+ "version": "1.1.254",
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.250",
3
+ "version": "1.1.254",
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.250",
3
+ "version": "1.1.254",
4
4
  "type": "module",
5
5
  "description": "OpenAI Codex provider adapter for pi-harness",
6
6
  "main": "dist/index.js",
@@ -37,6 +37,7 @@ export declare function getVisibleMessages(rolloutPath: string, options?: {
37
37
  * 1. Polls session_index.jsonl to detect active session changes
38
38
  * 2. Tracks file position so it only reads new lines (no re-read of full file)
39
39
  * 3. Calls onMessages with incremental messages each poll cycle
40
+ * 4. Preserves incomplete JSON lines until a complete newline-delimited record arrives
40
41
  */
41
42
  export declare function startWatcher(options?: WatcherOptions): WatcherHandle;
42
43
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAKH,OAAO,EAAE,eAAe,EAAoB,MAAM,aAAa,CAAC;AAChE,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChE,OAAO,KAAK,EACX,YAAY,EACZ,YAAY,EACZ,aAAa,EACb,cAAc,EACd,MAAM,YAAY,CAAC;AAEpB,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,CAAC;AAC1E,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,gBAAgB,EAAE,CAAC;AAM7D,oFAAoF;AACpF,wBAAsB,kBAAkB,CACvC,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE;IAAE,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAO,GACpD,OAAO,CAAC,YAAY,EAAE,CAAC,CAkBzB;AAMD;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAAC,OAAO,GAAE,cAAmB,GAAG,aAAa,CA6JxE"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAKH,OAAO,EAAE,eAAe,EAAoB,MAAM,aAAa,CAAC;AAChE,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChE,OAAO,KAAK,EACX,YAAY,EACZ,YAAY,EACZ,aAAa,EACb,cAAc,EACd,MAAM,YAAY,CAAC;AAEpB,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,CAAC;AAC1E,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,gBAAgB,EAAE,CAAC;AAM7D,oFAAoF;AACpF,wBAAsB,kBAAkB,CACvC,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE;IAAE,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAO,GACpD,OAAO,CAAC,YAAY,EAAE,CAAC,CAkBzB;AAMD;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAAC,OAAO,GAAE,cAAmB,GAAG,aAAa,CAsLxE"}
@@ -17,7 +17,7 @@
17
17
  * });
18
18
  * // later: handle.stop();
19
19
  */
20
- import { existsSync, openSync, readFileSync, statSync } from "node:fs";
20
+ import { existsSync, openSync, readFileSync, readSync, fstatSync, closeSync } from "node:fs";
21
21
  import { homedir } from "node:os";
22
22
  import { join } from "node:path";
23
23
  import { classifyMessage, parseNewMessages } from "./parser.js";
@@ -57,6 +57,7 @@ export async function getVisibleMessages(rolloutPath, options = {}) {
57
57
  * 1. Polls session_index.jsonl to detect active session changes
58
58
  * 2. Tracks file position so it only reads new lines (no re-read of full file)
59
59
  * 3. Calls onMessages with incremental messages each poll cycle
60
+ * 4. Preserves incomplete JSON lines until a complete newline-delimited record arrives
60
61
  */
61
62
  export function startWatcher(options = {}) {
62
63
  const { pollIntervalMs = 2000, codexDir, onMessages, onSessionChange, } = options;
@@ -65,6 +66,8 @@ export function startWatcher(options = {}) {
65
66
  let currentFd = null;
66
67
  let currentPath = null;
67
68
  let currentOrdinal = 0;
69
+ let currentBytePos = 0; // Track byte position we're at in the file
70
+ let pendingText = ""; // Preserve incomplete lines across reads
68
71
  let pollCount = 0;
69
72
  const maxIdlePolls = options.maxIdlePolls ?? Infinity;
70
73
  // Track last known session to detect changes
@@ -73,12 +76,12 @@ export function startWatcher(options = {}) {
73
76
  stopped = true;
74
77
  if (currentFd !== null) {
75
78
  try {
76
- const { closeSync } = require("node:fs");
77
79
  closeSync(currentFd);
78
80
  }
79
81
  catch {
80
82
  // ignore
81
83
  }
84
+ currentFd = null;
82
85
  }
83
86
  }
84
87
  function isRunning() {
@@ -93,32 +96,52 @@ export function startWatcher(options = {}) {
93
96
  function openRollout(path) {
94
97
  if (currentFd !== null && currentPath !== path) {
95
98
  try {
96
- const { closeSync } = require("node:fs");
97
99
  closeSync(currentFd);
98
100
  }
99
101
  catch {
100
102
  // ignore
101
103
  }
104
+ currentFd = null;
102
105
  }
103
- // stat to get current size
104
- const stat = statSync(path);
106
+ // Open the file for reading
105
107
  currentFd = openSync(path, "r");
106
108
  currentPath = path;
107
109
  currentOrdinal = 0;
108
- return { fd: currentFd, size: stat.size };
110
+ currentBytePos = 0;
111
+ pendingText = ""; // Reset pending text for new file
112
+ return currentFd;
109
113
  }
110
- function readNewLines(fd, knownSize) {
111
- const { readSync, fstatSync } = require("node:fs");
114
+ /**
115
+ * Read new lines from the file, preserving incomplete records.
116
+ * Returns complete lines only; incomplete trailing data is kept for next read.
117
+ */
118
+ function readNewLines(fd) {
112
119
  const stat = fstatSync(fd);
113
- const newSize = stat.size;
114
- if (newSize <= knownSize) {
115
- return { lines: [], newSize: knownSize };
120
+ const fileSize = stat.size;
121
+ // Read from our tracked position to current end of file
122
+ const bytesToRead = fileSize - currentBytePos;
123
+ if (bytesToRead <= 0) {
124
+ return { lines: [], newBytePos: currentBytePos };
116
125
  }
117
- const buf = Buffer.alloc(newSize - knownSize);
118
- const bytesRead = readSync(fd, buf, 0, buf.length, knownSize);
126
+ const buf = Buffer.alloc(bytesToRead);
127
+ const bytesRead = readSync(fd, buf, 0, buf.length, currentBytePos);
119
128
  const text = buf.subarray(0, bytesRead).toString("utf8");
120
- const lines = text.split("\n").filter((l) => l.trim());
121
- return { lines, newSize };
129
+ // Prepend any pending text from previous incomplete read
130
+ const fullText = pendingText + text;
131
+ // Split by newline, keeping track of whether we ended with a complete line
132
+ const lines = fullText.split("\n");
133
+ // If text doesn't end with newline, last element is incomplete - save it
134
+ if (!text.endsWith("\n")) {
135
+ pendingText = lines.pop() ?? "";
136
+ }
137
+ else {
138
+ pendingText = "";
139
+ }
140
+ // Filter out empty lines
141
+ const completeLines = lines.filter((l) => l.trim());
142
+ // Update our tracked position by bytes actually read
143
+ const newBytePos = currentBytePos + bytesRead;
144
+ return { lines: completeLines, newBytePos };
122
145
  }
123
146
  async function poll() {
124
147
  if (stopped)
@@ -155,8 +178,9 @@ export function startWatcher(options = {}) {
155
178
  }
156
179
  return;
157
180
  }
158
- const stat = statSync(session.rolloutPath);
159
- const { lines } = readNewLines(currentFd, stat.size);
181
+ // Read new lines from our tracked byte position
182
+ const { lines, newBytePos } = readNewLines(currentFd);
183
+ currentBytePos = newBytePos; // Update tracked position
160
184
  if (lines.length > 0) {
161
185
  pollCount = 0;
162
186
  const messages = parseNewMessages(lines, currentOrdinal);
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Session discovery — reads ~/.codex/session_index.jsonl to find active sessions.
3
3
  */
4
- import { existsSync, readFileSync } from "node:fs";
4
+ import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
5
5
  import { homedir } from "node:os";
6
6
  import { join } from "node:path";
7
7
  /** Find the most recently active Codex session. */
@@ -60,46 +60,40 @@ function findRolloutPath(sessionId, codexDir) {
60
60
  // The rollout path follows: sessions/YYYY/MM/DD/rollout-YYYY-MM-DDTHH-MM-SS-<sessionId>.jsonl
61
61
  // We need to find the file whose name ends with <sessionId>.jsonl
62
62
  // Since there can be multiple sessions per day, iterate all files.
63
- try {
64
- const { readdirSync } = require("node:fs");
65
- for (const dirPath of walkDirs(sessionsDir)) {
66
- for (const file of readdirSync(dirPath)) {
67
- if (file.endsWith(`${sessionId}.jsonl`)) {
68
- return join(dirPath, file);
69
- }
70
- }
71
- }
72
- }
73
- catch {
74
- // walkSync may not be available on all Node versions; fall back to find
75
- }
76
- return findRolloutPathFallback(sessionId, sessionsDir);
77
- }
78
- function findRolloutPathFallback(sessionId, sessionsDir) {
79
63
  const found = walkForSession(sessionsDir, sessionId);
80
- return found ?? join(sessionsDir, "unknown", `${sessionId}.jsonl`);
64
+ if (found)
65
+ return found;
66
+ return join(sessionsDir, "unknown", `${sessionId}.jsonl`);
81
67
  }
82
68
  /** Recursively walk all subdirectories, yielding each directory path. */
83
69
  function* walkDirs(dir) {
84
- const { readdirSync, statSync } = require("node:fs");
85
- for (const entry of readdirSync(dir)) {
86
- const full = join(dir, entry);
87
- const stat = statSync(full);
88
- if (stat.isDirectory()) {
89
- yield full;
90
- yield* walkDirs(full);
70
+ try {
71
+ for (const entry of readdirSync(dir)) {
72
+ const full = join(dir, entry);
73
+ const stat = statSync(full);
74
+ if (stat.isDirectory()) {
75
+ yield full;
76
+ yield* walkDirs(full);
77
+ }
91
78
  }
92
79
  }
80
+ catch {
81
+ // Directory may not exist or be readable
82
+ }
93
83
  }
94
84
  /** Find the rollout file for a given session ID by walking directories. */
95
85
  function walkForSession(sessionsDir, sessionId) {
96
- const { readdirSync } = require("node:fs");
97
86
  for (const dirPath of walkDirs(sessionsDir)) {
98
- for (const file of readdirSync(dirPath)) {
99
- if (file.startsWith("rollout-") && file.endsWith(`${sessionId}.jsonl`)) {
100
- return join(dirPath, file);
87
+ try {
88
+ for (const file of readdirSync(dirPath)) {
89
+ if (file.startsWith("rollout-") && file.endsWith(`${sessionId}.jsonl`)) {
90
+ return join(dirPath, file);
91
+ }
101
92
  }
102
93
  }
94
+ catch {
95
+ // Skip unreadable directories
96
+ }
103
97
  }
104
98
  return null;
105
99
  }