Skip to content

feat(factory-sdk): W1 scaffold + ports/config/constants#229

Merged
kjgbot merged 1 commit into
mainfrom
factory-sdk/w1-scaffold
Jun 11, 2026
Merged

feat(factory-sdk): W1 scaffold + ports/config/constants#229
kjgbot merged 1 commit into
mainfrom
factory-sdk/w1-scaffold

Conversation

@kjgbot

@kjgbot kjgbot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Scaffold @pear/factory-sdk as a source-only package under packages/factory-sdk.
  • Add config schema, Linear/Slack constants, mount/writeback/system ports, and the final relay#1056-aligned FleetClient surface.
  • Add FakeMountClient, FakeFleetClient, and the empty RelayFleetClient seam stub for the future ../relay SDK implementation.
  • Add SDK tests for config defaults/rejection and no Electron/main imports.

Verification

  • npx vitest run packages/factory-sdk
  • npx tsc --noEmit -p tsconfig.node.json

Guardrails

  • No src/main edits.
  • No root dependency or workspace changes.
  • No npm install; worktree uses the provisioned node_modules symlink.

@coderabbitai

coderabbitai Bot commented Jun 11, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 429ce893-4813-49e8-a7c9-b38982f0e71c

📥 Commits

Reviewing files that changed from the base of the PR and between b52db87 and 05e93ff.

📒 Files selected for processing (18)
  • packages/factory-sdk/package.json
  • packages/factory-sdk/src/__tests__/no-electron-imports.test.ts
  • packages/factory-sdk/src/config/schema.test.ts
  • packages/factory-sdk/src/config/schema.ts
  • packages/factory-sdk/src/constants/linear.ts
  • packages/factory-sdk/src/constants/slack.ts
  • packages/factory-sdk/src/fleet/relay-fleet-client.ts
  • packages/factory-sdk/src/index.ts
  • packages/factory-sdk/src/ports/fleet.ts
  • packages/factory-sdk/src/ports/index.ts
  • packages/factory-sdk/src/ports/mount.ts
  • packages/factory-sdk/src/ports/system.ts
  • packages/factory-sdk/src/ports/writeback.ts
  • packages/factory-sdk/src/testing/fakes.ts
  • packages/factory-sdk/src/testing/index.ts
  • packages/factory-sdk/src/types.ts
  • packages/factory-sdk/tsconfig.json
  • tsconfig.node.json

📝 Walkthrough

Walkthrough

This PR introduces a new @pear/factory-sdk package providing TypeScript type contracts, configuration schema validation, integration port interfaces (Fleet, Mount, Writeback, System), stub implementations, in-memory test fakes (FakeMountClient, FakeFleetClient), and a public API surface. Configuration defaults include Linear workflow state IDs, batch size constraints, and Slack style defaults.

Changes

Factory SDK Package

Layer / File(s) Summary
Package structure and TypeScript configuration
packages/factory-sdk/package.json, packages/factory-sdk/tsconfig.json, tsconfig.node.json
CommonJS package with . and ./testing export entrypoints; TypeScript configs extend shared base and include factory-sdk source globs.
Core type contracts and domain models
packages/factory-sdk/src/types.ts
Factory, FactoryPorts, LinearIssue, IterationReport, DispatchResult, FactoryStatus, TriageEngine, TriageContext, and PrSummary define the SDK's fundamental contracts and data shapes.
Configuration schema with validation and defaults
packages/factory-sdk/src/config/schema.ts, packages/factory-sdk/src/config/schema.test.ts, packages/factory-sdk/src/constants/linear.ts
FactoryConfigSchema Zod validator applies defaults for subscription arrays, batch size (5), models (implementer/reviewer), Slack style (threaded-summarized), and merge policy (never); LINEAR_STATE_IDS constant maps Linear workflow states to UUIDs; test cases validate parsing and batchSize constraints.
Integration port interfaces
packages/factory-sdk/src/ports/fleet.ts, packages/factory-sdk/src/ports/mount.ts, packages/factory-sdk/src/ports/writeback.ts, packages/factory-sdk/src/ports/system.ts, packages/factory-sdk/src/ports/index.ts
Fleet (agent spawn/resume/roster/messaging), Mount (filesystem read/write/subscribe/events), Writeback (Linear/Slack/GitHub async methods), and System (Logger, Clock) port modules define async contracts for integrations.
Path and constant helpers
packages/factory-sdk/src/constants/linear.ts, packages/factory-sdk/src/constants/slack.ts
Linear path builders (linearIssuePath, linearByStatePath, linearCommentPath) and Slack path builders (slackMessagePath, slackReplyPath) for JSON path construction.
Relay fleet client and factory stubs
packages/factory-sdk/src/fleet/relay-fleet-client.ts, packages/factory-sdk/src/index.ts (createFactory)
RelayFleetClient implements FleetClient with all methods throwing "not implemented" error; createFactory entry point also stubs with not-implemented.
Test fakes for mount and fleet clients
packages/factory-sdk/src/testing/fakes.ts, packages/factory-sdk/src/testing/index.ts
FakeMountClient and FakeFleetClient provide in-memory implementations: file maps with per-path revisions, event subscriptions and pagination, agent lifecycle tracking, message recording, and listener registration/emission for testing.
Public API barrel exports
packages/factory-sdk/src/index.ts, packages/factory-sdk/src/ports/index.ts
Main index.ts re-exports config schema, path helpers, stubs, types, and all port interfaces; ports/index.ts centralizes port-related types.
Import validation test
packages/factory-sdk/src/__tests__/no-electron-imports.test.ts
Vitest validates that SDK source does not import electron or src/main modules, enforcing packaging boundary constraints.

