portable-agent-layer 0.73.0 → 0.75.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
CHANGED
|
@@ -97,6 +97,7 @@ pal cli status # check your setup
|
|
|
97
97
|
| `pal cli subagent link <name>` | Install a personal `~/.pal/agents/<name>.md` (merged multi-platform definition) into every installed agent, split per platform |
|
|
98
98
|
| `pal cli subagent doctor <name>` | Evaluate a subagent definition against the authoring best practices (name/file match, per-platform blocks, model/tools/permission shape, shipped-name collision) |
|
|
99
99
|
| `pal cli subagent list` | List the user-authored subagents in `~/.pal/agents/` |
|
|
100
|
+
| `pal cli version` | Print the installed PAL version. `-v` and `--version` do the same |
|
|
100
101
|
|
|
101
102
|
### Target flags
|
|
102
103
|
|
package/package.json
CHANGED
package/src/cli/index.ts
CHANGED
|
@@ -17,12 +17,13 @@
|
|
|
17
17
|
* doctor Check prerequisites and system health
|
|
18
18
|
* usage Summarize token usage and cost
|
|
19
19
|
* ledger <sub> [filters] Query the action ledger (log · show · stats)
|
|
20
|
-
* server start|stop|status
|
|
20
|
+
* server start|stop|restart|status The control room, a local page over ~/.pal
|
|
21
21
|
* skill link <name> Link a personal ~/.pal/skills/<name>/ into installed agents
|
|
22
22
|
* skill doctor <name|--all> Evaluate one skill, or every installed skill, against the authoring best practices
|
|
23
23
|
* subagent link <name> Install a personal ~/.pal/agents/<name>.md into installed agents
|
|
24
24
|
* subagent doctor <name> Evaluate a subagent against the authoring best practices
|
|
25
25
|
* debug [on|off] Enable / disable verbose hook debug logging
|
|
26
|
+
* version | -v Print the installed PAL version
|
|
26
27
|
*/
|
|
27
28
|
|
|
28
29
|
import { spawnSync } from "node:child_process";
|
|
@@ -280,6 +281,11 @@ async function runCli(command: string | undefined, args: string[]) {
|
|
|
280
281
|
case "debug":
|
|
281
282
|
cliDebug(args);
|
|
282
283
|
break;
|
|
284
|
+
case "version":
|
|
285
|
+
case "-v":
|
|
286
|
+
case "--version":
|
|
287
|
+
showVersion();
|
|
288
|
+
break;
|
|
283
289
|
case "--help":
|
|
284
290
|
case "-h":
|
|
285
291
|
case "help":
|
|
@@ -342,7 +348,7 @@ function showHelp() {
|
|
|
342
348
|
(search · graph · stats · hubs · find · show · add · ls)
|
|
343
349
|
pal cli ledger <sub> [filters] Query the action ledger (log · show · stats)
|
|
344
350
|
e.g. ledger log --project X --since 7d
|
|
345
|
-
pal cli server start|stop|status
|
|
351
|
+
pal cli server start|stop|restart|status The control room: a local page to open before a terminal
|
|
346
352
|
pal cli skill link <name> Link a personal ~/.pal/skills/<name>/ into installed agents
|
|
347
353
|
pal cli skill doctor <name|--all> Evaluate one skill, or every installed skill
|
|
348
354
|
pal cli skill author-model Print the flagship model that authors skills for the active agent
|
|
@@ -351,6 +357,7 @@ function showHelp() {
|
|
|
351
357
|
pal cli subagent list List the user-authored subagents in ~/.pal/agents/
|
|
352
358
|
pal cli subagent author-model Print the flagship model that authors subagents for the active agent
|
|
353
359
|
pal cli debug [on|off] Enable/disable verbose hook debug logging (persisted)
|
|
360
|
+
pal cli version | -v Print the installed PAL version
|
|
354
361
|
|
|
355
362
|
Environment:
|
|
356
363
|
PAL_HOME Override user state directory (default: ~/.pal or repo root)
|
|
@@ -1287,9 +1294,28 @@ async function install(targets: Targets) {
|
|
|
1287
1294
|
`Shared: ${indexedSkills} skills indexed · ${palDocsCount} docs → ~/.pal/docs/ · AGENTS.md + context digests written`
|
|
1288
1295
|
);
|
|
1289
1296
|
|
|
1297
|
+
await refreshControlRoom();
|
|
1298
|
+
|
|
1290
1299
|
log.success("Done. Existing config was preserved — only new entries were added.");
|
|
1291
1300
|
}
|
|
1292
1301
|
|
|
1302
|
+
/**
|
|
1303
|
+
* A published install carries the page in its tarball; a checkout does not —
|
|
1304
|
+
* ui/dist is gitignored, so a pull leaves whatever was built last. Rebuild
|
|
1305
|
+
* there, then replace the process, because the API is the running code.
|
|
1306
|
+
*/
|
|
1307
|
+
async function refreshControlRoom(): Promise<void> {
|
|
1308
|
+
const { isRepoMode } = await import("../hooks/handlers/update-check");
|
|
1309
|
+
const { buildPage } = await import("../tools/control-room/static");
|
|
1310
|
+
if (isRepoMode() && !buildPage()) {
|
|
1311
|
+
log.warn("Control room page could not be rebuilt — run: bun run build:ui");
|
|
1312
|
+
return;
|
|
1313
|
+
}
|
|
1314
|
+
|
|
1315
|
+
const { restartIfRunning } = await import("./server");
|
|
1316
|
+
if (await restartIfRunning()) log.success("Control room restarted on the new build");
|
|
1317
|
+
}
|
|
1318
|
+
|
|
1293
1319
|
async function uninstall(args: string[]) {
|
|
1294
1320
|
const targets = parseTargets(args);
|
|
1295
1321
|
|
|
@@ -1598,21 +1624,29 @@ function cliDebug(args: string[]) {
|
|
|
1598
1624
|
}
|
|
1599
1625
|
}
|
|
1600
1626
|
|
|
1601
|
-
|
|
1602
|
-
const home = palHome();
|
|
1603
|
-
const pkg = palPkg();
|
|
1604
|
-
|
|
1605
|
-
let pkgJson: { version: string };
|
|
1627
|
+
function packageVersion(): string {
|
|
1606
1628
|
try {
|
|
1607
|
-
pkgJson = JSON.parse(
|
|
1629
|
+
const pkgJson = JSON.parse(
|
|
1630
|
+
readFileSync(resolve(palPkg(), "package.json"), "utf-8")
|
|
1631
|
+
) as {
|
|
1608
1632
|
version: string;
|
|
1609
1633
|
};
|
|
1634
|
+
return pkgJson.version;
|
|
1610
1635
|
} catch (e) {
|
|
1611
1636
|
throw new Error(`Failed to read package.json: ${e}`);
|
|
1612
1637
|
}
|
|
1638
|
+
}
|
|
1639
|
+
|
|
1640
|
+
function showVersion() {
|
|
1641
|
+
console.log(packageVersion());
|
|
1642
|
+
}
|
|
1643
|
+
|
|
1644
|
+
async function status() {
|
|
1645
|
+
const home = palHome();
|
|
1646
|
+
const pkg = palPkg();
|
|
1613
1647
|
|
|
1614
1648
|
console.log("");
|
|
1615
|
-
log.info(`Version: ${
|
|
1649
|
+
log.info(`Version: ${packageVersion()}`);
|
|
1616
1650
|
log.info(`Package: ${pkg}`);
|
|
1617
1651
|
log.info(`Home: ${home}`);
|
|
1618
1652
|
console.log("");
|
package/src/cli/server.ts
CHANGED
|
@@ -37,6 +37,8 @@ export async function runServer(args: string[]): Promise<number> {
|
|
|
37
37
|
return cmdStart(rest);
|
|
38
38
|
case "stop":
|
|
39
39
|
return cmdStop();
|
|
40
|
+
case "restart":
|
|
41
|
+
return cmdRestart();
|
|
40
42
|
case "status":
|
|
41
43
|
return cmdStatus();
|
|
42
44
|
case undefined:
|
|
@@ -60,6 +62,7 @@ function showHelp(): void {
|
|
|
60
62
|
Subcommands:
|
|
61
63
|
start [--port <n>] Start the control room in the background (default port ${DEFAULT_PORT})
|
|
62
64
|
stop Stop it
|
|
65
|
+
restart Replace a running one — the API only changes when the process does
|
|
63
66
|
status Show whether it is running, and where
|
|
64
67
|
|
|
65
68
|
The page listens on ${LOOPBACK} only.
|
|
@@ -156,6 +159,29 @@ async function cmdStart(args: string[]): Promise<number> {
|
|
|
156
159
|
return 0;
|
|
157
160
|
}
|
|
158
161
|
|
|
162
|
+
/**
|
|
163
|
+
* The page is read off disk per request, so a rebuilt dist reaches the browser
|
|
164
|
+
* on the next reload — but the API routes are the running process's own code,
|
|
165
|
+
* and those only change when the process does.
|
|
166
|
+
*/
|
|
167
|
+
async function cmdRestart(): Promise<number> {
|
|
168
|
+
const running = await runningServer();
|
|
169
|
+
if (!running) {
|
|
170
|
+
console.log("Not running — nothing to restart. Use `start`.");
|
|
171
|
+
return 0;
|
|
172
|
+
}
|
|
173
|
+
await cmdStop();
|
|
174
|
+
return cmdStart(["--port", String(running.port)]);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Used by `pal cli install`: an install that leaves an old build answering on
|
|
179
|
+
* the port has not finished. A server nobody started stays unstarted.
|
|
180
|
+
*/
|
|
181
|
+
export async function restartIfRunning(): Promise<boolean> {
|
|
182
|
+
return (await runningServer()) !== null && (await cmdRestart()) === 0;
|
|
183
|
+
}
|
|
184
|
+
|
|
159
185
|
/** The state file is a claim; the process answering on that port is the fact. */
|
|
160
186
|
async function runningServer(): Promise<ServerState | null> {
|
|
161
187
|
const state = readState();
|
|
@@ -18,15 +18,26 @@
|
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
20
|
import { spawn } from "node:child_process";
|
|
21
|
+
import { getActiveAgent } from "./agent";
|
|
21
22
|
import { logDebug, logError } from "./log";
|
|
22
23
|
|
|
24
|
+
/**
|
|
25
|
+
* A hook run by Cursor, Copilot or Codex knows its agent only from the
|
|
26
|
+
* `--agent=` flag its own config put on the command line, and argv does not
|
|
27
|
+
* cross a spawn. Re-declaring it here is what stops the child from taking the
|
|
28
|
+
* "claude" default and spawning the wrong CLI for its inference.
|
|
29
|
+
*/
|
|
30
|
+
function withAgentDeclaration(args: string[]): string[] {
|
|
31
|
+
return [...args, `--agent=${getActiveAgent()}`];
|
|
32
|
+
}
|
|
33
|
+
|
|
23
34
|
export function spawnDetachedInference(
|
|
24
35
|
scriptPath: string,
|
|
25
36
|
args: string[],
|
|
26
37
|
scope: string
|
|
27
38
|
): void {
|
|
28
39
|
try {
|
|
29
|
-
const child = spawn("bun", [scriptPath, ...args], {
|
|
40
|
+
const child = spawn("bun", [scriptPath, ...withAgentDeclaration(args)], {
|
|
30
41
|
detached: true,
|
|
31
42
|
stdio: "ignore",
|
|
32
43
|
env: { ...process.env, CLAUDECODE: undefined },
|
|
@@ -24,6 +24,14 @@ export const WATCHED_PATHS = [
|
|
|
24
24
|
"assets/agents",
|
|
25
25
|
];
|
|
26
26
|
|
|
27
|
+
/**
|
|
28
|
+
* A flag spelling of a command the README documents under its canonical name,
|
|
29
|
+
* or the `cli` prefix the dispatcher consumes before a command is ever named.
|
|
30
|
+
*/
|
|
31
|
+
function isAliasOrInternalRoute(cmd: string): boolean {
|
|
32
|
+
return ["--help", "-h", "help", "-v", "--version", "cli"].includes(cmd);
|
|
33
|
+
}
|
|
34
|
+
|
|
27
35
|
/** Extract CLI command names from the switch statement in index.ts */
|
|
28
36
|
function extractCliCommands(): string[] {
|
|
29
37
|
const pkg = palPkg();
|
|
@@ -36,8 +44,7 @@ function extractCliCommands(): string[] {
|
|
|
36
44
|
|
|
37
45
|
for (const match of matches) {
|
|
38
46
|
const cmd = match[1];
|
|
39
|
-
|
|
40
|
-
if (["--help", "-h", "help", "cli"].includes(cmd)) continue;
|
|
47
|
+
if (isAliasOrInternalRoute(cmd)) continue;
|
|
41
48
|
commands.push(cmd);
|
|
42
49
|
}
|
|
43
50
|
|