Skip to content

Refactor linear chat lead workflow into checked-in files#38

Merged
khaliqgant merged 3 commits into
mainfrom
codex/linear-chat-lead-workflow-file
Jun 4, 2026
Merged

Refactor linear chat lead workflow into checked-in files#38
khaliqgant merged 3 commits into
mainfrom
codex/linear-chat-lead-workflow-file

Conversation

@khaliqgant

@khaliqgant khaliqgant commented Jun 4, 2026

Copy link
Copy Markdown
Member

User description

Summary

  • move the linear-chat-lead implementation workflow into a checked-in workflow file
  • replace the base64 inlined PR script with a checked-in CommonJS helper that reads JSON args
  • keep the Linear chat/implement classification flow and pass structured invocation args through ctx.workflow.run

Verification

  • npm test
  • npm run compile

Summary by cubic

Refactored the Linear chat lead to use checked-in workflow and PR helper files, removing inline base64 scripts and runtime file writes for better security and reliability. The user flow is unchanged.

  • Refactors
    • Added workflows/linear-chat-lead.ts that reads process.env.invocationArgs, clones the repo, delegates work, and writes a UUID-based temp helper script and JSON args (with trap cleanup) before running it via @agent-relay/sdk/workflows.
    • Added workflows/linear-create-pr.cjs to open PRs from JSON args; auto-detects baseBranch from origin/HEAD or the base SHA, rejects symlinks and paths outside the repo, and posts to /api/v1/github/pull-request using WORKFORCE_WORKSPACE_TOKEN or CLOUD_API_ACCESS_TOKEN.
    • Removed linear/create-pr.script.ts; simplified linear/agent.ts to pass structured args to ctx.workflow.run('linear-chat-lead', ...).
    • Added workflows/agent-relay-workflows.d.ts and updated tsconfig.json to include workflow files; updated tests to cover structured invocation args, no base64 embedding, safety checks, and base-branch detection.

Written for commit 2870977. Summary will update on new commits.

Review in cubic


CodeAnt-AI Description

Move the Linear chat lead workflow and PR helper into checked-in files

What Changed

  • The Linear implementation flow now runs from a checked-in workflow file instead of being written at runtime.
  • The workflow now receives structured input directly, including issue details and PR details, instead of embedding script content in the request.
  • PR creation now uses a checked-in helper that can infer the base branch from the repository, includes deleted files in the PR payload, and rejects unsafe file paths or symlinks.
  • Tests were updated to verify the new workflow inputs and the checked-in helper files.

Impact

✅ Safer PR creation from agent-generated changes
✅ Fewer runtime workflow failures
✅ Correct PRs when the base branch is not main

💡 Usage Guide

Checking Your Pull Request

Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.

Talking to CodeAnt AI

Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:

@codeant-ai ask: Your question here

This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.

Example

@codeant-ai ask: Can you suggest a safer alternative to storing this secret?

Preserve Org Learnings with CodeAnt

You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:

@codeant-ai: Your feedback here

This helps CodeAnt AI learn and adapt to your team's coding style and standards.

Example

@codeant-ai: Do not flag unused imports.

Retrigger review

Ask CodeAnt AI to review the PR again, by typing:

@codeant-ai: review

Check Your Repository Health

To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.

@gemini-code-assist

Copy link
Copy Markdown

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@codeant-ai

codeant-ai Bot commented Jun 4, 2026

Copy link
Copy Markdown

CodeAnt AI is reviewing your PR.

@coderabbitai

coderabbitai Bot commented Jun 4, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Replaces runtime-generated workflow source with static workflows. Adds workflow type declarations and a linear-chat-lead workflow that clones the repo, runs a codex implementation step, and invokes a standalone linear-create-pr.cjs helper to open a PR. The Linear agent now calls the workflow directly and tests were updated accordingly.

Changes

Workflow-based Linear implementation and PR creation

