pi-harness-runtime 1.1.220 → 1.1.222

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 (102) hide show
  1. package/harness/honcho-init.ts +29 -29
  2. package/index.ts +81 -22
  3. package/package.json +1 -1
  4. package/packages/a2a-adapter/package.json +1 -1
  5. package/packages/agent-policy/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/codex-watcher/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/e2e-tester/package.json +1 -1
  30. package/packages/evaluation-engine/package.json +1 -1
  31. package/packages/evaluation-runner/package.json +1 -1
  32. package/packages/event-bus/package.json +1 -1
  33. package/packages/event-store/package.json +1 -1
  34. package/packages/experience-replay/package.json +1 -1
  35. package/packages/feedback-collector/package.json +1 -1
  36. package/packages/file-copy-helper/package.json +1 -1
  37. package/packages/framework-detector/package.json +1 -1
  38. package/packages/framework-plugin-sdk/package.json +1 -1
  39. package/packages/frappe-plugin/package.json +1 -1
  40. package/packages/generic-web-plugin/package.json +1 -1
  41. package/packages/health-monitor/package.json +1 -1
  42. package/packages/intent-analyzer/package.json +1 -1
  43. package/packages/jev-judge/package.json +1 -1
  44. package/packages/knowledge-graph/package.json +1 -1
  45. package/packages/knowledge-retrieval/package.json +1 -1
  46. package/packages/laravel-plugin/package.json +1 -1
  47. package/packages/learning-engine/package.json +1 -1
  48. package/packages/mcp-adapter/package.json +1 -1
  49. package/packages/memory-engine/package.json +1 -1
  50. package/packages/milestone-manager/package.json +1 -1
  51. package/packages/model-registry/package.json +1 -1
  52. package/packages/nextjs-plugin/package.json +1 -1
  53. package/packages/notification/package.json +1 -1
  54. package/packages/observability/package.json +1 -1
  55. package/packages/okf-indexer/package.json +1 -1
  56. package/packages/paperclip-integration/package.json +1 -1
  57. package/packages/performance-optimizer/package.json +1 -1
  58. package/packages/privilege-broker/package.json +1 -1
  59. package/packages/project-analyzer/package.json +1 -1
  60. package/packages/project-bootstrap/package.json +1 -1
  61. package/packages/projection-engine/package.json +1 -1
  62. package/packages/prompt-compiler/package.json +1 -1
  63. package/packages/prompt-versioning/package.json +1 -1
  64. package/packages/provider-adapter-sdk/package.json +1 -1
  65. package/packages/provider-router/package.json +1 -1
  66. package/packages/provider-selector/package.json +1 -1
  67. package/packages/providers/package.json +1 -1
  68. package/packages/qdrant-skills/package.json +1 -1
  69. package/packages/quota-manager/package.json +1 -1
  70. package/packages/rate-limiter/package.json +1 -1
  71. package/packages/react-vite-plugin/package.json +1 -1
  72. package/packages/release-manager/package.json +1 -1
  73. package/packages/requirement-compiler/package.json +1 -1
  74. package/packages/runtime/package.json +1 -1
  75. package/packages/scheduler/package.json +1 -1
  76. package/packages/scheduler-adapter/package.json +1 -1
  77. package/packages/session/package.json +1 -1
  78. package/packages/session-api/package.json +1 -1
  79. package/packages/session-export/package.json +1 -1
  80. package/packages/shared-context/package.json +1 -1
  81. package/packages/skill-mcp-client/package.json +1 -1
  82. package/packages/skill-registry/package.json +1 -1
  83. package/packages/skills/package.json +1 -1
  84. package/packages/sprint-planner/package.json +1 -1
  85. package/packages/subscription-engine/package.json +1 -1
  86. package/packages/task-compiler/package.json +1 -1
  87. package/packages/telegram/package.json +1 -1
  88. package/packages/tencentdb-memory/package.json +1 -1
  89. package/packages/tencentdb-sync/package.json +1 -1
  90. package/packages/test-data-generator/package.json +1 -1
  91. package/packages/test-generator/package.json +1 -1
  92. package/packages/todo-bd-sync/package.json +1 -1
  93. package/packages/token-estimation/package.json +1 -1
  94. package/packages/token-optimizer/package.json +1 -1
  95. package/packages/trajectory/package.json +1 -1
  96. package/packages/tui/package.json +1 -1
  97. package/packages/types/package.json +1 -1
  98. package/packages/webmcp-tester/package.json +1 -1
  99. package/packages/workflow-events/package.json +1 -1
  100. package/packages/workspace-scanner/package.json +1 -1
  101. package/packages/worktree/package.json +1 -1
  102. package/packages/write-review/package.json +1 -1
