patchrelay 0.69.1 → 0.69.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "service": "patchrelay",
3
- "version": "0.69.1",
4
- "commit": "33489627ce30",
5
- "builtAt": "2026-05-22T17:23:23.600Z"
3
+ "version": "0.69.2",
4
+ "commit": "aff7f71749de",
5
+ "builtAt": "2026-05-22T21:13:33.138Z"
6
6
  }
@@ -68,7 +68,7 @@ export async function handleLiveCommand(params) {
68
68
  throw new Error(`${params.parsed.flags.get("watch") === true ? "watch" : "status"} requires <issueKey>.`);
69
69
  }
70
70
  const watch = params.parsed.flags.get("watch") === true;
71
- do {
71
+ for (;;) {
72
72
  const result = await params.data.live(issueKey);
73
73
  if (!result) {
74
74
  throw new Error(`No active stage found for ${issueKey}`);
@@ -78,7 +78,7 @@ export async function handleLiveCommand(params) {
78
78
  break;
79
79
  }
80
80
  await delay(2000);
81
- } while (true);
81
+ }
82
82
  return 0;
83
83
  }
84
84
  export async function handleWorktreeCommand(params) {
@@ -29,7 +29,7 @@ export async function runConnectFlow(params) {
29
29
  writeOutput(params.stdout, `${result.projectId ? `Repo: ${result.projectId}\n` : ""}${opened ? "Opened browser for Linear OAuth.\n" : "Open this URL in a browser:\n"}${opened ? result.authorizeUrl : `${result.authorizeUrl}\n`}Waiting for OAuth approval...\n`);
30
30
  const deadline = Date.now() + (params.timeoutSeconds ?? 180) * 1000;
31
31
  const pollIntervalMs = params.connectPollIntervalMs ?? 1000;
32
- do {
32
+ for (;;) {
33
33
  const status = await params.data.connectStatus(result.state);
34
34
  if (status.status === "completed") {
35
35
  const label = status.installation?.workspaceName ?? status.installation?.actorName ?? `installation #${status.installation?.id ?? "unknown"}`;
@@ -50,5 +50,5 @@ export async function runConnectFlow(params) {
50
50
  throw new Error(`Timed out waiting for Linear OAuth after ${params.timeoutSeconds ?? 180} seconds.`);
51
51
  }
52
52
  await delay(pollIntervalMs);
53
- } while (true);
53
+ }
54
54
  }
@@ -5,9 +5,8 @@ export class CliOperatorApiClient {
5
5
  }
6
6
  close() { }
7
7
  async connect(projectId) {
8
- return await this.requestJson("/api/oauth/linear/start", {
9
- ...(projectId ? { projectId } : {}),
10
- });
8
+ const query = projectId ? { projectId } : undefined;
9
+ return await this.requestJson("/api/oauth/linear/start", query);
11
10
  }
12
11
  async connectStatus(state) {
13
12
  if (!state) {
@@ -31,9 +30,8 @@ export class CliOperatorApiClient {
31
30
  return await this.requestJson("/api/linear/workspaces");
32
31
  }
33
32
  async syncLinearWorkspace(workspace) {
34
- return await this.requestJson("/api/linear/workspaces/sync", {
35
- ...(workspace ? { workspace } : {}),
36
- }, { method: "POST" });
33
+ const query = workspace ? { workspace } : undefined;
34
+ return await this.requestJson("/api/linear/workspaces/sync", query, { method: "POST" });
37
35
  }
38
36
  async disconnectLinearWorkspace(workspace) {
39
37
  return await this.requestJson(`/api/linear/workspaces/${encodeURIComponent(workspace)}`, undefined, { method: "DELETE" });
@@ -5,7 +5,7 @@ import { HelpBar, buildHelpBarText } from "./HelpBar.js";
5
5
  import { buildDetailLines } from "./detail-rows.js";
6
6
  import { buildDetailStatusSegments, buildDetailStatusText } from "./detail-status.js";
7
7
  import { measureRenderedTextRows } from "./layout-measure.js";
8
- export function IssueDetailView({ issue, timeline, follow, scrollOffset, unreadBelow, activeRunStartedAt, activeRunId, tokenUsage, diffSummary, plan, issueContext, detailTab, rawRuns, rawFeedEvents, connected, lastServerMessageAt, reservedRows = 0, compact = false, onLayoutChange, }) {
8
+ export function IssueDetailView({ issue, timeline, follow, scrollOffset, unreadBelow, activeRunStartedAt, activeRunId, tokenUsage, diffSummary, plan, issueContext, detailTab, rawRuns, rawFeedEvents, connected, lastServerMessageAt, reservedRows = 0, onLayoutChange, }) {
9
9
  const { stdout } = useStdout();
10
10
  const width = Math.max(20, stdout?.columns ?? 80);
11
11
  const totalRows = stdout?.rows ?? 24;
@@ -95,7 +95,6 @@ function MainPathNode({ node, isLast, runOffset, plan, activeRunId, }) {
95
95
  const stateLabel = STATE_LABELS[node.state] ?? node.state;
96
96
  const marker = node.isCurrent ? "\u25c9" : "\u25cb";
97
97
  const stateColor = node.isCurrent ? "green" : "white";
98
- const hasActiveRun = node.runs.some((r) => r.id === activeRunId);
99
98
  const gutter = isLast && node.sideTrips.length === 0 ? " " : " \u2502 ";
100
99
  return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { children: [_jsxs(Text, { color: stateColor, bold: node.isCurrent, children: [" ", marker, " "] }), _jsx(Text, { color: stateColor, bold: node.isCurrent, children: stateLabel }), _jsxs(Text, { dimColor: true, children: [" ", formatTime(node.enteredAt)] })] }), node.reason && (_jsxs(Box, { children: [_jsx(Text, { dimColor: true, children: gutter }), _jsx(Text, { dimColor: true, children: node.reason })] })), node.runs.length > 5 && (_jsxs(Box, { children: [_jsx(Text, { dimColor: true, children: gutter }), _jsx(RunSummary, { runs: node.runs })] })), node.runs.map((run, ri) => (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { children: [_jsx(Text, { dimColor: true, children: gutter }), _jsx(RunLine, { run: run, index: runOffset + ri, gutter: gutter })] }), run.id === activeRunId && plan && plan.length > 0 && (_jsxs(Box, { children: [_jsx(Text, { dimColor: true, children: gutter }), _jsx(PlanSteps, { plan: plan })] }))] }, `run-${run.id}`))), node.sideTrips.length > 0 && (_jsx(Box, { flexDirection: "column", children: node.sideTrips.map((trip, ti) => {
101
100
  // Count runs before this side-trip for numbering
@@ -8,7 +8,7 @@ export function renderTextLines(text, options) {
8
8
  const lines = [];
9
9
  for (let index = 0; index < sourceLines.length; index += 1) {
10
10
  const sourceLine = sourceLines[index] ?? "";
11
- const wrapped = wrapSegments(tokenizeSegments([{ text: sourceLine, ...(options.style ?? {}) }]), width, index === 0 ? options.firstPrefix : options.continuationPrefix ?? options.firstPrefix, options.continuationPrefix ?? options.firstPrefix, `${options.key}-${index}`);
11
+ const wrapped = wrapSegments(tokenizeSegments([{ text: sourceLine, ...options.style }]), width, index === 0 ? options.firstPrefix : options.continuationPrefix ?? options.firstPrefix, options.continuationPrefix ?? options.firstPrefix, `${options.key}-${index}`);
12
12
  lines.push(...wrapped);
13
13
  }
14
14
  return lines.length > 0 ? lines : [{ key: `${options.key}-0`, segments: [] }];
@@ -91,7 +91,7 @@ export function renderRichTextLines(text, options) {
91
91
  const bulletMatch = line.match(/^\s*[-*]\s+(.*)$/);
92
92
  if (bulletMatch?.[1]) {
93
93
  flushParagraph();
94
- lines.push(...wrapSegments(tokenizeSegments(parseInlineMarkdown(bulletMatch[1], options.style)), width, appendSegments(options.firstPrefix, [{ text: "• ", ...(options.style ?? {}) }]), appendSegments(options.continuationPrefix ?? options.firstPrefix, [{ text: " ", ...(options.style ?? {}) }]), `${options.key}-b-${blockIndex}`));
94
+ lines.push(...wrapSegments(tokenizeSegments(parseInlineMarkdown(bulletMatch[1], options.style)), width, appendSegments(options.firstPrefix, [{ text: "• ", ...options.style }]), appendSegments(options.continuationPrefix ?? options.firstPrefix, [{ text: " ", ...options.style }]), `${options.key}-b-${blockIndex}`));
95
95
  blockIndex += 1;
96
96
  continue;
97
97
  }
@@ -110,7 +110,7 @@ function parseInlineMarkdown(text, style) {
110
110
  for (const match of text.matchAll(pattern)) {
111
111
  const index = match.index ?? 0;
112
112
  if (index > lastIndex) {
113
- segments.push({ text: text.slice(lastIndex, index), ...(style ?? {}) });
113
+ segments.push({ text: text.slice(lastIndex, index), ...style });
114
114
  }
115
115
  if (match[1] && match[2]) {
116
116
  segments.push({ text: match[1], color: "cyan" });
@@ -119,14 +119,14 @@ function parseInlineMarkdown(text, style) {
119
119
  segments.push({ text: match[3], color: "yellow" });
120
120
  }
121
121
  else if (match[4]) {
122
- segments.push({ text: match[4], ...(style ?? {}), bold: true });
122
+ segments.push({ text: match[4], ...style, bold: true });
123
123
  }
124
124
  lastIndex = index + match[0].length;
125
125
  }
126
126
  if (lastIndex < text.length) {
127
- segments.push({ text: text.slice(lastIndex), ...(style ?? {}) });
127
+ segments.push({ text: text.slice(lastIndex), ...style });
128
128
  }
129
- return segments.length > 0 ? segments : [{ text, ...(style ?? {}) }];
129
+ return segments.length > 0 ? segments : [{ text, ...style }];
130
130
  }
131
131
  function wrapSegments(tokens, width, firstPrefix, continuationPrefix, keyPrefix) {
132
132
  const initialPrefix = cloneSegments(firstPrefix);
@@ -8,7 +8,7 @@ export async function runProjectHook(repoPath, hookName, options) {
8
8
  }
9
9
  const result = await execCommand(hookPath, [], {
10
10
  cwd: options.cwd,
11
- env: { ...sanitizedParentEnv(), ...(options.env ?? {}) },
11
+ env: { ...sanitizedParentEnv(), ...options.env },
12
12
  timeoutMs: options.timeoutMs ?? 120_000,
13
13
  });
14
14
  return {
@@ -580,9 +580,8 @@ export class IdleIssueReconciler {
580
580
  prReviewState: "approved",
581
581
  });
582
582
  if (issue.factoryState !== "awaiting_queue" || hasFailureProvenance(issue)) {
583
- this.advanceIdleIssue(issue, "awaiting_queue", {
584
- ...(hasFailureProvenance(issue) ? { clearFailureProvenance: true } : {}),
585
- });
583
+ const options = hasFailureProvenance(issue) ? { clearFailureProvenance: true } : undefined;
584
+ this.advanceIdleIssue(issue, "awaiting_queue", options);
586
585
  }
587
586
  return;
588
587
  }
package/dist/install.js CHANGED
@@ -206,7 +206,7 @@ export async function upsertProjectInConfig(options) {
206
206
  const existingProject = existingIndex >= 0 ? existingProjects[existingIndex] : undefined;
207
207
  const resolvedProjectId = existingProject ? String(existingProject.id ?? projectId) : projectId;
208
208
  const nextProject = {
209
- ...(existingProject ?? {}),
209
+ ...existingProject,
210
210
  id: resolvedProjectId,
211
211
  repo_path: repoPath,
212
212
  };
@@ -328,7 +328,7 @@ export async function upsertRepositoryInConfig(options) {
328
328
  const existingIndex = existingRepositories.findIndex((repository) => String(repository.github_repo ?? "") === githubRepo);
329
329
  const existing = existingIndex >= 0 ? existingRepositories[existingIndex] : undefined;
330
330
  const nextRepository = {
331
- ...(existing ?? {}),
331
+ ...existing,
332
332
  github_repo: githubRepo,
333
333
  local_path: localPath,
334
334
  ...(workspace ? { workspace } : {}),
@@ -16,8 +16,8 @@ export function buildOperatorRetryEvent(issue, runType, source = "operator_retry
16
16
  return {
17
17
  eventType: "merge_steward_incident",
18
18
  eventJson: JSON.stringify({
19
- ...(queueIncident ?? {}),
20
- ...(failureContext ?? {}),
19
+ ...queueIncident,
20
+ ...failureContext,
21
21
  source,
22
22
  requiresFreshHead: true,
23
23
  promptContext: [
@@ -35,7 +35,7 @@ export function buildOperatorRetryEvent(issue, runType, source = "operator_retry
35
35
  return {
36
36
  eventType: "settled_red_ci",
37
37
  eventJson: JSON.stringify({
38
- ...(failureContext ?? {}),
38
+ ...failureContext,
39
39
  source,
40
40
  }),
41
41
  dedupeKey: `${source}:ci_repair:${issue.linearIssueId}:${issue.lastGitHubFailureSignature ?? issue.prHeadSha ?? "unknown-sha"}`,
@@ -40,9 +40,7 @@ export function queueSettledOrchestrationIssue(params) {
40
40
  const dispatched = params.wakeDispatcher.recordEventAndDispatch(params.issue.projectId, params.issue.linearIssueId, {
41
41
  eventType: "delegated",
42
42
  eventJson: JSON.stringify({
43
- ...(params.promptContext
44
- ? { promptContext: params.promptContext }
45
- : { promptContext: "The orchestration child set has settled enough to begin planning." }),
43
+ promptContext: params.promptContext ?? "The orchestration child set has settled enough to begin planning.",
46
44
  }),
47
45
  dedupeKey: `delegated:orchestration_settle:${params.issue.linearIssueId}`,
48
46
  });
@@ -32,7 +32,7 @@ export function buildReviewFixBranchUpkeepContext(prNumber, baseBranch, pr, cont
32
32
  "Do not stop just because the requested code change is already present. Review can only move forward after a new pushed head.",
33
33
  ].join(" ");
34
34
  return {
35
- ...(context ?? {}),
35
+ ...context,
36
36
  branchUpkeepRequired: true,
37
37
  reviewFixMode: "branch_upkeep",
38
38
  wakeReason: "branch_upkeep",
@@ -175,7 +175,7 @@ export class DesiredStageRecorder {
175
175
  ...(hydratedIssue.estimate != null ? { estimate: hydratedIssue.estimate } : {}),
176
176
  ...(hydratedIssue.stateName ? { currentLinearState: hydratedIssue.stateName } : {}),
177
177
  ...(hydratedIssue.stateType ? { currentLinearStateType: hydratedIssue.stateType } : {}),
178
- ...(linkedPrAdoption?.issueUpdates ?? {}),
178
+ ...linkedPrAdoption?.issueUpdates,
179
179
  delegatedToPatchRelay: delegated,
180
180
  ...resolvedPlan,
181
181
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "patchrelay",
3
- "version": "0.69.1",
3
+ "version": "0.69.2",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "repository": {