pi-harness-runtime 1.1.226 → 1.1.228
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.
- package/harness-startup-status.ts +27 -0
- package/index.ts +105 -99
- package/package.json +1 -1
- package/packages/a2a-adapter/package.json +1 -1
- package/packages/agent-policy/package.json +1 -1
- package/packages/architecture-generator/package.json +1 -1
- package/packages/auth/package.json +1 -1
- package/packages/autonomous-refactor/package.json +1 -1
- package/packages/autonomous-runtime/package.json +1 -1
- package/packages/cache-strategy/package.json +1 -1
- package/packages/capability-registry/package.json +1 -1
- package/packages/checkpoint/package.json +1 -1
- package/packages/cli-plugin-sdk/package.json +1 -1
- package/packages/clipboard/package.json +1 -1
- package/packages/clipboard-plugin/package.json +1 -1
- package/packages/code-generation/package.json +1 -1
- package/packages/code-review/package.json +1 -1
- package/packages/codex-adapter/package.json +1 -1
- package/packages/codex-watcher/package.json +1 -1
- package/packages/config-capture/package.json +1 -1
- package/packages/context-compiler/package.json +1 -1
- package/packages/context-discovery/package.json +1 -1
- package/packages/context-manager/package.json +1 -1
- package/packages/cookie-sanitizer/package.json +1 -1
- package/packages/cost-optimizer/package.json +1 -1
- package/packages/dependency-analyzer/package.json +1 -1
- package/packages/django-plugin/package.json +1 -1
- package/packages/doc-generator/package.json +1 -1
- package/packages/e2e-tester/package.json +1 -1
- package/packages/evaluation-engine/package.json +1 -1
- package/packages/evaluation-runner/package.json +1 -1
- package/packages/event-bus/package.json +1 -1
- package/packages/event-store/package.json +1 -1
- package/packages/experience-replay/package.json +1 -1
- package/packages/feedback-collector/package.json +1 -1
- package/packages/file-copy-helper/package.json +1 -1
- package/packages/framework-detector/package.json +1 -1
- package/packages/framework-plugin-sdk/package.json +1 -1
- package/packages/frappe-plugin/package.json +1 -1
- package/packages/generic-web-plugin/package.json +1 -1
- package/packages/health-monitor/package.json +1 -1
- package/packages/intent-analyzer/package.json +1 -1
- package/packages/jev-judge/package.json +1 -1
- package/packages/knowledge-graph/package.json +1 -1
- package/packages/knowledge-retrieval/package.json +1 -1
- package/packages/laravel-plugin/package.json +1 -1
- package/packages/learning-engine/package.json +1 -1
- package/packages/mcp-adapter/package.json +1 -1
- package/packages/memory-engine/package.json +1 -1
- package/packages/milestone-manager/package.json +1 -1
- package/packages/model-registry/package.json +1 -1
- package/packages/nextjs-plugin/package.json +1 -1
- package/packages/notification/package.json +1 -1
- package/packages/observability/package.json +1 -1
- package/packages/okf-indexer/package.json +1 -1
- package/packages/paperclip-integration/package.json +1 -1
- package/packages/performance-optimizer/package.json +1 -1
- package/packages/privilege-broker/package.json +1 -1
- package/packages/project-analyzer/package.json +1 -1
- package/packages/project-bootstrap/package.json +1 -1
- package/packages/projection-engine/package.json +1 -1
- package/packages/prompt-compiler/package.json +1 -1
- package/packages/prompt-versioning/package.json +1 -1
- package/packages/provider-adapter-sdk/package.json +1 -1
- package/packages/provider-router/package.json +1 -1
- package/packages/provider-selector/package.json +1 -1
- package/packages/providers/package.json +1 -1
- package/packages/qdrant-skills/package.json +1 -1
- package/packages/quota-manager/package.json +1 -1
- package/packages/rate-limiter/package.json +1 -1
- package/packages/react-vite-plugin/package.json +1 -1
- package/packages/release-manager/package.json +1 -1
- package/packages/requirement-compiler/package.json +1 -1
- package/packages/runtime/package.json +1 -1
- package/packages/scheduler/package.json +1 -1
- package/packages/scheduler-adapter/package.json +1 -1
- package/packages/session/package.json +1 -1
- package/packages/session-api/package.json +1 -1
- package/packages/session-export/package.json +1 -1
- package/packages/shared-context/package.json +1 -1
- package/packages/skill-mcp-client/package.json +1 -1
- package/packages/skill-registry/package.json +1 -1
- package/packages/skills/package.json +1 -1
- package/packages/sprint-planner/package.json +1 -1
- package/packages/subscription-engine/package.json +1 -1
- package/packages/task-compiler/package.json +1 -1
- package/packages/telegram/package.json +1 -1
- package/packages/tencentdb-memory/package.json +1 -1
- package/packages/tencentdb-sync/package.json +1 -1
- package/packages/test-data-generator/package.json +1 -1
- package/packages/test-generator/package.json +1 -1
- package/packages/todo-bd-sync/package.json +1 -1
- package/packages/token-estimation/package.json +1 -1
- package/packages/token-optimizer/package.json +1 -1
- package/packages/trajectory/package.json +1 -1
- package/packages/tui/package.json +1 -1
- package/packages/types/package.json +1 -1
- package/packages/webmcp-tester/package.json +1 -1
- package/packages/workflow-events/package.json +1 -1
- package/packages/workspace-scanner/package.json +1 -1
- package/packages/worktree/package.json +1 -1
- package/packages/write-review/package.json +1 -1
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export type HarnessStatus = "wait" | "ok" | "warn" | "err";
|
|
2
|
+
|
|
3
|
+
export interface HarnessMessage {
|
|
4
|
+
id: string;
|
|
5
|
+
label: string;
|
|
6
|
+
text: string;
|
|
7
|
+
status: HarnessStatus;
|
|
8
|
+
details?: string[];
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/** One store for initialization before, during, and after the widget mounts. */
|
|
12
|
+
export class HarnessStartupStatus {
|
|
13
|
+
readonly messages: HarnessMessage[] = [];
|
|
14
|
+
onChange?: () => void;
|
|
15
|
+
|
|
16
|
+
update(label: string, text: string, status: HarnessStatus = "wait", details?: string[]): void {
|
|
17
|
+
const next = { id: label, label, text, status, details };
|
|
18
|
+
const existing = this.messages.findIndex((message) => message.id === label);
|
|
19
|
+
if (existing === -1) this.messages.push(next);
|
|
20
|
+
else this.messages[existing] = next;
|
|
21
|
+
this.onChange?.();
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function harnessStatusMarker(status: HarnessStatus): string {
|
|
26
|
+
return { wait: "[WAIT]", ok: "[OK]", warn: "[WARN]", err: "[ERR]" }[status];
|
|
27
|
+
}
|
package/index.ts
CHANGED
|
@@ -19,6 +19,7 @@ import type {
|
|
|
19
19
|
ExtensionCommandContext,
|
|
20
20
|
ExtensionContext,
|
|
21
21
|
} from "@earendil-works/pi-coding-agent";
|
|
22
|
+
import { HarnessStartupStatus, harnessStatusMarker } from "./harness-startup-status.ts";
|
|
22
23
|
import { UsageTracker } from "./tracker.ts";
|
|
23
24
|
import { MirrorStore, type MirrorRecord } from "./mirror.ts";
|
|
24
25
|
import { MiniMaxQuotaScraper } from "./harness/e2e/minimax-quota-scraper.js";
|
|
@@ -122,30 +123,12 @@ async function getTaskContext(): Promise<{
|
|
|
122
123
|
}
|
|
123
124
|
|
|
124
125
|
// --- Harness Startup Widget Messages (used by init functions) -----------------
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
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
|
-
}
|
|
126
|
+
const startupStatus = new HarnessStartupStatus();
|
|
127
|
+
const harnessMessages = startupStatus.messages;
|
|
128
|
+
const addHarnessMessage = startupStatus.update.bind(startupStatus);
|
|
147
129
|
|
|
148
130
|
async function initAutoContinue(pi: ExtensionAPI): Promise<void> {
|
|
131
|
+
addHarnessMessage("Jev", "initializing", "wait");
|
|
149
132
|
try {
|
|
150
133
|
// Check if Jev API key is available (env var or keys file)
|
|
151
134
|
const homedir = process.env.HOME || process.env.USERPROFILE || "/home/frappe";
|
|
@@ -158,19 +141,21 @@ async function initAutoContinue(pi: ExtensionAPI): Promise<void> {
|
|
|
158
141
|
}
|
|
159
142
|
|
|
160
143
|
const hasEnvKey =
|
|
161
|
-
process.env.TYPESAFE_API_KEY || process.env.OPENROUTER_API_KEY;
|
|
144
|
+
process.env.TYPESAFE_API_KEY?.trim() || process.env.OPENROUTER_API_KEY?.trim();
|
|
162
145
|
const hasFileKey =
|
|
163
146
|
existsSync(`${keysDir}/jev-api-key.txt`) &&
|
|
164
|
-
readFileSync(`${keysDir}/jev-api-key.txt`, "utf8").trim().length >
|
|
147
|
+
readFileSync(`${keysDir}/jev-api-key.txt`, "utf8").trim().length > 0;
|
|
165
148
|
|
|
166
149
|
if (!hasEnvKey && !hasFileKey) {
|
|
150
|
+
addHarnessMessage("Jev", "API key missing or empty; auto-continue unavailable", "warn", [
|
|
151
|
+
"Set TYPESAFE_API_KEY or ~/.pi-harness-runtime/keys/jev-api-key.txt, then reload Pi.",
|
|
152
|
+
]);
|
|
167
153
|
logToFile("[auto-continue]", "No Jev API key found. Set TYPESAFE_API_KEY run: echo \"{api_key}\" > ~/.pi-harness-runtime/keys/jev-api-key.txt");
|
|
168
154
|
return;
|
|
169
155
|
}
|
|
170
156
|
|
|
171
157
|
// Resolve the actual API key: env takes priority, file is fallback
|
|
172
|
-
const resolvedApiKey =
|
|
173
|
-
process.env.OPENROUTER_API_KEY ||
|
|
158
|
+
const resolvedApiKey = hasEnvKey ||
|
|
174
159
|
readFileSync(`${keysDir}/jev-api-key.txt`, "utf8").trim();
|
|
175
160
|
|
|
176
161
|
const mod = await import("./packages/jev-judge/src/auto-continue.js");
|
|
@@ -450,13 +435,33 @@ async function initAutoContinue(pi: ExtensionAPI): Promise<void> {
|
|
|
450
435
|
} catch {
|
|
451
436
|
_inferenceInProgress = false;
|
|
452
437
|
updateAutoContinueStatus("ERROR");
|
|
438
|
+
addHarnessMessage("Jev", "auto-continue evaluation failed", "err");
|
|
453
439
|
}
|
|
454
440
|
};
|
|
455
441
|
|
|
456
442
|
// Start periodic check
|
|
457
443
|
autoContinueTimer = setInterval(checkAndAutoContinue, AUTO_CONTINUE_INTERVAL_MS);
|
|
458
|
-
|
|
459
|
-
|
|
444
|
+
addHarnessMessage("Jev", "auto-continue configured (verifying API...)", "ok");
|
|
445
|
+
|
|
446
|
+
// Verify API key works with a lightweight health check
|
|
447
|
+
try {
|
|
448
|
+
const { JevJudge } = await import("./packages/jev-judge/dist/index.js");
|
|
449
|
+
const judge = new JevJudge({ apiKey: resolvedApiKey });
|
|
450
|
+
// Lightweight verification - ask a simple question
|
|
451
|
+
await judge.evaluate("health check", {
|
|
452
|
+
test: { type: "noul" as const, instructions: "Is this a test?" }
|
|
453
|
+
});
|
|
454
|
+
addHarnessMessage("Jev", "auto-continue ready (API verified)", "ok");
|
|
455
|
+
} catch (verifyErr) {
|
|
456
|
+
addHarnessMessage("Jev", "auto-continue ready (API verification failed)", "warn", [
|
|
457
|
+
`Error: ${verifyErr instanceof Error ? verifyErr.message : String(verifyErr)}`,
|
|
458
|
+
"Check API key and network access, then reload Pi.",
|
|
459
|
+
]);
|
|
460
|
+
}
|
|
461
|
+
} catch (_err) {
|
|
462
|
+
addHarnessMessage("Jev", "auto-continue initialization failed", "err", [
|
|
463
|
+
"Check Jev package installation and key-file permissions, then reload Pi.",
|
|
464
|
+
]);
|
|
460
465
|
}
|
|
461
466
|
}
|
|
462
467
|
|
|
@@ -485,6 +490,7 @@ async function initConfigCapture(pi: ExtensionAPI): Promise<void> {
|
|
|
485
490
|
// --- qdrant-vector-search: Semantic skill search via Qdrant -------------------
|
|
486
491
|
// Check config and report status — right after Jev for discoverability
|
|
487
492
|
async function initQdrant(): Promise<void> {
|
|
493
|
+
addHarnessMessage("Qdrant", "checking configuration", "wait");
|
|
488
494
|
try {
|
|
489
495
|
const { getQdrantConfig } = await import("./packages/skills/src/loader.js");
|
|
490
496
|
const cfg = getQdrantConfig();
|
|
@@ -494,23 +500,48 @@ async function initQdrant(): Promise<void> {
|
|
|
494
500
|
const embeddingKey = getOpenAIApiKey();
|
|
495
501
|
if (embeddingKey) {
|
|
496
502
|
logStartup("[pi-harness] Qdrant vector search ready");
|
|
503
|
+
addHarnessMessage("Qdrant", "verifying connection...", "ok");
|
|
504
|
+
|
|
505
|
+
// Verify Qdrant connection with health check
|
|
506
|
+
try {
|
|
507
|
+
const healthUrl = `${cfg.url}/health`;
|
|
508
|
+
const healthResponse = await fetch(healthUrl, {
|
|
509
|
+
headers: cfg.apiKey ? { "api-key": cfg.apiKey } : {},
|
|
510
|
+
});
|
|
511
|
+
if (healthResponse.ok) {
|
|
512
|
+
addHarnessMessage("Qdrant", "ready (connection verified)", "ok");
|
|
513
|
+
} else {
|
|
514
|
+
addHarnessMessage("Qdrant", "ready (connection failed)", "warn", [
|
|
515
|
+
`Health check returned: ${healthResponse.status} ${healthResponse.statusText}`,
|
|
516
|
+
"Check cluster URL and network access, then reload Pi.",
|
|
517
|
+
]);
|
|
518
|
+
}
|
|
519
|
+
} catch (healthErr) {
|
|
520
|
+
addHarnessMessage("Qdrant", "ready (connection failed)", "warn", [
|
|
521
|
+
`Error: ${healthErr instanceof Error ? healthErr.message : String(healthErr)}`,
|
|
522
|
+
"Check cluster URL and network access, then reload Pi.",
|
|
523
|
+
]);
|
|
524
|
+
}
|
|
497
525
|
} else {
|
|
498
526
|
logStartup("[pi-harness] Qdrant ready (no embedding key — skills won't be vector-indexed)");
|
|
527
|
+
addHarnessMessage("Qdrant", "embedding key missing; vector indexing unavailable", "warn");
|
|
499
528
|
logStartup('[pi-harness] For vector search: echo "{openai-api-key}" > ~/.pi-harness-runtime/keys/openai-api-key.txt');
|
|
500
529
|
}
|
|
501
530
|
} else {
|
|
502
531
|
logStartup("[pi-harness] Qdrant not configured. Set keys to enable vector skill search:");
|
|
532
|
+
addHarnessMessage("Qdrant", "not configured", "warn");
|
|
503
533
|
logStartup(` echo "{cluster-url}" > ~/.pi-harness-runtime/keys/qdrant-cluster-url.txt`);
|
|
504
534
|
logStartup(` echo "{api-key}" > ~/.pi-harness-runtime/keys/qdrant-api-key.txt`);
|
|
505
535
|
}
|
|
506
536
|
} catch {
|
|
507
|
-
|
|
537
|
+
addHarnessMessage("Qdrant", "initialization failed", "err");
|
|
508
538
|
}
|
|
509
539
|
}
|
|
510
540
|
|
|
511
541
|
// --- telegram-notifications: Telegram bot for harness event notifications ------------
|
|
512
542
|
// Sends Telegram messages when jobs complete, tasks finish, or human input is needed.
|
|
513
543
|
async function initTelegram(pi: ExtensionAPI): Promise<void> {
|
|
544
|
+
addHarnessMessage("Telegram", "initializing", "wait");
|
|
514
545
|
try {
|
|
515
546
|
const {
|
|
516
547
|
NotificationCenter,
|
|
@@ -530,10 +561,10 @@ async function initTelegram(pi: ExtensionAPI): Promise<void> {
|
|
|
530
561
|
logStartup("[pi-harness] 3. echo \"{token}\" > ~/.pi-harness-runtime/keys/telegram-bot-token.txt");
|
|
531
562
|
logStartup("[pi-harness] 4. echo \"{chat-id}\" > ~/.pi-harness-runtime/keys/telegram-chat-id.txt");
|
|
532
563
|
logStartup("[pi-harness] 5. Reload pi — then DM @PiHarnessRuntimeBot to verify");
|
|
533
|
-
addHarnessMessage("Telegram", "
|
|
564
|
+
addHarnessMessage("Telegram", "credentials missing; notifications unavailable", "warn", [
|
|
534
565
|
"echo \"<TOKEN>\" > keys/telegram-bot-token.txt",
|
|
535
566
|
"echo \"<CHAT_ID>\" > keys/telegram-chat-id.txt",
|
|
536
|
-
"Then
|
|
567
|
+
"Then reload Pi.",
|
|
537
568
|
]);
|
|
538
569
|
return;
|
|
539
570
|
}
|
|
@@ -543,6 +574,9 @@ async function initTelegram(pi: ExtensionAPI): Promise<void> {
|
|
|
543
574
|
|
|
544
575
|
if (!botToken || !chatId) {
|
|
545
576
|
logStartup("[pi-harness] Telegram: bot token or chat ID is empty — skipping");
|
|
577
|
+
addHarnessMessage("Telegram", "bot token or chat ID is empty; notifications unavailable", "warn", [
|
|
578
|
+
"Fill telegram-bot-token.txt and telegram-chat-id.txt in ~/.pi-harness-runtime/keys/, then reload Pi.",
|
|
579
|
+
]);
|
|
546
580
|
return;
|
|
547
581
|
}
|
|
548
582
|
|
|
@@ -559,8 +593,11 @@ async function initTelegram(pi: ExtensionAPI): Promise<void> {
|
|
|
559
593
|
});
|
|
560
594
|
|
|
561
595
|
await center.initialize();
|
|
562
|
-
if (!center.
|
|
596
|
+
if (!center.hasHealthyChannels()) {
|
|
563
597
|
logStartup("[pi-harness] Telegram: initialization failed — skipping");
|
|
598
|
+
addHarnessMessage("Telegram", "bot verification failed; notifications unavailable", "err", [
|
|
599
|
+
"Check the bot token and network access, then reload Pi.",
|
|
600
|
+
]);
|
|
564
601
|
return;
|
|
565
602
|
}
|
|
566
603
|
|
|
@@ -609,13 +646,17 @@ async function initTelegram(pi: ExtensionAPI): Promise<void> {
|
|
|
609
646
|
|
|
610
647
|
// Log the actual bot username (fetched from Telegram API via getMe)
|
|
611
648
|
const botUsername = center.getTelegramBotUsername();
|
|
649
|
+
addHarnessMessage("Telegram", "bot verified (chat delivery not tested)", "ok");
|
|
612
650
|
if (botUsername) {
|
|
613
651
|
logStartup(`[pi-harness] Telegram (@${botUsername}) ready — DM the bot to receive alerts`);
|
|
614
652
|
} else {
|
|
615
653
|
logStartup(`[pi-harness] Telegram notifications ready`);
|
|
616
654
|
}
|
|
617
|
-
} catch (
|
|
618
|
-
logStartup("[pi-harness] Telegram: init failed
|
|
655
|
+
} catch (_err) {
|
|
656
|
+
logStartup("[pi-harness] Telegram: init failed (check installation, credentials, and network)");
|
|
657
|
+
addHarnessMessage("Telegram", "initialization failed; notifications unavailable", "err", [
|
|
658
|
+
"Check package installation, key-file permissions, and network access, then reload Pi.",
|
|
659
|
+
]);
|
|
619
660
|
}
|
|
620
661
|
}
|
|
621
662
|
|
|
@@ -627,6 +668,8 @@ async function initTelegram(pi: ExtensionAPI): Promise<void> {
|
|
|
627
668
|
// - Bounded context injection with provenance
|
|
628
669
|
|
|
629
670
|
async function initHoncho(pi: ExtensionAPI): Promise<void> {
|
|
671
|
+
addHarnessMessage("Honcho", "initializing", "wait");
|
|
672
|
+
try {
|
|
630
673
|
// Import new Honcho integration module
|
|
631
674
|
const { initHoncho: honchoInit, registerHonchoLifecycle } = await import("./harness/honcho-init.js");
|
|
632
675
|
|
|
@@ -639,10 +682,10 @@ async function initHoncho(pi: ExtensionAPI): Promise<void> {
|
|
|
639
682
|
logStartup("[pi-harness] Honcho not configured:");
|
|
640
683
|
logStartup("[pi-harness] Get key: https://app.honcho.dev/api-keys");
|
|
641
684
|
logStartup(`[pi-harness] Then: echo "{api-key}" > ~/.pi-harness-runtime/keys/honcho-api-key.txt`);
|
|
642
|
-
addHarnessMessage("Honcho", "API key missing", "
|
|
685
|
+
addHarnessMessage("Honcho", "API key missing", "warn", [
|
|
643
686
|
"Get key: https://app.honcho.dev/api-keys",
|
|
644
687
|
"echo \"<KEY>\" > keys/honcho-api-key.txt",
|
|
645
|
-
"Then
|
|
688
|
+
"Then reload Pi.",
|
|
646
689
|
]);
|
|
647
690
|
return;
|
|
648
691
|
}
|
|
@@ -650,14 +693,13 @@ async function initHoncho(pi: ExtensionAPI): Promise<void> {
|
|
|
650
693
|
const apiKey = readFileSync(keyPath, "utf8").trim();
|
|
651
694
|
if (!apiKey) {
|
|
652
695
|
logStartup("[pi-harness] Honcho: API key is empty — skipping");
|
|
653
|
-
addHarnessMessage("Honcho", "API key empty", "
|
|
696
|
+
addHarnessMessage("Honcho", "API key empty", "warn", [
|
|
654
697
|
"echo \"<KEY>\" > keys/honcho-api-key.txt",
|
|
655
|
-
"Then
|
|
698
|
+
"Then reload Pi.",
|
|
656
699
|
]);
|
|
657
700
|
return;
|
|
658
701
|
}
|
|
659
702
|
|
|
660
|
-
try {
|
|
661
703
|
// Register lifecycle hooks using the new integration
|
|
662
704
|
// SAFETY: pi.on accepts these event names at runtime
|
|
663
705
|
registerHonchoLifecycle(pi as unknown as { on: (event: string, handler: (...args: unknown[]) => void | Promise<void>) => void });
|
|
@@ -668,8 +710,10 @@ async function initHoncho(pi: ExtensionAPI): Promise<void> {
|
|
|
668
710
|
|
|
669
711
|
if (result) {
|
|
670
712
|
logStartup("[pi-harness] Honcho integration ready");
|
|
713
|
+
addHarnessMessage("Honcho", "initialized", "ok");
|
|
671
714
|
} else {
|
|
672
715
|
logStartup("[pi-harness] Honcho: initialization returned null");
|
|
716
|
+
addHarnessMessage("Honcho", "initialization returned no client", "err");
|
|
673
717
|
}
|
|
674
718
|
} catch (err) {
|
|
675
719
|
logStartup("[pi-harness] Honcho: init failed:", err instanceof Error ? err.message : String(err));
|
|
@@ -1100,6 +1144,7 @@ async function initLoopCompletions(pi: ExtensionAPI): Promise<void> {
|
|
|
1100
1144
|
* - Scan skills from ~/.pi-harness-runtime/skills/
|
|
1101
1145
|
*/
|
|
1102
1146
|
async function initHermesSkills(pi: ExtensionAPI): Promise<void> {
|
|
1147
|
+
addHarnessMessage("Skills", "initializing", "wait");
|
|
1103
1148
|
try {
|
|
1104
1149
|
// Dynamically import to avoid circular deps
|
|
1105
1150
|
const { initSkills } =
|
|
@@ -1108,6 +1153,7 @@ async function initHermesSkills(pi: ExtensionAPI): Promise<void> {
|
|
|
1108
1153
|
// Scan skills from default locations
|
|
1109
1154
|
const result = initSkills();
|
|
1110
1155
|
logStartup(`[pi-harness] Scanned ${result.skills.length} skills`);
|
|
1156
|
+
addHarnessMessage("Skills", `${result.skills.length} discovered`, "ok");
|
|
1111
1157
|
|
|
1112
1158
|
// Register /skill commands
|
|
1113
1159
|
try {
|
|
@@ -1147,6 +1193,7 @@ async function initHermesSkills(pi: ExtensionAPI): Promise<void> {
|
|
|
1147
1193
|
|
|
1148
1194
|
} catch (err) {
|
|
1149
1195
|
logStartup(`[pi-harness] Failed to initialize skills:`, err instanceof Error ? err.message : String(err));
|
|
1196
|
+
addHarnessMessage("Skills", "initialization failed", "err");
|
|
1150
1197
|
}
|
|
1151
1198
|
}
|
|
1152
1199
|
|
|
@@ -1604,7 +1651,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
1604
1651
|
void initSshDetachInterceptor(pi);
|
|
1605
1652
|
|
|
1606
1653
|
// --- jev-auto-continue: Agent autonomous decision when user unavailable -----
|
|
1607
|
-
|
|
1654
|
+
asyncInitPromises.push(initAutoContinue(pi));
|
|
1608
1655
|
|
|
1609
1656
|
// Register todo-driven continuation controller
|
|
1610
1657
|
createTodoContinuation(pi);
|
|
@@ -3080,24 +3127,12 @@ Run \`bd ready\` to see current bd issues.
|
|
|
3080
3127
|
// - Tree characters like Todos (├─ └─)
|
|
3081
3128
|
// - Trailing spacer line for breathing room
|
|
3082
3129
|
const HARNESS_WIDGET_KEY = "pi-harness-startup";
|
|
3083
|
-
interface HarnessMessage {
|
|
3084
|
-
id: string;
|
|
3085
|
-
label: string;
|
|
3086
|
-
text: string;
|
|
3087
|
-
status: "wait" | "ok" | "err";
|
|
3088
|
-
details?: string[]; // Multi-line fix instructions for errors
|
|
3089
|
-
}
|
|
3090
|
-
const harnessMessages: HarnessMessage[] = [];
|
|
3091
3130
|
let startupVisible = true;
|
|
3092
3131
|
let harnessTUI: { requestRender: (forced?: boolean) => void } | null = null;
|
|
3093
3132
|
let harnessWidgetRegistered = false;
|
|
3094
3133
|
let sessionGeneration = 0;
|
|
3095
3134
|
|
|
3096
|
-
|
|
3097
|
-
const id = `${label}-${Date.now()}`;
|
|
3098
|
-
harnessMessages.push({ id, label, text, status, details });
|
|
3099
|
-
harnessTUI?.requestRender();
|
|
3100
|
-
}
|
|
3135
|
+
startupStatus.onChange = () => harnessTUI?.requestRender();
|
|
3101
3136
|
|
|
3102
3137
|
function hideHarnessBlock() {
|
|
3103
3138
|
startupVisible = false;
|
|
@@ -3131,7 +3166,7 @@ Run \`bd ready\` to see current bd issues.
|
|
|
3131
3166
|
|
|
3132
3167
|
for (let i = 0; i < harnessMessages.length; i++) {
|
|
3133
3168
|
const msg = harnessMessages[i];
|
|
3134
|
-
const marker = msg.status
|
|
3169
|
+
const marker = harnessStatusMarker(msg.status);
|
|
3135
3170
|
const isLast = i === harnessMessages.length - 1;
|
|
3136
3171
|
const treeChar = isLast ? "└─" : "├─";
|
|
3137
3172
|
let text = `${treeChar} ${marker} ${msg.label}: ${msg.text}`;
|
|
@@ -3139,7 +3174,7 @@ Run \`bd ready\` to see current bd issues.
|
|
|
3139
3174
|
lines.push(text);
|
|
3140
3175
|
|
|
3141
3176
|
// Add fix instructions for errors (indented)
|
|
3142
|
-
if (msg.status === "err" && msg.details && msg.details.length > 0) {
|
|
3177
|
+
if ((msg.status === "err" || msg.status === "warn") && msg.details && msg.details.length > 0) {
|
|
3143
3178
|
for (const detail of msg.details) {
|
|
3144
3179
|
const detailLine = `${isLast ? " " : "│ "} Fix: ${detail}`;
|
|
3145
3180
|
lines.push(truncateToWidth(detailLine, width));
|
|
@@ -3170,7 +3205,7 @@ Run \`bd ready\` to see current bd issues.
|
|
|
3170
3205
|
sessionGeneration++;
|
|
3171
3206
|
const mySession = sessionGeneration;
|
|
3172
3207
|
startupVisible = true;
|
|
3173
|
-
|
|
3208
|
+
// Service states survive session changes; initialization runs once per extension load.
|
|
3174
3209
|
harnessWidgetRegistered = false; // Reset for new session
|
|
3175
3210
|
|
|
3176
3211
|
// --- Install harness widget (like Todos with placement: "aboveEditor") -------
|
|
@@ -3189,13 +3224,7 @@ Run \`bd ready\` to see current bd issues.
|
|
|
3189
3224
|
);
|
|
3190
3225
|
harnessWidgetRegistered = true;
|
|
3191
3226
|
|
|
3192
|
-
|
|
3193
|
-
for (const err of preSessionErrors) {
|
|
3194
|
-
harnessMessages.push(err);
|
|
3195
|
-
}
|
|
3196
|
-
preSessionErrors.length = 0; // Clear pre-session errors
|
|
3197
|
-
|
|
3198
|
-
harnessTUI?.requestRender(); // Show widget with error messages
|
|
3227
|
+
harnessTUI?.requestRender();
|
|
3199
3228
|
} else {
|
|
3200
3229
|
harnessTUI?.requestRender();
|
|
3201
3230
|
}
|
|
@@ -3203,42 +3232,19 @@ Run \`bd ready\` to see current bd issues.
|
|
|
3203
3232
|
// Add initial harness message
|
|
3204
3233
|
addHarnessMessage("Harness Runtime", `v${HARNESS_VERSION} initializing`, "wait");
|
|
3205
3234
|
|
|
3206
|
-
//
|
|
3207
|
-
const startupTimeout =
|
|
3208
|
-
|
|
3209
|
-
|
|
3210
|
-
|
|
3211
|
-
|
|
3212
|
-
startupTimeout
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
|
|
3216
|
-
|
|
3217
|
-
|
|
3218
|
-
|
|
3219
|
-
if (runtimeMsg) {
|
|
3220
|
-
runtimeMsg.status = "ok";
|
|
3221
|
-
runtimeMsg.text = `v${HARNESS_VERSION} initialized`;
|
|
3222
|
-
}
|
|
3223
|
-
|
|
3224
|
-
// Add service messages from startup
|
|
3225
|
-
for (const msg of startupMessages) {
|
|
3226
|
-
if (msg.includes("Qdrant") && msg.includes("ready")) {
|
|
3227
|
-
addHarnessMessage("Qdrant", "connected", "ok");
|
|
3228
|
-
}
|
|
3229
|
-
if (msg.includes("Telegram") && msg.includes("ready")) {
|
|
3230
|
-
addHarnessMessage("Telegram", "verified", "ok");
|
|
3231
|
-
}
|
|
3232
|
-
if (msg.includes("Honcho")) {
|
|
3233
|
-
addHarnessMessage("Honcho", "registered", "ok");
|
|
3234
|
-
}
|
|
3235
|
-
if (msg.includes("Scanned") && msg.includes("skills")) {
|
|
3236
|
-
const match = msg.match(/Scanned (\d+)/);
|
|
3237
|
-
if (match) {
|
|
3238
|
-
addHarnessMessage("Skills", `${match[1]} discovered`, "ok");
|
|
3239
|
-
}
|
|
3240
|
-
}
|
|
3241
|
-
}
|
|
3235
|
+
// A timeout is not success. Keep accepting late service updates.
|
|
3236
|
+
const startupTimeout = setTimeout(() => {
|
|
3237
|
+
if (mySession !== sessionGeneration) return;
|
|
3238
|
+
addHarnessMessage("Harness Runtime", `v${HARNESS_VERSION} waiting for service initialization`, "warn");
|
|
3239
|
+
}, 5000);
|
|
3240
|
+
Promise.allSettled(asyncInitPromises).then((results) => {
|
|
3241
|
+
clearTimeout(startupTimeout);
|
|
3242
|
+
if (mySession !== sessionGeneration) return;
|
|
3243
|
+
const degraded = results.some((result) => result.status === "rejected") ||
|
|
3244
|
+
harnessMessages.some((msg) => msg.label !== "Harness Runtime" && msg.status !== "ok");
|
|
3245
|
+
addHarnessMessage("Harness Runtime",
|
|
3246
|
+
`v${HARNESS_VERSION} ${degraded ? "initialized with unavailable services" : "initialized"}`,
|
|
3247
|
+
degraded ? "warn" : "ok");
|
|
3242
3248
|
});
|
|
3243
3249
|
});
|
|
3244
3250
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pi-harness/capability-registry",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.228",
|
|
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",
|