Skip to content

Expose Linear GraphQL through ADE CLI#451

Merged
arul28 merged 5 commits into
mainfrom
cursor/expand-ade-cli-linear-0819
May 31, 2026
Merged

Expose Linear GraphQL through ADE CLI#451
arul28 merged 5 commits into
mainfrom
cursor/expand-ade-cli-linear-0819

Conversation

@arul28
Copy link
Copy Markdown
Owner

@arul28 arul28 commented May 31, 2026

Summary

  • Route ade linear graphql and /linear graphql through the runtime-owned Linear issue tracker so agents can use the saved project Linear OAuth/API key without receiving token material.
  • Add deterministic Linear lane/chat card publishing for CLI-created lane links, session attachments, headless runtime lane cards, and lanes create-from-linear --start-chat.
  • Promote and update the bundled ade-linear / ade-deeplinks skills so agents know when ADE posts cards automatically and when direct Linear actions should include ADE deeplinks in comments.
  • Cover CLI planning, TUI routing, ADE action registry, RPC action execution, lane/session card hooks, and agent prompt guidance with tests.

Testing

  • npm --prefix apps/ade-cli run test -- src/cli.test.ts src/tuiClient/__tests__/commands.test.ts src/adeRpcServer.test.ts
  • npm --prefix apps/desktop run test -- src/main/services/lanes/laneService.test.ts src/main/services/chat/agentChatService.test.ts src/main/services/adeActions/registry.test.ts src/main/services/cto/linearLaneCardService.test.ts
  • npm --prefix apps/desktop run test -- src/main/services/adeActions/registry.test.ts src/main/services/cto/linearAuth.test.ts
  • npm --prefix apps/ade-cli run typecheck
  • npm --prefix apps/desktop run typecheck
  • npm --prefix apps/ade-cli run build
  • npm --prefix apps/desktop run lint (passes with existing warnings)
  • npm --prefix apps/desktop run build (passes with existing Vite chunk-size warnings)
Open in Web Open in Cursor 

Summary by CodeRabbit

Release Notes

  • New Features

    • Added ade linear graphql command for executing GraphQL queries directly against Linear
    • Linear cards now automatically publish when issues are linked to lanes or chat sessions
    • Linear issues automatically attach to newly created chat sessions
  • Documentation

    • Enhanced Linear skill documentation with GraphQL usage examples
    • Added guidance on including ADE deeplinks in Linear comments for better traceability

Greptile Summary