🎯 3 (Moderate) | ⏱️ ~25 minutes

🐰 A new SDK sprouts from the earth so fair,
With ports and fakes to handle with care,
Types dance with schemas, all locked and sound,
The factory awakens—automation found!

✨ 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 factory-sdk/w1-scaffold

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install failed due to a network error.


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.

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request introduces the @pear/factory-sdk package, establishing core configuration schemas, ports, and testing fakes for the Factory service. The feedback focuses on improving the robustness and isolation of the SDK: updating the Zod schema for stateIds to support partial overrides, stripping comments in the import-checking test to prevent false positives, deep-cloning files in FakeMountClient to avoid test pollution, and explicitly declaring external dependencies in package.json.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +31 to +36
stateIds: z.object({
readyForAgent: z.string(),
agentImplementing: z.string(),
done: z.string(),
inPlanning: z.string(),
}).default(LINEAR_STATE_IDS),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

Using .default(LINEAR_STATE_IDS) on the outer stateIds object means that if a user provides a partial stateIds object (e.g., only overriding readyForAgent), Zod validation will fail because the other fields are required and do not have individual defaults.

To allow partial overrides seamlessly, we should define defaults on the individual fields of the nested object and default the outer object to {}.

Suggested change
stateIds: z.object({
readyForAgent: z.string(),
agentImplementing: z.string(),
done: z.string(),
inPlanning: z.string(),
}).default(LINEAR_STATE_IDS),
stateIds: z.object({
readyForAgent: z.string().default(LINEAR_STATE_IDS.readyForAgent),
agentImplementing: z.string().default(LINEAR_STATE_IDS.agentImplementing),
done: z.string().default(LINEAR_STATE_IDS.done),
inPlanning: z.string().default(LINEAR_STATE_IDS.inPlanning),
}).default({}),

Comment on lines +33 to +46
async readFile(path: string): Promise<{ content: unknown; revision?: string }> {
const entry = this.files.get(path)
if (!entry) {
throw new Error(`File not found: ${path}`)
}

return { ...entry }
}

