Skip to content

Compose top-level persona-kit orchestration API#74

Merged
willwashburn merged 4 commits into
mainfrom
claude/submit-github-pr-COgHJ
May 10, 2026
Merged

Compose top-level persona-kit orchestration API#74
willwashburn merged 4 commits into
mainfrom
claude/submit-github-pr-COgHJ

Conversation

@willwashburn
Copy link
Copy Markdown
Member

Summary

Implements [persona-kit 3/8] (#66) — the top-level orchestration API the workforce CLI and relay SDK will consume.

  • buildPersonaSpawnPlan — pure plan builder. Composes buildInteractiveSpec, materializeSkills, resolvePersonaInputs, and the sidecar/mount/input resolvers into a single PersonaSpawnPlan value. No I/O, no subprocesses, JSON-serializable round-trip verified by tests.
  • executePersonaSpawnPlan — side-effecting executor. Runs applyPersonaMountrunSkillInstallswritePersonaSidecarsmaterializePersonaConfigFiles in order with abort-on-failure. Returns an ExecutionHandle whose dispose() reverses every side effect in LIFO order (idempotent).
  • Piecewise helpers — each with a uniform { dispose(): Promise<void> } shape so advanced callers can wire their own orchestration.

Notes for reviewers

Files

  • packages/persona-kit/src/plan.ts — types + buildPersonaSpawnPlan
  • packages/persona-kit/src/execute.tsexecutePersonaSpawnPlan
  • packages/persona-kit/src/mount.tsapplyPersonaMount
  • packages/persona-kit/src/sidecars.tswritePersonaSidecars
  • packages/persona-kit/src/config-files.tsmaterializePersonaConfigFiles
  • packages/persona-kit/src/skill-runner.tsrunSkillInstalls
  • packages/persona-kit/src/{plan,execute}.test.ts — round-trip + happy/failure paths
  • packages/persona-kit/README.md — end-to-end usage

Test plan

  • pnpm --filter @agentworkforce/persona-kit test — 73 tests pass (8 new).
  • pnpm -r build — every package builds.
  • pnpm -r test — full monorepo test suite passes (no regressions).
  • JSON round-trip for PersonaSpawnPlan.
  • executePersonaSpawnPlan failure path: a later step throwing causes prior handles to dispose and restores prior file contents.
  • Empty-skills path is a no-op for the skills phase across all three harnesses.

Closes #66.


Generated by Claude Code

Introduce the plan/execute API the workforce CLI and relay SDK consume:

- buildPersonaSpawnPlan: pure plan builder composing buildInteractiveSpec,
  materializeSkills, resolvePersonaInputs, and the sidecar/mount/input
  resolvers into a single JSON-serializable PersonaSpawnPlan.
- executePersonaSpawnPlan: side-effecting executor that runs mount → skills
  → sidecars → configFiles in order with LIFO dispose-on-error. Returns an
  ExecutionHandle whose dispose() reverses every side effect (idempotent).
- Piecewise helpers (applyPersonaMount, runSkillInstalls,
  writePersonaSidecars, materializePersonaConfigFiles), each returning a
  uniform { dispose(): Promise<void> } handle for advanced callers.

Closes #66.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 10, 2026

Review Change Stack
No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: aec27789-545f-4b5a-8287-f45f23b4921b

📥 Commits

Reviewing files that changed from the base of the PR and between fa14ddb and e500212.

📒 Files selected for processing (1)
  • packages/persona-kit/src/execute.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/persona-kit/src/execute.test.ts

📝 Walkthrough

Walkthrough

Adds a pure plan builder (buildPersonaSpawnPlan), piecewise helpers (applyPersonaMount, runSkillInstalls, writePersonaSidecars, materializePersonaConfigFiles), a deterministic executor (executePersonaSpawnPlan) with LIFO disposal and idempotent handles, top-level exports, README, package dependency, and comprehensive tests.

Changes

Persona Spawn Orchestration

Layer / File(s) Summary
Docs & packaging
packages/persona-kit/README.md, packages/persona-kit/package.json
Documents the two-phase orchestration API with an end-to-end TypeScript example; adds @relayfile/local-mount dependency.
Public Exports
packages/persona-kit/src/index.ts
Re-exports plan builder, executor, piecewise helpers, and associated option/handle types from the package barrel.
Plan Contracts & Types
packages/persona-kit/src/plan.ts
Adds Resolved* types, PersonaSpawnPlan, and PlanOptions describing JSON-serializable plan shape and env precedence.
Pure Plan Builder
packages/persona-kit/src/plan.ts
Implements buildPersonaSpawnPlan(persona, options?) and helpers (resolvedInputBindings, resolveSidecarWrite, resolveMountPolicy) producing a deterministic, serializable spawn plan.
Mount Helper
packages/persona-kit/src/mount.ts
Implements applyPersonaMount returning PersonaMountHandle (no-op when undefined) with cwd and idempotent dispose().
Skill Install Runner
packages/persona-kit/src/skill-runner.ts
Implements runSkillInstalls, buffered subprocess spawn, SkillInstallError, and PersonaSkillsHandle with configurable cleanup and path-escape validation.
Sidecar Writes
packages/persona-kit/src/sidecars.ts
Implements writePersonaSidecars with safe filename validation, overwrite/extend modes, snapshotting, and a PersonaSidecarHandle restoring prior files LIFO.
Config-file Materialization
packages/persona-kit/src/config-files.ts
Adds assertSafeRelativePath and materializePersonaConfigFiles to write nested relative config files and return a PersonaConfigFilesHandle that restores prior states; best-effort cleanup on mid-write errors.
Execution Orchestrator
packages/persona-kit/src/execute.ts
Implements executePersonaSpawnPlan(plan, options) running: applyPersonaMount → runSkillInstalls → writePersonaSidecars → materializePersonaConfigFiles, accumulates handles, disposes prior handles on failure, and returns an ExecutionHandle with cwd and idempotent dispose().
Tests
packages/persona-kit/src/plan.test.ts, packages/persona-kit/src/execute.test.ts
Adds tests for plan serialization and harness-specific outputs, sidecar overwrite/extend semantics and safety, config-file path validation, skill install lifecycle and cleanup, executor happy/failure paths, and idempotent LIFO disposal.

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant Executor as executePersonaSpawnPlan
  participant Mount as applyPersonaMount
  participant Skills as runSkillInstalls
  participant Sidecars as writePersonaSidecars
  participant Config as materializePersonaConfigFiles

  Caller->>Executor: executePersonaSpawnPlan(plan, options)
  Executor->>Mount: applyPersonaMount(plan.mount, options)
  Mount-->>Executor: mountHandle
  Executor->>Skills: runSkillInstalls(plan.skills, options)
  Skills-->>Executor: skillsHandle
  Executor->>Sidecars: writePersonaSidecars(plan.sidecars, options)
  Sidecars-->>Executor: sidecarHandle
  Executor->>Config: materializePersonaConfigFiles(plan.configFiles, options)
  Config-->>Executor: configHandle
  Executor-->>Caller: ExecutionHandle (cwd, dispose)
  Note over Executor: On error -> dispose handles in LIFO order
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related issues

Possibly related PRs

Poem

🐰 A plan is baked, JSON neat and bright,
Execute with care — mount, install, write.
If errors come, unwind in LIFO song,
Dispose is idempotent, nothing stays long.
Hop, restore, and then we sprint along.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 34.78% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed Title clearly summarizes the main change: composing a top-level orchestration API for persona-kit, which is the primary objective of this PR.
Description check ✅ Passed Description comprehensively explains the PR's objectives, implementation details, and verification steps, directly addressing the linked issue #66.
Linked Issues check ✅ Passed PR fully implements all core requirements from issue #66: buildPersonaSpawnPlan (pure plan builder), executePersonaSpawnPlan (side-effecting executor with LIFO disposal), piecewise helpers, JSON-serializable plan, comprehensive tests, and README documentation.
Out of Scope Changes check ✅ Passed All changes are scoped to persona-kit orchestration API implementation as defined in issue #66. Package.json dependency addition and README update are directly related to supporting the new API.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/submit-github-pr-COgHJ

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c74f1806c5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +118 to +122
const harness = selection.runtime.harness;
if (harness === 'claude') {
if (selection.claudeMdContent) {
return [
{
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve file-backed sidecars when building spawn plans

buildPersonaSpawnPlan only emits sidecar writes when claudeMdContent/agentsMdContent are already inlined, so personas that declare claudeMd or agentsMd file paths produce no sidecar entries and lose their operating instructions at runtime. This regresses local/pack personas that rely on path-based sidecars: execution succeeds but launches without the expected CLAUDE.md/AGENTS.md content.

Useful? React with 👍 / 👎.

Comment on lines +80 to +83
mountHandle = await applyPersonaMount(plan.mount, {
cwd: options.cwd,
...(options.mount ?? {})
});
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Populate mount personaId from the plan during execution

When a plan includes a mount policy, executePersonaSpawnPlan forwards only options.mount to applyPersonaMount, so callers must redundantly pass personaId even though plan.persona.personaId is already available. If they omit it (a likely case, since only mountDir is truly unknown), execution throws before any work starts, making mount-enabled plans fail unexpectedly.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/persona-kit/README.md`:
- Around line 25-28: The README example incorrectly passes an execution option
(cwd) into buildPersonaSpawnPlan; update the example so
buildPersonaSpawnPlan(persona, { inputValues: { TASK: 'tidy up the README' } })
only receives PlanOptions, and demonstrate passing { cwd: process.cwd() } as
part of the ExecuteOptions when actually executing the plan (e.g., when calling
spawn/execute on the returned plan). Reference buildPersonaSpawnPlan and the
plan execution call so readers see the PlanOptions vs ExecuteOptions split
clearly.

In `@packages/persona-kit/src/plan.ts`:
- Around line 78-80: PlanOptions.cwd is documented but never applied; either
remove it or wire it into all plan/harness creation paths. If keeping it, use
PlanOptions.cwd (defaulting to process.cwd()) when constructing the Plan and
when spawning any harness/child process (e.g., inside the Plan constructor,
createPlan/createPlanFromOptions, or spawnHarness/Harness.spawn) so the working
directory is passed to child_process spawn/execa calls; if you prefer to remove
it, delete cwd from PlanOptions and remove any related doc comments and default
handling.
- Around line 212-227: The code currently copies the entire ambient process.env
into the plan via the else branch, which can leak secrets; change the logic so
ambient env is NOT captured by default and only include process.env when
explicitly provided via options.processEnv. Concretely, remove the else block
that iterates over process.env (leave only the if (options.processEnv) branch
that copies string values), and ensure env is populated only from inputBindings,
options.envOverrides, and persona.env unless options.processEnv was passed;
update any related tests or callers that relied on implicit capture to pass
options.processEnv when they truly want full ambient env.

In `@packages/persona-kit/src/sidecars.ts`:
- Around line 40-42: The loop uses sidecar.filename directly when building
target (join(options.cwd, sidecar.filename)), allowing absolute paths or ../
traversal; validate/sanitize filename before joining: either replace
sidecar.filename with path.basename(sidecar.filename) or resolve the candidate
path and ensure it is inside options.cwd (resolve(join(options.cwd,
sidecar.filename)) startsWith resolve(options.cwd) + path.sep or equals it); if
validation fails, reject/skip the sidecar or throw. Update the logic around the
for (const sidecar of sidecars) block and the creation of target (used by
readIfExists and subsequent writes) to use the sanitized filename or validated
resolved path.

In `@packages/persona-kit/src/skill-runner.ts`:
- Around line 102-105: The cleanup loop using plan.installs ->
install.cleanupPaths currently resolves paths with isAbsolute/join and calls
rm(...{recursive:true, force:true}) without safety checks; restrict deletions to
inside the intended workspace by resolving each candidate via
path.resolve(options.cwd, path), verifying the resolved path startsWith the
resolved workspace root (e.g., const workspaceRoot = path.resolve(options.cwd)),
and skipping/throwing for any absolute/path-traversal targets or if the resolved
path equals filesystem root; only call rm on paths that pass this containment
check (reference: the loop iterating plan.installs and install.cleanupPaths and
the rm(...) call).
- Around line 36-39: signalExitCode currently returns a hardcoded 129 for any
signal; update the function to compute 128 + the actual signal number by looking
up the signal numeric code: use os.constants.signals[signal] when available and
otherwise fall back to a small internal mapping of common signals (e.g., SIGHUP,
SIGINT, SIGTERM, SIGQUIT, SIGKILL, SIGABRT) to their numbers; change the return
in signalExitCode to return 128 + signalNumber (defaulting to 1 only if lookup
fails). Ensure you update the signalExitCode function and reference
NodeJS.Signals for the lookup.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 18f7478b-34de-499a-be23-d47e87f0898e

📥 Commits

Reviewing files that changed from the base of the PR and between be61668 and c74f180.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (11)
  • packages/persona-kit/README.md
  • packages/persona-kit/package.json
  • packages/persona-kit/src/config-files.ts
  • packages/persona-kit/src/execute.test.ts
  • packages/persona-kit/src/execute.ts
  • packages/persona-kit/src/index.ts
  • packages/persona-kit/src/mount.ts
  • packages/persona-kit/src/plan.test.ts
  • packages/persona-kit/src/plan.ts
  • packages/persona-kit/src/sidecars.ts
  • packages/persona-kit/src/skill-runner.ts

Comment thread packages/persona-kit/README.md
Comment thread packages/persona-kit/src/plan.ts Outdated
Comment thread packages/persona-kit/src/plan.ts Outdated
Comment thread packages/persona-kit/src/sidecars.ts
Comment thread packages/persona-kit/src/skill-runner.ts
Comment thread packages/persona-kit/src/skill-runner.ts
Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 potential issue.

View 5 additional findings in Devin Review.

Open in Devin Review

Comment thread packages/persona-kit/src/mount.ts Outdated
async dispose(): Promise<void> {
if (disposed) return;
disposed = true;
handle.cleanup();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Missing await on potentially-async handle.cleanup() in mount dispose

At packages/persona-kit/src/mount.ts:85, handle.cleanup() is called without await inside an async dispose() method. If createMount from @relayfile/local-mount returns a handle whose cleanup() is async (returns a Promise), then dispose() resolves immediately before the mount teardown actually completes. This breaks the semantic contract of dispose(): callers of executePersonaSpawnPlan (packages/persona-kit/src/execute.ts:112) do await disposeAll(handles) and assume all side effects are reversed when it resolves. A caller that deletes the session directory or reuses the cwd immediately after await handle.dispose() could race against an incomplete mount cleanup.

Comparison with CLI code

The CLI at packages/cli/src/cli.ts:1526 also calls handle?.cleanup() without await, but that's in a process-exit teardown path where fire-and-forget is acceptable. The persona-kit wrapper wraps this in a composable dispose() that's explicitly awaited in orchestration sequences, so the missing await has more impact here.

Suggested change
handle.cleanup();
await handle.cleanup();
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

- Carry path-backed sidecars through the plan via `ResolvedSidecarWrite.sourcePath`
  so personas declaring `claudeMd` / `agentsMd` (file path, not inlined content)
  no longer drop their sidecar at runtime; `writePersonaSidecars` reads the
  source at write time, keeping the plan JSON-serializable. (codex P1)
- Default `applyPersonaMount` `personaId` from `plan.persona.personaId`
  inside `executePersonaSpawnPlan` so callers don't have to forward it
  redundantly. (codex P2)
- Make ambient `process.env` capture into `plan.env` opt-in via
  `PlanOptions.includeProcessEnv`; default is to populate `plan.env` only
  from persona/input/override sources, keeping ambient secrets out of the
  serialized plan. (coderabbit major)
- Validate sidecar filenames as basenames before joining with `cwd`, so
  hand-built or JSON-deserialized plans cannot escape the cwd via `..` or
  absolute paths. (coderabbit major)
- Constrain `runSkillInstalls` cleanup to paths inside `cwd` and reject any
  declared path that resolves outside the workspace. (coderabbit major)
- Use `os.constants.signals[signal]` for `signalExitCode` so signaled exits
  produce a meaningful 128+N rather than always 129. (coderabbit minor)
- Remove the unused `PlanOptions.cwd` field; cwd belongs to ExecuteOptions.
  Update README to reflect the PlanOptions vs ExecuteOptions split. (coderabbit minor)
- Defensively `await` the relayfile mount handle's `cleanup()` call inside
  `applyPersonaMount`'s dispose so future async cleanup variants do not
  break the dispose contract executors rely on. (devin)
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
packages/persona-kit/src/execute.test.ts (1)

176-185: ⚡ Quick win

This test never exercises the install-command path.

installs is empty here, so runSkillInstalls() only covers session-root scaffolding/disposal. A regression in actually spawning installCommand would still pass. Please add one harmless install entry, or rename the test so the coverage matches what it validates.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/persona-kit/src/execute.test.ts` around lines 176 - 185, The test
"runSkillInstalls executes the install command and disposes session install
root" never exercises the install-command path because the
SkillMaterializationPlan's installs array is empty; update the test so
runSkillInstalls actually spawns an install by adding a harmless install entry
(e.g., an object with an installCommand like "echo installed" or "true" and any
needed metadata) to the plan.installs array before calling runSkillInstalls,
ensuring the installCommand path is exercised; alternatively, if you prefer not
to run an install, rename the test to reflect it only validates
sessionInstallRoot scaffolding/disposal.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/persona-kit/src/plan.ts`:
- Around line 217-223: The code currently sets processEnv = options.processEnv
?? process.env which causes resolvePersonaInputs(...) to read host env even when
includeProcessEnv is false; change the logic so processEnv is only set to
options.processEnv or process.env when options.includeProcessEnv is truthy
(e.g., processEnv = options.includeProcessEnv ? (options.processEnv ??
process.env) : undefined) and pass that into resolvePersonaInputs (the call that
uses persona.inputs / persona.inputValues and resolvePersonaInputs) so
plan.inputs and plan.env are not populated from the ambient env unless
includeProcessEnv is explicitly enabled.

In `@packages/persona-kit/src/sidecars.ts`:
- Around line 49-50: The code reads sidecar.sourcePath directly via readFile,
but ResolvedSidecarWrite requires an absolute path; reject any relative paths to
avoid depending on process.cwd. In the function that performs the read (where
sidecar.sourcePath and readFile are used), validate using
path.isAbsolute(sidecar.sourcePath) and throw a clear error referencing
ResolvedSidecarWrite/sidecar.sourcePath if it is not absolute; only call
readFile when the path is confirmed absolute. Ensure the thrown error message
includes the offending path for debugging.

---

Nitpick comments:
In `@packages/persona-kit/src/execute.test.ts`:
- Around line 176-185: The test "runSkillInstalls executes the install command
and disposes session install root" never exercises the install-command path
because the SkillMaterializationPlan's installs array is empty; update the test
so runSkillInstalls actually spawns an install by adding a harmless install
entry (e.g., an object with an installCommand like "echo installed" or "true"
and any needed metadata) to the plan.installs array before calling
runSkillInstalls, ensuring the installCommand path is exercised; alternatively,
if you prefer not to run an install, rename the test to reflect it only
validates sessionInstallRoot scaffolding/disposal.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: b5b8b74b-d17d-42d8-81b6-00ffa33528fb

📥 Commits

Reviewing files that changed from the base of the PR and between c74f180 and c2c9fd9.

📒 Files selected for processing (8)
  • packages/persona-kit/README.md
  • packages/persona-kit/src/execute.test.ts
  • packages/persona-kit/src/execute.ts
  • packages/persona-kit/src/mount.ts
  • packages/persona-kit/src/plan.test.ts
  • packages/persona-kit/src/plan.ts
  • packages/persona-kit/src/sidecars.ts
  • packages/persona-kit/src/skill-runner.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/persona-kit/src/mount.ts
  • packages/persona-kit/src/skill-runner.ts

Comment thread packages/persona-kit/src/plan.ts Outdated
Comment thread packages/persona-kit/src/sidecars.ts
- Gate ambient process.env capture during input fallback resolution too:
  resolvePersonaInputs now sees an empty env when includeProcessEnv is
  off, so plan.inputs and plan.env stay deterministic across hosts and
  don't leak ambient values via persona inputs that declare an env binding.
- Reject relative ResolvedSidecarWrite.sourcePath in writePersonaSidecars
  so a hand-built or JSON-deserialized plan can't make sidecar resolution
  depend on the executor's process cwd.
- Replace the misnamed runSkillInstalls test with two focused cases: one
  verifies session scaffolding/disposal, one actually exercises the spawn
  path against a harmless `sh -c true` install. Add a third case covering
  SkillInstallError on non-zero exits.
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
packages/persona-kit/src/execute.test.ts (1)

164-165: ⚡ Quick win

Make spawn-path tests platform-agnostic.

These commands are POSIX-specific and can break on Windows runners. Use Node itself as the spawned command to keep coverage equivalent and deterministic across OSes.

Proposed diff
@@
-          installCommand: ['true'],
+          installCommand: [process.execPath, '-e', 'process.exit(0)'],
@@
-          installCommand: ['sh', '-c', 'true'],
+          installCommand: [process.execPath, '-e', 'process.exit(0)'],
@@
-          installCommand: ['sh', '-c', 'exit 17'],
+          installCommand: [process.execPath, '-e', 'process.exit(17)'],

Also applies to: 205-206, 228-229

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/persona-kit/src/execute.test.ts` around lines 164 - 165, Tests
currently spawn POSIX-only commands (e.g., installCommand: ['true']) which fail
on Windows; update the test cases in execute.test.ts (the blocks referencing
installCommand and installedDir, including the other occurrences at the same
pattern on lines around 205-206 and 228-229) to spawn Node itself instead (use
process.execPath as the command) and pass a short Node argument that
deterministically succeeds/fails to mirror the original intent so tests become
platform-agnostic while keeping installedDir assertions the same.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@packages/persona-kit/src/execute.test.ts`:
- Around line 164-165: Tests currently spawn POSIX-only commands (e.g.,
installCommand: ['true']) which fail on Windows; update the test cases in
execute.test.ts (the blocks referencing installCommand and installedDir,
including the other occurrences at the same pattern on lines around 205-206 and
228-229) to spawn Node itself instead (use process.execPath as the command) and
pass a short Node argument that deterministically succeeds/fails to mirror the
original intent so tests become platform-agnostic while keeping installedDir
assertions the same.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 5e83eef9-c9d8-4afa-bbbb-7450555bec71

📥 Commits

Reviewing files that changed from the base of the PR and between c2c9fd9 and fa14ddb.

📒 Files selected for processing (3)
  • packages/persona-kit/src/execute.test.ts
  • packages/persona-kit/src/plan.ts
  • packages/persona-kit/src/sidecars.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/persona-kit/src/plan.ts

@willwashburn willwashburn merged commit 93daf2a into main May 10, 2026
2 checks passed
@willwashburn willwashburn deleted the claude/submit-github-pr-COgHJ branch May 10, 2026 20:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[persona-kit 3/8] Compose top-level persona-kit orchestration API

2 participants