Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions .github/workflows/test-lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
name: Test & Lint

on:
pull_request:
types:
- opened
- synchronize
- reopened

jobs:
verify:
runs-on: ubuntu-latest
timeout-minutes: 20

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup pnpm
uses: pnpm/action-setup@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 23.7.0
cache: pnpm

- name: Install dependencies
run: pnpm install --frozen-lockfile

# Re-enable once the repo-level lint hang is resolved.
# - name: Lint
# run: pnpm lint

- name: Test
run: pnpm test
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,10 @@ pnpm parallax unregister ./parallax.yml
pnpm parallax stop
pnpm parallax preflight
pnpm parallax pending
pnpm parallax retry ENG-123
pnpm parallax cancel ENG-123
pnpm parallax logs --task ENG-123
pnpm parallax pr-review <task-id>
pnpm parallax retry <task-id>
pnpm parallax cancel <task-id>
pnpm parallax logs --task <task-id>
```

Commands:
Expand All @@ -77,6 +78,7 @@ Commands:
- `parallax stop`
- `parallax preflight`
- `parallax pending [--approve <id>] [--reject <id>]`
- `parallax pr-review <task-id>` (experimental)
- `parallax retry <task-id>`
- `parallax cancel <task-id>`
- `parallax logs [--task <id>]`
Expand Down Expand Up @@ -116,7 +118,7 @@ Release steps:
```bash
pnpm install
pnpm release:pack
# inspect packages/cli/parallax-cli-0.0.2.tgz, then:
# inspect packages/cli/parallax-cli-0.0.3.tgz, then:
pnpm release:publish
```

Expand Down
16 changes: 16 additions & 0 deletions docs/cli-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,22 @@ Cancel a pending or running task.
parallax cancel <task-id>
```

## `parallax pr-review`

Experimental on-demand trigger for applying open human PR review comments to an existing PR branch.

```bash
parallax pr-review <task-id>
```

Notes:

- prints a prominent experimental warning before triggering
- uses the existing task/project context to locate the repo and branch
- fails unless the task already has a related open PR
- ignores automated/bot review comments
- attempts to resolve the fetched review threads after a successful push

## `parallax logs`

