opencode-swarm 7.87.0 → 7.87.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.
@@ -122,6 +122,27 @@ function isGitBinaryMissing(err) {
122
122
 
123
123
  // src/git/branch.ts
124
124
  init_logger();
125
+
126
+ // src/utils/transient-retry.ts
127
+ var MAX_TRANSIENT_RETRIES = 5;
128
+ var RETRY_BASE_DELAY_MS = 200;
129
+ function isTransientSpawnError(error2) {
130
+ if (!error2 || typeof error2 !== "object")
131
+ return false;
132
+ const code = error2.code;
133
+ return code === "ETIMEDOUT";
134
+ }
135
+ function transientBackoff(attempt) {
136
+ const delay = RETRY_BASE_DELAY_MS * 2 ** attempt;
137
+ try {
138
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, delay);
139
+ } catch {
140
+ const start = Date.now();
141
+ while (Date.now() - start < delay) {}
142
+ }
143
+ }
144
+
145
+ // src/git/branch.ts
125
146
  var GIT_TIMEOUT_MS = 30000;
126
147
  var GIT_MAX_BUFFER_BYTES = 5 * 1024 * 1024;
127
148
  function unique(values) {
@@ -153,26 +174,34 @@ function gitExec(args, cwd) {
153
174
  const subcommand = args[0];
154
175
  const hardenedArgs = subcommand === "commit" || subcommand === "tag" ? ["-c", "commit.gpgsign=false", "-c", "tag.gpgsign=false", ...args] : args;
155
176
  for (const command of windowsGitCandidates()) {
156
- const result = child_process.spawnSync(command, hardenedArgs, {
157
- cwd,
158
- encoding: "utf-8",
159
- timeout: GIT_TIMEOUT_MS,
160
- windowsHide: true,
161
- maxBuffer: GIT_MAX_BUFFER_BYTES,
162
- stdio: ["ignore", "pipe", "pipe"],
163
- env: { ...process.env, GIT_TERMINAL_PROMPT: "0" }
164
- });
165
- if (result.error) {
166
- if (isGitBinaryMissing(result.error)) {
167
- missingGitError ??= result.error;
168
- continue;
177
+ for (let attempt = 0;attempt < MAX_TRANSIENT_RETRIES; attempt++) {
178
+ const result = child_process.spawnSync(command, hardenedArgs, {
179
+ cwd,
180
+ encoding: "utf-8",
181
+ timeout: GIT_TIMEOUT_MS,
182
+ windowsHide: true,
183
+ maxBuffer: GIT_MAX_BUFFER_BYTES,
184
+ stdio: ["ignore", "pipe", "pipe"],
185
+ env: { ...process.env, GIT_TERMINAL_PROMPT: "0" }
186
+ });
187
+ if (!result.error && result.status === 0) {
188
+ return result.stdout;
189
+ }
190
+ if (result.error) {
191
+ if (isGitBinaryMissing(result.error)) {
192
+ missingGitError ??= result.error;
193
+ break;
194
+ }
195
+ if (isTransientSpawnError(result.error) && attempt < MAX_TRANSIENT_RETRIES - 1) {
196
+ transientBackoff(attempt);
197
+ continue;
198
+ }
199
+ throw new Error(errorMessage(result.error));
200
+ }
201
+ if (result.status !== 0) {
202
+ throw new Error(result.stderr || result.stdout || `git exited with ${result.status}`);
169
203
  }
170
- throw new Error(errorMessage(result.error));
171
- }
172
- if (result.status !== 0) {
173
- throw new Error(result.stderr || result.stdout || `git exited with ${result.status}`);
174
204
  }
175
- return result.stdout;
176
205
  }
177
206
  throw new GitBinaryMissingError(process.platform === "win32" ? "git executable is not available on PATH or common Windows install locations" : "git executable is not available on PATH", { cause: missingGitError });
178
207
  }
@@ -3859,4 +3888,4 @@ function mergeDurableGateEntriesFromEvidence(taskId, entries, evidence) {
3859
3888
  return merged;
3860
3889
  }
3861
3890
 
3862
- export { PlanSchema, getGitRepositoryStatus, isGitRepo, resetToRemoteBranch, resetToMainAfterMerge, isStateUnreadable, loadEpicSessionState, isEpicModeActive, enableEpicMode, disableEpicMode, normalizePath, pathsConflict, isGlobalFile, isProtectedPath, readTaskScopes, loadSddStatusSync, buildOpenSpecProjectionSync, readEffectiveSpecSync, writeProjectedSpecSync, computeSpecHash, derivePlanId, computePlanHash, initLedger, appendLedgerEvent, loadPlanJsonOnly, loadPlan, savePlan, closePlanTerminalState, derivePlanMarkdown, RetrospectiveEvidenceSchema, isValidEvidenceType, sanitizeTaskId2 as sanitizeTaskId, validateProjectRoot, saveEvidence, loadEvidence, listEvidenceTaskIds, checkRequirementCoverage, archiveEvidence, readDurableGateEvidence, getDurableGateEvidenceStatus, getDurableGateEvidenceStatusForTask, mergeDurableGateEntriesFromEvidence };
3891
+ export { PlanSchema, MAX_TRANSIENT_RETRIES, isTransientSpawnError, transientBackoff, getGitRepositoryStatus, isGitRepo, resetToRemoteBranch, resetToMainAfterMerge, isStateUnreadable, loadEpicSessionState, isEpicModeActive, enableEpicMode, disableEpicMode, normalizePath, pathsConflict, isGlobalFile, isProtectedPath, readTaskScopes, loadSddStatusSync, buildOpenSpecProjectionSync, readEffectiveSpecSync, writeProjectedSpecSync, computeSpecHash, derivePlanId, computePlanHash, initLedger, appendLedgerEvent, loadPlanJsonOnly, loadPlan, savePlan, closePlanTerminalState, derivePlanMarkdown, RetrospectiveEvidenceSchema, isValidEvidenceType, sanitizeTaskId2 as sanitizeTaskId, validateProjectRoot, saveEvidence, loadEvidence, listEvidenceTaskIds, checkRequirementCoverage, archiveEvidence, readDurableGateEvidence, getDurableGateEvidenceStatus, getDurableGateEvidenceStatusForTask, mergeDurableGateEntriesFromEvidence };
@@ -12,7 +12,7 @@ import {
12
12
  detectPosixWrites,
13
13
  detectWindowsWrites,
14
14
  resolveWriteTargets
15
- } from "./index-wv2yj8ka.js";
15
+ } from "./index-6qkwgdsg.js";
16
16
  import {
17
17
  checkFileAuthority,
18
18
  classifyFile,
@@ -1,7 +1,7 @@
1
1
  // @bun
2
2
  import {
3
3
  handleGuardrailExplain
4
- } from "./index-f13d3b69.js";
4
+ } from "./index-f41fa3f0.js";
5
5
  import {
6
6
  handleGuardrailLog
7
7
  } from "./index-5vpe6vq9.js";
@@ -76,7 +76,7 @@ import {
76
76
  handleWriteRetroCommand,
77
77
  normalizeSwarmCommandInput,
78
78
  resolveCommand
79
- } from "./index-wv2yj8ka.js";
79
+ } from "./index-6qkwgdsg.js";
80
80
  import"./index-5hvbw5xh.js";
81
81
  import"./index-yhsmmv2z.js";
82
82
  import"./index-s8bj492g.js";
@@ -87,7 +87,7 @@ import {
87
87
  ORCHESTRATOR_NAME,
88
88
  stripKnownSwarmPrefix
89
89
  } from "./index-q9h0wb04.js";
90
- import"./index-89xjr3h4.js";
90
+ import"./index-8y7qetpg.js";
91
91
  import"./index-adz3nk9b.js";
92
92
  import"./index-v4fcn4tr.js";
93
93
  import"./index-e7h9bb6v.js";
package/dist/cli/index.js CHANGED
@@ -7,7 +7,7 @@ import {
7
7
  getPluginLockFilePaths,
8
8
  package_default,
9
9
  resolveCommand
10
- } from "./index-wv2yj8ka.js";
10
+ } from "./index-6qkwgdsg.js";
11
11
  import"./index-5hvbw5xh.js";
