@jaybeeuu/agent-cortex 2.1.0 → 2.2.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 (178) hide show
  1. package/CHANGELOG.md +387 -0
  2. package/README.md +33 -13
  3. package/agents/README.md +22 -10
  4. package/agents/plan/agent.md +2 -2
  5. package/agents/ralph/agent.md +126 -88
  6. package/agents/ralph/claude/frontmatter.json +3 -3
  7. package/agents/ralph/claude/wake.md +46 -0
  8. package/agents/ralph/pi/{polling.md → wake.md} +35 -20
  9. package/agents/ralph-plan/agent.md +23 -11
  10. package/bin/agent-cortex.mjs +66 -4
  11. package/bin/installers/claude.mjs +182 -68
  12. package/bin/installers/pi.mjs +200 -24
  13. package/extensions/agent-guardrails/README.md +1 -1
  14. package/extensions/agent-guardrails/guardrails.ts +1 -1
  15. package/extensions/agent-guardrails/index.ts +1 -1
  16. package/extensions/agent-modes/discover.test.ts +2 -2
  17. package/hooks/claude/scripts/notify.mjs +8 -1
  18. package/lib/cli.mjs +91 -2
  19. package/package.json +27 -3
  20. package/scripts/check-changeset.mjs +4 -0
  21. package/scripts/check-no-sync.mjs +5 -1
  22. package/scripts/lib/compose-agent.mjs +69 -9
  23. package/scripts/lib/fs.mjs +10 -2
  24. package/scripts/lib/migrate.mjs +736 -0
  25. package/scripts/lib/release-gates.mjs +21 -1
  26. package/scripts/lib/skill-frontmatter.mjs +23 -6
  27. package/scripts/lib/skill-links.mjs +52 -0
  28. package/scripts/lib/verify-worker-tree.mjs +25 -0
  29. package/scripts/resolve-publish-command.mjs +4 -0
  30. package/skills/engineering/design-an-interface/SKILL.md +3 -3
  31. package/skills/engineering/grill-with-docs/SKILL.md +3 -5
  32. package/skills/engineering/improve-codebase-architecture/SKILL.md +5 -4
  33. package/skills/engineering/tdd/SKILL.md +5 -7
  34. package/skills/engineering/technical-direction/SKILL.md +5 -5
  35. package/skills/planning/classify-bead/REFERENCE.md +3 -3
  36. package/skills/planning/classify-bead/SKILL.md +14 -9
  37. package/skills/planning/classify-bead/scripts/classify-bead.mjs +5 -4
  38. package/skills/planning/create-task/REFERENCE.md +52 -3
  39. package/skills/planning/create-task/SKILL.md +70 -26
  40. package/skills/planning/create-task/scripts/{create-chores.ts → create-chores.mjs} +48 -23
  41. package/skills/planning/flesh-out-idea/REFERENCE.md +116 -0
  42. package/skills/planning/flesh-out-idea/SKILL.md +146 -0
  43. package/skills/planning/prd-to-tasks/REFERENCE.md +54 -5
  44. package/skills/planning/prd-to-tasks/SKILL.md +22 -16
  45. package/skills/planning/record-idea/FORMAT.md +66 -17
  46. package/skills/planning/record-idea/SKILL.md +48 -24
  47. package/skills/planning/request-refactor-plan/SKILL.md +4 -4
  48. package/skills/planning/spec-to-tickets/SKILL.md +5 -5
  49. package/skills/planning/write-a-prd/SKILL.md +8 -9
  50. package/skills/planning/write-a-ticket/SKILL.md +4 -6
  51. package/skills/productivity/bd-tool/SKILL.md +15 -10
  52. package/skills/productivity/grill-me/SKILL.md +5 -0
  53. package/skills/productivity/init-beads/SKILL.md +3 -3
  54. package/skills/productivity/migration/REFERENCE.md +227 -0
  55. package/skills/productivity/migration/SKILL.md +188 -0
  56. package/skills/productivity/validate-agent-dir/scripts/{validate-agent-dir.ts → validate-agent-dir.mjs} +49 -28
  57. package/skills/productivity/write-a-skill/SKILL.md +5 -5
  58. package/skills/review/maintain-agent-docs/SKILL.md +5 -7
  59. package/skills/review/refactor-skill/SKILL.md +4 -3
  60. package/skills/review/review-security/SKILL.md +3 -5
  61. package/skills/style/style-code/SKILL.md +5 -10
  62. package/skills/style/style-comms/SKILL.md +5 -7
  63. package/skills/style/style-documentation/SKILL.md +5 -6
  64. package/skills/style/style-tests/SKILL.md +5 -7
  65. package/skills/workflow/git-workflow/SKILL.md +28 -4
  66. package/skills/workflow/hitl-collab/SKILL.md +4 -6
  67. package/skills/workflow/plan/SKILL.md +41 -30
  68. package/skills/workflow/ralph/REFERENCE.md +182 -51
  69. package/skills/workflow/ralph/SKILL.md +89 -50
  70. package/skills/workflow/run-pipeline-stage/SKILL.md +72 -71
  71. package/skills/workflow/run-pipeline-stage/playbooks/code.md +11 -0
  72. package/skills/workflow/run-pipeline-stage/playbooks/document.md +12 -0
  73. package/skills/workflow/run-pipeline-stage/playbooks/fix.md +12 -0
  74. package/skills/workflow/run-pipeline-stage/playbooks/review.md +11 -0
  75. package/skills/workflow/run-pipeline-stage/playbooks/verify.md +13 -0
  76. package/skills/workflow/run-pipeline-stage/prompts/stage-runner.md +73 -1
  77. package/token-map.README.md +9 -4
  78. package/token-map.json +13 -6
  79. package/.agents/skills/style-versioning/SKILL.md +0 -172
  80. package/.changeset/README.md +0 -8
  81. package/.changeset/config.json +0 -11
  82. package/.github/workflows/ci.yml +0 -302
  83. package/.junie/guidelines.md +0 -87
  84. package/.junie/mcp/mcp.json +0 -10
  85. package/AGENTS.md +0 -153
  86. package/agents/ralph/claude/polling.md +0 -31
  87. package/agents-native/ralph.md +0 -203
  88. package/docs/claude-hooks.md +0 -144
  89. package/docs/commit-signing.md +0 -231
  90. package/docs/ideas/auto-model-selection.md +0 -75
  91. package/docs/ideas/ban-content-assertion-tests.md +0 -75
  92. package/docs/ideas/bead-progress-notes-for-session-resumption.md +0 -75
  93. package/docs/ideas/classify-beads-via-deterministic-script-with-agent-fallback.md +0 -70
  94. package/docs/ideas/ctx-alias-version-and-update-commands.md +0 -65
  95. package/docs/ideas/ctx-feedback-command-for-capturing-ideas-from-any-machine.md +0 -67
  96. package/docs/ideas/dedicated-review-tests-skill.md +0 -71
  97. package/docs/ideas/deployment-beads-for-post-merge-pipelines.md +0 -36
  98. package/docs/ideas/design-and-delivery-as-separate-bead-trees/design-and-delivery-as-separate-bead-trees.md +0 -99
  99. package/docs/ideas/enable-signed-commit-enforcement-changesets-bot-commits-must-be-signed.md +0 -42
  100. package/docs/ideas/extension-manifests.md +0 -121
  101. package/docs/ideas/improve-pi-system-prompt.md +0 -43
  102. package/docs/ideas/map-every-cortex-tool-to-a-real-pi-equivalent.md +0 -95
  103. package/docs/ideas/model-selector.md +0 -40
  104. package/docs/ideas/pi-task-memory.md +0 -34
  105. package/docs/ideas/qa-extension.md +0 -43
  106. package/docs/ideas/record-idea-implementation-questions.md +0 -68
  107. package/docs/ideas/record-ideas-as-beads.md +0 -115
  108. package/docs/ideas/self-flushing-session.md +0 -72
  109. package/docs/ideas/state-in-beads-not-md.md +0 -69
  110. package/docs/ideas/subagent-visibility.md +0 -72
  111. package/docs/ideas/task-session-context.local.md +0 -95
  112. package/docs/ideas/task-session-context.md +0 -89
  113. package/docs/ideas/test-data-creation-helpers.md +0 -92
  114. package/docs/ideas/test-planning-stage-bead-in-feature-planning.md +0 -68
  115. package/docs/ideas/unified-ci-pipeline.md +0 -28
  116. package/docs/ideas/unify-the-ticket-and-task-decomposition-workflows.md +0 -71
  117. package/docs/ideas/worktree-housekeeping-for-closed-beads.md +0 -39
  118. package/docs/inspirations.md +0 -33
  119. package/docs/research/disable-model-invocation.md +0 -82
  120. package/docs/research/gas-city-research.md +0 -256
  121. package/docs/research/skill-design-research.md +0 -286
  122. package/docs/research/skill-improvements-analysis.md +0 -117
  123. package/docs/research/skill-patterns-research.md +0 -24
  124. package/docs/skills/skill-anatomy.md +0 -200
  125. package/docs/technical-direction/harness-config.md +0 -177
  126. package/docs/technical-direction/migration-execution-labels.md +0 -177
  127. package/docs/user-preferences.md +0 -17
  128. package/extensions/agent-guardrails/tsconfig.json +0 -12
  129. package/extensions/agent-modes/tsconfig.json +0 -12
  130. package/extensions/output-style/tsconfig.json +0 -12
  131. package/extensions/session-start/tsconfig.json +0 -12
  132. package/extensions/skill-stats/pnpm-lock.yaml +0 -329
  133. package/extensions/skill-stats/tsconfig.json +0 -12
  134. package/extensions/subagent/agents/planner.md +0 -37
  135. package/extensions/subagent/agents/reviewer.md +0 -35
  136. package/extensions/subagent/agents/scout.md +0 -50
  137. package/extensions/subagent/agents/worker.md +0 -24
  138. package/extensions/subagent/prompts/implement-and-review.md +0 -10
  139. package/extensions/subagent/prompts/implement.md +0 -10
  140. package/extensions/subagent/prompts/scout-and-plan.md +0 -9
  141. package/extensions/subagent/tsconfig.json +0 -12
  142. package/pi/keybindings.json +0 -3
  143. package/pi/settings.json +0 -34
  144. package/pnpm-workspace.yaml +0 -14
  145. package/skills/planning/create-task/scripts/package.json +0 -14
  146. package/skills/planning/create-task/scripts/pnpm-lock.yaml +0 -342
  147. package/skills/planning/create-task/scripts/tsconfig.json +0 -12
  148. package/skills/planning/record-idea/scripts/new-idea.sh +0 -89
  149. package/skills/productivity/validate-agent-dir/scripts/package.json +0 -15
  150. package/skills/productivity/validate-agent-dir/scripts/pnpm-lock.yaml +0 -329
  151. package/skills/productivity/validate-agent-dir/scripts/pnpm-workspace.yaml +0 -2
  152. package/skills/productivity/validate-agent-dir/scripts/tsconfig.json +0 -19
  153. package/skills/productivity/validate-agent-dir/scripts/validate-agent-dir.test.ts +0 -317
  154. package/skills/workflow/run-pipeline-stage/REFERENCE.md +0 -22
  155. package/skills/workflow/run-pipeline-stage/scripts/generate-progress.test.ts +0 -682
  156. package/skills/workflow/run-pipeline-stage/scripts/generate-progress.ts +0 -588
  157. package/skills/workflow/run-pipeline-stage/scripts/package.json +0 -15
  158. package/skills/workflow/run-pipeline-stage/scripts/pnpm-lock.yaml +0 -342
  159. package/skills/workflow/run-pipeline-stage/scripts/pnpm-workspace.yaml +0 -2
  160. package/skills/workflow/run-pipeline-stage/scripts/tsconfig.json +0 -12
  161. package/test/classify-bead.test.mjs +0 -277
  162. package/test/claude-installer.test.mjs +0 -308
  163. package/test/cli.test.mjs +0 -314
  164. package/test/create-chores.test.mjs +0 -85
  165. package/test/fake-bd.test.mjs +0 -72
  166. package/test/fs.test.mjs +0 -76
  167. package/test/helpers/fake-bd.mjs +0 -87
  168. package/test/helpers/fake-claude.mjs +0 -152
  169. package/test/helpers/fake-pi.mjs +0 -132
  170. package/test/installer.test.mjs +0 -806
  171. package/test/notify-hook.test.mjs +0 -63
  172. package/test/pending-gates.test.mjs +0 -147
  173. package/test/pi-installer.test.mjs +0 -785
  174. package/test/pi-register.test.mjs +0 -342
  175. package/test/pi-sweep.test.mjs +0 -619
  176. package/test/release-gates.test.mjs +0 -190
  177. package/test/skill-frontmatter.test.mjs +0 -137
  178. package/test/verify-worker-tree.test.mjs +0 -120