@@ -380,29 +380,29 @@ export async function initHoncho(options?: {
380
380
  piEvents?: PiEvents;
381
381
  }): Promise<HonchoMemory | null> {
382
382
  if (_disposed) {
383
- console.error("[honcho] Integration has been disposed, cannot reinitialize");
383
+ logServiceEvent({ ts: new Date().toISOString(), level: "error", service: "honcho", operation: "dispose", phase: "failed", reason: "integration has been disposed, cannot reinitialize" });
384
384
  return null;
385
385
  }
386
386
 
387
387
  // Allow retry if previous init failed
388
388
  if (_initialized && _initSucceeded) {
389
- console.debug("[honcho] Already initialized, returning existing instance");
389
+ logServiceEvent({ ts: new Date().toISOString(), level: "debug", service: "honcho", operation: "init", phase: "completed", reason: "already initialized, returning existing instance" });
390
390
  return _honchoMemory;
391
391
  }
392
392
 
393
393
  // Reset state if retrying
394
394
  if (_initialized && !_initSucceeded) {
395
- console.info("[honcho] Retrying initialization...");
395
+ logServiceEvent({ ts: new Date().toISOString(), level: "info", service: "honcho", operation: "init", phase: "start", reason: "retrying initialization" });
396
396
  }
397
397
  _initialized = true;
398
398
  _initSucceeded = false;
399
399
 
400
- console.info("[honcho] Initializing Honcho MCP integration...");
400
+ logServiceEvent({ ts: new Date().toISOString(), level: "info", service: "honcho", operation: "init", phase: "start" });
401
401
 
402
402
  // Load API key
403
403
  const key = options?.apiKey ?? loadHonchoApiKey();
404
404
  if (!key) {
405
- console.error("[honcho] No API key found. Run: echo \"YOUR_KEY\" > ~/.pi-harness-runtime/keys/honcho-api-key.txt");
405
+ logServiceEvent({ ts: new Date().toISOString(), level: "error", service: "honcho", operation: "init", phase: "failed", reason: "No API key found", helpUrl: "https://app.honcho.dev" });
406
406
  honchoStatus.setConfigured(false);
407
407
  honchoStatus.recordFailure("init", "no_key", { error: "No API key" });
408
408
  return null;
@@ -421,9 +421,9 @@ export async function initHoncho(options?: {
421
421
  // Write MCP config for the adapter to pick up
422
422
  try {
423
423
  writeHonchoMcpConfig(key);
424
- console.info("[honcho] MCP config written");
424
+ logServiceEvent({ ts: new Date().toISOString(), level: "info", service: "honcho", operation: "mcp_config", phase: "completed" });
425
425
  } catch (err) {
426
- console.warn("[honcho] Failed to write MCP config:", err);
426
+ logServiceEvent({ ts: new Date().toISOString(), level: "warn", service: "honcho", operation: "mcp_config", phase: "failed", reason: err instanceof Error ? err.message : String(err) });
427
427
  // Continue anyway - adapter may use its own config
428
428
  }
429
429
 
@@ -431,7 +431,7 @@ export async function initHoncho(options?: {
431
431
  const piEvents = options?.piEvents ?? (globalThis as { pi?: { events?: PiEvents } }).pi?.events;
432
432
 
433
433
  if (!piEvents) {
434
- console.error("[honcho] pi.events not available - MCP adapter may not be installed");
434
+ logServiceEvent({ ts: new Date().toISOString(), level: "error", service: "honcho", operation: "init", phase: "failed", reason: "pi.events not available" });
435
435
  honchoStatus.recordFailure("init", "adapter_missing", { error: "pi.events not available" });
436
436
  return null;
437
437
  }
@@ -453,8 +453,8 @@ export async function initHoncho(options?: {
453
453
 
454
454
  // Read result immediately after emit
455
455
  if (request.result === undefined) {
456
- console.error("[honcho] MCP adapter not responding to registration");
457
- console.error("[honcho] Install: pi install npm:pi-mcp-adapter");
456
+ logServiceEvent({ ts: new Date().toISOString(), level: "error", service: "honcho", operation: "mcp_register", phase: "failed", reason: "MCP adapter not responding" });
457
+ logServiceEvent({ ts: new Date().toISOString(), level: "info", service: "honcho", operation: "mcp_register", phase: "failed", helpUrl: "pi install npm:pi-mcp-adapter" });
458
458
  honchoStatus.recordFailure("init", "no_listener", { error: "No adapter responded" });
459
459
  return null;
460
460
  }
@@ -464,17 +464,17 @@ export async function initHoncho(options?: {
464
464
 
465
465
  // Check for duplicate name - an existing server may already be registered
466
466
  if (errorMsg.includes("already") || errorMsg.includes("duplicate")) {
467
- console.warn(`[honcho] Server already registered (duplicate name), continuing...`);
467
+ logServiceEvent({ ts: new Date().toISOString(), level: "warn", service: "honcho", operation: "mcp_register", phase: "completed", reason: "server already registered (duplicate name)" });
468
468
  // Continue with memory initialization - the existing server should work
469
469
  } else {
470
- console.error(`[honcho] Registration failed: ${errorMsg}`);
470
+ logServiceEvent({ ts: new Date().toISOString(), level: "error", service: "honcho", operation: "mcp_register", phase: "failed", reason: errorMsg });
471
471
  honchoStatus.recordFailure("init", "registration_rejected", { error: errorMsg });
472
472
  return null;
473
473
  }
474
474
  } else {
475
475
  // Registration accepted - store handle for disposal
476
476
  _honchoRegistration = request.result.registration;
477
- console.info("[honcho] MCP server registered");
477
+ logServiceEvent({ ts: new Date().toISOString(), level: "info", service: "honcho", operation: "mcp_register", phase: "completed" });
478
478
  }
479
479
 
480
480
  // Create memory instance
@@ -488,43 +488,43 @@ export async function initHoncho(options?: {
488
488
  const userName = options?.userName ?? "pi-user";
489
489
  const sessionId = options?.sessionId ?? `pi-session-${Date.now()}`;
490
490
 
491
- console.info("[honcho] Establishing workspace/peer identity...");
491
+ logServiceEvent({ ts: new Date().toISOString(), level: "info", service: "honcho", operation: "identity", phase: "start" });
492
492
 
493
493
  // Step 1: Create/get workspace
494
494
  const workspaceId = await ensureWorkspace(workspaceName);
495
495
  if (!workspaceId) {
496
- console.error("[honcho] Failed to create workspace");
496
+ logServiceEvent({ ts: new Date().toISOString(), level: "error", service: "honcho", operation: "create_workspace", phase: "failed" });
497
497
  honchoStatus.recordFailure("init", "workspace_failed", {});
498
498
  return _honchoMemory; // Return instance but mark as not ready
499
499
  }
500
- console.info(`[honcho] Workspace: ${workspaceId}`);
500
+ logServiceEvent({ ts: new Date().toISOString(), level: "info", service: "honcho", operation: "create_workspace", phase: "completed", workspaceId });
501
501
 
502
502
  // Step 2: Create/get user peer
503
503
  const userPeerId = await ensureUserPeer(workspaceId, userName);
504
504
  if (!userPeerId) {
505
- console.error("[honcho] Failed to create user peer");
505
+ logServiceEvent({ ts: new Date().toISOString(), level: "error", service: "honcho", operation: "create_user_peer", phase: "failed" });
506
506
  honchoStatus.recordFailure("init", "user_peer_failed", {});
507
507
  return _honchoMemory;
508
508
  }
509
- console.info(`[honcho] User peer: ${userPeerId}`);
509
+ logServiceEvent({ ts: new Date().toISOString(), level: "info", service: "honcho", operation: "create_user_peer", phase: "completed", userPeerId });
510
510
 
511
511
  // Step 3: Create/get assistant peer
512
512
  const assistantPeerId = await ensureAssistantPeer(workspaceId, assistantName);
513
513
  if (!assistantPeerId) {
514
- console.error("[honcho] Failed to create assistant peer");
514
+ logServiceEvent({ ts: new Date().toISOString(), level: "error", service: "honcho", operation: "create_assistant_peer", phase: "failed" });
515
515
  honchoStatus.recordFailure("init", "assistant_peer_failed", {});
516
516
  return _honchoMemory;
517
517
  }
518
- console.info(`[honcho] Assistant peer: ${assistantPeerId}`);
518
+ logServiceEvent({ ts: new Date().toISOString(), level: "info", service: "honcho", operation: "create_assistant_peer", phase: "completed", assistantPeerId });
519
519
 
520
520
  // Step 4: Create/get session
521
521
  const honchoSessionId = await ensureSession(workspaceId, userPeerId, assistantPeerId, sessionId);
522
522
  if (!honchoSessionId) {
523
- console.error("[honcho] Failed to create session");
523
+ logServiceEvent({ ts: new Date().toISOString(), level: "error", service: "honcho", operation: "create_session", phase: "failed" });
524
524
  honchoStatus.recordFailure("init", "session_failed", {});
525
525
  return _honchoMemory;
526
526
  }
527
- console.info(`[honcho] Session: ${honchoSessionId}`);
527
+ logServiceEvent({ ts: new Date().toISOString(), level: "info", service: "honcho", operation: "create_session", phase: "completed", honchoSessionId });
528
528
 
529
529
  // Store identity
530
530
  _identity = {
@@ -540,7 +540,7 @@ export async function initHoncho(options?: {
540
540
  _honchoMemory.setWorkspace(workspaceId);
541
541
  _honchoMemory.setSession(honchoSessionId);
542
542
 
543
- console.info("[honcho] Memory ready");
543
+ logServiceEvent({ ts: new Date().toISOString(), level: "info", service: "honcho", operation: "memory_init", phase: "completed" });
544
544
  honchoStatus.recordSuccess("init", undefined, {
545
545
  workspaceId,
546
546
  userPeerId,
@@ -650,7 +650,7 @@ export async function shutdownHoncho(): Promise<void> {
650
650
  }
651
651
 
652
652
  _disposed = true;
653
- console.info("[honcho] Shutting down...");
653
+ logServiceEvent({ ts: new Date().toISOString(), level: "info", service: "honcho", operation: "shutdown", phase: "start" });
654
654
 
655
655
  // Dispose memory instance
656
656
  if (_honchoMemory) {
@@ -665,15 +665,15 @@ export async function shutdownHoncho(): Promise<void> {
665
665
  if (_honchoRegistration) {
666
666
  try {
667
667
  await _honchoRegistration.dispose();
668
- console.info("[honcho] Registration disposed");
668
+ logServiceEvent({ ts: new Date().toISOString(), level: "info", service: "honcho", operation: "dispose_registration", phase: "completed" });
669
669
  } catch (err) {
670
- console.warn("[honcho] Failed to dispose registration:", err);
670
+ logServiceEvent({ ts: new Date().toISOString(), level: "warn", service: "honcho", operation: "dispose_registration", phase: "failed", reason: err instanceof Error ? err.message : String(err) });
671
671
  }
672
672
  _honchoRegistration = null;
673
673
  }
674
674
 
675
675
  _initialized = false;
676
- console.info("[honcho] Shutdown complete");
676
+ logServiceEvent({ ts: new Date().toISOString(), level: "info", service: "honcho", operation: "shutdown", phase: "completed" });
677
677
  }
678
678
 
679
679
  /**
@@ -704,7 +704,7 @@ export function registerHonchoLifecycle(
704
704
  ): void {
705
705
  // Initialize at session start
706
706
  pi.on("session_start", async () => {
707
- console.info("[honcho] Session started, initializing...");
707
+ logServiceEvent({ ts: new Date().toISOString(), level: "info", service: "honcho", operation: "session_start", phase: "start" });
708
708
  await initHoncho();
709
709
  });
710
710
 
@@ -741,5 +741,5 @@ export function registerHonchoLifecycle(
741
741
  }
742
742
  });
743
743
 
744
- console.info("[honcho] Lifecycle hooks registered");
744
+ logServiceEvent({ ts: new Date().toISOString(), level: "info", service: "honcho", operation: "lifecycle_hooks", phase: "completed" });
745
745
  }
package/index.ts CHANGED
@@ -121,6 +121,30 @@ async function getTaskContext(): Promise<{
121
121
  }
122
122
  }
123
123
 
124
+ // --- Harness Startup Widget Messages (used by init functions) -----------------
125
+ interface HarnessMessage {
126
+ id: string;
127
+ label: string;
128
+ text: string;
129
+ status: "wait" | "ok" | "err";
130
+ details?: string[]; // Multi-line fix instructions for errors
131
+ }
132
+ const harnessMessages: HarnessMessage[] = [];
133
+ const preSessionErrors: HarnessMessage[] = []; // Errors from init functions (before session_start)
134
+
135
+ function addHarnessMessage(label: string, text: string, status: "wait" | "ok" | "err" = "wait", details?: string[]) {
136
+ const id = `${label}-${Date.now()}`;
137
+ const msg: HarnessMessage = { id, label, text, status, details };
138
+
139
+ // If session hasn't started yet, store in preSessionErrors
140
+ // The session_start handler will merge these into harnessMessages
141
+ if (harnessMessages.length === 0) {
142
+ preSessionErrors.push(msg);
143
+ } else {
144
+ harnessMessages.push(msg);
145
+ }
146
+ }
147
+
124
148
  async function initAutoContinue(pi: ExtensionAPI): Promise<void> {
125
149
  try {
126
150
  // Check if Jev API key is available (env var or keys file)
@@ -506,6 +530,11 @@ async function initTelegram(pi: ExtensionAPI): Promise<void> {
506
530
  logStartup("[pi-harness] 3. echo \"{token}\" > ~/.pi-harness-runtime/keys/telegram-bot-token.txt");
507
531
  logStartup("[pi-harness] 4. echo \"{chat-id}\" > ~/.pi-harness-runtime/keys/telegram-chat-id.txt");
508
532
  logStartup("[pi-harness] 5. Reload pi — then DM @PiHarnessRuntimeBot to verify");
533
+ addHarnessMessage("Telegram", "not configured", "err", [
534
+ "echo \"<TOKEN>\" > keys/telegram-bot-token.txt",
535
+ "echo \"<CHAT_ID>\" > keys/telegram-chat-id.txt",
536
+ "Then: pi restart",
537
+ ]);
509
538
  return;
510
539
  }
511
540
 
@@ -610,12 +639,21 @@ async function initHoncho(pi: ExtensionAPI): Promise<void> {
610
639
  logStartup("[pi-harness] Honcho not configured:");
611
640
  logStartup("[pi-harness] Get key: https://app.honcho.dev/api-keys");
612
641
  logStartup(`[pi-harness] Then: echo "{api-key}" > ~/.pi-harness-runtime/keys/honcho-api-key.txt`);
642
+ addHarnessMessage("Honcho", "API key missing", "err", [
643
+ "Get key: https://app.honcho.dev/api-keys",
644
+ "echo \"<KEY>\" > keys/honcho-api-key.txt",
645
+ "Then: pi restart",
646
+ ]);
613
647
  return;
614
648
  }
615
649
 
616
650
  const apiKey = readFileSync(keyPath, "utf8").trim();
617
651
  if (!apiKey) {
618
652
  logStartup("[pi-harness] Honcho: API key is empty — skipping");
653
+ addHarnessMessage("Honcho", "API key empty", "err", [
654
+ "echo \"<KEY>\" > keys/honcho-api-key.txt",
655
+ "Then: pi restart",
656
+ ]);
619
657
  return;
620
658
  }
621
659
 
@@ -635,6 +673,10 @@ async function initHoncho(pi: ExtensionAPI): Promise<void> {
635
673
  }
636
674
  } catch (err) {
637
675
  logStartup("[pi-harness] Honcho: init failed:", err instanceof Error ? err.message : String(err));
676
+ addHarnessMessage("Honcho", "init failed", "err", [
677
+ err instanceof Error ? err.message : String(err),
678
+ "Check keys/honcho-api-key.txt",
679
+ ]);
638
680
  }
639
681
  }
640
682
 
@@ -719,15 +761,15 @@ function initLangChain(pi: {
719
761
  handler: async (_args: string, _ctx: unknown) => {
720
762
  const allModels = listAllModels();
721
763
  if (allModels.length === 0) {
722
- console.error("[pi-harness] /langchain-config: no models found in ~/.pi/agent/models-store.json");
723
- console.error("[pi-harness] Configure models first via /model in pi");
764
+ logToFile("[pi-harness]", "/langchain-config: no models found in ~/.pi/agent/models-store.json");
765
+ logToFile("[pi-harness]", " Configure models first via /model in pi");
724
766
  return;
725
767
  }
726
768
 
727
769
  // Print available models
728
- console.error("[pi-harness] Available models:");
770
+ logToFile("[pi-harness]", "Available models:");
729
771
  for (const m of allModels) {
730
- console.error(` [${m.index}] ${m.provider}/${m.id}`);
772
+ logToFile("[pi-harness]", ` [${m.index}] ${m.provider}/${m.id}`);
731
773
  }
732
774
 
733
775
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
@@ -755,7 +797,7 @@ function initLangChain(pi: {
755
797
  }
756
798
 
757
799
  if (!plannerSpec || !coderSpec || !reviewerSpec) {
758
- console.error("[pi-harness] /langchain-config: all three roles must be selected");
800
+ logToFile("[pi-harness]", "/langchain-config: all three roles must be selected");
759
801
  return;
760
802
  }
761
803
 
@@ -767,20 +809,20 @@ function initLangChain(pi: {
767
809
  };
768
810
  writeFileSync(roleConfigPath, JSON.stringify(config, null, 2), "utf8");
769
811
 
770
- console.error("[pi-harness] LangChain role config saved:");
771
- console.error(`[pi-harness] planner: ${plannerSpec}`);
772
- console.error(`[pi-harness] coder: ${coderSpec}`);
773
- console.error(`[pi-harness] reviewer: ${reviewerSpec}`);
812
+ logToFile("[pi-harness]", "LangChain role config saved:");
813
+ logToFile("[pi-harness]", ` planner: ${plannerSpec}`);
814
+ logToFile("[pi-harness]", ` coder: ${coderSpec}`);
815
+ logToFile("[pi-harness]", ` reviewer: ${reviewerSpec}`);
774
816
 
775
817
  // Also prompt for API keys if missing
776
818
  if (!existsSync(`${keysDir}/planner-api-key.txt`)) {
777
- console.error(`[pi-harness] planner-api-key.txt missing. echo "{key}" > ${keysDir}/planner-api-key.txt`);
819
+ logToFile("[pi-harness]", ` planner-api-key.txt missing. echo "{key}" > ${keysDir}/planner-api-key.txt`);
778
820
  }
779
821
  if (!existsSync(`${keysDir}/reviewer-api-key.txt`)) {
780
- console.error(`[pi-harness] reviewer-api-key.txt missing. echo "{key}" > ${keysDir}/reviewer-api-key.txt`);
822
+ logToFile("[pi-harness]", ` reviewer-api-key.txt missing. echo "{key}" > ${keysDir}/reviewer-api-key.txt`);
781
823
  }
782
824
  if (!existsSync(`${keysDir}/coder-api-key.txt`)) {
783
- console.error(`[pi-harness] coder-api-key.txt missing. echo "{key}" > ${keysDir}/coder-api-key.txt`);
825
+ logToFile("[pi-harness]", ` coder-api-key.txt missing. echo "{key}" > ${keysDir}/coder-api-key.txt`);
784
826
  }
785
827
  },
786
828
  });
@@ -807,13 +849,13 @@ function initLangChain(pi: {
807
849
  const coderKeyExists = existsSync(`${keysDir}/coder-api-key.txt`);
808
850
 
809
851
  if (!activeConfig) {
810
- console.error("[pi-harness] /langchain not configured — run /langchain-config");
852
+ logToFile("[pi-harness]", "/langchain not configured — run /langchain-config");
811
853
  } else if (!plannerKeyExists || !reviewerKeyExists || !coderKeyExists) {
812
854
  const missingKeys: string[] = [];
813
855
  if (!plannerKeyExists) missingKeys.push("planner-api-key.txt");
814
856
  if (!reviewerKeyExists) missingKeys.push("reviewer-api-key.txt");
815
857
  if (!coderKeyExists) missingKeys.push("coder-api-key.txt");
816
- console.error(`[pi-harness] /langchain missing API keys: ${missingKeys.join(", ")}`);
858
+ logToFile("[pi-harness]", `/langchain missing API keys: ${missingKeys.join(", ")}`);
817
859
  } else {
818
860
  logStartup(`[pi-harness] /langchain ready (${activeConfig.planner.id} + ${activeConfig.coder.id} + ${activeConfig.reviewer.id})`);
819
861
  }
@@ -823,14 +865,14 @@ function initLangChain(pi: {
823
865
  prompt: "Describe the feature or task for the LangChain loop to implement.",
824
866
  handler: async (request: string) => {
825
867
  if (!request.trim()) {
826
- console.error("[pi-harness] /langchain requires a request.");
827
- console.error("[pi-harness] Example: /langchain implement user auth module");
868
+ logToFile("[pi-harness]", "/langchain requires a request.");
869
+ logToFile("[pi-harness]", " Example: /langchain implement user auth module");
828
870
  return;
829
871
  }
830
872
 
831
873
  const cfg = loadActiveConfig();
832
874
  if (!cfg) {
833
- console.error("[pi-harness] /langchain: not configured. Run /langchain-config first.");
875
+ logToFile("[pi-harness]", "/langchain: not configured. Run /langchain-config first.");
834
876
  return;
835
877
  }
836
878
 
@@ -857,7 +899,7 @@ function initLangChain(pi: {
857
899
  stdio: "inherit",
858
900
  });
859
901
  proc.on("exit", (code: number | null) => {
860
- if (code !== 0) console.error(`[pi-harness] /langchain exited with code ${code}`);
902
+ if (code !== 0) logToFile("[pi-harness]", `/langchain exited with code ${code}`);
861
903
  });
862
904
  },
863
905
  });
@@ -1875,7 +1917,7 @@ Run \`bd ready\` to see current bd issues.
1875
1917
  !content.includes("bd ready") &&
1876
1918
  !content.includes("TODO UPDATE")
1877
1919
  ) {
1878
- console.log(TODO_BUILD_REMINDER.trim());
1920
+ logToFile(TODO_BUILD_REMINDER.trim());
1879
1921
  }
1880
1922
  });
1881
1923
 
@@ -2447,7 +2489,7 @@ Run \`bd ready\` to see current bd issues.
2447
2489
  mirrorStore,
2448
2490
  currentSession.machine,
2449
2491
  );
2450
- console.log(`[GLM countdown] Started - will auto-resume at ${resetAt}`);
2492
+ logToFile("[GLM countdown]", `Started - will auto-resume at ${resetAt}`);
2451
2493
  }
2452
2494
 
2453
2495
  if (!suppressErrors) {
@@ -3033,6 +3075,7 @@ Run \`bd ready\` to see current bd issues.
3033
3075
  label: string;
3034
3076
  text: string;
3035
3077
  status: "wait" | "ok" | "err";
3078
+ details?: string[]; // Multi-line fix instructions for errors
3036
3079
  }
3037
3080
  const harnessMessages: HarnessMessage[] = [];
3038
3081
  let startupVisible = true;
@@ -3040,9 +3083,9 @@ Run \`bd ready\` to see current bd issues.
3040
3083
  let harnessWidgetRegistered = false;
3041
3084
  let sessionGeneration = 0;
3042
3085
 
3043
- function addHarnessMessage(label: string, text: string, status: "wait" | "ok" | "err" = "wait") {
3086
+ function addHarnessMessage(label: string, text: string, status: "wait" | "ok" | "err" = "wait", details?: string[]) {
3044
3087
  const id = `${label}-${Date.now()}`;
3045
- harnessMessages.push({ id, label, text, status });
3088
+ harnessMessages.push({ id, label, text, status, details });
3046
3089
  harnessTUI?.requestRender();
3047
3090
  }
3048
3091
 
@@ -3066,6 +3109,14 @@ Run \`bd ready\` to see current bd issues.
3066
3109
  let text = `${treeChar} ${marker} ${msg.label}: ${msg.text}`;
3067
3110
  text = truncateToWidth(text, width);
3068
3111
  lines.push(text);
3112
+
3113
+ // Add fix instructions for errors (indented)
3114
+ if (msg.status === "err" && msg.details && msg.details.length > 0) {
3115
+ for (const detail of msg.details) {
3116
+ const detailLine = `${isLast ? " " : "│ "} Fix: ${detail}`;
3117
+ lines.push(truncateToWidth(detailLine, width));
3118
+ }
3119
+ }
3069
3120
  }
3070
3121
 
3071
3122
  // Trailing spacer for breathing room (like Todos)
@@ -3109,6 +3160,14 @@ Run \`bd ready\` to see current bd issues.
3109
3160
  { placement: "aboveEditor" }, // Like Todos!
3110
3161
  );
3111
3162
  harnessWidgetRegistered = true;
3163
+
3164
+ // Merge pre-session errors into harnessMessages
3165
+ for (const err of preSessionErrors) {
3166
+ harnessMessages.push(err);
3167
+ }
3168
+ preSessionErrors.length = 0; // Clear pre-session errors
3169
+
3170
+ harnessTUI?.requestRender(); // Show widget with error messages
3112
3171
  } else {
3113
3172
  harnessTUI?.requestRender();
3114
3173
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-harness-runtime",
3
- "version": "1.1.220",
3
+ "version": "1.1.222",
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.220",
3
+ "version": "1.1.222",
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.220",
3
+ "version": "1.1.222",
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.220",
3
+ "version": "1.1.222",
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.220",
3
+ "version": "1.1.222",
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.220",
3
+ "version": "1.1.222",
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.220",
3
+ "version": "1.1.222",
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.220",
3
+ "version": "1.1.222",
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.220",
3
+ "version": "1.1.222",
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.220",
3
+ "version": "1.1.222",
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.220",
3
+ "version": "1.1.222",
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.220",
3
+ "version": "1.1.222",
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.220",
3
+ "version": "1.1.222",
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.220",
3
+ "version": "1.1.222",
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.220",
3
+ "version": "1.1.222",
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.220",
3
+ "version": "1.1.222",
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": "@pi-harness/codex-watcher",
3
- "version": "1.1.220",
3
+ "version": "1.1.222",
4
4
  "description": "Watches Codex CLI sessions and emits visible messages for PING-PONG monitoring",
5
5
  "type": "module",
6
6
  "main": "./dist/src/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moocoding/config-capture",
3
- "version": "1.1.220",
3
+ "version": "1.1.222",
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.220",
3
+ "version": "1.1.222",
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.220",
3
+ "version": "1.1.222",
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.220",
3
+ "version": "1.1.222",
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.220",
3
+ "version": "1.1.222",
4
4
  "description": "pi-harness-runtime — cookie sanitizer (provider-quota cookie file normaliser)",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",