12
12
  import"./index-yhsmmv2z.js";
13
13
  import"./index-s8bj492g.js";
@@ -16,7 +16,7 @@ import"./index-1cb4wxnm.js";
16
16
  import {
17
17
  DEFAULT_AGENT_CONFIGS
18
18
  } from "./index-q9h0wb04.js";
19
- import"./index-89xjr3h4.js";
19
+ import"./index-8y7qetpg.js";
20
20
  import"./index-adz3nk9b.js";
21
21
  import"./index-v4fcn4tr.js";
22
22
  import"./index-e7h9bb6v.js";
@@ -78,12 +78,18 @@ export interface CloseStageContext {
78
78
  archivedFileCount: number;
79
79
  archivedActiveStateFiles: Set<string>;
80
80
  archivedActiveStateDirs: Set<string>;
81
+ archiveFailureReasons: Map<string, string>;
81
82
  timestamp: string;
82
83
  archiveDir: string;
83
84
  archiveSuffix: string;
84
85
  args: string[];
85
86
  }
86
87
  declare function countSessionKnowledgeEntries(entries: CloseKnowledgeEntry[], sessionStart: string | undefined, fallbackCount: number): number;
88
+ /**
89
+ * Backward-compatible wrapper that returns only the copied count.
90
+ * Direct callers (including tests) that expect a number continue to work.
91
+ * Use copyDirRecursiveWithFailures when per-file failure tracking is needed.
92
+ */
87
93
  declare function copyDirRecursive(src: string, dest: string): Promise<number>;