Tail logs from orchestrator API.
Expand Down
10 changes: 5 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
{
"name": "parallax",
"version": "0.0.2",
"version": "0.0.3",
"private": true,
"type": "module",
"scripts": {
"build": "pnpm -r build",
"test": "pnpm -r test",
"lint": "eslint .",
"lint:fix": "eslint . --fix",
"lint": "pnpm exec eslint .",
"lint:fix": "pnpm exec eslint . --fix",
"parallax": "NODE_ENV=dev pnpm --filter parallax-cli start",
"clean": "rm -rf packages/orchestrator/parallax.db packages/orchestrator/workspaces",
"release:pack": "pnpm --filter parallax-cli pack:tarball",
"release:publish": "pnpm --dir packages/cli publish:package"
},
"devDependencies": {
"@eslint/js": "10.0.1",
"@eslint/js": "9.32.0",
"@typescript-eslint/eslint-plugin": "8.56.1",
"@typescript-eslint/parser": "8.56.1",
"eslint": "10.0.2",
"eslint": "9.32.0",
"eslint-plugin-prettier": "5.5.5",
"eslint-plugin-react": "7.37.5",
"globals": "17.3.0",
Expand Down
1 change: 1 addition & 0 deletions packages/cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ Requirements:
parallax preflight
parallax start --server-api-port 3000 --server-ui-port 8080 --concurrency 2
parallax register ./parallax.yml
parallax pr-review <task-id>
```

## Example `parallax.yml`
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "parallax-cli",
"version": "0.0.2",
"version": "0.0.3",
"type": "module",
"bin": {
"parallax": "dist/cli/src/index.js"
Expand Down
6 changes: 3 additions & 3 deletions packages/cli/scripts/prepare-package.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const bundledPackages = [
sourceDir: path.join(workspaceRoot, 'packages/common'),
packageJson: {
name: '@parallax/common',
version: '0.0.2',
version: '0.0.3',
type: 'module',
main: './dist/index.js',
types: './dist/index.d.ts',
Expand All @@ -38,7 +38,7 @@ const bundledPackages = [
sourceDir: path.join(workspaceRoot, 'packages/orchestrator'),
packageJson: {
name: '@parallax/orchestrator',
version: '0.0.2',
version: '0.0.3',
type: 'module',
},
},
Expand All @@ -47,7 +47,7 @@ const bundledPackages = [
sourceDir: path.join(workspaceRoot, 'packages/ui'),
packageJson: {
name: '@parallax/ui',
version: '0.0.2',
version: '0.0.3',
type: 'module',
},
},
Expand Down
17 changes: 17 additions & 0 deletions packages/cli/src/args.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type {
LogsCommandOptions,
PendingCommandOptions,
PreflightCommandOptions,
PrReviewCommandOptions,
RegisterCommandOptions,
RetryCommandOptions,
StartCommandOptions,
Expand Down Expand Up @@ -169,6 +170,22 @@ export function parseCancelOptions(args: string[]): CancelCommandOptions {
}
}

export function parsePrReviewOptions(args: string[]): PrReviewCommandOptions {
const taskId = args[0]

if (!taskId || taskId.startsWith('--')) {
throw new Error('parallax pr-review requires <task-id>.')
}

if (args.length > 1) {
throw new Error('parallax pr-review does not accept flags.')
}

return {
taskId,
}
}

export function parseLogsOptions(args: string[]): LogsCommandOptions {
const allowedFlags = new Set(['--task'])
for (let index = 0; index < args.length; index += 1) {
Expand Down
46 changes: 46 additions & 0 deletions packages/cli/src/commands/pr-review.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { parsePrReviewOptions } from '../args.js'
import type { CliContext } from '../types.js'

const YELLOW = '\x1b[33m'
const BOLD = '\x1b[1m'
const RESET = '\x1b[0m'

async function postJson<T>(url: string, body: unknown): Promise<T> {
const response = await fetch(url, {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify(body),
})

if (!response.ok) {
const payload = (await response.json().catch(() => undefined)) as { error?: string } | undefined
throw new Error(payload?.error ?? `Request failed: ${url} ${response.status} ${response.statusText}`)
}

return response.json() as Promise<T>
}

export async function runPrReview(args: string[], context: CliContext) {
const options = parsePrReviewOptions(args)
const apiBase = await context.resolveDefaultApiBase()

console.log('')
console.log(`${YELLOW}${BOLD}⚠ Experimental: pr-review is an early on-demand workflow.${RESET}`)
console.log(`${YELLOW}It will try to apply open human PR review comments to the existing PR branch.${RESET}`)
console.log('')

let queuedTask: { reviewTaskId: string; prNumber: number }
try {
queuedTask = await postJson(`${apiBase}/tasks/${encodeURIComponent(options.taskId)}/pr-review`, {})
} catch (error) {
throw new Error(
`Failed to queue PR review for task ${options.taskId}: ${
error instanceof Error ? error.message : String(error)
}`
)
}

console.log(
`Queued PR review run for task ${options.taskId} as new task ${queuedTask.reviewTaskId} on PR #${queuedTask.prNumber}.`
)
}
7 changes: 6 additions & 1 deletion packages/cli/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import fs from 'node:fs'
import path from 'node:path'
import { fileURLToPath, pathToFileURL } from 'node:url'
import { DEFAULT_API_PORT } from '@parallax/common'
import { hasFlag, parseCancelOptions, parseLogsOptions, parsePendingOptions, parsePreflightOptions, parseRegisterOptions, parseRetryOptions, parseStartOptions, parseStopOptions as parseStopOptionsInternal, resolvePath } from './args.js'
import { hasFlag, parseCancelOptions, parseLogsOptions, parsePendingOptions, parsePreflightOptions, parsePrReviewOptions, parseRegisterOptions, parseRetryOptions, parseStartOptions, parseStopOptions as parseStopOptionsInternal, resolvePath } from './args.js'
import {
ensureFileExists,
loadRegistry as loadRegistryFromDisk,
Expand All @@ -25,6 +25,7 @@ import {
scopePendingTasks,
} from './commands/pending.js'
import { runPreflight } from './commands/preflight.js'
import { runPrReview } from './commands/pr-review.js'
import { runRegister } from './commands/register.js'
import { runRetry } from './commands/retry.js'
import { runStart } from './commands/start.js'
Expand Down Expand Up @@ -144,6 +145,9 @@ async function cli() {
case 'preflight':
await runPreflight(commandArgs)
return
case 'pr-review':
await runPrReview(commandArgs, cliContext)
return
case 'stop':
await runStop(commandArgs, cliContext)
return
Expand Down Expand Up @@ -171,6 +175,7 @@ export {
parseLogsOptions,
parsePendingOptions,
parsePreflightOptions,
parsePrReviewOptions,
parseRegisterOptions,
parseRegistryState,
parseRetryOptions,
Expand Down
4 changes: 4 additions & 0 deletions packages/cli/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ export type CancelCommandOptions = {
taskId: string
}

export type PrReviewCommandOptions = {
taskId: string
}

export type LogsCommandOptions = {
taskId?: string
}
Expand Down
2 changes: 2 additions & 0 deletions packages/cli/src/usage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export function printUsage(): void {
parallax unregister <config-file>
parallax pending [--approve <id>] [--reject <id>]
parallax preflight
parallax pr-review <task-id>
parallax retry <task-id>
parallax cancel <task-id>
parallax stop
Expand All @@ -18,6 +19,7 @@ Commands:
unregister Remove a repository config from ~/.parallax.
pending List pending plans and optionally approve/reject them.
preflight Validate local prerequisites and auth.
pr-review [experimental] Apply open human PR review comments to the task's existing open PR.
retry Queue a task for manual retry.
cancel Cancel a pending or running task.
stop Force-stop the running Parallax processes.
Expand Down
11 changes: 11 additions & 0 deletions packages/cli/vitest.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { defineConfig } from 'vitest/config'
import path from 'node:path'

export default defineConfig({
resolve: {
alias: {
'@parallax/common': path.resolve(__dirname, '../common/src/index.ts'),
'@parallax/common/executor': path.resolve(__dirname, '../common/src/executor.ts'),
},
},
})
2 changes: 1 addition & 1 deletion packages/common/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@parallax/common",
"version": "0.0.2",
"version": "0.0.3",
"private": true,
"type": "module",
"main": "./dist/index.js",
Expand Down
1 change: 1 addition & 0 deletions packages/common/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ export interface AgentResult {
error?: string
prTitle?: string
prSummary?: string
commitMessage?: string
planMarkdown?: string
}

Expand Down
6 changes: 4 additions & 2 deletions packages/marketing/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
{
"name": "@parallax/marketing",
"private": true,
"version": "0.0.2",
"version": "0.0.3",
"type": "module",
"scripts": {
"dev": "node ./scripts/sync-docs.mjs && vite",
"build": "node ./scripts/sync-docs.mjs && vite build",
Expand Down Expand Up @@ -65,9 +66,9 @@
},
"devDependencies": {
"@eslint/js": "9.32.0",
"@tailwindcss/typography": "0.5.16",
"@testing-library/jest-dom": "6.6.0",
"@testing-library/react": "16.0.0",
"@tailwindcss/typography": "0.5.16",
"@types/node": "22.16.5",
"@types/react": "18.3.23",
"@types/react-dom": "18.3.7",
Expand All @@ -78,6 +79,7 @@
"eslint-plugin-react-refresh": "0.4.20",
"globals": "15.15.0",
"jsdom": "20.0.3",
"lodash": "4.17.23",
"postcss": "8.5.6",
"tailwindcss": "3.4.17",
"typescript": "5.8.3",
Expand Down
2 changes: 1 addition & 1 deletion packages/marketing/src/test/setup.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import "@testing-library/jest-dom";
export {}

Object.defineProperty(window, "matchMedia", {
writable: true,
Expand Down
2 changes: 1 addition & 1 deletion packages/orchestrator/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@parallax/orchestrator",
"version": "0.0.2",
"version": "0.0.3",
"private": true,
"type": "module",
"scripts": {
Expand Down
3 changes: 2 additions & 1 deletion packages/orchestrator/src/ai-adapters/base-adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ export abstract class BaseAgentAdapter {
task: Task,
workingDir: string,
project: ProjectConfig,
approvedPlan?: string
approvedPlan?: string,
outputMode?: 'pr' | 'commit'
): Promise<AgentResult>

abstract runPlan(task: Task, workingDir: string, project: ProjectConfig): Promise<PlanResult>
Expand Down
Loading
Loading