package/lib/cli.mjs CHANGED
@@ -1,9 +1,28 @@
1
+ /**
2
+ * Result of parsing the CLI argv. Every branch returns `command`; the rest are
3
+ * populated only for the commands that accept them.
4
+ * @typedef {object} ParsedArgs
5
+ * @property {"help" | "version" | "install" | "migrate" | "unknown"} command
6
+ * @property {string | null} [harness]
7
+ * @property {string} [name]
8
+ * @property {string} [optionError]
9
+ * @property {boolean} [dryRun]
10
+ * @property {string} [output]
11
+ * @property {string} [pluginRoot]
12
+ * @property {boolean} [requireRegister]
13
+ * @property {boolean} [apply]
14
+ * @property {string} [dir]
15
+ */
16
+
17
+ /** @typedef {{ key: string, boolean?: boolean }} OptionSpec */
18
+
1
19
  const SUPPORTED_HARNESSES = ["claude", "pi"];
2
20
 
3
21
  // Options accepted by `install <harness>`. `--output`/`--dry-run` are shared by
4
22
  // the claude and pi installers; `--plugin-root` is pi-specific. Unknown or
5
23
  // malformed options surface as `optionError` on the parsed result; the CLI
6
24
  // prints them and exits 1.
25
+ /** @type {Record<string, OptionSpec>} */
7
26
  const INSTALL_OPTIONS = {
8
27
  "--dry-run": { key: "dryRun", boolean: true },
9
28
  "--output": { key: "output" },
@@ -11,11 +30,22 @@ const INSTALL_OPTIONS = {
11
30
  "--require-register": { key: "requireRegister", boolean: true },
12
31
  };
13
32
 
33
+ /**
34
+ * Parse the CLI argv.
35
+ * @param {string[]} argv
36
+ * @returns {ParsedArgs}
37
+ */
14
38
  export function parseArgs(argv) {
15
39
  if (argv.length === 0 || argv[0] === "--help" || argv[0] === "-h") {
16
40
  return { command: "help" };
17
41
  }
18
42
 
43
+ // Like `--help`, the version flags are only recognised as the first argument,
44
+ // so they never shadow a command's own options.
45
+ if (argv[0] === "--version" || argv[0] === "-V") {
46
+ return { command: "version" };
47
+ }
48
+
19
49
  const [command, ...rest] = argv;
20
50
 
21
51
  if (command === "install") {
@@ -26,6 +56,7 @@ export function parseArgs(argv) {
26
56
  i = 1;
27
57
  }
28
58
 
59
+ /** @type {Record<string, string | true>} */
29
60
  const options = {};
30
61
  for (; i < rest.length; i++) {
31
62
  const arg = rest[i];
@@ -57,9 +88,54 @@ export function parseArgs(argv) {
57
88
  return { command: "install", harness, ...options };
58
89
  }
59
90
 
91
+ if (command === "migrate") {
92
+ // Dry run is the default, so `--apply` is the only state-changing flag;
93
+ // `--dry-run` stays accepted for scripts that pass it explicitly. `--dir`
94
+ // points the ideas step at a workspace that keeps its idea files elsewhere.
95
+ let sawApply = false;
96
+ let sawDryRun = false;
97
+ /** @type {string | undefined} */
98
+ let dir;
99
+ for (let i = 0; i < rest.length; i++) {
100
+ const arg = rest[i];
101
+ if (arg === "--help" || arg === "-h") return { command: "help" };
102
+ if (arg === "--apply") {
103
+ sawApply = true;
104
+ continue;
105
+ }
106
+ if (arg === "--dry-run") {
107
+ sawDryRun = true;
108
+ continue;
109
+ }
110
+ // Support both `--dir=<path>` and `--dir <path>`, like install's `--output`.
111
+ const inlineDir = arg.startsWith("--dir=") ? arg.slice("--dir=".length) : null;
112
+ if (inlineDir !== null && inlineDir !== "") {
113
+ dir = inlineDir;
114
+ continue;
115
+ }
116
+ if (arg === "--dir" || inlineDir !== null) {
117
+ const value = rest[i + 1];
118
+ if (inlineDir !== null || value == null || value.startsWith("--")) {
119
+ return { command: "migrate", optionError: `Missing value for "--dir". Run "agent-cortex --help" for usage.` };
120
+ }
121
+ dir = value;
122
+ i += 1;
123
+ continue;
124
+ }
125
+ return { command: "migrate", optionError: `Unknown option "${arg}". Run "agent-cortex --help" for usage.` };
126
+ }
127
+ if (sawApply && sawDryRun) {
128
+ return { command: "migrate", optionError: '"--apply" and "--dry-run" are mutually exclusive.' };
129
+ }
130
+ return dir === undefined ? { command: "migrate", apply: sawApply } : { command: "migrate", apply: sawApply, dir };
131
+ }
132
+
60
133
  return { command: "unknown", name: command };
61
134
  }
62
135
 
136
+ /**
137
+ * @returns {string}
138
+ */
63
139
  export function buildHelpText() {
64
140
  return `Usage: agent-cortex <command> [options]
65
141
 
@@ -125,11 +201,24 @@ Commands:
125
201
  cannot register the staged package
126
202
  (missing from PATH); default warns and
127
203
  prints the manual commands
128
- --help, -h Show this help text`;
204
+ migrate Migrate the current beads workspace to the latest
205
+ agent-cortex migration version, applying versioned steps
206
+ in order (repo-agnostic — works in any beads workspace)
207
+ Options:
208
+ (no option) Dry run — print the pending plan, write nothing
209
+ --apply Apply every pending step, verifying each
210
+ --dir <path> Read idea files from <path> instead of
211
+ docs/ideas (step v2's source)
212
+ --help, -h Show this help text
213
+ --version, -V Print the package version`;
129
214
  }
130
215
 
216
+ /**
217
+ * @param {string | null | undefined} harness
218
+ * @returns {{ ok: true } | { ok: false, error: string }}
219
+ */
131
220
  export function validateHarness(harness) {
132
- if (harness === null) {
221
+ if (harness === null || harness === undefined) {
133
222
  return {
134
223
  ok: false,
135
224
  error: `Missing harness argument. Supported harnesses: ${SUPPORTED_HARNESSES.join(", ")}`,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jaybeeuu/agent-cortex",
3
- "version": "2.1.0",
3
+ "version": "2.2.0",
4
4
  "description": "Personal PI package with custom agents, skills, and extensions",
5
5
  "keywords": [
6
6
  "pi-package"
@@ -13,12 +13,35 @@
13
13
  "bin": {
14
14
  "agent-cortex": "./bin/agent-cortex.mjs"
15
15
  },
16
+ "files": [
17
+ "bin/",
18
+ "lib/",
19
+ "scripts/",
20
+ "skills/",
21
+ "agents/",
22
+ "extensions/*.ts",
23
+ "extensions/lib/",
24
+ "extensions/*/*.ts",
25
+ "extensions/*/*.md",
26
+ "extensions/*/package.json",
27
+ "extensions/*/agents/",
28
+ "extensions/*/prompts/",
29
+ "hooks/",
30
+ "claude/",
31
+ "claude-extras/",
32
+ "token-map.json",
33
+ "token-map.README.md",
34
+ "README.md",
35
+ "CHANGELOG.md"
36
+ ],
16
37
  "publishConfig": {
17
38
  "access": "public"
18
39
  },
19
40
  "devDependencies": {
20
41
  "@changesets/cli": "^2.31.1",
42
+ "@types/node": "^22.20.1",
21
43
  "tsx": "^4.0.0",
44
+ "typescript": "^5.9.3",
22
45
  "yaml": "^2.0.0"
23
46
  },
24
47
  "pi": {
@@ -39,10 +62,11 @@
39
62
  "check:sync": "node scripts/check-no-sync.mjs",
40
63
  "check:skills": "node scripts/check-skill-frontmatter.mjs",
41
64
  "test": "node --test test/*.test.mjs && pnpm -r test",
42
- "typecheck": "pnpm -r typecheck",
65
+ "typecheck": "tsc --noEmit -p tsconfig.json && pnpm -r typecheck",
66
+ "verify": "pnpm typecheck && pnpm test",
43
67
  "changeset": "changeset",
44
68
  "version-packages": "changeset version",
45
- "publish-package": "TARBALL=$(pnpm pack | tail -n 1) && npm publish \"$TARBALL\" --provenance --access public",
69
+ "publish-package": "pnpm verify && TARBALL=$(pnpm pack | tail -n 1) && npm publish \"$TARBALL\" --provenance --access public",
46
70
  "publish-noop": "echo 'No publish: the merged PR carries the no-publish label.'",
47
71
  "release": "changeset publish"
48
72
  }
@@ -10,6 +10,10 @@ async function readStdin() {
10
10
  return Buffer.concat(chunks).toString("utf8");
11
11
  }
12
12
 
13
+ /**
14
+ * @param {string} raw
15
+ * @returns {string[]}
16
+ */
13
17
  function readLabels(raw) {
14
18
  try {
15
19
  return JSON.parse(raw);
@@ -14,7 +14,11 @@ const SELF = "scripts/check-no-sync.mjs";
14
14
 
15
15
  const SYNC_CALL = /\b\w*Sync\s*\(/;
16
16
 
17
- /** Recursively collect files under dir, skipping this script and node_modules. */
17
+ /**
18
+ * Recursively collect files under dir, skipping this script and node_modules.
19
+ * @param {string} dir
20
+ * @returns {Promise<string[]>}
21
+ */
18
22
  async function collect(dir) {
19
23
  const out = [];
20
24
  const entries = await readdir(dir, { withFileTypes: true });
@@ -32,7 +32,49 @@
32
32
  import { readFile, stat } from "node:fs/promises";
33
33
  import { join } from "node:path";
34
34
 
35
- /** True when a path exists (stat succeeds). */
35
+ /** @typedef {{ base: string, relative: string }} PathSpec */
36
+
37
+ /**
38
+ * Parsed token-map.json. `tools` maps a canonical tool key to its per-harness
39
+ * name (null = the harness has no equivalent); `paths` maps a path key to its
40
+ * per-harness spec (a literal string, or a {base, relative} pair resolved
41
+ * recursively through the same table).
42
+ * @typedef {object} TokenMap
43
+ * @property {number} [version]
44
+ * @property {Record<string, Record<string, string | null>>} tools
45
+ * @property {Record<string, Record<string, string | PathSpec>>} paths
46
+ */
47
+
48
+ /**
49
+ * Options shared by the composer entry points.
50
+ * @typedef {object} ComposeOptions
51
+ * @property {boolean} [dropNullTools]
52
+ * @property {string} [pluginRoot]
53
+ * @property {boolean} [resolveRelativePaths]
54
+ * @property {(message: string) => void} [warn]
55
+ * @property {string} [context]
56
+ */
57
+
58
+ /**
59
+ * Parsed and schema-checked harness frontmatter.json.
60
+ * @typedef {object} AgentFrontmatter
61
+ * @property {string} name
62
+ * @property {string} description
63
+ * @property {string[]} tools
64
+ * @property {string} [model]
65
+ * @property {string} [argumentHint]
66
+ */
67
+
68
+ /**
69
+ * A composed agent: its frontmatter plus the substituted body.
70
+ * @typedef {AgentFrontmatter & { body: string }} ComposedAgent
71
+ */
72
+
73
+ /**
74
+ * True when a path exists (stat succeeds).
75
+ * @param {string} p
76
+ * @returns {Promise<boolean>}
77
+ */
36
78
  async function pathExists(p) {
37
79
  try {
38
80
  await stat(p);
@@ -47,6 +89,7 @@ async function pathExists(p) {
47
89
  const TOOL_RE = /\{\{TOOL:([^}]+)\}\}/g;
48
90
  const PATH_RE = /\{\{PATH:([^}]+)\}\}/g;
49
91
 
92
+ /** @returns {void} */
50
93
  function noop() {}
51
94
 
52
95
  /**
@@ -62,8 +105,8 @@ function noop() {}
62
105
  *
63
106
  * @param {string} content Source text containing {{TOOL:...}}/{{PATH:...}} tokens
64
107
  * @param {string} harness Harness id: "claude" | "pi"
65
- * @param {object} tokenMap Parsed token-map.json (from loadTokenMap)
66
- * @param {object} options { dropNullTools, pluginRoot, resolveRelativePaths, warn, context }
108
+ * @param {TokenMap} tokenMap Parsed token-map.json (from loadTokenMap)
109
+ * @param {ComposeOptions} [options] { dropNullTools, pluginRoot, resolveRelativePaths, warn, context }
67
110
  * @returns {string}
68
111
  */
69
112
  export function substituteTokens(content, harness, tokenMap, options = {}) {
@@ -100,7 +143,8 @@ export function substituteTokens(content, harness, tokenMap, options = {}) {
100
143
  * @param {string} root Package root (contains agents/ and token-map.json)
101
144
  * @param {string} name Agent directory name (e.g. "ralph", "plan")
102
145
  * @param {string} harness Harness id: "claude" | "pi"
103
- * @returns {{ name: string, description: string, tools: string[], model?: string, argumentHint?: string, body: string }}
146
+ * @param {ComposeOptions} [options]
147
+ * @returns {Promise<ComposedAgent>}
104
148
  */
105
149
  export async function composeAgent(root, name, harness, options = {}) {
106
150
  const { dropNullTools = false, pluginRoot, resolveRelativePaths = false, warn = noop } = options;
@@ -144,14 +188,21 @@ export async function composeAgent(root, name, harness, options = {}) {
144
188
  const REQUIRED_FIELDS = ["name", "description", "tools"];
145
189
  const KNOWN_OPTIONAL_FIELDS = ["model", "argumentHint"];
146
190
 
147
- /** Parse and schema-check a harness frontmatter.json (strict, per agents/README.md). */
191
+ /**
192
+ * Parse and schema-check a harness frontmatter.json (strict, per agents/README.md).
193
+ * @param {string} path
194
+ * @param {string} name
195
+ * @param {string} harness
196
+ * @returns {Promise<AgentFrontmatter>}
197
+ */
148
198
  async function parseFrontmatter(path, name, harness) {
149
199
  const raw = await readFile(path, "utf-8");
200
+ /** @type {Record<string, unknown>} */
150
201
  let fm;
151
202
  try {
152
203
  fm = JSON.parse(raw);
153
204
  } catch (err) {
154
- throw new Error(`agent "${name}": invalid JSON in ${path}: ${err.message}`);
205
+ throw new Error(`agent "${name}": invalid JSON in ${path}: ${/** @type {Error} */ (err).message}`);
155
206
  }
156
207
  if (typeof fm !== "object" || fm === null) {
157
208
  throw new Error(`agent "${name}": ${path} must be a JSON object`);
@@ -188,6 +239,11 @@ async function parseFrontmatter(path, name, harness) {
188
239
  * With the installer options (`pluginRoot`, `resolveRelativePaths`) the
189
240
  * plugin_root base and bare relative paths resolve against the actual install
190
241
  * layout instead.
242
+ * @param {string} arg
243
+ * @param {string} harness
244
+ * @param {TokenMap} tokenMap
245
+ * @param {ComposeOptions} [opts]
246
+ * @returns {string}
191
247
  */
192
248
  function resolvePath(arg, harness, tokenMap, opts = {}) {
193
249
  const entry = tokenMap.paths?.[arg];
@@ -217,9 +273,9 @@ function resolvePath(arg, harness, tokenMap, opts = {}) {
217
273
  * translation in extensions/agent-modes/discover.ts.
218
274
  *
219
275
  * @param {string[]} tools Canonical tool names from a harness frontmatter.json
220
- * @param {object} tokenMap Parsed token-map.json (from loadTokenMap)
276
+ * @param {TokenMap} tokenMap Parsed token-map.json (from loadTokenMap)
221
277
  * @param {string} harness Harness id: "claude" | "pi"
222
- * @param {object} options { warn }
278
+ * @param {ComposeOptions} [options] { warn }
223
279
  * @returns {string[]}
224
280
  */
225
281
  export function translateToolList(tools, tokenMap, harness, { warn = noop } = {}) {
@@ -242,7 +298,11 @@ export function translateToolList(tools, tokenMap, harness, { warn = noop } = {}
242
298
 
243
299
  // ─── Token map ───────────────────────────────────────────────────────────────
244
300
 
245
- /** Load token-map.json from the package root; missing/incomplete maps hard-fail. */
301
+ /**
302
+ * Load token-map.json from the package root; missing/incomplete maps hard-fail.
303
+ * @param {string} root
304
+ * @returns {Promise<TokenMap>}
305
+ */
246
306
  export async function loadTokenMap(root) {
247
307
  const path = join(root, "token-map.json");
248
308
  let raw;
@@ -12,7 +12,11 @@
12
12
 
13
13
  import { stat } from "node:fs/promises";
14
14
 
15
- /** True when `p` exists and is a regular file; false on any error. */
15
+ /**
16
+ * True when `p` exists and is a regular file; false on any error.
17
+ * @param {string} p
18
+ * @returns {Promise<boolean>}
19
+ */
16
20
  export async function isFile(p) {
17
21
  try {
18
22
  return (await stat(p)).isFile();
@@ -21,7 +25,11 @@ export async function isFile(p) {
21
25
  }
22
26
  }
23
27
 
24
- /** True when `p` exists and is a directory; false on any error. */
28
+ /**
29
+ * True when `p` exists and is a directory; false on any error.
30
+ * @param {string} p
31
+ * @returns {Promise<boolean>}
32
+ */
25
33
  export async function isDirectory(p) {
26
34
  try {
27
35
  return (await stat(p)).isDirectory();