portable-agent-layer 0.75.0 → 0.76.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.
Files changed (56) hide show
  1. package/assets/agents/gemini-researcher.md +1 -1
  2. package/assets/agents/grok-researcher.md +3 -3
  3. package/assets/agents/perplexity-researcher.md +1 -1
  4. package/assets/skills/analyze-pdf/SKILL.md +2 -2
  5. package/assets/skills/analyze-youtube/SKILL.md +1 -1
  6. package/assets/skills/consulting-report/SKILL.md +5 -5
  7. package/assets/skills/consulting-report/tools/dev.ts +1 -1
  8. package/assets/skills/consulting-report/tools/generate-pdf.ts +1 -1
  9. package/assets/skills/consulting-report/tools/scaffold.ts +2 -2
  10. package/assets/skills/create-pdf/SKILL.md +3 -3
  11. package/assets/skills/create-pdf/tools/md-to-html-pdf.ts +1 -1
  12. package/assets/skills/fyzz-chat-api/SKILL.md +3 -3
  13. package/assets/skills/onboarding/SKILL.md +1 -1
  14. package/assets/skills/pal-analyze/SKILL.md +1 -1
  15. package/assets/skills/pal-reflect/SKILL.md +2 -2
  16. package/assets/skills/playwright/SKILL.md +1 -1
  17. package/assets/skills/playwright/tools/shot.ts +1 -1
  18. package/assets/skills/presentation/README.md +3 -3
  19. package/assets/skills/presentation/SKILL.md +8 -8
  20. package/assets/skills/presentation/template/README.md +1 -1
  21. package/assets/skills/presentation/tools/new-deck.ts +1 -1
  22. package/assets/skills/presentation/tools/setup-template.ts +1 -1
  23. package/assets/skills/projects/SKILL.md +17 -8
  24. package/assets/skills/telos/SKILL.md +1 -1
  25. package/assets/templates/AGENTS.md.template +1 -1
  26. package/assets/templates/PAL/ALGORITHM.md +18 -18
  27. package/assets/templates/PAL/PROJECT_LIFECYCLE.md +1 -1
  28. package/assets/templates/PAL/WORK_TRACKING.md +1 -1
  29. package/assets/templates/rules.codex.rules +65 -0
  30. package/assets/templates/settings.claude.json +11 -1
  31. package/package.json +1 -1
  32. package/src/cli/builtin-tools.ts +30 -0
  33. package/src/cli/index.ts +17 -9
  34. package/src/cli/knowledge.ts +2 -1
  35. package/src/cli/skill.ts +56 -4
  36. package/src/cli/subagent.ts +1 -1
  37. package/src/hooks/lib/agent.ts +34 -3
  38. package/src/hooks/lib/bindings.ts +2 -2
  39. package/src/hooks/lib/context.ts +2 -4
  40. package/src/hooks/lib/paths.ts +48 -8
  41. package/src/hooks/lib/projects.ts +1 -1
  42. package/src/hooks/lib/which.ts +19 -12
  43. package/src/tools/agent/algorithm-reflect.ts +3 -2
  44. package/src/tools/agent/algorithm-synthesize.ts +5 -2
  45. package/src/tools/agent/analyze.ts +2 -1
  46. package/src/tools/agent/handoff-note.ts +7 -6
  47. package/src/tools/agent/project.ts +21 -20
  48. package/src/tools/agent/relationship-note.ts +11 -8
  49. package/src/tools/agent/synthesize.ts +4 -3
  50. package/src/tools/agent/thread.ts +6 -5
  51. package/src/tools/agent/wisdom-frame.ts +3 -2
  52. package/src/tools/lib/script-args.ts +4 -0
  53. package/src/tools/lib/skill-doctor.ts +2 -2
  54. package/src/tools/self-model.ts +1 -1
  55. package/src/tools/skill-doctor.ts +1 -1
  56. package/src/tools/subagent-doctor.ts +4 -4
@@ -6,8 +6,8 @@
6
6
  * Written by Claude in-session — no inference call needed.
7
7
  *
8
8
  * Usage:
9
- * bun ~/.pal/tools/handoff-note.ts --title "what we were doing" --text "what remains + next steps"
10
- * bun ~/.pal/tools/handoff-note.ts --done # mark completed, suppress next-session injection
9
+ * pal cli handoff-note --title "what we were doing" --text "what remains + next steps"
10
+ * pal cli handoff-note --done # mark completed, suppress next-session injection
11
11
  */
12
12
 
13
13
  import { writeFileSync } from "node:fs";
@@ -20,13 +20,14 @@ import {
20
20
  recordNote,
21
21
  statusOf,
22
22
  } from "../lib/handoff-note";
23
+ import { scriptArgs } from "../lib/script-args";
23
24
 
24
25
  const HELP = `
25
26
  HandoffNote — Write a handoff note for the current project
26
27
 
27
28
  Usage:
28
- bun ~/.pal/tools/handoff-note.ts --title "what we were doing" --text "what remains"
29
- bun ~/.pal/tools/handoff-note.ts --done # mark session completed
29
+ pal cli handoff-note --title "what we were doing" --text "what remains"
30
+ pal cli handoff-note --done # mark session completed
30
31
 
31
32
  Arguments:
32
33
  --title Brief title of what was being worked on (5-10 words)
@@ -44,9 +45,9 @@ function saveNote(note: NoteInput): void {
44
45
  emit.receipt(file, { status: statusOf(note), entries: Object.keys(store).length });
45
46
  }
46
47
 
47
- function run() {
48
+ export function run(argv: string[] = scriptArgs()) {
48
49
  const { values } = parseArgs({
49
- args: Bun.argv.slice(2),
50
+ args: argv,
50
51
  options: {
51
52
  title: { type: "string" },
52
53
  text: { type: "string" },
@@ -6,27 +6,27 @@
6
6
  * Frontmatter holds operational state; body holds ISA spec sections.
7
7
  *
8
8
  * Usage:
9
- * bun ~/.pal/tools/project.ts list
10
- * bun ~/.pal/tools/project.ts create [name] [--path PATH] [--objectives "..."] [--serves goal|revenue|fun]
11
- * bun ~/.pal/tools/project.ts serves <name> <goal|revenue|fun> [note]
12
- * bun ~/.pal/tools/project.ts resume <name>
13
- * bun ~/.pal/tools/project.ts complete | archive | pause | unpause <name>
14
- * bun ~/.pal/tools/project.ts add-next <name> "text"
15
- * bun ~/.pal/tools/project.ts add-blocker <name> "text"
16
- * bun ~/.pal/tools/project.ts add-decision <name> "decision" "rationale"
17
- * bun ~/.pal/tools/project.ts add-handoff <name> "text"
18
- * bun ~/.pal/tools/project.ts rm-next | rm-blocker <name> <index>
19
- * bun ~/.pal/tools/project.ts update-section <name> <section> "content"
20
- * bun ~/.pal/tools/project.ts criteria <name>
21
- * bun ~/.pal/tools/project.ts isa-init <name>
22
- * bun ~/.pal/tools/project.ts migrate
9
+ * pal cli project list
10
+ * pal cli project create [name] [--path PATH] [--objectives "..."] [--serves goal|revenue|fun]
11
+ * pal cli project serves <name> <goal|revenue|fun> [note]
12
+ * pal cli project resume <name>
13
+ * pal cli project complete | archive | pause | unpause <name>
14
+ * pal cli project add-next <name> "text"
15
+ * pal cli project add-blocker <name> "text"
16
+ * pal cli project add-decision <name> "decision" "rationale"
17
+ * pal cli project add-handoff <name> "text"
18
+ * pal cli project rm-next | rm-blocker <name> <index>
19
+ * pal cli project update-section <name> <section> "content"
20
+ * pal cli project criteria <name>
21
+ * pal cli project isa-init <name>
22
+ * pal cli project migrate
23
23
  */
24
24
 
25
25
  import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from "node:fs";
26
26
  import { resolve } from "node:path";
27
27
  import { parseArgs } from "node:util";
28
28
  import { writeBinding } from "../../hooks/lib/bindings";
29
- import { paths } from "../../hooks/lib/paths";
29
+ import { paths, toPath } from "../../hooks/lib/paths";
30
30
  import {
31
31
  defaultSlug,
32
32
  deleteProject,
@@ -55,6 +55,7 @@ import {
55
55
  selectIscs,
56
56
  taskSlug,
57
57
  } from "../lib/project-isc";
58
+ import { scriptArgs } from "../lib/script-args";
58
59
 
59
60
  function now(): string {
60
61
  return new Date().toISOString();
@@ -106,7 +107,7 @@ function cmdCreate(args: string[]): void {
106
107
  allowPositionals: true,
107
108
  });
108
109
 
109
- const path = resolve(values.path ?? process.cwd());
110
+ const path = toPath(values.path ?? process.cwd());
110
111
  const name = (values.name ?? positionals[0] ?? defaultSlug(path)).trim();
111
112
 
112
113
  if (!/^[a-z0-9_-]+$/.test(name)) {
@@ -271,7 +272,7 @@ function addHandoff(name: string, text: string): void {
271
272
  function cmdSetPath(args: string[]): void {
272
273
  const [name, ...rest] = args;
273
274
  if (!name || rest.length === 0) fail("Usage: set-path <name> <new-path>");
274
- const newPath = resolve(rest.join(" ").trim());
275
+ const newPath = toPath(rest.join(" ").trim());
275
276
  const p = requireProject(name);
276
277
  writeBinding(p.name, newPath);
277
278
  p.updated = now();
@@ -693,8 +694,8 @@ Commands:
693
694
  `);