88
94
  /**
89
95
  * Guarantee all phases and tasks in a plan are marked complete/closed.
@@ -28,6 +28,11 @@ export type GitRepositoryStatus = {
28
28
  * signing entirely. This is the single source of truth for
29
29
  * non-interactive git, so the hardening covers every caller
30
30
  * (current and future) uniformly.
31
+ *
32
+ * Transient retry: transient spawn errors (e.g. ETIMEDOUT) are retried
33
+ * with exponential backoff up to MAX_TRANSIENT_RETRIES before throwing.
34
+ * Permanent errors — non-zero exit, missing git binary, non-transient
35
+ * spawn errors — throw immediately with no retry.
31
36
  */
32
37
  declare function gitExec(args: string[], cwd: string): string;
33
38
  export declare function getGitRepositoryStatus(cwd: string): GitRepositoryStatus;
package/dist/git/pr.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import * as child_process from 'node:child_process';
1
2
  export declare const GIT_TIMEOUT_MS = 30000;
2
3
  /**
3
4
  * Sanitize input string to prevent command injection
@@ -6,8 +7,23 @@ export declare const GIT_TIMEOUT_MS = 30000;
6
7
  export declare function sanitizeInput(input: string): string;
7
8
  /**
8
9
  * Execute gh CLI command
10
+ *
11
+ * Follows canonical gitExec safety pattern from branch.ts:
12
+ * - result.error check before result.status
13
+ * - maxBuffer to prevent ERR_CHILD_PROCESS_STDIO_MAXBUFFER on large output
14
+ * - windowsHide: true to prevent console window flash on Windows
15
+ * - Bounded transient retry for ETIMEDOUT per AGENTS.md invariant 9
9
16
  */
10
17
  export declare function ghExec(args: string[], cwd: string): string;
18
+ /**
19
+ * Shared spawnSync wrapper with bounded ETIMEDOUT-only transient retry.
20
+ *
21
+ * Mirrors the retry shape from ghExec (invariant 9):
22
+ * - Up to MAX_TRANSIENT_RETRIES attempts with exponential backoff on ETIMEDOUT
23
+ * - ENOENT and non-zero exit are thrown immediately (not retried)
24
+ * - On success, returns the raw spawnSync result transparently
25
+ */
26
+ declare function spawnSyncWithTransientRetry(command: string, args: string[], options: child_process.SpawnSyncOptions): child_process.SpawnSyncReturns<string>;
11
27
  /**
12
28
  * Execute gh CLI command asynchronously (non-blocking).
13
29
  * Used by background workers that must not block the event loop.
@@ -23,6 +39,7 @@ export declare function ghExecAsync(args: string[], cwd: string): Promise<string
23
39
  export declare const _internals: {
24
40
  ghExec: typeof ghExec;
25
41
  ghExecAsync: typeof ghExecAsync;
42
+ spawnSyncWithTransientRetry: typeof spawnSyncWithTransientRetry;
26
43
  };
27
44
  /**
28
45
  * Check if gh CLI is available
@@ -106,3 +123,4 @@ export declare function getMergeState(prNumber: number, repoFullName: string, cw
106
123
  * Uses async ghExecAsync to avoid blocking the event loop.
107
124
  */
108
125
  export declare function getPRReviewState(prNumber: number, repoFullName: string, cwd: string): Promise<ReviewStateResult>;
126
+ export {};