portable-agent-layer 0.75.1 → 0.76.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.
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/migrate.ts +135 -1
  36. package/src/cli/skill.ts +56 -4
  37. package/src/cli/subagent.ts +1 -1
  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 +49 -8
  41. package/src/hooks/lib/projects.ts +1 -1
  42. package/src/hooks/lib/work-tracking.ts +19 -14
  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
@@ -4,8 +4,9 @@
4
4
  */
5
5
 
6
6
  import { appendFileSync, existsSync, readFileSync, writeFileSync } from "node:fs";
7
- import { resolve } from "node:path";
7
+ import { dirname, resolve } from "node:path";
8
8
  import { ensureDir, paths } from "./paths";
9
+ import { defaultSlug, readAllProjects, resolveProjectFromCwd } from "./projects";
9
10
 
10
11
  // ── Session Records ──────────────────────────────────────────────
11
12
 
@@ -146,25 +147,29 @@ interface ProjectHistoryEntry {
146
147
  insights: string;
147
148
  }
148
149
 
149
- /** Convert a cwd path to a filesystem-safe slug (last directory segment) */
150
- function cwdToSlug(cwd: string): string {
151
- const normalized = cwd.replaceAll("\\", "/").replace(/\/+$/, "");
152
- return normalized.split("/").pop() || "unknown";
150
+ /**
151
+ * A directory under `memory/projects/` is what `list`, `resume` and the export
152
+ * read as a project, so only a registered one may own a folder there. Writer and
153
+ * readers share this resolver: keying them apart is what filed a project's
154
+ * history under its parent directory's name.
155
+ */
156
+ function historyFileFor(cwd: string): string {
157
+ const project = resolveProjectFromCwd(cwd, readAllProjects());
158
+ return project
159
+ ? resolve(paths.projectHistory(), project.name, "history.jsonl")
160
+ : resolve(paths.unboundHistory(), `${defaultSlug(cwd)}.jsonl`);
153
161
  }
154
162
 
155
- /** Append a learning entry to the project's history.jsonl */
163
+ /** Append a learning entry to the history file owning this cwd */
156
164
  export function appendProjectHistory(cwd: string, entry: ProjectHistoryEntry): void {
157
- const slug = cwdToSlug(cwd);
158
- const dir = ensureDir(resolve(paths.projectHistory(), slug));
159
- const historyPath = resolve(dir, "history.jsonl");
160
- const line = `${JSON.stringify(entry)}\n`;
161
- appendFileSync(historyPath, line, "utf-8");
165
+ const historyPath = historyFileFor(cwd);
166
+ ensureDir(dirname(historyPath));
167
+ appendFileSync(historyPath, `${JSON.stringify(entry)}\n`, "utf-8");
162
168
  }
163
169
 
164
- /** Read the project history for a given cwd */
170
+ /** Read the session history for a given cwd */
165
171
  export function readProjectHistory(cwd: string, limit = 15): ProjectHistoryEntry[] {
166
- const slug = cwdToSlug(cwd);
167
- const historyPath = resolve(paths.projectHistory(), slug, "history.jsonl");
172
+ const historyPath = historyFileFor(cwd);
168
173
  if (!existsSync(historyPath)) return [];
169
174
  try {
170
175
  const lines = readFileSync(historyPath, "utf-8").trim().split("\n").filter(Boolean);
@@ -18,6 +18,7 @@ import { parseArgs } from "node:util";
18
18
  import { paths } from "../../hooks/lib/paths";
19
19
  import { buildReflection, intOr, reflectionLine } from "../lib/algorithm-reflect";
20
20
  import { emit } from "../lib/emit";
21
+ import { scriptArgs } from "../lib/script-args";
21
22
 
22
23
  const HELP = `
23
24
  AlgorithmReflect — Log algorithm performance after LEARN phase
@@ -45,9 +46,9 @@ function reflectionsPath(): string {
45
46
  return paths.reflectionsFile();
46
47
  }
47
48
 
48
- function run() {
49
+ export function run(argv: string[] = scriptArgs()) {
49
50
  const { values } = parseArgs({
50
- args: Bun.argv.slice(2),
51
+ args: argv,
51
52
  options: {
52
53
  task: { type: "string" },
53
54
  criteria: { type: "string" },
@@ -20,6 +20,7 @@
20
20
  import { parseArgs } from "node:util";
21
21
  import { readReflections } from "../../hooks/lib/learning-store";
22
22
  import { paths } from "../../hooks/lib/paths";
23
+ import { scriptArgs } from "../lib/script-args";
23
24
 
24
25
  /** Algorithm areas a Q2 idea can target, mapped to ALGORITHM.md structure. */
25
26
  const BUCKETS: { key: string; label: string; patterns: RegExp }[] = [
@@ -202,9 +203,9 @@ export function formatAlgorithmReport(s: AlgorithmSynthesis): string {
202
203
  return lines.join("\n");
203
204
  }
204
205
 
205
- if (import.meta.main) {
206
+ export function run(argv: string[] = scriptArgs()) {
206
207
  const { values } = parseArgs({
207
- args: process.argv.slice(2),
208
+ args: argv,
208
209
  options: {
209
210
  since: { type: "string" },
210
211
  json: { type: "boolean", default: false },
@@ -216,3 +217,5 @@ if (import.meta.main) {
216
217
  values.json ? JSON.stringify(result, null, 2) : formatAlgorithmReport(result)
217
218
  );
218
219
  }
220
+
221
+ if (import.meta.main) run();
@@ -14,6 +14,7 @@ import { parseArgs } from "node:util";
14
14
  import { writeLastAnalyzeDate } from "../../hooks/lib/analyze-nudge";
15
15
  import { analyze } from "../../hooks/lib/graduation";
16
16
  import { reportLines } from "../lib/analyze-report";
17
+ import { scriptArgs } from "../lib/script-args";
17
18
 
18
19
  const HELP = `
19
20
  PAL Learning Analysis — unified graduation + ratings report
@@ -36,7 +37,7 @@ const HELP = `
36
37
  Usage: pal cli analyze [--actionable]
37
38
  `;
38
39
 
39
- export async function run(argv: string[] = Bun.argv.slice(2)) {
40
+ export async function run(argv: string[] = scriptArgs()) {
40
41
  const { values } = parseArgs({
41
42
  args: argv,
42
43
  options: {
@@ -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));