pi-better-harness 0.1.9 → 0.1.12
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/README.md +15 -12
- package/bin/pi-better-harness.mjs +5 -0
- package/extensions/background-tasks/index.ts +1 -0
- package/extensions/goal/index.ts +1 -0
- package/extensions/subagents/index.ts +1 -0
- package/lib/cli.mjs +62 -0
- package/node_modules/pi-better-background-tasks/package.json +1 -1
- package/node_modules/pi-better-goal/package.json +1 -1
- package/node_modules/pi-better-subagents/index.ts +11 -7
- package/node_modules/pi-better-subagents/package.json +1 -1
- package/node_modules/pi-better-subagents/parse.ts +3 -5
- package/package.json +16 -9
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
## Quick Answer
|
|
6
6
|
|
|
7
|
-
Use `pi-better-harness` when you want the full background-work
|
|
7
|
+
Use `pi-better-harness` when you want the full background-work set for Pi. It manages:
|
|
8
8
|
|
|
9
9
|
- `pi-better-subagents` for detached, sandboxed subagent runs.
|
|
10
10
|
- `pi-better-background-tasks` for durable shell tasks and watchers.
|
|
@@ -18,43 +18,46 @@ Use `pi-better-harness` when you want the full background-work bundle for Pi in
|
|
|
18
18
|
|
|
19
19
|
## Install
|
|
20
20
|
|
|
21
|
+
Install the three extensions as standalone Pi packages, so Pi displays and manages each by its own package name:
|
|
22
|
+
|
|
21
23
|
```sh
|
|
22
|
-
|
|
24
|
+
npx pi-better-harness install
|
|
23
25
|
```
|
|
24
26
|
|
|
25
|
-
|
|
27
|
+
For project-local Pi settings:
|
|
26
28
|
|
|
27
29
|
```sh
|
|
28
|
-
|
|
30
|
+
npx pi-better-harness install --local
|
|
29
31
|
```
|
|
30
32
|
|
|
31
|
-
|
|
33
|
+
The bundled installation remains available for compatibility:
|
|
32
34
|
|
|
33
35
|
```sh
|
|
34
|
-
pi install npm:pi-better-
|
|
35
|
-
pi install npm:pi-better-background-tasks
|
|
36
|
-
pi install npm:pi-better-goal
|
|
36
|
+
pi install npm:pi-better-harness
|
|
37
37
|
```
|
|
38
38
|
|
|
39
39
|
## When To Use
|
|
40
40
|
|
|
41
|
-
Use
|
|
41
|
+
Use the installer when you want all three core extensions with standalone package identities. Install an individual package instead when you only need subagents, shell task supervision, or goal tracking.
|
|
42
42
|
|
|
43
43
|
## Compatibility
|
|
44
44
|
|
|
45
45
|
| Requirement | Support |
|
|
46
46
|
|-------------|---------|
|
|
47
47
|
| Pi | Required |
|
|
48
|
-
|
|
|
48
|
+
| Recommended install | `npx pi-better-harness install` |
|
|
49
49
|
| Development runtime | Node.js 22+ |
|
|
50
50
|
|
|
51
51
|
## Update Or Remove
|
|
52
52
|
|
|
53
|
+
Remove all three standalone packages:
|
|
54
|
+
|
|
53
55
|
```sh
|
|
54
|
-
|
|
55
|
-
pi remove npm:pi-better-harness
|
|
56
|
+
npx pi-better-harness uninstall
|
|
56
57
|
```
|
|
57
58
|
|
|
59
|
+
Add `--local` to remove them from project-local settings.
|
|
60
|
+
|
|
58
61
|
## More Detail
|
|
59
62
|
|
|
60
63
|
- Repository: https://github.com/1aboveio/pi-better-harness
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from "../../node_modules/pi-better-background-tasks/src/index.ts";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from "../../node_modules/pi-better-goal/src/index.ts";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from "../../node_modules/pi-better-subagents/index.ts";
|
package/lib/cli.mjs
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
import { readFileSync } from "node:fs";
|
|
3
|
+
import { dirname, resolve } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
|
|
6
|
+
const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
7
|
+
const { version } = JSON.parse(readFileSync(resolve(packageRoot, "package.json"), "utf8"));
|
|
8
|
+
|
|
9
|
+
export const componentPackages = [
|
|
10
|
+
"pi-better-subagents",
|
|
11
|
+
"pi-better-background-tasks",
|
|
12
|
+
"pi-better-goal",
|
|
13
|
+
];
|
|
14
|
+
|
|
15
|
+
const usage = `Usage: pi-better-harness <install|uninstall> [--local]
|
|
16
|
+
|
|
17
|
+
Commands:
|
|
18
|
+
install Configure all Pi Better Harness component packages
|
|
19
|
+
uninstall Remove all Pi Better Harness component packages
|
|
20
|
+
|
|
21
|
+
Options:
|
|
22
|
+
-l, --local Use project-local Pi settings
|
|
23
|
+
-h, --help Show this help
|
|
24
|
+
-v, --version Show the package version`;
|
|
25
|
+
|
|
26
|
+
export function run(argv, options = {}) {
|
|
27
|
+
const spawn = options.spawn ?? spawnSync;
|
|
28
|
+
const stdout = options.stdout ?? process.stdout;
|
|
29
|
+
const stderr = options.stderr ?? process.stderr;
|
|
30
|
+
|
|
31
|
+
if (argv.includes("--help") || argv.includes("-h")) {
|
|
32
|
+
stdout.write(`${usage}\n`);
|
|
33
|
+
return 0;
|
|
34
|
+
}
|
|
35
|
+
if (argv.includes("--version") || argv.includes("-v")) {
|
|
36
|
+
stdout.write(`${version}\n`);
|
|
37
|
+
return 0;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const local = argv.includes("--local") || argv.includes("-l");
|
|
41
|
+
const positional = argv.filter((arg) => !["--local", "-l"].includes(arg));
|
|
42
|
+
const command = positional[0];
|
|
43
|
+
if (!command || positional.length !== 1 || !["install", "uninstall"].includes(command)) {
|
|
44
|
+
stderr.write(`${usage}\n`);
|
|
45
|
+
return 2;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const piCommand = process.platform === "win32" ? "pi.cmd" : "pi";
|
|
49
|
+
const piAction = command === "install" ? "install" : "remove";
|
|
50
|
+
for (const packageName of componentPackages) {
|
|
51
|
+
const args = [piAction, `npm:${packageName}`, ...(local ? ["--local"] : [])];
|
|
52
|
+
const result = spawn(piCommand, args, { stdio: "inherit" });
|
|
53
|
+
if (result.error) {
|
|
54
|
+
stderr.write(`Failed to run Pi for ${packageName}: ${result.error.message}\n`);
|
|
55
|
+
return 1;
|
|
56
|
+
}
|
|
57
|
+
if (result.status !== 0) {
|
|
58
|
+
return result.status ?? 1;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return 0;
|
|
62
|
+
}
|
|
@@ -30,7 +30,7 @@ import {
|
|
|
30
30
|
type BackgroundWorkRow,
|
|
31
31
|
} from "./shared-navigator.ts";
|
|
32
32
|
import { spawnDetached, type SpawnResult } from "./spawn.ts";
|
|
33
|
-
import { parseRun, resetParseRunCursor, type Usage } from "./parse.ts";
|
|
33
|
+
import { parseRun, resetParseRunCursor, tailLog, type Usage } from "./parse.ts";
|
|
34
34
|
import { finalizeRun as finalizeRunCore } from "./finalization.ts";
|
|
35
35
|
import { loadConfig, normalizeTools, resolveExtensionPath, SAFE_DEFAULT_TOOLS, SAFE_CLEAN_TOOLS, DEFAULT_MAX_CONCURRENT } from "./config.ts";
|
|
36
36
|
import { resolveExtensions, extensionArgs } from "./extensions.ts";
|
|
@@ -659,8 +659,7 @@ function isTerminalNavigatorStatus(status: string): boolean {
|
|
|
659
659
|
}
|
|
660
660
|
|
|
661
661
|
/** Live detail snapshot for one run (registry + log parse + health). */
|
|
662
|
-
function navigatorDetail(id: string) {
|
|
663
|
-
const now = Date.now();
|
|
662
|
+
function navigatorDetail(id: string, now: number = Date.now()) {
|
|
664
663
|
return buildNavigatorDetail(id, {
|
|
665
664
|
readMeta,
|
|
666
665
|
effectiveStatus,
|
|
@@ -742,9 +741,10 @@ function subagentWorkRows(now: number): BackgroundWorkRow[] {
|
|
|
742
741
|
});
|
|
743
742
|
}
|
|
744
743
|
|
|
745
|
-
function subagentWorkDetail(id: string, now: number): BackgroundWorkDetail | null {
|
|
746
|
-
const detail = navigatorDetail(id);
|
|
744
|
+
function subagentWorkDetail(id: string, now: number, options?: { logTailLines?: number }): BackgroundWorkDetail | null {
|
|
745
|
+
const detail = navigatorDetail(id, now);
|
|
747
746
|
if (!detail) return null;
|
|
747
|
+
const logTailLines = options?.logTailLines ?? 10;
|
|
748
748
|
const metadata = [
|
|
749
749
|
{ label: "provider", value: "Subagents" },
|
|
750
750
|
{ label: "model", value: detail.effort ? `${detail.model} · effort ${detail.effort}` : detail.model },
|
|
@@ -762,7 +762,11 @@ function subagentWorkDetail(id: string, now: number): BackgroundWorkDetail | nul
|
|
|
762
762
|
statusTone: statusTone(detail.status),
|
|
763
763
|
subtitle: detail.currentTool ? `current tool ${detail.currentTool}` : undefined,
|
|
764
764
|
metadata,
|
|
765
|
-
|
|
765
|
+
// The shared navigator refreshes this provider once a second while the
|
|
766
|
+
// detail overlay is open. Read the selected logical tail rows each
|
|
767
|
+
// time so the evidence behaves like `tail -f`, not a single parsed
|
|
768
|
+
// activity/result snapshot.
|
|
769
|
+
evidence: { label: "log tail", text: tailLog(id, logTailLines) },
|
|
766
770
|
footerActions: [detail.status === "running" || detail.status === "orphaned" ? "x stop" : "x dismiss"],
|
|
767
771
|
};
|
|
768
772
|
}
|
|
@@ -775,7 +779,7 @@ function ensureSubagentProvider(): void {
|
|
|
775
779
|
priority: 10,
|
|
776
780
|
visibleCount: () => navigatorRunningCount(),
|
|
777
781
|
listRows: (now) => subagentWorkRows(now),
|
|
778
|
-
detail: (id, now) => subagentWorkDetail(id, now),
|
|
782
|
+
detail: (id, now, options) => subagentWorkDetail(id, now, options),
|
|
779
783
|
armCloseLabel: (row) => row.status === "running" || row.status === "orphaned" ? "x again to stop" : "x again to dismiss",
|
|
780
784
|
close: (id) => {
|
|
781
785
|
const outcome = navigatorCloseRun(id) as { action: string; id: string; status?: string };
|
|
@@ -26,7 +26,7 @@ import {
|
|
|
26
26
|
readSync,
|
|
27
27
|
statSync,
|
|
28
28
|
} from "node:fs";
|
|
29
|
-
import { readBoundedTail } from "./shared-log-utils.ts";
|
|
29
|
+
import { readBoundedTail, tailTerminalDisplay } from "./shared-log-utils.ts";
|
|
30
30
|
import { readAppendedLines, type LogCursor } from "./log-cursor.ts";
|
|
31
31
|
import { logPathFor } from "./registry.ts";
|
|
32
32
|
|
|
@@ -89,13 +89,11 @@ interface TailRead {
|
|
|
89
89
|
*/
|
|
90
90
|
const readTail: (path: string, maxBytes: number) => TailRead = readBoundedTail;
|
|
91
91
|
|
|
92
|
-
/** Last `n`
|
|
92
|
+
/** Last `n` terminal display rows of a run's log, or a placeholder if empty/unreadable. */
|
|
93
93
|
export function tailLog(id: string, n: number, maxBytes = maxRawTailBytes()): string {
|
|
94
94
|
const tail = readTail(logPathFor(id), maxBytes);
|
|
95
95
|
if (tail.error || tail.text.trim() === "") return "(no output yet)";
|
|
96
|
-
const
|
|
97
|
-
const kept = lines.slice(Math.max(0, lines.length - n));
|
|
98
|
-
const out = kept.join("\n").trim();
|
|
96
|
+
const out = tailTerminalDisplay(tail.text, n).trim();
|
|
99
97
|
return out === "" ? "(no output yet)" : out;
|
|
100
98
|
}
|
|
101
99
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-better-harness",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.12",
|
|
4
4
|
"description": "Pi extension bundle for subagents, durable background tasks, and goal tracking.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -14,9 +14,9 @@
|
|
|
14
14
|
],
|
|
15
15
|
"pi": {
|
|
16
16
|
"extensions": [
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
-
"
|
|
17
|
+
"extensions/subagents/index.ts",
|
|
18
|
+
"extensions/background-tasks/index.ts",
|
|
19
|
+
"extensions/goal/index.ts"
|
|
20
20
|
],
|
|
21
21
|
"image": "https://raw.githubusercontent.com/1aboveio/pi-better-harness/main/docs/images/package-gallery/pi-better-harness.png"
|
|
22
22
|
},
|
|
@@ -29,16 +29,23 @@
|
|
|
29
29
|
"url": "https://github.com/1aboveio/pi-better-harness/issues"
|
|
30
30
|
},
|
|
31
31
|
"homepage": "https://github.com/1aboveio/pi-better-harness/tree/main/packages/pi-better-harness#readme",
|
|
32
|
+
"bin": {
|
|
33
|
+
"pi-better-harness": "./bin/pi-better-harness.mjs"
|
|
34
|
+
},
|
|
32
35
|
"files": [
|
|
33
|
-
"README.md"
|
|
36
|
+
"README.md",
|
|
37
|
+
"bin/*.mjs",
|
|
38
|
+
"lib/*.mjs",
|
|
39
|
+
"extensions/**/*.ts"
|
|
34
40
|
],
|
|
35
41
|
"scripts": {
|
|
36
|
-
"prepack": "node ../../scripts/stage-harness-dependencies.mjs"
|
|
42
|
+
"prepack": "node ../../scripts/stage-harness-dependencies.mjs",
|
|
43
|
+
"test": "node --test test/*.test.mjs"
|
|
37
44
|
},
|
|
38
45
|
"dependencies": {
|
|
39
|
-
"pi-better-background-tasks": "0.1.
|
|
40
|
-
"pi-better-goal": "0.1.
|
|
41
|
-
"pi-better-subagents": "0.1.
|
|
46
|
+
"pi-better-background-tasks": "0.1.12",
|
|
47
|
+
"pi-better-goal": "0.1.12",
|
|
48
|
+
"pi-better-subagents": "0.1.12"
|
|
42
49
|
},
|
|
43
50
|
"bundledDependencies": [
|
|
44
51
|
"pi-better-background-tasks",
|