portable-agent-layer 0.73.0 → 0.74.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "portable-agent-layer",
3
- "version": "0.73.0",
3
+ "version": "0.74.0",
4
4
  "description": "PAL — Portable Agent Layer: persistent personal context for AI coding assistants",
5
5
  "type": "module",
6
6
  "bin": {
package/src/cli/index.ts CHANGED
@@ -17,7 +17,7 @@
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 The control room, a local page over ~/.pal
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
@@ -342,7 +342,7 @@ function showHelp() {
342
342
  (search · graph · stats · hubs · find · show · add · ls)
343
343
  pal cli ledger <sub> [filters] Query the action ledger (log · show · stats)
344
344
  e.g. ledger log --project X --since 7d
345
- pal cli server start|stop|status The control room: a local page to open before a terminal
345
+ pal cli server start|stop|restart|status The control room: a local page to open before a terminal
346
346
  pal cli skill link <name> Link a personal ~/.pal/skills/<name>/ into installed agents
347
347
  pal cli skill doctor <name|--all> Evaluate one skill, or every installed skill
348
348
  pal cli skill author-model Print the flagship model that authors skills for the active agent
@@ -1287,9 +1287,28 @@ async function install(targets: Targets) {
1287
1287
  `Shared: ${indexedSkills} skills indexed · ${palDocsCount} docs → ~/.pal/docs/ · AGENTS.md + context digests written`
1288
1288
  );
1289
1289
 
1290
+ await refreshControlRoom();
1291
+
1290
1292
  log.success("Done. Existing config was preserved — only new entries were added.");
1291
1293
  }
1292
1294
 
1295
+ /**
1296
+ * A published install carries the page in its tarball; a checkout does not —
1297
+ * ui/dist is gitignored, so a pull leaves whatever was built last. Rebuild
1298
+ * there, then replace the process, because the API is the running code.
1299
+ */
1300
+ async function refreshControlRoom(): Promise<void> {
1301
+ const { isRepoMode } = await import("../hooks/handlers/update-check");
1302
+ const { buildPage } = await import("../tools/control-room/static");
1303
+ if (isRepoMode() && !buildPage()) {
1304
+ log.warn("Control room page could not be rebuilt — run: bun run build:ui");
1305
+ return;
1306
+ }
1307
+
1308
+ const { restartIfRunning } = await import("./server");
1309
+ if (await restartIfRunning()) log.success("Control room restarted on the new build");
1310
+ }
1311
+
1293
1312
  async function uninstall(args: string[]) {
1294
1313
  const targets = parseTargets(args);
1295
1314
 
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();
@@ -46,7 +46,7 @@ function writeCache(cache: UpdateCache): void {
46
46
  }
47
47
  }
48
48
 
49
- function isRepoMode(): boolean {
49
+ export function isRepoMode(): boolean {
50
50
  return existsSync(resolve(palPkg(), ".git"));
51
51
  }
52
52