Skip to content

feat: extract spawn operation to core/operations/spawn.ts#98

Open
2witstudios wants to merge 3 commits into
mainfrom
ppg/issue-62-spawn-op
Open

feat: extract spawn operation to core/operations/spawn.ts#98
2witstudios wants to merge 3 commits into
mainfrom
ppg/issue-62-spawn-op

Conversation

@2witstudios

@2witstudios 2witstudios commented Feb 27, 2026

Copy link
Copy Markdown
Owner

Summary

  • Extracted full spawn pipeline (generate IDs → git worktree add → setup env → tmux → prompt → send-keys → update manifest) from commands/spawn.ts into core/operations/spawn.ts
  • New performSpawn() function with typed PerformSpawnOptions input and SpawnResult output
  • Simplified commands/spawn.ts to ~30 lines: arg parsing + output formatting
  • All three spawn paths preserved: new worktree, existing branch (--branch), existing worktree (--worktree)

Test plan

  • 14 new tests in core/operations/spawn.test.ts covering all spawn paths, validation, and result shape
  • Existing commands/spawn.test.ts tests still pass (2/2)
  • Full test suite passes (207/207 tests, 20/20 test files — 2 pre-existing failures from missing cron-parser dep)
  • TypeCheck passes for new files (pre-existing errors in schedule.ts and spawn.test.ts unrelated)

Closes #62

Summary by CodeRabbit

  • Tests
    • Added comprehensive unit test coverage for spawn operations, verifying worktree creation, agent provisioning, tmux session management, and error handling across various scenarios.

Move worktree creation + agent spawning pipeline from commands/spawn.ts
into core/operations/spawn.ts as performSpawn() with typed options and
result. Commands layer now handles only arg parsing + output formatting.

Closes #62
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

@coderabbitai

coderabbitai Bot commented Feb 27, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

This PR extracts the spawn command's core workflow into a new core/operations/spawn.ts module. The spawn command is refactored to delegate to performSpawn(), which orchestrates worktree creation, environment setup, tmux management, agent spawning, and manifest synchronization. Comprehensive tests validate the extraction.

Changes

Cohort / File(s) Summary
Core Spawn Operations
src/core/operations/spawn.ts, src/core/operations/spawn.test.ts
New module implementing the complete spawn pipeline with public API (PerformSpawnOptions, SpawnResult, performSpawn). Handles worktree creation, git operations, tmux session/window management, agent spawning, manifest updates, and prompt resolution. Includes 446 lines of comprehensive unit tests covering new worktree, existing branch/worktree, prompt validation, and error conditions.
Command Refactoring
src/commands/spawn.ts, src/commands/spawn.test.ts
Simplified spawn command to delegate to performSpawn(). SpawnOptions now extends PerformSpawnOptions with only json?: boolean. Internal helpers and complex orchestration logic removed. Type annotation added to test helper (createManifest).

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Poem

🐰 Hop, hop! The spawn logic hops away,
From commands to core, where it shall stay,
Worktrees and agents in grand harmony,
Tests all aligned—what perfection to see! 🌿✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% 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 The title 'feat: extract spawn operation to core/operations/spawn.ts' accurately describes the main change—extracting the spawn pipeline into a core operations module.
Description check ✅ Passed The description covers all required sections: Summary (What/How), Test plan (How), and provides clear details on implementation and testing approach.
Linked Issues check ✅ Passed All acceptance criteria from issue #62 are met: performSpawn() exported with typed options, full pipeline implemented, template variable rendering included, results return worktree/agent IDs and tmux targets, commands/spawn.ts simplified, and comprehensive tests provided.
Out of Scope Changes check ✅ Passed All changes align with the stated objective of extracting spawn operation to core/operations/spawn.ts; no unrelated modifications detected in the changeset.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch ppg/issue-62-spawn-op

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

- P2: Replace inline import('...').Config with top-level type import
- P3: Restore context-specific success messages (new vs branch vs existing)
- P4: Only show attach hint for newly created worktrees
- P5: Remove redundant result-shape test (TypeScript already guarantees)
- P6: Add --template prompt resolution test
- P7: Add manifest updater ordering tests (skeleton before agents, tmux
  window persisted before spawn, partial failure scenario)