This PR adds ade linear graphql / /linear graphql commands that proxy raw GraphQL through the runtime-owned Linear OAuth connection, wires deterministic Linear lane/chat card publishing to laneService.onLinearIssueLinked and onLinearIssueSessionLinked (headless and desktop), inserts an explicit attachLinearIssueToSession step into the create-from-linear --start-chat plan so the runtime posts chat cards, and promotes the ade-linear / ade-deeplinks skills to the bundled set.

  • GraphQL passthrough: new readLinearGraphQLArgs / parseGraphQLVariables with full validation (inline, file, positional query; variables must be a JSON object; re-validated after --arg-json overrides); both CLI and TUI paths tested.
  • Lane/session card hooks: notifyLinearIssueLinked wired into linkLinearIssues (guarded by source !== \"chat_attach\") and attachLinearIssueToSession (for newly mirrored lane links); independent dedup sets prevent duplicate cards and duplicate onAgentLaunched calls.
  • Skill bundles & guidance: ade-linear added to the bundled agent skills manifest on Mac, Windows, and the shared guidance list; both skill docs updated with GraphQL examples and the ADE-deeplinks matrix."

Confidence Score: 4/5

Safe to merge after fixing the linkedAt timestamp passed to Linear lane card attachments.

The new notifyLinearIssueLinked call sites in both linkLinearIssues and attachLinearIssueToSession pass lane.createdAt as the linkedAt metadata written to Linear, instead of the actual link-creation timestamp. For new lanes this difference is negligible, but for issues linked to an existing lane the attachment in Linear will show the wrong date. The GraphQL passthrough, dedup guards, and skill bundles are well-structured and thoroughly tested.

apps/desktop/src/main/services/lanes/laneService.ts — the notifyLinearIssueLinked call sites should pass the link's own createdAt rather than relying on lane.createdAt.

Important Files Changed

Filename Overview
apps/desktop/src/main/services/lanes/laneService.ts Adds onLinearIssueSessionLinked callback, resolveSessionTitle, notifyLinearIssueSessionLinked, and laneSummaryForLinearNotification; wires notifyLinearIssueLinked into linkLinearIssues and attachLinearIssueToSession. The new call sites use lane.createdAt as linkedAt instead of the link's own createdAt.
apps/desktop/src/main/main.ts Refactors chat-session card publishing and live-status launch into a shared publishLinearChatLink closure with independent dedup sets for cards and for onAgentLaunched; subscribes it to both laneService.onLinearIssueSessionLinked and the existing agentChatService.onLinearIssueChatLinked.
apps/ade-cli/src/bootstrap.ts Adds onLinearIssueLinked (lane cards) and onLinearIssueSessionLinked (session cards) subscribers to laneService; initialises linearIssueTrackerRef / githubServiceRef refs after createHeadlessLinearServices so callbacks safely guard via the refs.
apps/ade-cli/src/cli.ts Adds ade linear graphql sub-command with readLinearGraphQLArgs (inline, file, and positional query; variables validation; post-override re-validation); inserts an attachLinearIssueToSession step into create-from-linear --start-chat plan.
apps/ade-cli/src/tuiClient/linearCommands.ts Adds /linear graphql TUI routing with parseGraphQLVariables returning a typed result union; correctly surfaces parse errors back to the user and updates both usage strings to include graphql.
apps/desktop/src/main/services/adeActions/registry.ts Exposes graphql and runGraphQL aliases in the linear_issue_tracker domain service and allowlist, both validated through readLinearGraphQLActionArgs before forwarding to tracker.runGraphQL.
apps/desktop/src/main/services/cto/linearClient.ts Adds public runGraphQL wrapper and threads operationName through the existing request helper's JSON body.
apps/desktop/src/main/services/cto/issueTracker.ts Adds runGraphQL to the IssueTracker interface, cleanly extending the contract for all implementors.
apps/desktop/src/main/services/chat/agentChatService.ts Appends an ade-deeplinks skill reference to buildLinearSessionDirective so agents are guided to include ADE deeplinks in Linear comments.

Sequence Diagram

sequenceDiagram
    participant CLI as ade CLI / TUI
    participant RPC as ADE RPC Server
    participant Reg as Action Registry
    participant Tracker as LinearIssueTracker
    participant Linear as Linear API

    Note over CLI,Linear: ade linear graphql
    CLI->>RPC: "run_ade_action(linear_issue_tracker, graphql, {query, variables})"
    RPC->>Reg: dispatch(graphql, args)
    Reg->>Reg: readLinearGraphQLActionArgs(args)
    Reg->>Tracker: "runGraphQL({query, variables, operationName})"
    Tracker->>Linear: POST /graphql (Bearer token)
    Linear-->>Tracker: response data
    Tracker-->>CLI: result

    Note over CLI,Linear: create-from-linear --start-chat
    CLI->>RPC: Step 1 - create_lane (with Linear issue)
    RPC-->>CLI: "{laneId}"
    CLI->>RPC: Step 2 - chat createSession
    RPC-->>CLI: "{sessionId}"
    CLI->>RPC: "Step 3 - attachLinearIssueToSession(sessionId, issue, source=chat_attach)"
    RPC->>Tracker: onLinearIssueSessionLinked → publishLinearChatSessionCard
    Tracker->>Linear: create attachment (chat card)
    CLI->>RPC: Step 4 - send kickoff message
Loading

Comments Outside Diff (2)

  1. apps/ade-cli/src/tuiClient/linearCommands.ts, line 395-399 (link)

    P2 Silent variable drop on invalid --variables-json

    parseGraphQLVariables swallows both JSON parse failures and non-object values, returning undefined without any diagnostic. A user who mistypes '{first:10}' (unquoted key) or passes an array '[1,2]' will silently get a request with no variables. The CLI path (readLinearGraphQLArgs) correctly throws a CliUsageError in both cases. The TUI path should give the same feedback so the author can fix the input instead of debugging a mysteriously missing parameter.

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: apps/ade-cli/src/tuiClient/linearCommands.ts
    Line: 395-399
    
    Comment:
    **Silent variable drop on invalid `--variables-json`**
    
    `parseGraphQLVariables` swallows both JSON parse failures and non-object values, returning `undefined` without any diagnostic. A user who mistypes `'{first:10}'` (unquoted key) or passes an array `'[1,2]'` will silently get a request with no variables. The CLI path (`readLinearGraphQLArgs`) correctly throws a `CliUsageError` in both cases. The TUI path should give the same feedback so the author can fix the input instead of debugging a mysteriously missing parameter.
    
    How can I resolve this? If you propose a fix, please make it concise.

    Fix in Claude Code

  2. apps/ade-cli/src/tuiClient/linearCommands.ts, line 428-431 (link)

    P2 The final fallthrough usage string was not updated when graphql was added, so a user who mistypes the subcommand gets a help message that omits the new command.

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: apps/ade-cli/src/tuiClient/linearCommands.ts
    Line: 428-431
    
    Comment:
    The final fallthrough usage string was not updated when `graphql` was added, so a user who mistypes the subcommand gets a help message that omits the new command.
    
    
    
    How can I resolve this? If you propose a fix, please make it concise.

    Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

    Fix in Claude Code

Fix All in Claude Code

Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
apps/desktop/src/main/services/lanes/laneService.ts:988-1004
**`linkedAt` uses lane creation date, not issue-link creation date**

`notifyLinearIssueLinked` hard-codes `lane.createdAt` as the `linkedAt` value sent to `onLinearIssueLinked` (and ultimately to `publishLinearLaneCard`). This is the lane's own creation timestamp — not when the Linear issue was actually linked. For the `create-from-linear` case both timestamps are nearly identical, but for `ade lanes link-linear-issue` (or the mirror path in `attachLinearIssueToSession`) applied to an existing lane, the card timestamp in Linear will be wrong by however old the lane is.

Both new call sites in this PR have the correct value available (`link.createdAt` from the returned `LaneLinearIssueLink`), but the function signature doesn't accept it. Adding an optional third parameter — e.g. `linkedAt?: string` — and defaulting to `lane.createdAt` is a backwards-compatible fix; the call sites in this PR can then pass `link.createdAt`.

Reviews (4): Last reviewed commit: "ship: dedupe Linear live-status updates" | Re-trigger Greptile

Co-authored-by: Arul Sharma <arul28@users.noreply.github.com>
@vercel
Copy link
Copy Markdown

vercel Bot commented May 31, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
ade Ignored Ignored Preview May 31, 2026 6:17am

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 31, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

This PR adds Linear GraphQL query execution via a new ade linear graphql CLI subcommand, extends the issue tracker and Linear client with a runGraphQL method, integrates GraphQL actions into the ADE action registry, adds session-linked callbacks to the lane service, and publishes Linear chat session cards when issues are attached to chat sessions.

Changes

Linear GraphQL execution and session-linked publishing

Layer / File(s) Summary
IssueTracker interface GraphQL method
apps/desktop/src/main/services/cto/issueTracker.ts
IssueTracker type gains a runGraphQL method that accepts query, variables, operationName, and maxRetries.
LinearClient GraphQL support
apps/desktop/src/main/services/cto/linearClient.ts
Request params accept operationName and the POST body conditionally includes it; a new runGraphQL helper wraps the request function and is exported from the client factory.
LinearIssueTracker and RPC server GraphQL
apps/desktop/src/main/services/cto/linearIssueTracker.ts, apps/ade-cli/src/adeRpcServer.test.ts
LinearIssueTracker delegates runGraphQL to the client; RPC server tests mock and assert GraphQL action forwarding.
ADE action registry GraphQL operations
apps/desktop/src/main/services/adeActions/registry.ts, apps/desktop/src/main/services/adeActions/registry.test.ts
graphql and runGraphQL actions are allowlisted, implemented as thin wrappers with argument validation, and tested for dispatch and result handling.
CLI linear graphql subcommand and lanes integration
apps/ade-cli/src/cli.ts, apps/ade-cli/src/cli.test.ts
New ade linear graphql subcommand with --query/--query-file, --variables-json/--variables-file, and --operationName flags; lanes create-from-linear --start-chat inserts an issue-attachment step before kickoff; test coverage for both flows.
TUI linear command routing
apps/ade-cli/src/tuiClient/linearCommands.ts, apps/ade-cli/src/tuiClient/__tests__/commands.test.ts
GraphQL variables parser and extended buildLinearToolRequest handler for /linear graphql commands; test coverage for TUI routing.
Lane service session-linked Linear issue callbacks
apps/desktop/src/main/services/lanes/laneService.ts, apps/desktop/src/main/services/lanes/laneService.test.ts
Lane service gains onLinearIssueSessionLinked callback, session title resolution, lane summary building; attachment flow refactored to collect and notify mirrored lane links and session-scoped links with separate callbacks; test coverage for both lane-scoped and session-scoped linking.
Linear chat session card publishing handlers
apps/ade-cli/src/bootstrap.ts, apps/desktop/src/main/main.ts
New publishLinearChatLink helper deduplicates by issue/session, publishes chat cards, and reflects agent launch status; handlers wired into laneService and agent chat service; prior inline implementations removed.
Documentation, test expectations, and build validation
apps/desktop/resources/agent-skills/ade-linear/SKILL.md, apps/desktop/resources/agent-skills/ade-deeplinks/SKILL.md, apps/desktop/src/main/services/chat/agentChatService.ts, apps/desktop/src/main/services/chat/agentChatService.test.ts, apps/desktop/scripts/validate-*.mjs, apps/desktop/src/shared/adeCliGuidance.ts
Skill documentation updated with ade linear graphql examples and deeplinks guidance; chat service test expectations require ade-deeplinks content; ade-linear added to bundled skill validation; CLI guidance constants updated.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes


Possibly related PRs

  • arul28/ADE#395: Both PRs modify the same Linear GraphQL execution path in apps/desktop/src/main/services/cto/linearClient.ts—this PR adds the runGraphQL helper and operationName support, while #395 changes the underlying request retry/auth flow to proactively refresh tokens via ensureFreshToken.

  • arul28/ADE#446: This PR extends the same ade lanes create-from-linear --start-chat execution planning in apps/ade-cli/src/cli.ts by inserting an additional "attach Linear issue to chat session" step before the kickoff/send step, building on the flow modified in #446.


Suggested labels

desktop

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.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 'Expose Linear GraphQL through ADE CLI' is concise, clear, and directly describes the main change—enabling Linear GraphQL access via the ADE CLI. The summary confirms this is the primary focus.
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 Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ 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 cursor/expand-ade-cli-linear-0819

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.

Co-authored-by: Arul Sharma <arul28@users.noreply.github.com>
@arul28 arul28 marked this pull request as ready for review May 31, 2026 05:33
@arul28
Copy link
Copy Markdown
Owner Author

arul28 commented May 31, 2026

@copilot review but do not make fixes
@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 31, 2026

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Get PR details
gh pr view 451 --repo arul28/ADE --json title,body,additions,deletions,changedFiles,baseRefName,headRefName 2>&1

echo "---FILES CHANGED---"
gh pr diff 451 --repo arul28/ADE 2>&1 | head -3000

Length of output: 53592



The PR description images show the "Open in Web" and "Open in Cursor" buttons linking to the Cursor agent session that generated this PR.

@arul28 Here is the review:


PR Review: Expose Linear GraphQL through ADE CLI

Summary

Well-structured PR with good test coverage across CLI planning, TUI routing, RPC execution, and lane/session card hooks. A few items worth addressing:


🔴 Issues

1. parseGraphQLVariables silently discards malformed JSON — linearCommands.ts

} catch {
  return undefined;  // ← user gets no feedback; their --variables-json is just dropped
}