async writeFile(path: string, content: unknown): Promise<void> {
const revision = String((Number(this.files.get(path)?.revision ?? 0) || 0) + 1)
this.files.set(path, { content, revision })
this.writes.push({ path, content })
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

In FakeMountClient, returning or storing object references directly can lead to accidental state mutation and test pollution. If a test or the system under test mutates the object returned by readFile or passed to writeFile, it will unexpectedly modify the internal state of the fake.

Using structuredClone to deep-clone the content on both read and write operations ensures that the fake's state remains isolated and consistent.

  async readFile(path: string): Promise<{ content: unknown; revision?: string }> {
    const entry = this.files.get(path)
    if (!entry) {
      throw new Error(`File not found: ${path}`)
    }

    const content = entry.content && typeof entry.content === 'object'
      ? structuredClone(entry.content)
      : entry.content

    return { content, revision: entry.revision }
  }

  async writeFile(path: string, content: unknown): Promise<void> {
    const revision = String((Number(this.files.get(path)?.revision ?? 0) || 0) + 1)
    const clonedContent = content && typeof content === 'object'
      ? structuredClone(content)
      : content
    this.files.set(path, { content: clonedContent, revision })
    this.writes.push({ path, content: clonedContent })
  }

Comment on lines +28 to +30
for (const file of await walk(sourceRoot)) {
const source = await readFile(file, 'utf8')
for (const match of source.matchAll(importSpecifierPattern)) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The current import specifier regex matches any import/export statements in the file, including those inside single-line or multi-line comments. This can lead to false positives if a developer comments out an import or writes a comment containing an import-like string.

Stripping comments from the source code before running the regex match will make the test much more robust.

Suggested change
for (const file of await walk(sourceRoot)) {
const source = await readFile(file, 'utf8')
for (const match of source.matchAll(importSpecifierPattern)) {
for (const file of await walk(sourceRoot)) {
const rawSource = await readFile(file, 'utf8')
const source = rawSource.replace(/\/\*[\s\S]*?\*\//g, '').replace(/\/\/.*/g, '')
for (const match of source.matchAll(importSpecifierPattern)) {

Comment on lines +3 to +5
"private": true,
"type": "commonjs",
"exports": {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The package @pear/factory-sdk imports external packages like zod, @relayfile/sdk, and @agent-relay/harness-driver but does not declare them in its package.json dependencies or peerDependencies.

Even in a monorepo, explicitly declaring dependencies is a best practice to ensure correct dependency resolution, prevent phantom dependency issues, and support strict package managers (like pnpm or Yarn PnP).

  "private": true,
  "type": "commonjs",
  "dependencies": {
    "@relayfile/sdk": "workspace:*",
    "zod": "^3.22.0"
  },
  "peerDependencies": {
    "@agent-relay/harness-driver": "workspace:*"
  },
  "exports": {

@kjgbot kjgbot marked this pull request as ready for review June 11, 2026 18:58
@kjgbot kjgbot merged commit e0637c7 into main Jun 11, 2026
4 checks passed
@kjgbot kjgbot deleted the factory-sdk/w1-scaffold branch June 11, 2026 18:58
@agent-relay-code

Copy link
Copy Markdown
Contributor

Implemented the PR-scoped fixes for the confirmed review feedback.

Addressed comments

  • CodeRabbit: review skipped because the PR is draft. No code action needed.
  • gemini-code-assist[bot]: stateIds partial overrides failed validation because defaults were only on the outer object; fixed in packages/factory-sdk/src/config/schema.ts:31 and covered in packages/factory-sdk/src/config/schema.test.ts:55.
  • gemini-code-assist[bot]: FakeMountClient stored/returned object references directly; fixed with cloned content in packages/factory-sdk/src/testing/fakes.ts:17 and covered in packages/factory-sdk/src/testing/fakes.test.ts:6.
  • gemini-code-assist[bot]: import scanner matched import-like text inside comments; fixed in packages/factory-sdk/src/__tests__/no-electron-imports.test.ts:11 and covered in packages/factory-sdk/src/__tests__/no-electron-imports.test.ts:45.
  • gemini-code-assist[bot]: package imported external dependencies without declaring them; fixed in packages/factory-sdk/package.json:5.
  • gemini-code-assist[bot]: summary review also mentioned the same four items above; addressed via the specific fixes listed here. The Gemini sunset notice was informational.

Verification

Passed locally:

  • npm ci
  • npm run verify:mcp-resources-drift
  • npm run lint with existing warnings only
  • npm run typecheck:web
  • npm run typecheck:node
  • npm test
  • npx vitest run
  • npx vitest run packages/factory-sdk/src
  • npm run build
  • npm run build:web
  • npx playwright test --config playwright.redraw.config.ts
  • npx playwright test --config playwright.fidelity.config.ts after installing Chromium; one initial timeout passed on rerun and then the full config passed

I could not reproduce the macOS-only packaged-mcp-smoke CI job in this Linux container, and I did not verify GitHub mergeability or post-edit cloud CI status.

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.

1 participant