- P8: Remove unused mock variable declarations

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/core/operations/spawn.ts`:
- Line 60: Validate and sanitize options.count at the start of the spawn routine
before any side effects: ensure the value read from options.count (used to set
const count) is a finite integer >= 1 (e.g. coerce via Math.floor or parseInt
then check Number.isFinite and >=1) and reject or default invalid values (NaN,
0, negative, decimals) so the subsequent spawn loop and any side-effecting code
(references around const count and the later spawn loop at the section around
lines 165-166) cannot create zero or too many agents; if invalid, set a safe
default (1) or throw a clear error.
- Line 59: resolveAgentConfig(config, options.agent) can throw a plain Error
which bypasses our typed CLI error handling; wrap the call in a try/catch around
the const agentConfig = resolveAgentConfig(...) expression and on failure throw
a PpgError with the proper code (e.g. ErrorCode.INVALID_ARGS) that includes the
original error message (or sets the original error as the cause) so callers
receive a typed error. Ensure you reference the symbols resolveAgentConfig and
PpgError (and ErrorCode.INVALID_ARGS) when making the change and preserve the
original error text in the new PpgError.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 34deb69 and fbce7a3.

📒 Files selected for processing (4)
  • src/commands/spawn.test.ts
  • src/commands/spawn.ts
  • src/core/operations/spawn.test.ts
  • src/core/operations/spawn.ts

throw new NotInitializedError(projectRoot);
}

const agentConfig = resolveAgentConfig(config, options.agent);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Unknown --agent errors leak as untyped Error.

resolveAgentConfig can throw a generic Error, so this operation may bypass typed error codes and break consistent CLI error handling.

Proposed fix
-  const agentConfig = resolveAgentConfig(config, options.agent);
+  let agentConfig: AgentConfig;
+  try {
+    agentConfig = resolveAgentConfig(config, options.agent);
+  } catch (error) {
+    throw new PpgError(
+      error instanceof Error ? error.message : 'Invalid --agent value',
+      'INVALID_ARGS',
+    );
+  }

As per coding guidelines: "Use PpgError hierarchy with typed error codes: ... INVALID_ARGS ...".

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const agentConfig = resolveAgentConfig(config, options.agent);
let agentConfig: AgentConfig;
try {
agentConfig = resolveAgentConfig(config, options.agent);
} catch (error) {
throw new PpgError(
error instanceof Error ? error.message : 'Invalid --agent value',
'INVALID_ARGS',
);
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/core/operations/spawn.ts` at line 59, resolveAgentConfig(config,
options.agent) can throw a plain Error which bypasses our typed CLI error
handling; wrap the call in a try/catch around the const agentConfig =
resolveAgentConfig(...) expression and on failure throw a PpgError with the
proper code (e.g. ErrorCode.INVALID_ARGS) that includes the original error
message (or sets the original error as the cause) so callers receive a typed
error. Ensure you reference the symbols resolveAgentConfig and PpgError (and
ErrorCode.INVALID_ARGS) when making the change and preserve the original error
text in the new PpgError.

}

const agentConfig = resolveAgentConfig(config, options.agent);
const count = options.count ?? 1;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Validate count before any spawn side effects.

count currently accepts non-integer/invalid values (0, negative, NaN, decimals), which can create worktrees/windows with zero agents or over-spawn due loop semantics.

Proposed fix
   const count = options.count ?? 1;
+  if (!Number.isInteger(count) || count < 1) {
+    throw new PpgError('--count must be a positive integer', 'INVALID_ARGS');
+  }

Also applies to: 165-166

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/core/operations/spawn.ts` at line 60, Validate and sanitize options.count
at the start of the spawn routine before any side effects: ensure the value read
from options.count (used to set const count) is a finite integer >= 1 (e.g.
coerce via Math.floor or parseInt then check Number.isFinite and >=1) and reject
or default invalid values (NaN, 0, negative, decimals) so the subsequent spawn
loop and any side-effecting code (references around const count and the later
spawn loop at the section around lines 165-166) cannot create zero or too many
agents; if invalid, set a safe default (1) or throw a clear error.

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.

Extract spawn operation to core/operations/spawn.ts

1 participant