If a user passes --variables-json '{bad json}', the variables are silently dropped and the query is sent without them. This should surface a parse error to the user, consistent with how readJsonFileOption in cli.ts throws a CliUsageError.


2. Both graphql and runGraphQL in the ADE action allowlist — registry.ts

export const ADE_ACTION_ALLOWLIST = {
  linear_issue_tracker: [
    ...
    "graphql",       // new agent-facing name
    ...
    "runGraphQL",    // also added — same implementation
    ...
  ]
}

And in the service:

async graphql(args?: unknown) {
  return tracker.runGraphQL(readLinearGraphQLActionArgs(args));
},
async runGraphQL(args?: unknown) {
  return tracker.runGraphQL(readLinearGraphQLActionArgs(args));
},

Both names resolve to identical logic. If runGraphQL is an intentional alias for backward compatibility, it should be documented. Otherwise it unnecessarily widens the attack surface and creates confusion about the canonical action name.


3. Unsafe type assertion on githubServicebootstrap.ts

githubServiceRef = headlessLinearServices.githubService as ReturnType<typeof createGithubService>;

The as cast suppresses a structural mismatch that the compiler already caught. If headlessLinearServices.githubService doesn't conform to createGithubService's return type, this silences the error rather than fixing it, and the subsequent .getRepoOrThrow() call could throw unexpectedly at runtime.


🟡 Warnings

4. variables: undefined / operationName: undefined in buildLinearToolRequestlinearCommands.ts

return action("Linear GraphQL", "linear_issue_tracker", "graphql", {
  query,
  variables: parseGraphQLVariables(options),       // may be undefined
  operationName: optionString(...) ?? undefined,   // may be undefined
});

Explicit undefined values on object keys may serialize as "variables": null in some JSON stringifiers or be included as undefined keys in spread operations. Prefer conditional spreading:

const actionArgs: Record<string, unknown> = { query };
const vars = parseGraphQLVariables(options);
if (vars !== undefined) actionArgs.variables = vars;
const opName = optionString(options, "operationName", "operation");
if (opName) actionArgs.operationName = opName;
return action("Linear GraphQL", "linear_issue_tracker", "graphql", actionArgs);

5. notifyLinearIssueSessionLinked references resolveSessionTitle defined ~230 lines later — laneService.ts

Both are const arrow functions inside createLaneService. At runtime this is safe (the closure captures the binding, which is set before any external caller can invoke the service). But it creates a confusing temporal dependency within a ~2800-line function body. Consider co-locating resolveSessionTitle before notifyLinearIssueSessionLinked, or extracting both to a shared helper.


6. laneSummaryForLinearNotification uses zeroed-out git status

const laneSummaryForLinearNotification = (row: LaneRow): LaneSummary =>
  toLaneSummary({
    row,
    status: {
      dirty: false,
      ahead: 0,
      behind: 0,
      remoteBehind: -1,
      rebaseInProgress: false,
    },
    ...
  });

The returned LaneSummary has fabricated git status fields. This is fine for the current notification use-case (card publishers only need lane metadata), but if a downstream consumer ever checks lane.status.ahead or lane.status.dirty from a notification-originated summary, it will silently receive wrong data. Adding a comment would help future maintainers:

// NOTE: git status fields are zeroed here — this summary is only for
// Linear card publishing which does not use git status fields.

7. Security surface: runGraphQL permits arbitrary mutations

runGraphQL is now callable by any agent via run_ade_action domain=linear_issue_tracker action=graphql. The implementation correctly proxies through the runtime-owned credential (token not exposed to agent), but it allows arbitrary mutations (create issues, delete comments, etc.) with no query type restrictions. This is likely intentional given the PR goals, but is worth documenting explicitly in the skill file or adding a note in the registry.


✅ Positives

  • Dedup via linearChatCardPublishKeys correctly prevents double card publishing when both onLinearIssueSessionLinked (laneService) and onLinearIssueChatLinked (agentChatService) fire for the same issue+session pair.
  • The 4-step plan for create-from-linear --start-chat (lane → session → attach → kickoff) is the right order to ensure the attach fires before the kickoff message.
  • readLinearGraphQLActionArgs in registry.ts properly clamps maxRetries to [0, 10].
  • The Linear card/comment matrix added to ade-deeplinks/SKILL.md is clear and well-structured.
  • ade-linear skill promotion to bundled status in both Mac and Windows artifact validators is consistent.

Copy link
Copy Markdown
Contributor

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

PR Review

Scope: 21 file(s), +570 / −54
Verdict: Needs changes

This PR adds ade linear graphql (CLI/TUI/ADE actions), wires Linear lane/chat card publishing through laneService callbacks, and extends create-from-linear --start-chat to attach the issue after chat creation. The main risk is duplicate Linear lane attachments when a laned Work chat links an issue through the existing agent path.


🐛 Functionality

[High] Duplicate Linear lane cards on laned chat attach

File: apps/desktop/src/main/services/lanes/laneService.ts:L2768-L2773 and apps/desktop/src/main/services/lanes/laneService.ts:L2856-L2862
Issue: linkLinearIssues and attachLinearIssueToSession (lane mirror path) both call notifyLinearIssueLinked, which posts a lane attachment/comment via publishLinearLaneCard. The agent chat path runs both in sequence for the same issue.
Repro: Open a Work chat with a laneId. Attach a Linear issue that is not the lane's primary issue (e.g. via agent context / recordLinearIssueContextForLane). attachLinearIssueToSession mirrors into lane_linear_issue_links and notifies once; linkLinearIssues upserts the same worked link and notifies again. Linear shows two ADE lane cards/comments for one attach.
Fix: Notify from only one layer (e.g. drop notifyLinearIssueLinked from linkLinearIssues when source === "chat_attach", or skip the linkLinearIssues call in agentChatService when attachLinearIssueToSession already mirrored). Alternatively dedupe lane-card publishes the same way chat cards use linearChatCardPublishKeys.


🎨 UI/UX

[Low] TUI drops invalid GraphQL variables silently

File: apps/ade-cli/src/tuiClient/linearCommands.ts:L164-L175
Issue: /linear graphql with malformed --variables-json parses to undefined and runs the query without variables instead of surfacing a usage error, so the user sees a confusing Linear API failure.
Fix: On JSON.parse failure or non-object payload, return a usage(...) error (match CLI readLinearGraphQLArgs, which throws CliUsageError for bad --variables-json).


Notes

  • GraphQL passthrough is intentionally broad (full Linear API with project OAuth). It is gated by existing ADE action allowlisting and runtime auth like other linear_issue_tracker writes; not flagged as a new auth bypass.
  • In-process dedupe for chat session cards (linearChatCardPublishKeys) should prevent duplicate chat attachments when onLinearIssueSessionLinked and onLinearIssueChatLinked both fire; lane cards have no equivalent dedupe today.
  • Bundling ade-linear in desktop artifacts and agent guidance looks consistent with the new surface.
Open in Web View Automation 

Sent by Cursor Automation: BUGBOT in Versic

Comment thread apps/desktop/src/main/services/lanes/laneService.ts
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: 3

Caution

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

⚠️ Outside diff range comments (1)
apps/ade-cli/src/tuiClient/linearCommands.ts (1)

428-431: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Keep the fallback /linear usage list in sync with the new graphql command.

The bottom fallback usage text still omits graphql, so users can get contradictory help text depending on path.

💡 Suggested fix
   return usage(
     "Linear",
-    "Usage: /linear <attach|detach|issues|comment|set-state|assign|label|issue|create-from|workflows|run|route|sync|ingress> ...",
+    "Usage: /linear <attach|detach|issues|comment|set-state|assign|label|issue|graphql|create-from|workflows|run|route|sync|ingress> ...",
   );
