pi-harness-runtime 1.1.49 → 1.1.71-3
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/CHANGELOG.md +30 -9
- package/README.md +119 -0
- package/harness/langchain/agents.d.ts +143 -0
- package/harness/langchain/agents.test.d.ts +2 -0
- package/harness/langchain/agents.test.ts +0 -1
- package/harness/langchain/agents.ts +196 -13
- package/harness/langchain/checkpointer.d.ts +48 -0
- package/harness/langchain/checkpointer.test.d.ts +8 -0
- package/harness/langchain/cron-cli.d.ts +12 -0
- package/harness/langchain/cron-cli.ts +169 -0
- package/harness/langchain/daemon.d.ts +161 -0
- package/harness/langchain/daemon.test.d.ts +11 -0
- package/harness/langchain/daemon.test.ts +62 -5
- package/harness/langchain/daemon.ts +231 -12
- package/harness/langchain/file-tools.d.ts +97 -0
- package/harness/langchain/file-tools.ts +29 -11
- package/harness/langchain/graph.d.ts +706 -0
- package/harness/langchain/graph.ts +184 -26
- package/harness/langchain/model-router.d.ts +63 -0
- package/harness/langchain/model-router.test.d.ts +2 -0
- package/harness/langchain/model-router.test.ts +191 -0
- package/harness/langchain/model-router.ts +188 -0
- package/harness/langchain/models.d.ts +72 -0
- package/harness/langchain/models.ts +111 -49
- package/harness/langchain/ping-pong-middleware.d.ts +28 -0
- package/harness/langchain/ping-pong-middleware.test.d.ts +2 -0
- package/harness/langchain/ping-pong-middleware.test.ts +69 -0
- package/harness/langchain/ping-pong-middleware.ts +204 -0
- package/harness/langchain/run.d.ts +15 -0
- package/harness/langchain/run.ts +15 -3
- package/harness/langchain/scoreboard.test.d.ts +13 -0
- package/harness/langchain/scoreboard.test.ts +28 -5
- package/harness/langchain/status-line.d.ts +91 -0
- package/harness/langchain/status-line.test.d.ts +8 -0
- package/harness/langchain/surge.d.ts +103 -0
- package/harness/langchain/surge.test.d.ts +10 -0
- package/harness/langchain/surge.test.ts +179 -0
- package/harness/langchain/surge.ts +188 -19
- package/harness/langchain/widget.d.ts +105 -0
- package/harness/langchain/widget.test.d.ts +8 -0
- package/harness/ssh-detach-interceptor.test.ts +263 -0
- package/harness/ssh-detach-interceptor.ts +438 -0
- package/index.ts +212 -47
- package/package.json +4 -2
- package/packages/a2a-adapter/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/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/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/dist/src/index.d.ts +2 -0
- package/packages/intent-analyzer/dist/src/index.d.ts.map +1 -1
- package/packages/intent-analyzer/dist/src/index.js +1 -0
- package/packages/intent-analyzer/dist/src/index.js.map +1 -1
- package/packages/intent-analyzer/dist/src/ping-pong.d.ts +56 -0
- package/packages/intent-analyzer/dist/src/ping-pong.d.ts.map +1 -0
- package/packages/intent-analyzer/dist/src/ping-pong.js +286 -0
- package/packages/intent-analyzer/dist/src/ping-pong.js.map +1 -0
- package/packages/intent-analyzer/package.json +1 -1
- package/packages/intent-analyzer/src/index.ts +13 -0
- package/packages/intent-analyzer/src/ping-pong.ts +387 -0
- package/packages/intent-analyzer/test/ping-pong.test.ts +96 -0
- package/packages/jev-judge/README.md +234 -0
- package/packages/jev-judge/dist/decision-engine.d.ts +100 -0
- package/packages/jev-judge/dist/decision-engine.d.ts.map +1 -0
- package/packages/jev-judge/dist/decision-engine.js +151 -0
- package/packages/jev-judge/dist/decision-engine.js.map +1 -0
- package/packages/jev-judge/dist/e2e-judge.d.ts +61 -0
- package/packages/jev-judge/dist/e2e-judge.d.ts.map +1 -0
- package/packages/jev-judge/dist/e2e-judge.js +268 -0
- package/packages/jev-judge/dist/e2e-judge.js.map +1 -0
- package/packages/jev-judge/dist/flaky-detector.d.ts +34 -0
- package/packages/jev-judge/dist/flaky-detector.d.ts.map +1 -0
- package/packages/jev-judge/dist/flaky-detector.js +154 -0
- package/packages/jev-judge/dist/flaky-detector.js.map +1 -0
- package/packages/jev-judge/dist/index.d.ts +77 -0
- package/packages/jev-judge/dist/index.d.ts.map +1 -0
- package/packages/jev-judge/dist/index.js +271 -0
- package/packages/jev-judge/dist/index.js.map +1 -0
- package/packages/jev-judge/dist/types.d.ts +97 -0
- package/packages/jev-judge/dist/types.d.ts.map +1 -0
- package/packages/jev-judge/dist/types.js +8 -0
- package/packages/jev-judge/dist/types.js.map +1 -0
- package/packages/jev-judge/package.json +46 -0
- package/packages/jev-judge/src/decision-engine.ts +231 -0
- package/packages/jev-judge/src/e2e-judge.ts +364 -0
- package/packages/jev-judge/src/flaky-detector.ts +190 -0
- package/packages/jev-judge/src/index.ts +345 -0
- package/packages/jev-judge/src/types.ts +131 -0
- 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/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/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/sprint-planner/package.json +1 -1
- package/packages/subscription-engine/package.json +1 -1
- package/packages/task-compiler/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/README.md +71 -0
- package/packages/todo-bd-sync/package.json +1 -1
- package/packages/todo-bd-sync/src/extension.ts +16 -1
- package/packages/token-estimation/package.json +1 -1
- package/packages/token-optimizer/package.json +1 -1
- package/packages/trajectory/dist/src/approved-patterns.d.ts +51 -0
- package/packages/trajectory/dist/src/approved-patterns.d.ts.map +1 -0
- package/packages/trajectory/dist/src/approved-patterns.js +134 -0
- package/packages/trajectory/dist/src/approved-patterns.js.map +1 -0
- package/packages/trajectory/dist/src/index.d.ts +13 -0
- package/packages/trajectory/dist/src/index.d.ts.map +1 -0
- package/packages/trajectory/dist/src/index.js +12 -0
- package/packages/trajectory/dist/src/index.js.map +1 -0
- package/packages/trajectory/dist/src/store.d.ts +69 -0
- package/packages/trajectory/dist/src/store.d.ts.map +1 -0
- package/packages/trajectory/dist/src/store.js +253 -0
- package/packages/trajectory/dist/src/store.js.map +1 -0
- package/packages/trajectory/dist/src/types.d.ts +73 -0
- package/packages/trajectory/dist/src/types.d.ts.map +1 -0
- package/packages/trajectory/dist/src/types.js +9 -0
- package/packages/trajectory/dist/src/types.js.map +1 -0
- package/packages/trajectory/dist/test/store.test.d.ts +2 -0
- package/packages/trajectory/dist/test/store.test.d.ts.map +1 -0
- package/packages/trajectory/dist/test/store.test.js +228 -0
- package/packages/trajectory/dist/test/store.test.js.map +1 -0
- package/packages/trajectory/package.json +29 -0
- package/packages/trajectory/src/approved-patterns.ts +180 -0
- package/packages/trajectory/src/index.ts +26 -0
- package/packages/trajectory/src/store.ts +285 -0
- package/packages/trajectory/src/types.ts +84 -0
- package/packages/trajectory/test/store.test.d.ts +2 -0
- package/packages/trajectory/test/store.test.ts +250 -0
- package/packages/tui/package.json +1 -1
- package/packages/types/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
- package/packages/write-review/src/blackboard.ts +38 -5
- package/packages/write-review/src/types.ts +13 -0
- package/skills/harness-runtime/SKILL.md +67 -4
package/index.ts
CHANGED
|
@@ -13,7 +13,6 @@
|
|
|
13
13
|
* Runs directly from Bun.
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
|
-
import { Key } from "@earendil-works/pi-tui";
|
|
17
16
|
import type {
|
|
18
17
|
CompactOptions,
|
|
19
18
|
ExtensionAPI,
|
|
@@ -24,8 +23,6 @@ import { UsageTracker } from "./tracker.ts";
|
|
|
24
23
|
import { MirrorStore, type MirrorRecord } from "./mirror.ts";
|
|
25
24
|
import { MiniMaxQuotaScraper } from "./harness/e2e/minimax-quota-scraper.js";
|
|
26
25
|
import { OpenAIQuotaScraper } from "./harness/e2e/openai-quota-scraper.js";
|
|
27
|
-
import { GLMQuotaScraper } from "./harness/e2e/glm-quota-scraper.js";
|
|
28
|
-
import { ChatGPTQuotaScraper } from "./harness/e2e/chatgpt-quota-scraper.js";
|
|
29
26
|
import { parseMiniMaxQuotaText } from "./harness/e2e/minimax-quota-parser.js";
|
|
30
27
|
import {
|
|
31
28
|
CookieWatcher,
|
|
@@ -43,7 +40,6 @@ import {
|
|
|
43
40
|
import { QuotaManager } from "./packages/quota-manager/src/quota-manager.ts";
|
|
44
41
|
import { buildFooterStatusValue } from "./footer-status.ts";
|
|
45
42
|
import { registerGithubLoginCommand } from "./packages/clipboard/src/github-login.js";
|
|
46
|
-
import { registerCopySyncShortcut } from "./packages/clipboard/src/copy-sync.js";
|
|
47
43
|
import {
|
|
48
44
|
MAX_PROACTIVE_COMPACT_FAILURES,
|
|
49
45
|
OUTPUT_LIMIT_RESUME_PROMPT,
|
|
@@ -116,37 +112,152 @@ async function initFileCopyHelper(pi: ExtensionAPI): Promise<void> {
|
|
|
116
112
|
// file-copy-helper not available
|
|
117
113
|
}
|
|
118
114
|
}
|
|
119
|
-
import { homedir } from "node:os";
|
|
120
|
-
import { appendFileSync, existsSync, mkdirSync } from "node:fs";
|
|
121
|
-
import { join } from "node:path";
|
|
122
115
|
|
|
123
|
-
// ---
|
|
124
|
-
|
|
125
|
-
|
|
116
|
+
// --- SSH detach interceptor: Auto-transform bare ssh ... & to detached pattern ---
|
|
117
|
+
// Prevents 2000+ second hangs when SSH background commands aren't detached.
|
|
118
|
+
// Intercepts every bash tool call before execution and rewrites risky SSH commands.
|
|
119
|
+
//
|
|
120
|
+
// Also guards foreground `ssh ... "<daemon>"` commands (pollers, servers) by
|
|
121
|
+
// prefixing `timeout Ns` so the local call always returns (PI_HARNESS_SSH_TIMEOUT_S).
|
|
122
|
+
async function initSshDetachInterceptor(pi: ExtensionAPI): Promise<void> {
|
|
123
|
+
try {
|
|
124
|
+
const interceptor = await import("./harness/ssh-detach-interceptor.js");
|
|
125
|
+
// Register on tool_call with default priority (100)
|
|
126
|
+
// NOTE: module functions are captured in closure scope — do NOT use require()
|
|
127
|
+
// here; this package is ESM ("type": "module") and require is undefined.
|
|
128
|
+
pi.on("tool_call", (event, _api) => {
|
|
129
|
+
if (event.toolName !== "bash") return {};
|
|
130
|
+
const input = event.input as { command?: string; timeout?: number };
|
|
131
|
+
const command = input.command ?? "";
|
|
132
|
+
if (!interceptor.isSshCommand(command)) return {};
|
|
133
|
+
|
|
134
|
+
// 1) Detach transform: bare `ssh ... &` or `ssh "a && b &"` chains
|
|
135
|
+
if (
|
|
136
|
+
!interceptor.isDetachedPattern(command) &&
|
|
137
|
+
(interceptor.hasBareAmpersand(command) ||
|
|
138
|
+
interceptor.hasCommandChainWithAmpersand(command))
|
|
139
|
+
) {
|
|
140
|
+
const transformed = interceptor.transformToDetached(command);
|
|
141
|
+
if (transformed !== command) {
|
|
142
|
+
input.command = transformed;
|
|
143
|
+
return {};
|
|
144
|
+
}
|
|
145
|
+
}
|
|
126
146
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
147
|
+
// 2) Timeout guard: foreground SSH running a daemon-ish remote command
|
|
148
|
+
// (e.g. `ssh -tt host "python -m amos_worker --video | head -10"`)
|
|
149
|
+
if (interceptor.isForegroundDaemonSsh(command)) {
|
|
150
|
+
const seconds = interceptor.getDefaultSshTimeoutSeconds();
|
|
151
|
+
input.command = interceptor.addSshTimeoutGuard(command, seconds);
|
|
152
|
+
// Also cap the bash tool's own timeout as belt-and-suspenders
|
|
153
|
+
if (input.timeout === undefined || input.timeout > seconds) {
|
|
154
|
+
input.timeout = seconds;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return {};
|
|
158
|
+
});
|
|
159
|
+
} catch {
|
|
160
|
+
// ssh-detach-interceptor not available
|
|
161
|
+
}
|
|
131
162
|
}
|
|
132
163
|
|
|
133
|
-
//
|
|
134
|
-
|
|
164
|
+
// --- loop-completions: Watch daemon loop completions → update TUI todos ---------
|
|
165
|
+
// When the daemon loop finishes, it writes a completion event to
|
|
166
|
+
// ~/.pi-harness-runtime/loop-completions/. The harness extension watches this
|
|
167
|
+
// dir and sends a steer message to the agent so the TUI todo count updates.
|
|
168
|
+
async function initLoopCompletions(pi: ExtensionAPI): Promise<void> {
|
|
169
|
+
const { existsSync, mkdirSync, watch } = await import("node:fs");
|
|
170
|
+
const { join: joinPath } = await import("node:path");
|
|
171
|
+
const { homedir: getHomeDir } = await import("node:os");
|
|
172
|
+
|
|
173
|
+
const COMPLETION_DIR = joinPath(
|
|
174
|
+
getHomeDir(),
|
|
175
|
+
".pi-harness-runtime",
|
|
176
|
+
"loop-completions",
|
|
177
|
+
);
|
|
178
|
+
|
|
135
179
|
try {
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
args
|
|
140
|
-
.map((a) => (typeof a === "object" ? JSON.stringify(a) : String(a)))
|
|
141
|
-
.join(" ");
|
|
142
|
-
appendFileSync(DEBUG_LOG_PATH, line + "\n");
|
|
180
|
+
if (!existsSync(COMPLETION_DIR)) {
|
|
181
|
+
mkdirSync(COMPLETION_DIR, { recursive: true });
|
|
182
|
+
}
|
|
143
183
|
} catch {
|
|
144
|
-
//
|
|
184
|
+
return; // can't create dir — skip
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Process any pre-existing files (e.g. from a previous session)
|
|
188
|
+
try {
|
|
189
|
+
const { readdirSync } = await import("node:fs");
|
|
190
|
+
const files = readdirSync(COMPLETION_DIR).filter((f) => f.endsWith(".json"));
|
|
191
|
+
for (const file of files) {
|
|
192
|
+
processCompletionFile(joinPath(COMPLETION_DIR, file), pi);
|
|
193
|
+
}
|
|
194
|
+
} catch {
|
|
195
|
+
// ignore — best-effort
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// Watch for new completion files
|
|
199
|
+
try {
|
|
200
|
+
const watcher = watch(
|
|
201
|
+
COMPLETION_DIR,
|
|
202
|
+
{ persistent: false },
|
|
203
|
+
(event, filename) => {
|
|
204
|
+
if (event !== "rename") return;
|
|
205
|
+
if (!filename || !filename.endsWith(".json")) return;
|
|
206
|
+
const filePath = joinPath(COMPLETION_DIR, filename);
|
|
207
|
+
// Delay so the write finishes before we read
|
|
208
|
+
setTimeout(() => processCompletionFile(filePath, pi), 500);
|
|
209
|
+
},
|
|
210
|
+
);
|
|
211
|
+
watcher.on("error", () => {});
|
|
212
|
+
} catch {
|
|
213
|
+
// fs.watch not available — skip
|
|
145
214
|
}
|
|
146
215
|
}
|
|
147
216
|
|
|
217
|
+
interface LoopCompletion {
|
|
218
|
+
taskId: string;
|
|
219
|
+
request: string;
|
|
220
|
+
verdict: string;
|
|
221
|
+
iterations: number;
|
|
222
|
+
finishedAt: string;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function processCompletionFile(filePath: string, pi: ExtensionAPI): void {
|
|
226
|
+
const { existsSync, readFileSync, unlinkSync } = require("node:fs");
|
|
227
|
+
try {
|
|
228
|
+
if (!existsSync(filePath)) return;
|
|
229
|
+
const raw = readFileSync(filePath, "utf8");
|
|
230
|
+
const completion = JSON.parse(raw) as LoopCompletion;
|
|
231
|
+
|
|
232
|
+
const tag =
|
|
233
|
+
completion.verdict === "approved"
|
|
234
|
+
? "[ok]"
|
|
235
|
+
: completion.verdict === "blocked"
|
|
236
|
+
? "[blocked]"
|
|
237
|
+
: "[done]";
|
|
238
|
+
|
|
239
|
+
const message =
|
|
240
|
+
`Loop completed ${tag}: ${completion.taskId}\n` +
|
|
241
|
+
` verdict: ${completion.verdict}\n` +
|
|
242
|
+
` iterations: ${completion.iterations}\n` +
|
|
243
|
+
` task: ${completion.request.slice(0, 80)}${completion.request.length > 80 ? "..." : ""}\n\n` +
|
|
244
|
+
`Run \`bd close ${completion.taskId} --reason "${completion.verdict}"\` if not already closed.`;
|
|
245
|
+
|
|
246
|
+
try {
|
|
247
|
+
pi.sendUserMessage(message, { deliverAs: "steer" });
|
|
248
|
+
} catch {
|
|
249
|
+
// ignore — best-effort
|
|
250
|
+
}
|
|
251
|
+
unlinkSync(filePath);
|
|
252
|
+
} catch {
|
|
253
|
+
// ignore — best-effort
|
|
254
|
+
}
|
|
255
|
+
}
|
|
148
256
|
// --- Debug logging (file only, no console override) ---------------
|
|
149
257
|
// Logs written to file only. Real console output preserved for pi's TUI.
|
|
258
|
+
import { homedir } from "node:os";
|
|
259
|
+
import { existsSync, mkdirSync } from "node:fs";
|
|
260
|
+
import { join } from "node:path";
|
|
150
261
|
|
|
151
262
|
// --- Harness Runtime State --------------------------------------------
|
|
152
263
|
const HARNESS_ROOT_DIR = join(homedir(), ".pi", "harness");
|
|
@@ -210,6 +321,7 @@ async function getCheckpointManager(): Promise<CheckpointManager> {
|
|
|
210
321
|
const { JsonCheckpointManager } = await import(
|
|
211
322
|
"./packages/checkpoint/src/checkpoint-manager.ts"
|
|
212
323
|
);
|
|
324
|
+
// SAFETY: JsonCheckpointManager implements CheckpointManager via structural typing
|
|
213
325
|
return new JsonCheckpointManager(
|
|
214
326
|
HARNESS_ROOT_DIR,
|
|
215
327
|
) as unknown as CheckpointManager;
|
|
@@ -260,14 +372,39 @@ export default function (pi: ExtensionAPI) {
|
|
|
260
372
|
// --- file-copy-helper: Inject cp rule when mimicking files -------------
|
|
261
373
|
void initFileCopyHelper(pi);
|
|
262
374
|
|
|
375
|
+
// --- ssh-detach-interceptor: Auto-fix bare ssh & → nohup pattern ---------
|
|
376
|
+
void initSshDetachInterceptor(pi);
|
|
377
|
+
|
|
378
|
+
// --- loop-completions: Watch daemon completions → agent TUI todos --------
|
|
379
|
+
void initLoopCompletions(pi);
|
|
380
|
+
|
|
381
|
+
// --- TASK TRACKING TERMINOLOGY CLARIFICATION ------------------------
|
|
382
|
+
// CRITICAL: This project has TWO separate task trackers. Agents often confuse them.
|
|
383
|
+
const TASK_TERMINOLOGY_CLARIFICATION = `
|
|
384
|
+
## TASK TRACKING TERMINOLOGY (CRITICAL)
|
|
385
|
+
|
|
386
|
+
This project uses TWO different task tracking systems. **Always clarify which one the user means:**
|
|
387
|
+
|
|
388
|
+
| What you say | Tool | Purpose |
|
|
389
|
+
|-------------|------|---------|
|
|
390
|
+
| **bd** / **beads** / **issues** | \`bd create\`, \`bd list\`, \`bd close\` | Issue tracker (GitHub-synced) |
|
|
391
|
+
| **todo** / **todos** | \`todo\` tool (JSON-RPC) | Local task list (session-only) |
|
|
392
|
+
|
|
393
|
+
**When in doubt, ASK:** "Did you mean **bd** (issue tracker) or **todo** (local task list)?"
|
|
394
|
+
|
|
395
|
+
### When to use each:
|
|
396
|
+
- **bd (beads)**: Long-lived issues, bugs, features, GitHub issues
|
|
397
|
+
- **todo**: Short-lived session tasks, immediate action items
|
|
398
|
+
`;
|
|
399
|
+
|
|
263
400
|
// --- Auto-Invoke rpiv-todo via System Prompt ------------------------
|
|
264
401
|
// This makes the todo overlay ALWAYS activate at session start
|
|
265
402
|
const AUTO_TODO_INVOKE_HINT = `
|
|
266
403
|
|
|
267
|
-
You have access to a todo tool that shows a persistent task overlay.
|
|
404
|
+
You have access to a **todo tool** that shows a persistent task overlay.
|
|
268
405
|
ALWAYS use it at the START of every session to capture user requirements as tasks.
|
|
269
406
|
When the user gives you a multi-step task:
|
|
270
|
-
1. Immediately create todo items for each step using the todo tool
|
|
407
|
+
1. Immediately create todo items for each step using the **todo tool** (not bd!)
|
|
271
408
|
2. Keep tasks updated - mark in_progress when working, completed when done
|
|
272
409
|
3. When a task is completed, continue to the next or ask the user
|
|
273
410
|
|
|
@@ -277,10 +414,12 @@ The todo overlay persists and helps track progress across your conversation.
|
|
|
277
414
|
const COMMIT_BUILD_CHECKLIST = `
|
|
278
415
|
|
|
279
416
|
BEFORE committing code or triggering builds, ALWAYS check:
|
|
280
|
-
1. Run
|
|
281
|
-
2. Mark completed
|
|
282
|
-
3. Acknowledge pending
|
|
283
|
-
4. Never commit/build without acknowledging pending
|
|
417
|
+
1. Run \`bd ready\` to see pending **bd issues**
|
|
418
|
+
2. Mark completed issues with \`bd close <id> --reason "Done"\`
|
|
419
|
+
3. Acknowledge pending issues before proceeding
|
|
420
|
+
4. Never commit/build without acknowledging pending bd issues
|
|
421
|
+
|
|
422
|
+
NOTE: Use \`todo\` tool for session task tracking, \`bd\` for issue tracker.
|
|
284
423
|
`;
|
|
285
424
|
|
|
286
425
|
const WRITE_REVIEW_HINT = `
|
|
@@ -289,10 +428,11 @@ WRITER-REVIEWER WORKFLOW:
|
|
|
289
428
|
When working on a feature from {project}/wiki/* or {project}/.write-review/:
|
|
290
429
|
1. Read the prompt/task file to understand requirements
|
|
291
430
|
2. Write clean, complete code
|
|
292
|
-
3. Mark task "in_progress"
|
|
293
|
-
4. When code is ready, trigger review with \`
|
|
294
|
-
5.
|
|
295
|
-
6.
|
|
431
|
+
3. Mark task "in_progress" using **todo tool**
|
|
432
|
+
4. When code is ready, trigger review with \`bd create "Review: <task>" -t review -p 1\`
|
|
433
|
+
5. After review, close the issue: \`bd close <id> --reason "Approved"\`
|
|
434
|
+
6. If reviewer requests changes, update code and re-review
|
|
435
|
+
7. Never skip review on non-trivial features
|
|
296
436
|
`;
|
|
297
437
|
|
|
298
438
|
const DOCKER_CLEANUP_HINT = `
|
|
@@ -304,13 +444,34 @@ AFTER running any Docker build command (docker build, docker compose build, dock
|
|
|
304
444
|
3. Example: After \`docker compose up --build\`, run \`docker builder prune -f\`
|
|
305
445
|
4. For aggressive cleanup: \`docker builder prune -a -f\` (removes ALL unused cache)
|
|
306
446
|
`;
|
|
447
|
+
// --- SSH Guard Rules: Never run servers over SSH in the foreground --------
|
|
448
|
+
// This runs in EVERY repo the agent enters — not just pi-harness-runtime.
|
|
449
|
+
// Pattern: embed as constant (no file dependency) so it works everywhere.
|
|
450
|
+
const SSH_GUARD_RULES = `
|
|
451
|
+
## SSH / Remote Server Commands
|
|
452
|
+
|
|
453
|
+
**CRITICAL — SSH BACKGROUNDING RULE:**
|
|
454
|
+
Never run a server or long-running process over SSH in the foreground. This causes the SSH session to hang indefinitely, blocking the agent for hours.
|
|
455
|
+
|
|
456
|
+
- BAD: \`ssh host "python -m uvicorn ..."\` (no &, SSH will hang)
|
|
457
|
+
- GOOD: \`ssh host "nohup python -m uvicorn ... > /tmp/log 2>&1 & echo DONE"\`
|
|
458
|
+
- GOOD: \`ssh host "cd /path && python -m uvicorn ... > log 2>&1 & echo DONE"\`
|
|
459
|
+
|
|
460
|
+
Every SSH command that starts a server, daemon, or background process MUST use the detached SSH pattern: nohup + redirect + & + echo DONE.
|
|
461
|
+
If you are unsure whether a command will hang, ALWAYS use nohup + backgrounding. It is always safe to detach; it is never safe to run a server in the foreground over SSH.
|
|
462
|
+
|
|
463
|
+
Server process examples that must be detached: uvicorn, fastapi dev server, gunicorn, node server, flask run, django runserver, python http.server, any listening daemon.
|
|
464
|
+
`;
|
|
465
|
+
|
|
307
466
|
let firstAgentStart = true;
|
|
308
467
|
pi.on("before_agent_start", async (event) => {
|
|
309
468
|
if (firstAgentStart) {
|
|
469
|
+
event.systemPrompt += TASK_TERMINOLOGY_CLARIFICATION;
|
|
310
470
|
event.systemPrompt += AUTO_TODO_INVOKE_HINT;
|
|
311
471
|
event.systemPrompt += COMMIT_BUILD_CHECKLIST;
|
|
312
472
|
event.systemPrompt += WRITE_REVIEW_HINT;
|
|
313
473
|
event.systemPrompt += DOCKER_CLEANUP_HINT;
|
|
474
|
+
event.systemPrompt += SSH_GUARD_RULES;
|
|
314
475
|
firstAgentStart = false;
|
|
315
476
|
}
|
|
316
477
|
});
|
|
@@ -335,12 +496,13 @@ AFTER running any Docker build command (docker build, docker compose build, dock
|
|
|
335
496
|
|
|
336
497
|
const TODO_BUILD_REMINDER = `
|
|
337
498
|
|
|
338
|
-
IMPORTANT -
|
|
499
|
+
IMPORTANT - TASK UPDATE REMINDER:
|
|
339
500
|
Before running a build, ensure you update the current task status:
|
|
340
|
-
1.
|
|
341
|
-
2.
|
|
501
|
+
1. If tracking in **todo tool**: mark task in_progress
|
|
502
|
+
2. If tracking in **bd issues**: use \`bd update <id> --status in_progress\`
|
|
503
|
+
3. After build succeeds: mark completed in the appropriate tracker
|
|
342
504
|
|
|
343
|
-
Run \`bd ready\` to see current
|
|
505
|
+
Run \`bd ready\` to see current bd issues.
|
|
344
506
|
`;
|
|
345
507
|
|
|
346
508
|
// Detect build commands and append todo reminder to their output
|
|
@@ -458,8 +620,9 @@ Run \`bd ready\` to see current tasks.
|
|
|
458
620
|
// );
|
|
459
621
|
tuiMonitor.processMessage(text);
|
|
460
622
|
}
|
|
461
|
-
|
|
462
|
-
|
|
623
|
+
// message_end: no-op on parse error (already logged upstream)
|
|
624
|
+
} catch {
|
|
625
|
+
// ignore — the message was already logged by the TUI layer
|
|
463
626
|
}
|
|
464
627
|
});
|
|
465
628
|
|
|
@@ -468,7 +631,10 @@ Run \`bd ready\` to see current tasks.
|
|
|
468
631
|
const MINIMAX_REFRESH_TOKEN_THRESHOLD = 200_000;
|
|
469
632
|
const MINIMAX_REFRESH_REQUEST_THRESHOLD = 12;
|
|
470
633
|
const quotaScraper = process.env.QUOTA_COOKIE_FILE
|
|
471
|
-
? new MiniMaxQuotaScraper({
|
|
634
|
+
? new MiniMaxQuotaScraper({
|
|
635
|
+
cookieFile: process.env.QUOTA_COOKIE_FILE,
|
|
636
|
+
quiet: true,
|
|
637
|
+
})
|
|
472
638
|
: new MiniMaxQuotaScraper({ quiet: true });
|
|
473
639
|
|
|
474
640
|
// --- Smart quota fetch for OpenAI status -------------------------
|
|
@@ -497,7 +663,6 @@ Run \`bd ready\` to see current tasks.
|
|
|
497
663
|
}
|
|
498
664
|
};
|
|
499
665
|
|
|
500
|
-
|
|
501
666
|
// --- TUI quota signal plumbing (OpenAI / GLM / Anthropic / OpenRouter) --
|
|
502
667
|
// The TUIUsageMonitor parses provider quota-exhaustion messages from pi's
|
|
503
668
|
// TUI / message stream and emits signals we write to per-provider mirror
|
|
@@ -589,8 +754,7 @@ Run \`bd ready\` to see current tasks.
|
|
|
589
754
|
let pendingOutputLimitResumeAfterCompact = false;
|
|
590
755
|
let pendingOutputLimitResumeAfterSettled = false;
|
|
591
756
|
let providerOverloadResumeAttempts = 0;
|
|
592
|
-
let providerOverloadResumeTimer: ReturnType<typeof setTimeout> | null =
|
|
593
|
-
null;
|
|
757
|
+
let providerOverloadResumeTimer: ReturnType<typeof setTimeout> | null = null;
|
|
594
758
|
|
|
595
759
|
// --- Context-usage escalating warning tiers -----------------------------
|
|
596
760
|
// Amber at 75%, red at 85%. No notify above 90% (proactive compact handles it).
|
|
@@ -950,8 +1114,7 @@ Run \`bd ready\` to see current tasks.
|
|
|
950
1114
|
description: "Force refresh quota from provider console",
|
|
951
1115
|
handler: async (_args: string, ctx: ExtensionCommandContext) => {
|
|
952
1116
|
const autoFetchAvailable =
|
|
953
|
-
hasCookieSource() ||
|
|
954
|
-
(await hasBrowserProfileAutoFetchSource());
|
|
1117
|
+
hasCookieSource() || (await hasBrowserProfileAutoFetchSource());
|
|
955
1118
|
if (!autoFetchAvailable) {
|
|
956
1119
|
ctx.ui.notify(
|
|
957
1120
|
"MiniMax cookies not found. Drop any cookie file (Netscape or EditThisCookie JSON) into ~/.pi-harness-runtime/cookies/ — the runtime normalizes it for you. Or run `bun packages/auth/src/run-minimax-auth.ts auth`.",
|
|
@@ -1431,7 +1594,9 @@ Run \`bd ready\` to see current tasks.
|
|
|
1431
1594
|
}
|
|
1432
1595
|
}
|
|
1433
1596
|
|
|
1434
|
-
function scheduleProviderOverloadResume(
|
|
1597
|
+
function scheduleProviderOverloadResume(
|
|
1598
|
+
hasPendingMessages: () => boolean,
|
|
1599
|
+
): void {
|
|
1435
1600
|
clearProviderOverloadResume();
|
|
1436
1601
|
const delayMs = getProviderOverloadResumeDelayMs();
|
|
1437
1602
|
const delayMinutes = Math.max(1, Math.round(delayMs / 60_000));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-harness-runtime",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.71-3",
|
|
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": {
|
|
@@ -17,7 +17,9 @@
|
|
|
17
17
|
"skills:sync": "bun scripts/skills-sync.ts",
|
|
18
18
|
"skills:sync:check": "bun scripts/skills-sync.ts --check-only",
|
|
19
19
|
"build": "for pkg in packages/*/; do [ -f \"${pkg}tsconfig.json\" ] && [ \"$pkg\" != \"packages/provider-router/\" ] && node_modules/.bin/tsc -p \"${pkg}tsconfig.json\" --skipLibCheck > /dev/null 2>&1 || true; done",
|
|
20
|
-
"prepublishOnly": "bun run build"
|
|
20
|
+
"prepublishOnly": "bun run build",
|
|
21
|
+
"test:harness": "bun test harness/langchain/",
|
|
22
|
+
"test:all": "node --test && bun test harness/langchain/"
|
|
21
23
|
},
|
|
22
24
|
"bin": {
|
|
23
25
|
"harness-auth": "packages/auth/src/run-minimax-auth.ts"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pi-harness/capability-registry",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.71-3",
|
|
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",
|