@osolmaz/pi-workflows 0.8.1 → 0.9.0
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 +19 -0
- package/dist/extension/herdr-viewer.d.ts +50 -0
- package/dist/extension/herdr-viewer.js +314 -0
- package/dist/extension/herdr-viewer.js.map +1 -0
- package/dist/extension/index.js +104 -1
- package/dist/extension/index.js.map +1 -1
- package/dist/extension/widget.d.ts +1 -1
- package/dist/extension/widget.js +15 -6
- package/dist/extension/widget.js.map +1 -1
- package/dist/herdr/constants.d.ts +2 -0
- package/dist/herdr/constants.js +3 -0
- package/dist/herdr/constants.js.map +1 -0
- package/dist/herdr/setup.d.ts +8 -0
- package/dist/herdr/setup.js +78 -0
- package/dist/herdr/setup.js.map +1 -0
- package/dist/viewer/cli.d.ts +1 -0
- package/dist/viewer/cli.js +18 -1
- package/dist/viewer/cli.js.map +1 -1
- package/docs/2026-08-18-herdr-piw-plan.md +73 -0
- package/docs/MONITOR.md +4 -4
- package/docs/tui-viewer.md +14 -0
- package/herdr-plugin.toml +12 -0
- package/package.json +3 -1
- package/plugins/herdr/viewer.mjs +56 -0
- package/skills/monitor/SKILL.md +17 -4
- package/src/extension/herdr-viewer.ts +399 -0
- package/src/extension/index.ts +130 -0
- package/src/extension/widget.ts +23 -5
- package/src/herdr/constants.ts +2 -0
- package/src/herdr/setup.ts +93 -0
- package/src/viewer/cli.ts +20 -1
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { spawnSync, type SpawnSyncReturns } from "node:child_process";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { HERDR_PLUGIN_ID } from "./constants.js";
|
|
5
|
+
|
|
6
|
+
export type HerdrSetupResult = {
|
|
7
|
+
changed: boolean;
|
|
8
|
+
message: string;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
type Spawn = (command: string, args: readonly string[]) => SpawnSyncReturns<string>;
|
|
12
|
+
|
|
13
|
+
export function setupHerdrPlugin(packageRoot: string, spawn: Spawn = runCommand): HerdrSetupResult {
|
|
14
|
+
const root = path.resolve(packageRoot);
|
|
15
|
+
const manifest = path.join(root, "herdr-plugin.toml");
|
|
16
|
+
if (!fs.existsSync(manifest)) {
|
|
17
|
+
throw new Error(`Herdr plugin manifest not found: ${manifest}`);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const listed = spawn("herdr", ["plugin", "list", "--plugin", HERDR_PLUGIN_ID, "--json"]);
|
|
21
|
+
if (listed.error) throw new Error(`Could not run Herdr: ${listed.error.message}`);
|
|
22
|
+
if (listed.status !== 0) {
|
|
23
|
+
throw new Error(`Could not inspect Herdr plugins: ${bounded(listed.stderr || listed.stdout)}`);
|
|
24
|
+
}
|
|
25
|
+
const installed = installedPlugin(listed.stdout);
|
|
26
|
+
if (installed !== undefined) {
|
|
27
|
+
if (path.resolve(installed.root) !== root) {
|
|
28
|
+
throw new Error(
|
|
29
|
+
`Herdr plugin ${HERDR_PLUGIN_ID} is already registered from ${installed.root}. Unlink it before linking ${root}.`,
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
if (installed.enabled) {
|
|
33
|
+
return { changed: false, message: `Herdr plugin ${HERDR_PLUGIN_ID} is already linked.` };
|
|
34
|
+
}
|
|
35
|
+
const enabled = spawn("herdr", ["plugin", "enable", HERDR_PLUGIN_ID]);
|
|
36
|
+
if (enabled.error) throw new Error(`Could not run Herdr: ${enabled.error.message}`);
|
|
37
|
+
if (enabled.status !== 0) {
|
|
38
|
+
throw new Error(
|
|
39
|
+
`Could not enable the Herdr plugin: ${bounded(enabled.stderr || enabled.stdout)}`,
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
return { changed: true, message: `Enabled Herdr plugin ${HERDR_PLUGIN_ID}.` };
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const linked = spawn("herdr", ["plugin", "link", root]);
|
|
46
|
+
if (linked.error) throw new Error(`Could not run Herdr: ${linked.error.message}`);
|
|
47
|
+
if (linked.status !== 0) {
|
|
48
|
+
throw new Error(`Could not link the Herdr plugin: ${bounded(linked.stderr || linked.stdout)}`);
|
|
49
|
+
}
|
|
50
|
+
return { changed: true, message: `Linked Herdr plugin ${HERDR_PLUGIN_ID} from ${root}.` };
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function installedPlugin(stdout: string): { root: string; enabled: boolean } | undefined {
|
|
54
|
+
let value: unknown;
|
|
55
|
+
try {
|
|
56
|
+
value = JSON.parse(stdout) as unknown;
|
|
57
|
+
} catch {
|
|
58
|
+
throw new Error("Herdr returned invalid plugin JSON.");
|
|
59
|
+
}
|
|
60
|
+
if (!isRecord(value) || !isRecord(value.result) || !Array.isArray(value.result.plugins)) {
|
|
61
|
+
throw new Error("Herdr returned an invalid plugin list.");
|
|
62
|
+
}
|
|
63
|
+
for (const plugin of value.result.plugins) {
|
|
64
|
+
if (
|
|
65
|
+
isRecord(plugin) &&
|
|
66
|
+
plugin.plugin_id === HERDR_PLUGIN_ID &&
|
|
67
|
+
typeof plugin.plugin_root === "string" &&
|
|
68
|
+
typeof plugin.enabled === "boolean"
|
|
69
|
+
) {
|
|
70
|
+
return { root: plugin.plugin_root, enabled: plugin.enabled };
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return undefined;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function runCommand(command: string, args: readonly string[]): SpawnSyncReturns<string> {
|
|
77
|
+
return spawnSync(command, [...args], {
|
|
78
|
+
encoding: "utf8",
|
|
79
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function bounded(value: string): string {
|
|
84
|
+
const compact = value
|
|
85
|
+
.replace(/[\r\n\t]+/gu, " ")
|
|
86
|
+
.replace(/ +/gu, " ")
|
|
87
|
+
.trim();
|
|
88
|
+
return compact.length <= 300 ? compact : `${compact.slice(0, 299)}…`;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
92
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
93
|
+
}
|
package/src/viewer/cli.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import fs, { realpathSync } from "node:fs";
|
|
3
3
|
import path from "node:path";
|
|
4
|
-
import { pathToFileURL } from "node:url";
|
|
4
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
5
5
|
import { SqliteControllerStore } from "../controllers/sqlite.js";
|
|
6
6
|
import { projectControllerStoreBaseDir } from "../controllers/store.js";
|
|
7
|
+
import { setupHerdrPlugin } from "../herdr/setup.js";
|
|
7
8
|
import { sanitizeText } from "../render/ansi.js";
|
|
8
9
|
import { listRunBundles, readRunBundle, workflowRunsBaseDir } from "../workflows/store.js";
|
|
9
10
|
import {
|
|
@@ -23,6 +24,7 @@ Usage:
|
|
|
23
24
|
pi-workflows controllers [--controller-dir <dir>]
|
|
24
25
|
pi-workflows controller <controller> <key> [--controller-dir <dir>]
|
|
25
26
|
pi-workflows host [--project <dir>] [-- <extra pi args>]
|
|
27
|
+
pi-workflows herdr setup
|
|
26
28
|
|
|
27
29
|
Commands:
|
|
28
30
|
view Open the live workflow TUI. With --once, print a snapshot.
|
|
@@ -30,6 +32,7 @@ Commands:
|
|
|
30
32
|
controllers List durable controller resources.
|
|
31
33
|
controller Show one resource, its effects, child workflows, and events.
|
|
32
34
|
host Run the always-on workflow host in the foreground.
|
|
35
|
+
herdr Set up the bundled Herdr plugin.
|
|
33
36
|
|
|
34
37
|
Options:
|
|
35
38
|
--dir <runsDir> Runs directory (default: ~/.pi/agent/workflows/runs)
|
|
@@ -43,6 +46,7 @@ export type CliArgs = {
|
|
|
43
46
|
runId?: string;
|
|
44
47
|
controllerName?: string;
|
|
45
48
|
resourceKey?: string;
|
|
49
|
+
herdrAction?: string;
|
|
46
50
|
dir: string;
|
|
47
51
|
controllerDir: string;
|
|
48
52
|
once: boolean;
|
|
@@ -98,6 +102,12 @@ export function parseCliArgs(argv: string[]): CliArgs {
|
|
|
98
102
|
once,
|
|
99
103
|
};
|
|
100
104
|
}
|
|
105
|
+
if (command === "herdr") {
|
|
106
|
+
if (positionals.length !== 1 || positionals[0] !== "setup") {
|
|
107
|
+
throw new Error("herdr requires the setup action");
|
|
108
|
+
}
|
|
109
|
+
return { command, herdrAction: positionals[0], dir, controllerDir, once };
|
|
110
|
+
}
|
|
101
111
|
if (positionals.length > 1) {
|
|
102
112
|
throw new Error(`Unexpected argument: ${positionals[1]}`);
|
|
103
113
|
}
|
|
@@ -229,6 +239,11 @@ export async function main(argv: string[] = process.argv.slice(2)): Promise<numb
|
|
|
229
239
|
if (args.command === "host") {
|
|
230
240
|
return await runHost(args.project ?? process.cwd(), args.piArgs);
|
|
231
241
|
}
|
|
242
|
+
if (args.command === "herdr") {
|
|
243
|
+
const result = setupHerdrPlugin(packageRoot());
|
|
244
|
+
process.stdout.write(`${result.message}\n`);
|
|
245
|
+
return 0;
|
|
246
|
+
}
|
|
232
247
|
if (args.command === "view") {
|
|
233
248
|
if (args.once || !process.stdout.isTTY) {
|
|
234
249
|
await printOnce(args.dir, args.runId);
|
|
@@ -271,6 +286,10 @@ function openControllerStore(controllerDir: string): SqliteControllerStore | und
|
|
|
271
286
|
return new SqliteControllerStore(file, { readOnly: true });
|
|
272
287
|
}
|
|
273
288
|
|
|
289
|
+
function packageRoot(): string {
|
|
290
|
+
return path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../..");
|
|
291
|
+
}
|
|
292
|
+
|
|
274
293
|
function requiredValue(args: string[], option: string): string {
|
|
275
294
|
const value = args.shift();
|
|
276
295
|
if (!value) {
|