694
695
  }
695
696
 
696
- function run(): void {
697
- const [cmd, ...rest] = Bun.argv.slice(2);
697
+ export function run(argv: string[] = scriptArgs()): void {
698
+ const [cmd, ...rest] = argv;
698
699
  if (!cmd || cmd === "help" || cmd === "--help" || cmd === "-h") {
699
700
  help();
700
701
  return;
@@ -810,7 +811,7 @@ function run(): void {
810
811
  cmdRm(rest);
811
812
  return;
812
813
  default:
813
- fail(`Unknown command "${cmd}". Run 'project.ts help' for usage.`);
814
+ fail(`Unknown command "${cmd}". Run 'pal cli project help' for usage.`);
814
815
  }
815
816
  }
816
817
 
@@ -6,9 +6,9 @@
6
6
  * the user (O, W) and session diary entries (--b).
7
7
  *
8
8
  * Usage:
9
- * bun ~/.pal/tools/relationship-note.ts --o "User prefers X" --confidence 0.80
10
- * bun ~/.pal/tools/relationship-note.ts --w "User is building X in TypeScript"
11
- * bun ~/.pal/tools/relationship-note.ts --b "Debugged the cache split logic"
9
+ * pal cli relationship-note --o "User prefers X" --confidence 0.80
10
+ * pal cli relationship-note --w "User is building X in TypeScript"
11
+ * pal cli relationship-note --b "Debugged the cache split logic"
12
12
  *
13
13
  * Note types:
14
14
  * --o Opinion/behavioral observation about the user (requires --confidence)
@@ -22,14 +22,15 @@ import { parseArgs } from "node:util";
22
22
  import { appendNotes } from "../../hooks/lib/relationship";
23
23
  import { emit } from "../lib/emit";
24
24
  import { notesFromFlags } from "../lib/note-flags";
25
+ import { scriptArgs } from "../lib/script-args";
25
26
 
26
27
  const HELP = `
27
28
  RelationshipNote — Append W/O/Session entries to today's relationship log
28
29
 
29
30
  Usage:
30
- bun ~/.pal/tools/relationship-note.ts --o "User prefers X" --confidence 0.80
31
- bun ~/.pal/tools/relationship-note.ts --w "User is building X in TypeScript"
32
- bun ~/.pal/tools/relationship-note.ts --b "Debugged the cache split logic"
31
+ pal cli relationship-note --o "User prefers X" --confidence 0.80
32
+ pal cli relationship-note --w "User is building X in TypeScript"
33
+ pal cli relationship-note --b "Debugged the cache split logic"
33
34
 
34
35
  Flags:
35
36
  --o TEXT Opinion/behavioral observation about the user
@@ -42,9 +43,9 @@ Multiple flags may be combined in one call. At least one of --o, --w, --b is req
42
43
  Output: appends to memory/relationship/YYYY-MM/YYYY-MM-DD.md
43
44
  `;
44
45
 
45
- if (import.meta.main) {
46
+ export function run(argv: string[] = scriptArgs()) {
46
47
  const { values } = parseArgs({
47
- args: Bun.argv.slice(2),
48
+ args: argv,
48
49
  options: {
49
50
  o: { type: "string", multiple: true },
50
51
  w: { type: "string", multiple: true },
@@ -68,3 +69,5 @@ if (import.meta.main) {
68
69
  const { file, written } = appendNotes(result.notes);
69
70
  emit.receipt(file, { written, deduped: result.notes.length - written });
70
71
  }
72
+
73
+ if (import.meta.main) run();
@@ -7,7 +7,7 @@
7
7
  * reads and formats with behavioral guidance.
8
8
  *
9
9
  * Usage:
10
- * bun ~/.pal/tools/synthesize.ts [--days 7] [--force]
10
+ * pal cli synthesize [--days 7] [--force]
11
11
  *
12
12
  * Guards: skips if last synthesis was < 24h ago (unless --force).
13
13
  * Output: ~/.pal/memory/state/synthesis.json
@@ -17,6 +17,7 @@ import { existsSync, readdirSync, readFileSync, writeFileSync } from "node:fs";
17
17
  import { resolve } from "node:path";
18
18
  import { parseArgs } from "node:util";
19
19
  import { ensureDir, paths } from "../../hooks/lib/paths";
20
+ import { scriptArgs } from "../lib/script-args";
20
21
  import { readJsonl } from "../lib/self-model";
21
22
 
22
23
  // ── Config ──
@@ -303,9 +304,9 @@ export function synthesize(days: number): SynthesisState {
303
304
 
304
305
  // ── CLI ──
305
306
 
306
- function run() {
307
+ export function run(argv: string[] = scriptArgs()) {
307
308
  const { values } = parseArgs({
308
- args: Bun.argv.slice(2),
309
+ args: argv,
309
310
  options: {
310
311
  days: { type: "string", default: "7" },
311
312
  force: { type: "boolean" },
@@ -6,13 +6,14 @@
6
6
  * Stored in memory/state/threads.jsonl as structured records.
7
7
  *
8
8
  * Usage:
9
- * bun ~/.pal/tools/thread.ts --add --title "..." [--context "..."]
10
- * bun ~/.pal/tools/thread.ts --resolve --id <id>
11
- * bun ~/.pal/tools/thread.ts --list [--all]
9
+ * pal cli thread --add --title "..." [--context "..."]
10
+ * pal cli thread --resolve --id <id>
11
+ * pal cli thread --list [--all]
12
12
  */
13
13
 
14
14
  import { parseArgs } from "node:util";
15
15
  import { emit } from "../lib/emit";
16
+ import { scriptArgs } from "../lib/script-args";
16
17
  import {
17
18
  addThread,
18
19
  readThreads,
@@ -59,9 +60,9 @@ function markResolved(id: string | undefined) {
59
60
  emit.receipt(file, { id, status: "resolved", title: resolution.thread.title });
60
61
  }
61
62
 
62
- function run() {
63
+ export function run(argv: string[] = scriptArgs()) {
63
64
  const { values } = parseArgs({
64
- args: Bun.argv.slice(2),
65
+ args: argv,
65
66
  options: {
66
67
  add: { type: "boolean" },
67
68
  resolve: { type: "boolean" },
@@ -20,6 +20,7 @@ import { resolve } from "node:path";
20
20
  import { parseArgs } from "node:util";
21
21
  import { paths } from "../../hooks/lib/paths";
22
22
  import { emit } from "../lib/emit";
23
+ import { scriptArgs } from "../lib/script-args";
23
24
 
24
25
  // ── Types ──
25
26
 
@@ -192,9 +193,9 @@ ${antiPatternEntry}
192
193
 
193
194
  // ── CLI ──
194
195
 
195
- function run() {
196
+ export function run(argv: string[] = scriptArgs()) {
196
197
  const { values } = parseArgs({
197
- args: Bun.argv.slice(2),
198
+ args: argv,
198
199
  options: {
199
200
  domain: { type: "string", short: "d" },
200
201
  observation: { type: "string", short: "o" },
@@ -0,0 +1,4 @@
1
+ /** The arguments a spawned tool was given: argv leads with the runtime and the script path. */
2
+ export function scriptArgs(argv: string[] = process.argv): string[] {
3
+ return argv.slice(2);
4
+ }
@@ -12,7 +12,7 @@
12
12
 
13
13
  import { existsSync, readdirSync, readFileSync } from "node:fs";
14
14
  import { basename, extname, relative, resolve } from "node:path";
15
- import { palHome } from "../../hooks/lib/paths";
15
+ import { palHome, toPath } from "../../hooks/lib/paths";
16
16
  import { declaredTriggers } from "../../hooks/lib/skill-triggers";
17
17
 
18
18
  type Level = "pass" | "warn" | "error";
@@ -449,7 +449,7 @@ export function formatReport(r: DoctorReport): string {
449
449
  * report names the directory the caller meant rather than a guess.
450
450
  */
451
451
  export function resolveSkillDir(arg: string): string {
452
- const asPath = resolve(arg);
452
+ const asPath = toPath(arg);
453
453
  if (existsSync(resolve(asPath, "SKILL.md"))) return asPath;
454
454
  const byName = resolve(palHome(), "skills", arg);
455
455
  if (existsSync(resolve(byName, "SKILL.md"))) return byName;
@@ -9,7 +9,7 @@
9
9
  * ~/.pal/memory/self-model/current.md that is injected at session start.
10
10
  *
11
11
  * Usage:
12
- * bun ~/.pal/tools/self-model.ts [--days 30] [--force] [--dry-run]
12
+ * bun src/tools/self-model.ts [--days 30] [--force] [--dry-run]
13
13
  *
14
14
  * Every decision this makes lives in ./lib/self-model.ts, where the suite
15
15
  * reaches it directly; what stays here is paths, inference and the writes.
@@ -15,7 +15,7 @@ import { formatReport, lintSkill, resolveSkillDir } from "./lib/skill-doctor";
15
15
  if (import.meta.main) {
16
16
  const arg = process.argv[2];
17
17
  if (!arg) {
18
- console.error("Usage: bun src/tools/skill-doctor.ts <skill-dir-or-name>");
18
+ console.error("Usage: pal cli skill doctor <skill-dir-or-name>");
19
19
  process.exit(2);
20
20
  }
21
21
  const report = lintSkill(resolveSkillDir(arg));
@@ -13,7 +13,7 @@
13
13
 
14
14
  import { existsSync, readdirSync, readFileSync } from "node:fs";
15
15
  import { basename, resolve } from "node:path";
16
- import { assets, palHome } from "../hooks/lib/paths";
16
+ import { assets, namesAPath, palHome, toPath } from "../hooks/lib/paths";
17
17
 
18
18
  type Level = "pass" | "warn" | "error";
19
19
 
@@ -396,16 +396,16 @@ export function formatSubagentReport(r: SubagentReport): string {
396
396
 
397
397
  /** Resolve a doctor argument to a subagent .md path (a path, or a name in the store). */
398
398
  export function resolveSubagentFile(arg: string): string {
399
- if (arg.endsWith(".md") && existsSync(resolve(arg))) return resolve(arg);
400
- const direct = resolve(arg);
399
+ const direct = toPath(arg);
401
400
  if (existsSync(direct) && direct.endsWith(".md")) return direct;
401
+ if (namesAPath(arg)) return direct.endsWith(".md") ? direct : `${direct}.md`;
402
402
  return resolve(palHome(), "agents", arg.endsWith(".md") ? arg : `${arg}.md`);
403
403
  }
404
404
 
405
405
  if (import.meta.main) {
406
406
  const arg = process.argv[2];
407
407
  if (!arg) {
408
- console.error("Usage: bun src/tools/subagent-doctor.ts <file-or-name>");
408
+ console.error("Usage: pal cli subagent doctor <file-or-name>");
409
409
  process.exit(2);
410
410
  }
411
411
  const report = lintSubagent(resolveSubagentFile(arg));