Layer / File(s) Summary
Workflow SDK types and TypeScript configuration
workflows/agent-relay-workflows.d.ts, tsconfig.json
Adds @agent-relay/sdk/workflows declarations (WorkflowBuilder, AgentOptions, StepOptions) and updates tsconfig.json include to workflows/*.ts and workflows/*.d.ts.
Linear workflow orchestration and execution
workflows/linear-chat-lead.ts
Adds linear-chat-lead workflow: parses invocation args, clones the target repo, runs the codex impl step (no commit/push), builds openPrArgs, and includes JSON parsing and shell-escaping helpers.
PR creation script for cloud API submission
workflows/linear-create-pr.cjs
Adds a CommonJS helper that reads JSON args, resolves baseSha/baseBranch, computes changed and deleted file payloads (base64-encoded contents or deleted markers), posts to the cloud PR API, and logs prUrl and branch.
Agent delegation to static workflows
linear/agent.ts
Stops generating/persisting workflow source; delegateImplementation now calls ctx.workflow.run for linear-chat-lead, passing ...workflowArgs and issue identity fields. Removes prior workflowSource generation code and related constants.
Test assertion refactoring for workflow execution
tests/linear-agent.test.mjs
Removes dependency on embedded script template, adds readFile import, asserts runtime.fileWrites is empty, validates runtime.workflowRuns[0].args.openPrArgs, and verifies emitted workflow files contain expected code patterns.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Suggested labels

size:XXL

Poem

🐇 In quiet code the workflows land,
no more generated scripts by hand.
Clone the branch, let codex play,
serialize args, then send away.
PRs bloom where the rabbit planned.

🚥 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 PR title accurately reflects the main change: moving the linear chat lead workflow from runtime-generated files into checked-in files, which is the core refactoring objective.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description check ✅ Passed The pull request description accurately describes the changeset: moving the Linear workflow into checked-in files, replacing inline scripts with a CommonJS helper, and passing structured args through ctx.workflow.run.

✏️ 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 codex/linear-chat-lead-workflow-file

Warning

Review ran into problems

🔥 Problems

Git: Failed to clone repository. Please run the @coderabbitai full review command to re-trigger a full review. If the issue persists, set path_filters to include or exclude specific files.


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.

@codeant-ai codeant-ai Bot added the size:L This PR changes 100-499 lines, ignoring generated files label Jun 4, 2026
Comment on lines +71 to +74
files.push({
path: filePath,
content: fs.readFileSync(path.join(repoDir, filePath)).toString('base64'),
encoding: 'base64',

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggestion: Reading every changed path with fs.readFileSync follows symlinks, so a symlink committed in the repo can cause this step to read and exfiltrate arbitrary files from the runner filesystem in the PR payload. Reject symlinks (or encode link metadata instead of dereferencing) before reading file contents. [security]

Severity Level: Critical 🚨
- ❌ Linear implement workflow can exfiltrate runner filesystem via PR.
- ⚠️ Cloud PR API receives unintended sensitive file contents.
Steps of Reproduction ✅
1. Trigger the Linear implementation workflow so that `delegateImplementation()` runs and
calls `ctx.workflow.run(IMPLEMENT_WORKFLOW_NAME, ...)` with repo information (see
`linear/agent.ts:95-114` and `linear/agent.ts:116-160`).

2. The `linear-chat-lead` workflow in `workflows/linear-chat-lead.ts:34-88` clones the
target GitHub repo into `REPO_DIR = './repo'` and writes `.linear-chat-base-sha` (lines
45-55), then in the `open-pr` step runs `node ${CREATE_PR_SCRIPT_PATH}
${CREATE_PR_ARGS_PATH}` (lines 76-83), invoking `workflows/linear-create-pr.cjs` with
`repoDir: './repo'` (from `openPrArgs`).

3. In the cloned repo at `./repo`, create or modify a symlink that points outside the
repository, e.g. `ln -s /etc/passwd leak` and leave it untracked or changed; Git will
surface this path via `git diff --name-only ...` and/or `git ls-files --others
--exclude-standard`, which `collectDiffPaths()` in `workflows/linear-create-pr.cjs:53-65`
uses to build the `changed` set.

4. When `linear-create-pr.cjs` executes, it iterates `changed` at
`workflows/linear-create-pr.cjs:69-75`; for each `filePath` it calls
`fs.readFileSync(path.join(repoDir, filePath)).toString('base64')` (line 73) and pushes
into `files`. For the symlink, `fs.readFileSync` follows the link and reads the target
(e.g. `/etc/passwd`), and this base64 content is then sent to
`${cloudApiUrl}/api/v1/github/pull-request` in the `files` array (lines 82-86),
exfiltrating arbitrary runner filesystem contents via the PR payload.

Fix in Cursor | Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** workflows/linear-create-pr.cjs
**Line:** 71:74
**Comment:**
	*Security: Reading every changed path with `fs.readFileSync` follows symlinks, so a symlink committed in the repo can cause this step to read and exfiltrate arbitrary files from the runner filesystem in the PR payload. Reject symlinks (or encode link metadata instead of dereferencing) before reading file contents.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

Comment thread workflows/linear-create-pr.cjs Outdated
const response = await fetch(cloudApiUrl + '/api/v1/github/pull-request', {
method: 'POST',
headers: { authorization: 'Bearer ' + pullRequestAuthToken, 'content-type': 'application/json' },
body: JSON.stringify({ owner, repo, branch, baseSha, baseBranch: 'main', title, body, files }),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggestion: The PR target branch is hardcoded to main, which breaks repositories that use a different default/base branch (for example master or develop) and can cause PR creation to fail or target the wrong branch. Pass the intended base branch via arguments (or discover it from the remote) instead of hardcoding it. [logic error]

Severity Level: Major ⚠️
- ❌ Linear implement workflow may fail for non-main-base repos.
- ⚠️ PRs may target wrong base branch, confusing reviewers.
Steps of Reproduction ✅
1. A Linear event is handled by `handleLinearEvent()` in `linear/agent.ts:74-139`; when
the LLM classifies the intent as `"implement"`, `delegateImplementation()` is called at
`linear/agent.ts:95-114`.

2. `delegateImplementation()` computes `repo = parseRepo(issue) ?? 'AgentWorkforce/cloud'`
and then calls `workflowInputs()` to build `workflowArgs` (see `linear/agent.ts:95-105`
and `linear/agent.ts:116-160`), which includes `branch` and `openPrArgs` for an arbitrary
repo derived from `issue` metadata.

3. The `linear-chat-lead` workflow in `workflows/linear-chat-lead.ts:34-88` uses these
`openPrArgs` and in its `open-pr` step (lines 76-83) runs `node
./workflows/linear-create-pr.cjs /tmp/linear-chat-lead-open-pr.args.json`, passing
`owner`, `repo`, `branch`, etc. read from JSON (see
`workflows/linear-create-pr.cjs:8-14`).

4. Inside `workflows/linear-create-pr.cjs`, after collecting diffs, the script POSTs to
`${cloudApiUrl}/api/v1/github/pull-request` with `baseBranch: 'main'` hardcoded in the
body at line 85; when the workflow is configured to operate on a repo whose primary branch
is `master`, `develop`, or any non-`main` branch, the remote API will receive an incorrect
`baseBranch` value, causing PR creation to either fail or target the wrong base branch,
breaking the Linear implementation flow for such repositories.

Fix in Cursor | Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** workflows/linear-create-pr.cjs
**Line:** 85:85
**Comment:**
	*Logic Error: The PR target branch is hardcoded to `main`, which breaks repositories that use a different default/base branch (for example `master` or `develop`) and can cause PR creation to fail or target the wrong branch. Pass the intended base branch via arguments (or discover it from the remote) instead of hardcoding it.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

Comment thread workflows/linear-chat-lead.ts Outdated
Comment on lines +6 to +82
const CREATE_PR_ARGS_PATH = `/tmp/${WORKFLOW_NAME}-open-pr.args.json`;
const CREATE_PR_SCRIPT_PATH = fileURLToPath(new URL('./linear-create-pr.cjs', import.meta.url));

type OpenPrArgs = {
repoDir: string;
owner: string;
repo: string;
branch: string;
title: string;
body: string;
};

type ImplementWorkflowArgs = {
repo: string;
repoOwner: string;
repoName: string;
branch: string;
issueTitle: string;
issueBody: string;
userPrompt: string;
issueId?: string;
issueIdentifier?: string;
issueUrl?: string;
openPrArgs: OpenPrArgs;
};

const args = readInvocationArgs();

await workflow(WORKFLOW_NAME)
.description('Implement a Linear issue delegated by the chat lead')
.pattern('dag')
.timeout(4_500_000)
.agent('impl', {
cli: 'codex',
preset: 'worker',
role: 'Implement the Linear issue and prepare a PR.',
retries: 1,
maxTokens: 32000,
})
.step('clone', {
type: 'deterministic',
command: [
'set -e',
`rm -rf ${shellArg(REPO_DIR)}`,
`git clone --filter=blob:none ${shellArg(`https://github.com/${args.repo}.git`)} ${shellArg(REPO_DIR)}`,
`cd ${shellArg(REPO_DIR)} && git checkout -B ${shellArg(args.branch)}`,
`cd ${shellArg(REPO_DIR)} && git config user.email ${shellArg('linear-chat-lead@agentworkforce.local')}`,
`cd ${shellArg(REPO_DIR)} && git config user.name ${shellArg('linear-chat-lead')}`,
`cd ${shellArg(REPO_DIR)} && git rev-parse HEAD > .linear-chat-base-sha`,
].join(' && '),
captureOutput: true,
failOnError: true,
timeoutMs: 900000,
})
.step('implement', {
agent: 'impl',
dependsOn: ['clone'],
task: [
`Work in ${REPO_DIR} on branch ${args.branch}.`,
`Linear issue: ${args.issueIdentifier ? `${args.issueIdentifier}: ` : ''}${args.issueTitle}`,
args.issueUrl ? `Issue URL: ${args.issueUrl}` : '',
`User prompt: ${args.userPrompt || '(no explicit prompt)'}`,
`Issue body:\n${args.issueBody}`,
'Make the code changes needed to fully satisfy the Linear request.',
'Do not commit, push, or open a PR; the final deterministic step handles that.',
].filter(Boolean).join('\n\n'),
verification: { type: 'exit_code', value: '0' },
timeoutMs: 1_800_000,
retries: 1,
})
.step('open-pr', {
type: 'deterministic',
dependsOn: ['implement'],
command: [
'set -e',
`printf %s ${shellArg(JSON.stringify(args.openPrArgs, null, 2))} > ${shellArg(CREATE_PR_ARGS_PATH)}`,
`node ${shellArg(CREATE_PR_SCRIPT_PATH)} ${shellArg(CREATE_PR_ARGS_PATH)}`,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggestion: The workflow writes PR arguments to a fixed global path in /tmp, so concurrent runs of the same workflow can overwrite each other's args file before the node step reads it. This can cause one run to open a PR with another run's data. Use a per-run unique temp file path (for example, include a run id or random suffix) to avoid cross-run collisions. [race condition]

Severity Level: Critical 🚨
- ❌ Linear implement runs can open PRs with wrong metadata.
- ⚠️ GitHub PRs may reference incorrect branch or repository.
Steps of Reproduction ✅
1. A Linear event with intent "implement" is received and handled by the default agent in
`linear/agent.ts:51-72`, which calls `handleLinearEvent()` at `linear/agent.ts:74-139`.

2. For "implement" intent, `delegateImplementation()` at `linear/agent.ts:234-253`
constructs workflow args via `workflowInputs()` (`linear/agent.ts:255-261`) and calls
`ctx.workflow.run('linear-chat-lead', ...)` at `linear/agent.ts:245`, starting a
`linear-chat-lead` workflow run.

3. Each workflow run executes the `open-pr` step defined in
`workflows/linear-chat-lead.ts:76-87`, which writes PR arguments to the fixed path
`CREATE_PR_ARGS_PATH = "/tmp/linear-chat-lead-open-pr.args.json"` at
`workflows/linear-chat-lead.ts:6` via the shell command at
`workflows/linear-chat-lead.ts:81` and then invokes `node linear-create-pr.cjs
/tmp/linear-chat-lead-open-pr.args.json` at `workflows/linear-chat-lead.ts:82`.

4. Trigger two implementation flows close together (e.g., two Linear issues both
classified as "implement") so the workflow engine runs two `linear-chat-lead` workflows
concurrently on the same worker host; when both reach the `open-pr` step, one run's
`printf` at `workflows/linear-chat-lead.ts:81` can overwrite
`/tmp/linear-chat-lead-open-pr.args.json` between the other run's `printf` and the
`fs.readFileSync(argsPath, 'utf8')` in `workflows/linear-create-pr.cjs:8`, causing the
first run's `linear-create-pr.cjs` process to read the second run's PR arguments and open
a PR with mismatched metadata (owner/repo/branch from another run, see
`workflows/linear-create-pr.cjs:9-14`).

Fix in Cursor | Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** workflows/linear-chat-lead.ts
**Line:** 6:82
**Comment:**
	*Race Condition: The workflow writes PR arguments to a fixed global path in `/tmp`, so concurrent runs of the same workflow can overwrite each other's args file before the `node` step reads it. This can cause one run to open a PR with another run's data. Use a per-run unique temp file path (for example, include a run id or random suffix) to avoid cross-run collisions.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

@codeant-ai

codeant-ai Bot commented Jun 4, 2026

Copy link
Copy Markdown

CodeAnt AI finished reviewing your PR.

@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: 3

🤖 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 `@workflows/linear-chat-lead.ts`:
- Around line 6-7: The current CREATE_PR_ARGS_PATH constant uses a fixed /tmp
path which allows concurrent workflow runs to clobber each other's payloads;
replace the single constant with a per-run computed path (e.g., include
process.pid, Date.now(), or crypto.randomUUID()) and update all usages that
write/read the args file (where CREATE_PR_ARGS_PATH is referenced and where
CREATE_PR_SCRIPT_PATH is invoked) to use this per-run path; ensure the writer
that serializes the PR args and the child script invocation both use the same
generated filename and optionally unlink the temp file after the script
completes.

In `@workflows/linear-create-pr.cjs`:
- Around line 69-75: The current loop reads file contents using
fs.readFileSync(path.join(repoDir, filePath)) which follows symlinks and can
leak host files; before reading, use fs.lstatSync(path.join(repoDir, filePath))
to detect symbolic links (fs.Stats.isSymbolicLink()), and if a symlink is found
either skip the entry or resolve the link with fs.readlinkSync and path.resolve
then verify the resolved target starts with the repoDir path; only read and push
content into files when the target is inside repoDir. Refer to the
variables/file names filePath, repoDir, files, and the push block where
fs.readFileSync is called to implement this check and reject or ignore external
symlink targets.
- Line 85: The PR payload currently hardcodes baseBranch: 'main' in the JSON
body (see the JSON.stringify call that includes owner, repo, branch, baseSha,
baseBranch), which breaks repos with non-main default branches; update the code
to derive baseBranch from the cloned repository or the repo metadata (e.g., read
the repo's default branch via git remote/branch lookup or the repo API) and pass
that variable (e.g., defaultBranch or derivedBaseBranch) instead of the string
'main' when building the body for PR creation so baseSha and baseBranch remain
consistent.
🪄 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: 57d9de7a-132c-42de-baf8-eb6102661e7b

📥 Commits

Reviewing files that changed from the base of the PR and between 845635f and 91fffbb.

📒 Files selected for processing (7)
  • linear/agent.ts
  • linear/create-pr.script.ts
  • tests/linear-agent.test.mjs
  • tsconfig.json
  • workflows/agent-relay-workflows.d.ts
  • workflows/linear-chat-lead.ts
  • workflows/linear-create-pr.cjs
💤 Files with no reviewable changes (1)
  • linear/create-pr.script.ts

Comment thread workflows/linear-chat-lead.ts Outdated
Comment thread workflows/linear-create-pr.cjs
Comment thread workflows/linear-create-pr.cjs Outdated

@cubic-dev-ai cubic-dev-ai 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.

4 issues found across 7 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread workflows/linear-chat-lead.ts Outdated
Comment thread workflows/linear-create-pr.cjs Outdated
Comment thread workflows/linear-chat-lead.ts Outdated
Comment thread workflows/linear-create-pr.cjs Outdated
@codeant-ai

codeant-ai Bot commented Jun 4, 2026

Copy link
Copy Markdown

CodeAnt AI is running Incremental review

@codeant-ai codeant-ai Bot added size:L This PR changes 100-499 lines, ignoring generated files and removed size:L This PR changes 100-499 lines, ignoring generated files labels Jun 4, 2026
@codeant-ai

codeant-ai Bot commented Jun 4, 2026

Copy link
Copy Markdown

CodeAnt AI Incremental review completed.

@cubic-dev-ai cubic-dev-ai 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.

1 issue found across 4 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="workflows/linear-create-pr.cjs">

<violation number="1" location="workflows/linear-create-pr.cjs:68">
P1: Fallback base-branch detection can pick `origin/HEAD -> ...` as a branch name, producing an invalid `baseBranch` like `HEAD -> origin/main` in PR creation requests.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

if (remoteHeadMatch) return remoteHeadMatch[1];
const branchAtBase = gitLinesOrEmpty(['branch', '-r', '--points-at', baseSha])
.map((line) => line.trim())
.find((line) => line.startsWith('origin/') && line !== 'origin/HEAD');

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: Fallback base-branch detection can pick origin/HEAD -> ... as a branch name, producing an invalid baseBranch like HEAD -> origin/main in PR creation requests.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At workflows/linear-create-pr.cjs, line 68:

<comment>Fallback base-branch detection can pick `origin/HEAD -> ...` as a branch name, producing an invalid `baseBranch` like `HEAD -> origin/main` in PR creation requests.</comment>

<file context>
@@ -50,6 +59,17 @@
+    if (remoteHeadMatch) return remoteHeadMatch[1];
+    const branchAtBase = gitLinesOrEmpty(['branch', '-r', '--points-at', baseSha])
+      .map((line) => line.trim())
+      .find((line) => line.startsWith('origin/') && line !== 'origin/HEAD');
+    if (branchAtBase) return branchAtBase.replace(/^origin\//, '');
+    return 'main';
</file context>
Suggested change
.find((line) => line.startsWith('origin/') && line !== 'origin/HEAD');
.find((line) => /^origin\/[^\s]+$/.test(line) && !line.startsWith('origin/HEAD'));

@agent-relay-code

Copy link
Copy Markdown
Contributor

Fixed a runtime break in PR #38: the checked-in workflow was referencing ./linear-create-pr.cjs, but ctx.workflow.run uploads only the workflow source, so the helper file would not exist remotely.

Changes made:

  • Made workflows/linear-chat-lead.ts self-contained by materializing the PR helper script into a randomized temp file before running it.
  • Kept temp cleanup for both script and args.
  • Added test coverage that verifies the embedded helper matches workflows/linear-create-pr.cjs and parses as JavaScript.

Verification run locally:

  • npm run typecheck
  • npm test

@codeant-ai

codeant-ai Bot commented Jun 4, 2026

Copy link
Copy Markdown

CodeAnt AI is running Incremental review

@agent-relay-code

Copy link
Copy Markdown
Contributor

pr-reviewer applied fixes — committed and pushed 2870977 to this PR. The notes below describe what changed.

Fixed a runtime break in PR #38: the checked-in workflow was referencing ./linear-create-pr.cjs, but ctx.workflow.run uploads only the workflow source, so the helper file would not exist remotely.

Changes made:

  • Made workflows/linear-chat-lead.ts self-contained by materializing the PR helper script into a randomized temp file before running it.
  • Kept temp cleanup for both script and args.
  • Added test coverage that verifies the embedded helper matches workflows/linear-create-pr.cjs and parses as JavaScript.

Verification run locally:

  • npm run typecheck
  • npm test

@codeant-ai codeant-ai Bot added size:L This PR changes 100-499 lines, ignoring generated files and removed size:L This PR changes 100-499 lines, ignoring generated files labels Jun 4, 2026
@codeant-ai

codeant-ai Bot commented Jun 4, 2026

Copy link
Copy Markdown

CodeAnt AI Incremental review completed.

@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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
workflows/linear-chat-lead.ts (1)

177-186: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Collapse the duplicated repo/branch/repoDir contract.

The workflow clones args.repo into REPO_DIR on args.branch, but open-pr reads an independent openPrArgs.repoDir/repo/branch. A mismatched caller payload will publish the wrong tree or target the wrong PR branch. Derive these fields from the workflow’s canonical values, or at least reject mismatches during readInvocationArgs().

Suggested guard
 function readInvocationArgs(): ImplementWorkflowArgs {
   const raw = process.env.invocationArgs ?? '{}';
   const parsed = parseJsonObject(raw, 'invocationArgs');
   const openPrArgs = readObject(parsed.openPrArgs, 'openPrArgs');
+  const repo = readRequiredString(parsed, 'repo');
+  const branch = readRequiredString(parsed, 'branch');
+  const prRepoDir = readRequiredString(openPrArgs, 'repoDir');
+  const prOwner = readRequiredString(openPrArgs, 'owner');
+  const prRepo = readRequiredString(openPrArgs, 'repo');
+  const prBranch = readRequiredString(openPrArgs, 'branch');
+
+  if (prRepoDir !== REPO_DIR) {
+    throw new Error(`invocationArgs.openPrArgs.repoDir must be ${REPO_DIR}`);
+  }
+  if (`${prOwner}/${prRepo}` !== repo) {
+    throw new Error('invocationArgs.openPrArgs owner/repo must match invocationArgs.repo');
+  }
+  if (prBranch !== branch) {
+    throw new Error('invocationArgs.openPrArgs.branch must match invocationArgs.branch');
+  }
+
   return {
-    repo: readRequiredString(parsed, 'repo'),
-    branch: readRequiredString(parsed, 'branch'),
+    repo,
+    branch,
     issueTitle: readRequiredString(parsed, 'issueTitle'),
     issueBody: readString(parsed.issueBody),
     userPrompt: readString(parsed.userPrompt),
@@
     openPrArgs: {
-      repoDir: readRequiredString(openPrArgs, 'repoDir'),
-      owner: readRequiredString(openPrArgs, 'owner'),
-      repo: readRequiredString(openPrArgs, 'repo'),
-      branch: readRequiredString(openPrArgs, 'branch'),
+      repoDir: prRepoDir,
+      owner: prOwner,
+      repo: prRepo,
+      branch: prBranch,
       title: readRequiredString(openPrArgs, 'title'),
       body: readRequiredString(openPrArgs, 'body'),
     },

Also applies to: 229-246

🤖 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 `@workflows/linear-chat-lead.ts` around lines 177 - 186, The workflow currently
duplicates repository/branch/dir across the clone step and the open-pr payload
(see step 'clone' using args.repo, args.branch, REPO_DIR and the open-pr handler
reading openPrArgs.repoDir/repo/branch), which can cause mismatched publishes;
update readInvocationArgs() (or the open-pr handler) to either derive
openPrArgs.repo/openPrArgs.branch/openPrArgs.repoDir from the canonical workflow
values (args.repo, args.branch, REPO_DIR) or validate and reject any invocation
where openPrArgs.* differs from those canonical values—implement a clear check
that compares openPrArgs.repo === args.repo && openPrArgs.branch === args.branch
&& openPrArgs.repoDir === REPO_DIR and throw/return an error if not, so the
clone and open-pr cannot drift.
♻️ Duplicate comments (1)
workflows/linear-chat-lead.ts (1)

6-7: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Generate the temp file paths inside the step, not at module load.

This is still process-global state. If the workflow runtime reuses the loaded module across invocations, overlapping runs will share the same script_path/args_path and can overwrite each other's PR payloads. Create both paths inside the open-pr command (mktemp or equivalent) so each execution gets fresh files.

Suggested fix
-import { randomUUID } from 'node:crypto';
@@
-const createPrScriptPath = `/tmp/${WORKFLOW_NAME}-create-pr-${randomUUID()}.cjs`;
-const createPrArgsPath = `/tmp/${WORKFLOW_NAME}-open-pr-${randomUUID()}.args.json`;
@@
-      `script_path=${shellArg(createPrScriptPath)}`,
-      `args_path=${shellArg(createPrArgsPath)}`,
+      `script_path=$(mktemp /tmp/${WORKFLOW_NAME}-create-pr.XXXXXX.cjs)`,
+      `args_path=$(mktemp /tmp/${WORKFLOW_NAME}-open-pr.XXXXXX.args.json)`,
       'trap \'rm -f "$args_path" "$script_path"\' EXIT',

Also applies to: 213-218

🤖 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 `@workflows/linear-chat-lead.ts` around lines 6 - 7, The temp file paths
createPrScriptPath and createPrArgsPath are generated at module load, creating
process-global state that can collide across concurrent workflow invocations;
move the creation of these temp paths into the execution scope of the "open-pr"
step/command (e.g., inside the function that builds/runs the open-pr command or
the step handler), using a per-run temp generator (mktemp or randomUUID() called
at runtime) so each invocation gets fresh script and args files; update any
references to createPrScriptPath/createPrArgsPath to use the locally generated
variables and remove the module-level globals.
🤖 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.

Outside diff comments:
In `@workflows/linear-chat-lead.ts`:
- Around line 177-186: The workflow currently duplicates repository/branch/dir
across the clone step and the open-pr payload (see step 'clone' using args.repo,
args.branch, REPO_DIR and the open-pr handler reading
openPrArgs.repoDir/repo/branch), which can cause mismatched publishes; update
readInvocationArgs() (or the open-pr handler) to either derive
openPrArgs.repo/openPrArgs.branch/openPrArgs.repoDir from the canonical workflow
values (args.repo, args.branch, REPO_DIR) or validate and reject any invocation
where openPrArgs.* differs from those canonical values—implement a clear check
that compares openPrArgs.repo === args.repo && openPrArgs.branch === args.branch
&& openPrArgs.repoDir === REPO_DIR and throw/return an error if not, so the
clone and open-pr cannot drift.

---

Duplicate comments:
In `@workflows/linear-chat-lead.ts`:
- Around line 6-7: The temp file paths createPrScriptPath and createPrArgsPath
are generated at module load, creating process-global state that can collide
across concurrent workflow invocations; move the creation of these temp paths
into the execution scope of the "open-pr" step/command (e.g., inside the
function that builds/runs the open-pr command or the step handler), using a
per-run temp generator (mktemp or randomUUID() called at runtime) so each
invocation gets fresh script and args files; update any references to
createPrScriptPath/createPrArgsPath to use the locally generated variables and
remove the module-level globals.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: cc5cdafb-c2f2-4557-9e75-6d566892b6e9

📥 Commits

Reviewing files that changed from the base of the PR and between 91fffbb and 2870977.

📒 Files selected for processing (4)
  • linear/agent.ts
  • tests/linear-agent.test.mjs
  • workflows/linear-chat-lead.ts
  • workflows/linear-create-pr.cjs
💤 Files with no reviewable changes (1)
  • linear/agent.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • workflows/linear-create-pr.cjs

@khaliqgant khaliqgant merged commit 2b837d8 into main Jun 4, 2026
2 checks passed
@khaliqgant khaliqgant deleted the codex/linear-chat-lead-workflow-file branch June 4, 2026 16:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L This PR changes 100-499 lines, ignoring generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant