portable-agent-layer 0.78.0 → 0.78.1

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
@@ -63,7 +63,7 @@ alias pal="bun run ~/path/to/portable-agent-layer/src/cli/index.ts"
63
63
 
64
64
  ```bash
65
65
  pal cli init # scaffold home, install hooks for all targets
66
- pal # start a Claude session (with session summary on exit)
66
+ pal # start the first installed agent in the terminal
67
67
  pal cli status # check your setup
68
68
  ```
69
69
 
@@ -73,7 +73,7 @@ pal cli status # check your setup
73
73
 
74
74
  | Command | Description |
75
75
  |---------|-------------|
76
- | `pal` | Start a Claude session with session summary on exit |
76
+ | `pal` | Start the first installed agent, in order: Claude Code, Codex, Cursor CLI, Copilot CLI, opencode. Claude sessions print a summary on exit |
77
77
  | `pal cli init` | Scaffold PAL home directory and install hooks |
78
78
  | `pal cli install` | Register hooks/skills for targets |
79
79
  | `pal cli uninstall` | Remove hooks/skills for targets |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "portable-agent-layer",
3
- "version": "0.78.0",
3
+ "version": "0.78.1",
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
@@ -3,7 +3,7 @@
3
3
  * PAL CLI — Portable Agent Layer
4
4
  *
5
5
  * Usage:
6
- * pal [claude-args...] Start a Claude session with session summary on exit
6
+ * pal [agent-args...] Start the first installed agent: claude, codex, cursor-agent, copilot, opencode
7
7
  * pal cli <command> [options] Admin commands
8
8
  *
9
9
  * Admin commands (pal cli ...):
@@ -56,6 +56,7 @@ import { findBinaryOnPath } from "../hooks/lib/which";
56
56
  import { log } from "../targets/lib";
57
57
  import { builtinToolVerbs, runBuiltinTool } from "./builtin-tools";
58
58
  import { checkPendingMigrations } from "./migrate";
59
+ import { findSessionAgent, NO_SESSION_AGENT_MESSAGE } from "./session-agent";
59
60
 
60
61
  const allArgs = process.argv.slice(2);
61
62
 
@@ -109,16 +110,10 @@ function checkCopilot(): ToolCheck {
109
110
  return cli;
110
111
  }
111
112
 
112
- function detectAgent(): string | null {
113
- if (checkTool("claude").available) return "claude";
114
- if (checkTool("opencode").available) return "opencode";
115
- return null;
116
- }
117
-
118
113
  async function session(sessionArgs: string[]) {
119
- const agent = detectAgent();
114
+ const agent = findSessionAgent();
120
115
  if (!agent) {
121
- log.error("No supported agent found. Install Claude Code or opencode.");
116
+ log.error(NO_SESSION_AGENT_MESSAGE);
122
117
  process.exit(1);
123
118
  }
124
119
 
@@ -328,7 +323,7 @@ function pointAtOnboarding(): void {
328
323
  function showHelp() {
329
324
  console.log(`
330
325
  Usage:
331
- pal [claude-args...] Start a Claude session
326
+ pal [agent-args...] Start the first installed agent
332
327
  pal cli <command> [options] Admin commands
333
328
 
334
329
  Admin commands:
@@ -1159,7 +1154,7 @@ function doctor(silent = false): DoctorResult {
1159
1154
 
1160
1155
  if (!hasAgent) {
1161
1156
  console.log("");
1162
- log.error("No supported agent found. Install Claude Code or opencode.");
1157
+ log.error(NO_SESSION_AGENT_MESSAGE);
1163
1158
  }
1164
1159
  console.log("");
1165
1160
  }
@@ -0,0 +1,20 @@
1
+ import { findBinaryOnPath } from "../hooks/lib/which";
2
+
3
+ const SESSION_AGENT_BINARIES = [
4
+ "claude",
5
+ "codex",
6
+ "cursor-agent",
7
+ "copilot",
8
+ "opencode",
9
+ ] as const;
10
+
11
+ export type SessionAgent = (typeof SESSION_AGENT_BINARIES)[number];
12
+
13
+ export function findSessionAgent(): SessionAgent | null {
14
+ return (
15
+ SESSION_AGENT_BINARIES.find((binary) => findBinaryOnPath(binary) !== null) ?? null
16
+ );
17
+ }
18
+
19
+ export const NO_SESSION_AGENT_MESSAGE =
20
+ "No supported agent found. Install Claude Code, Codex, Cursor CLI, Copilot CLI or opencode.";
@@ -349,10 +349,11 @@ export function resolveProjectFromCwd(
349
349
 
350
350
  export function isStale(
351
351
  p: ProjectProgress,
352
- thresholdDays = PROJECT_STALE_DAYS_DEFAULT
352
+ thresholdDays = PROJECT_STALE_DAYS_DEFAULT,
353
+ now: Date = new Date()
353
354
  ): boolean {
354
355
  if (!p.updated) return false;
355
- const age = Date.now() - new Date(p.updated).getTime();
356
+ const age = now.getTime() - new Date(p.updated).getTime();
356
357
  if (!Number.isFinite(age) || age < 0) return false;
357
358
  return age > thresholdDays * 86_400_000;
358
359
  }
@@ -16,6 +16,7 @@ import { loadAnalyzeNudge } from "../../hooks/lib/analyze-nudge";
16
16
  import { paths } from "../../hooks/lib/paths";
17
17
  import {
18
18
  isStale,
19
+ PROJECT_STALE_DAYS_DEFAULT,
19
20
  type ProjectProgress,
20
21
  readAllProjects,
21
22
  type ServesAuthority,
@@ -188,7 +189,7 @@ function toCard(
188
189
  snoozes: Record<string, string>
189
190
  ): ProjectCard {
190
191
  const path = p.path ?? null;
191
- const stale = isStale(p);
192
+ const stale = isStale(p, PROJECT_STALE_DAYS_DEFAULT, now);
192
193
  const history = path ? readProjectHistory(path, 1) : [];
193
194
  const last = history.at(-1);
194
195
  return {