🤖 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 `@apps/ade-cli/src/tuiClient/linearCommands.ts` around lines 428 - 431, The
fallback help string returned by usage in linearCommands.ts is missing the new
graphql command; update the string passed to usage (the "Usage: /linear <...>"
literal) to include "graphql" in the angle-bracket command list so the fallback
output from the usage(...) call matches the added graphql command (locate the
usage(...) call in linearCommands.ts that returns the "Usage: /linear
<attach|...|ingress>" string and insert "|graphql" at the appropriate position).
🧹 Nitpick comments (2)
apps/desktop/src/main/services/adeActions/registry.test.ts (1)

388-400: ⚡ Quick win

Add coverage for the runGraphQL alias as well.

Line 388 and Lines 394-400 verify graphql, but linear_issue_tracker now exposes both aliases. Add a matching assertion/invocation for runGraphQL to lock parity and prevent alias drift.

🤖 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 `@apps/desktop/src/main/services/adeActions/registry.test.ts` around lines 388
- 400, Tests currently cover the "graphql" alias but not the "runGraphQL" alias;
add parity by asserting listAllowedAdeActionNames("linear_issue_tracker",
service) contains "runGraphQL", then invoke service.runGraphQL with the same
query/variables used for service.graphql and assert it resolves to the same
payload, and finally assert tracker.runGraphQL was called with the same argument
object (or add a second call expectation / adjust call count accordingly) so
both the action list and runtime alias behavior are covered.
apps/ade-cli/src/bootstrap.ts (1)

497-520: ⚡ Quick win

Extract the shared chat-card publish path.

These two blocks duplicate the same dedupe/publish/error-handling flow. Pulling them into one local helper will keep lane-service and agent-chat publishing behavior from drifting the next time this logic changes.

♻️ Suggested consolidation
+  const publishLinearChatLink = ({
+    laneId,
+    sessionId,
+    sessionTitle,
+    issue,
+    linkedAt,
+  }: {
+    laneId: string | null;
+    sessionId: string;
+    sessionTitle: string | null;
+    issue: { id: string; identifier: string };
+    linkedAt: string;
+  }) => {
+    const tracker = linearIssueTrackerRef;
+    if (!tracker) return;
+    const key = `${issue.id}:${sessionId}`;
+    if (linearChatCardPublishKeys.has(key)) return;
+    linearChatCardPublishKeys.add(key);
+    void publishLinearChatSessionCard({
+      issueTracker: tracker,
+      issue,
+      laneId,
+      sessionId,
+      sessionTitle,
+      linkedAt,
+    }).catch((error) => {
+      linearChatCardPublishKeys.delete(key);
+      logger.warn("linear.chat_session_card_publish_failed", {
+        laneId,
+        sessionId,
+        issueId: issue.id,
+        issueIdentifier: issue.identifier,
+        error: error instanceof Error ? error.message : String(error),
+      });
+    });
+  };
+
-    onLinearIssueSessionLinked: ({ laneId, sessionId, sessionTitle, issue, linkedAt }) => {
-      const tracker = linearIssueTrackerRef;
-      if (!tracker) return;
-      const key = `${issue.id}:${sessionId}`;
-      if (linearChatCardPublishKeys.has(key)) return;
-      linearChatCardPublishKeys.add(key);
-      void publishLinearChatSessionCard({
-        issueTracker: tracker,
-        issue,
-        laneId,
-        sessionId,
-        sessionTitle,
-        linkedAt,
-      }).catch((error) => {
-        linearChatCardPublishKeys.delete(key);
-        logger.warn("linear.chat_session_card_publish_failed", {
-          laneId,
-          sessionId,
-          issueId: issue.id,
-          issueIdentifier: issue.identifier,
-          error: error instanceof Error ? error.message : String(error),
-        });
-      });
-    },
+    onLinearIssueSessionLinked: publishLinearChatLink,
...
-      onLinearIssueChatLinked: ({ laneId, sessionId, sessionTitle, issue, linkedAt }) => {
-        const tracker = linearIssueTrackerRef;
-        if (!tracker) return;
-        const key = `${issue.id}:${sessionId}`;
-        if (linearChatCardPublishKeys.has(key)) return;
-        linearChatCardPublishKeys.add(key);
-        void publishLinearChatSessionCard({
-          issueTracker: tracker,
-          issue,
-          laneId,
-          sessionId,
-          sessionTitle,
-          linkedAt,
-        }).catch((error) => {
-          linearChatCardPublishKeys.delete(key);
-          logger.warn("linear.chat_session_card_publish_failed", {
-            laneId,
-            sessionId,
-            issueId: issue.id,
-            issueIdentifier: issue.identifier,
-            error: error instanceof Error ? error.message : String(error),
-          });
-        });
-      },
+      onLinearIssueChatLinked: publishLinearChatLink,

Also applies to: 965-988

🤖 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 `@apps/ade-cli/src/bootstrap.ts` around lines 497 - 520, The
onLinearIssueSessionLinked block duplicates the dedupe/publish/error-handling
flow for linear chat-card publishing; extract a local helper (e.g.,
publishLinearChatCardOnce) that accepts parameters { tracker, issue, laneId,
sessionId, sessionTitle, linkedAt } and encapsulates the
linearChatCardPublishKeys check, key construction `${issue.id}:${sessionId}`,
adding/removing keys, calling publishLinearChatSessionCard, and the
logger.warn(error) handling; replace the body of onLinearIssueSessionLinked and
the similar block (lines ~965-988) to call this helper, referencing
linearIssueTrackerRef, linearChatCardPublishKeys, publishLinearChatSessionCard,
and logger.warn for locating the code.
🤖 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 `@apps/ade-cli/src/cli.ts`:
- Around line 2075-2098: readLinearGraphQLArgs currently calls
collectGenericObjectArgs which can overwrite reserved GraphQL fields (query,
variables, maxRetries) validated earlier; update the function so either (A)
prevent overrides by calling collectGenericObjectArgs with a mechanism to block
reserved keys (query, variables, operationName, maxRetries) or (B) re-validate
and normalize the returned object: ensure result.query is present and equal to
the previously determined query (or throw), ensure result.variables (from
readJsonPayloadOption or overridden) is either undefined or a record (throw if
not), and ensure result.maxRetries is undefined or a number (coerce/throw if
invalid); implement this change in readLinearGraphQLArgs around the
collectGenericObjectArgs call and preserve the original semantics of
maybePut/readNumberOption/readJsonPayloadOption.

In `@apps/ade-cli/src/tuiClient/linearCommands.ts`:
- Around line 164-176: The parseGraphQLVariables function currently swallows
malformed or non-object JSON and returns undefined, causing invalid
--variables-json to be silently ignored; update parseGraphQLVariables to
validate the optionString value and, on JSON parse errors or when the parsed
value is not a plain object, throw or return a user-facing error (e.g., throw a
descriptive Error or return a Result/Err) so the CLI surfaces a clear validation
message; apply the same change to the other variables-parsing helper used around
the second occurrence (the similar function at lines ~290-305) so both malformed
JSON and non-object JSON input produce an explicit error instead of silently
dropping variables.

In `@apps/desktop/src/main/main.ts`:
- Around line 1765-1808: The handler publishLinearChatLink currently uses
linearChatCardPublishKeys to short-circuit the entire function (skipping both
publishLinearChatSessionCard and linearLiveStatusServiceRef.onAgentLaunched)
which prevents retries of the live-status path; change the logic so deduping
only affects publishLinearChatSessionCard (e.g. only skip calling
publishLinearChatSessionCard when linearChatCardPublishKeys.has(key) but always
proceed to call linearLiveStatusServiceRef?.onAgentLaunched), or maintain a
separate dedupe set for the live-status path; update publishLinearChatLink to
ensure linearLiveStatusServiceRef.onAgentLaunched is invoked on every event (and
still catches/logs errors) even when the publish key exists.

---

Outside diff comments:
In `@apps/ade-cli/src/tuiClient/linearCommands.ts`:
- Around line 428-431: The fallback help string returned by usage in
linearCommands.ts is missing the new graphql command; update the string passed
to usage (the "Usage: /linear <...>" literal) to include "graphql" in the
angle-bracket command list so the fallback output from the usage(...) call
matches the added graphql command (locate the usage(...) call in
linearCommands.ts that returns the "Usage: /linear <attach|...|ingress>" string
and insert "|graphql" at the appropriate position).

---

Nitpick comments:
In `@apps/ade-cli/src/bootstrap.ts`:
- Around line 497-520: The onLinearIssueSessionLinked block duplicates the
dedupe/publish/error-handling flow for linear chat-card publishing; extract a
local helper (e.g., publishLinearChatCardOnce) that accepts parameters {
tracker, issue, laneId, sessionId, sessionTitle, linkedAt } and encapsulates the
linearChatCardPublishKeys check, key construction `${issue.id}:${sessionId}`,
adding/removing keys, calling publishLinearChatSessionCard, and the
logger.warn(error) handling; replace the body of onLinearIssueSessionLinked and
the similar block (lines ~965-988) to call this helper, referencing
linearIssueTrackerRef, linearChatCardPublishKeys, publishLinearChatSessionCard,
and logger.warn for locating the code.

In `@apps/desktop/src/main/services/adeActions/registry.test.ts`:
- Around line 388-400: Tests currently cover the "graphql" alias but not the
"runGraphQL" alias; add parity by asserting
listAllowedAdeActionNames("linear_issue_tracker", service) contains
"runGraphQL", then invoke service.runGraphQL with the same query/variables used
for service.graphql and assert it resolves to the same payload, and finally
assert tracker.runGraphQL was called with the same argument object (or add a
second call expectation / adjust call count accordingly) so both the action list
and runtime alias behavior are covered.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: c5b31b15-5c44-4aad-bbcf-2ea9085c2692

📥 Commits

Reviewing files that changed from the base of the PR and between 986203e and cbb020a.

📒 Files selected for processing (21)
  • apps/ade-cli/src/adeRpcServer.test.ts
  • apps/ade-cli/src/bootstrap.ts
  • apps/ade-cli/src/cli.test.ts
  • apps/ade-cli/src/cli.ts
  • apps/ade-cli/src/tuiClient/__tests__/commands.test.ts
  • apps/ade-cli/src/tuiClient/linearCommands.ts
  • apps/desktop/resources/agent-skills/ade-deeplinks/SKILL.md
  • apps/desktop/resources/agent-skills/ade-linear/SKILL.md
  • apps/desktop/scripts/validate-mac-artifacts.mjs
  • apps/desktop/scripts/validate-win-artifacts.mjs
  • apps/desktop/src/main/main.ts
  • apps/desktop/src/main/services/adeActions/registry.test.ts
  • apps/desktop/src/main/services/adeActions/registry.ts
  • apps/desktop/src/main/services/chat/agentChatService.test.ts
  • apps/desktop/src/main/services/chat/agentChatService.ts
  • apps/desktop/src/main/services/cto/issueTracker.ts
  • apps/desktop/src/main/services/cto/linearClient.ts
  • apps/desktop/src/main/services/cto/linearIssueTracker.ts
  • apps/desktop/src/main/services/lanes/laneService.test.ts
  • apps/desktop/src/main/services/lanes/laneService.ts
  • apps/desktop/src/shared/adeCliGuidance.ts

Comment thread apps/ade-cli/src/cli.ts
Comment thread apps/ade-cli/src/tuiClient/linearCommands.ts Outdated
Comment thread apps/desktop/src/main/main.ts
@capy-ai
Copy link
Copy Markdown

capy-ai Bot commented May 31, 2026

Capy auto-review is paused for this organization because the monthly auto-review limit has been reached. Increase the limit or turn it off in billing settings to resume automatic reviews.

Comment thread apps/desktop/src/main/main.ts
@arul28 arul28 merged commit 3f363b9 into main May 31, 2026
28 checks passed
@arul28 arul28 deleted the cursor/expand-ade-cli-linear-0819 branch May 31, 2026 08:37
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.

2 participants