aiwcli 0.12.3 → 0.12.7
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.
- package/bin/dev.cmd +3 -3
- package/bin/dev.js +16 -16
- package/bin/run.cmd +3 -3
- package/bin/run.js +21 -21
- package/dist/commands/branch.js +7 -2
- package/dist/lib/bmad-installer.js +37 -37
- package/dist/lib/terminal.d.ts +2 -0
- package/dist/lib/terminal.js +57 -7
- package/dist/templates/CLAUDE.md +205 -205
- package/dist/templates/_shared/.claude/commands/handoff-resume.md +12 -64
- package/dist/templates/_shared/.claude/commands/handoff.md +12 -198
- package/dist/templates/_shared/.claude/settings.json +65 -65
- package/dist/templates/_shared/.codex/workflows/handoff.md +226 -226
- package/dist/templates/_shared/.windsurf/workflows/handoff.md +226 -226
- package/dist/templates/_shared/handoff-system/CLAUDE.md +421 -0
- package/dist/templates/_shared/{lib-ts/handoff → handoff-system/lib}/document-generator.ts +215 -216
- package/dist/templates/_shared/{lib-ts/handoff → handoff-system/lib}/handoff-reader.ts +157 -158
- package/dist/templates/_shared/{scripts → handoff-system/scripts}/resume_handoff.ts +373 -373
- package/dist/templates/_shared/{scripts → handoff-system/scripts}/save_handoff.ts +469 -358
- package/dist/templates/_shared/handoff-system/workflows/handoff-resume.md +66 -0
- package/dist/templates/_shared/{workflows → handoff-system/workflows}/handoff.md +254 -254
- package/dist/templates/_shared/hooks-ts/_utils/git-state.ts +2 -2
- package/dist/templates/_shared/hooks-ts/archive_plan.ts +159 -159
- package/dist/templates/_shared/hooks-ts/context_monitor.ts +147 -147
- package/dist/templates/_shared/hooks-ts/file-suggestion.ts +128 -128
- package/dist/templates/_shared/hooks-ts/pre_compact.ts +49 -49
- package/dist/templates/_shared/hooks-ts/session_end.ts +196 -183
- package/dist/templates/_shared/hooks-ts/session_start.ts +163 -151
- package/dist/templates/_shared/hooks-ts/task_create_capture.ts +48 -48
- package/dist/templates/_shared/hooks-ts/task_update_capture.ts +74 -74
- package/dist/templates/_shared/hooks-ts/user_prompt_submit.ts +93 -93
- package/dist/templates/_shared/lib-ts/CLAUDE.md +367 -367
- package/dist/templates/_shared/lib-ts/base/atomic-write.ts +138 -138
- package/dist/templates/_shared/lib-ts/base/constants.ts +303 -303
- package/dist/templates/_shared/lib-ts/base/git-state.ts +58 -58
- package/dist/templates/_shared/lib-ts/base/hook-utils.ts +582 -582
- package/dist/templates/_shared/lib-ts/base/inference.ts +301 -301
- package/dist/templates/_shared/lib-ts/base/logger.ts +247 -247
- package/dist/templates/_shared/lib-ts/base/state-io.ts +202 -130
- package/dist/templates/_shared/lib-ts/base/stop-words.ts +184 -184
- package/dist/templates/_shared/lib-ts/base/subprocess-utils.ts +56 -0
- package/dist/templates/_shared/lib-ts/base/utils.ts +184 -184
- package/dist/templates/_shared/lib-ts/context/context-formatter.ts +566 -560
- package/dist/templates/_shared/lib-ts/context/context-selector.ts +524 -515
- package/dist/templates/_shared/lib-ts/context/context-store.ts +712 -668
- package/dist/templates/_shared/lib-ts/context/plan-manager.ts +312 -312
- package/dist/templates/_shared/lib-ts/context/task-tracker.ts +185 -185
- package/dist/templates/_shared/lib-ts/package.json +20 -20
- package/dist/templates/_shared/lib-ts/templates/formatters.ts +102 -102
- package/dist/templates/_shared/lib-ts/templates/plan-context.ts +58 -58
- package/dist/templates/_shared/lib-ts/tsconfig.json +13 -13
- package/dist/templates/_shared/lib-ts/types.ts +186 -180
- package/dist/templates/_shared/scripts/resolve_context.ts +33 -33
- package/dist/templates/_shared/scripts/status_line.ts +690 -690
- package/dist/templates/cc-native/.claude/commands/{rlm → cc-native/rlm}/ask.md +136 -136
- package/dist/templates/cc-native/.claude/commands/{rlm → cc-native/rlm}/index.md +21 -21
- package/dist/templates/cc-native/.claude/commands/{rlm → cc-native/rlm}/overview.md +56 -56
- package/dist/templates/cc-native/.claude/commands/cc-native/specdev.md +10 -10
- package/dist/templates/cc-native/.windsurf/workflows/cc-native/fix.md +8 -8
- package/dist/templates/cc-native/.windsurf/workflows/cc-native/implement.md +8 -8
- package/dist/templates/cc-native/.windsurf/workflows/cc-native/research.md +8 -8
- package/dist/templates/cc-native/CC-NATIVE-README.md +189 -189
- package/dist/templates/cc-native/TEMPLATE-SCHEMA.md +304 -304
- package/dist/templates/cc-native/_cc-native/agents/CLAUDE.md +143 -143
- package/dist/templates/cc-native/_cc-native/agents/PLAN-ORCHESTRATOR.md +213 -213
- package/dist/templates/cc-native/_cc-native/agents/plan-questions/PLAN-QUESTIONER.md +70 -70
- package/dist/templates/cc-native/_cc-native/cc-native.config.json +96 -96
- package/dist/templates/cc-native/_cc-native/hooks/CLAUDE.md +247 -247
- package/dist/templates/cc-native/_cc-native/hooks/cc-native-plan-review.ts +76 -76
- package/dist/templates/cc-native/_cc-native/hooks/enhance_plan_post_subagent.ts +54 -54
- package/dist/templates/cc-native/_cc-native/hooks/enhance_plan_post_write.ts +51 -51
- package/dist/templates/cc-native/_cc-native/hooks/mark_questions_asked.ts +53 -53
- package/dist/templates/cc-native/_cc-native/hooks/plan_questions_early.ts +61 -61
- package/dist/templates/cc-native/_cc-native/lib-ts/agent-selection.ts +163 -163
- package/dist/templates/cc-native/_cc-native/lib-ts/aggregate-agents.ts +156 -156
- package/dist/templates/cc-native/_cc-native/lib-ts/artifacts/format.ts +597 -597
- package/dist/templates/cc-native/_cc-native/lib-ts/artifacts/index.ts +26 -26
- package/dist/templates/cc-native/_cc-native/lib-ts/artifacts/tracker.ts +107 -107
- package/dist/templates/cc-native/_cc-native/lib-ts/artifacts/write.ts +119 -119
- package/dist/templates/cc-native/_cc-native/lib-ts/artifacts.ts +21 -21
- package/dist/templates/cc-native/_cc-native/lib-ts/cc-native-state.ts +319 -319
- package/dist/templates/cc-native/_cc-native/lib-ts/cli-output-parser.ts +144 -144
- package/dist/templates/cc-native/_cc-native/lib-ts/config.ts +57 -57
- package/dist/templates/cc-native/_cc-native/lib-ts/constants.ts +83 -83
- package/dist/templates/cc-native/_cc-native/lib-ts/corroboration.ts +119 -119
- package/dist/templates/cc-native/_cc-native/lib-ts/debug.ts +79 -79
- package/dist/templates/cc-native/_cc-native/lib-ts/graduation.ts +132 -132
- package/dist/templates/cc-native/_cc-native/lib-ts/index.ts +116 -116
- package/dist/templates/cc-native/_cc-native/lib-ts/json-parser.ts +168 -168
- package/dist/templates/cc-native/_cc-native/lib-ts/orchestrator.ts +70 -70
- package/dist/templates/cc-native/_cc-native/lib-ts/output-builder.ts +130 -130
- package/dist/templates/cc-native/_cc-native/lib-ts/plan-discovery.ts +80 -80
- package/dist/templates/cc-native/_cc-native/lib-ts/plan-enhancement.ts +41 -41
- package/dist/templates/cc-native/_cc-native/lib-ts/plan-questions.ts +101 -101
- package/dist/templates/cc-native/_cc-native/lib-ts/review-pipeline.ts +511 -511
- package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/agent.ts +71 -71
- package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/base/base-agent.ts +217 -217
- package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/index.ts +12 -12
- package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/providers/claude-agent.ts +66 -65
- package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/providers/codex-agent.ts +184 -184
- package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/providers/gemini-agent.ts +39 -39
- package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/providers/orchestrator-claude-agent.ts +196 -195
- package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/schemas.ts +201 -201
- package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/types.ts +21 -21
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/CLAUDE.md +480 -480
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/embedding-indexer.ts +287 -287
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/hyde.ts +148 -148
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/index.ts +54 -54
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/logger.ts +58 -58
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/ollama-client.ts +208 -208
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/retrieval-pipeline.ts +460 -460
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/transcript-indexer.ts +446 -447
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/transcript-loader.ts +280 -280
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/transcript-searcher.ts +274 -274
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/types.ts +201 -201
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/vector-store.ts +278 -278
- package/dist/templates/cc-native/_cc-native/lib-ts/settings.ts +184 -184
- package/dist/templates/cc-native/_cc-native/lib-ts/state.ts +275 -275
- package/dist/templates/cc-native/_cc-native/lib-ts/tsconfig.json +18 -18
- package/dist/templates/cc-native/_cc-native/lib-ts/types.ts +329 -329
- package/dist/templates/cc-native/_cc-native/lib-ts/verdict.ts +72 -72
- package/dist/templates/cc-native/_cc-native/workflows/specdev.md +9 -9
- package/oclif.manifest.json +1 -1
- package/package.json +108 -108
- package/dist/templates/cc-native/_cc-native/lib-ts/nul +0 -3
|
@@ -1,138 +1,138 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Cross-platform atomic file writes with security.
|
|
3
|
-
* Crash-safe writes by writing to temp file then renaming.
|
|
4
|
-
* NOT for concurrent access — assumes single-session-per-context.
|
|
5
|
-
* See SPEC.md §4
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import * as crypto from "node:crypto";
|
|
9
|
-
import * as fs from "node:fs";
|
|
10
|
-
import * as _os from "node:os";
|
|
11
|
-
import * as path from "node:path";
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Write file atomically with retry logic.
|
|
15
|
-
* Creates temp file, writes, fsyncs, renames.
|
|
16
|
-
* Returns [success, error].
|
|
17
|
-
* See SPEC.md §4.2
|
|
18
|
-
*/
|
|
19
|
-
export function atomicWrite(
|
|
20
|
-
filePath: string,
|
|
21
|
-
content: string,
|
|
22
|
-
maxAttempts = 2,
|
|
23
|
-
backoffMs: number[] = [500, 1000],
|
|
24
|
-
): [boolean, null | string] {
|
|
25
|
-
// Ensure parent directory exists
|
|
26
|
-
const dir = path.dirname(filePath);
|
|
27
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
28
|
-
|
|
29
|
-
const stem = path.basename(filePath, path.extname(filePath));
|
|
30
|
-
|
|
31
|
-
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
32
|
-
const tmpName = `.${stem}_${crypto.randomBytes(4).toString("hex")}.tmp`;
|
|
33
|
-
const tmpPath = path.join(dir, tmpName);
|
|
34
|
-
|
|
35
|
-
try {
|
|
36
|
-
// Write to temp file
|
|
37
|
-
const fd = fs.openSync(tmpPath, "w");
|
|
38
|
-
try {
|
|
39
|
-
fs.writeSync(fd, content, undefined, "utf-8");
|
|
40
|
-
fs.fsyncSync(fd);
|
|
41
|
-
} finally {
|
|
42
|
-
fs.closeSync(fd);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// Set restrictive permissions (best-effort)
|
|
46
|
-
try {
|
|
47
|
-
fs.chmodSync(tmpPath, 0o600);
|
|
48
|
-
} catch {
|
|
49
|
-
// May fail on some filesystems
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// Atomic rename (cross-platform on modern Node/Bun)
|
|
53
|
-
fs.renameSync(tmpPath, filePath);
|
|
54
|
-
|
|
55
|
-
return [true, null];
|
|
56
|
-
} catch (error: any) {
|
|
57
|
-
// Clean up temp file
|
|
58
|
-
try {
|
|
59
|
-
fs.unlinkSync(tmpPath);
|
|
60
|
-
} catch {
|
|
61
|
-
// Best-effort cleanup
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
if (attempt < maxAttempts - 1) {
|
|
65
|
-
const waitMs = backoffMs[Math.min(attempt, backoffMs.length - 1)] ?? backoffMs.at(-1) ?? 500;
|
|
66
|
-
sleepSync(waitMs);
|
|
67
|
-
} else {
|
|
68
|
-
const errType = error?.constructor?.name ?? "Error";
|
|
69
|
-
const errMsg = String(error).split("\n")[0]?.slice(0, 200) ?? "";
|
|
70
|
-
return [false, `${errType}: ${errMsg}`];
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
return [false, "Max retry attempts exceeded"];
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Append to file with retry logic.
|
|
80
|
-
* For JSONL files where each line is independent.
|
|
81
|
-
* See SPEC.md §4.3
|
|
82
|
-
*/
|
|
83
|
-
export function atomicAppend(
|
|
84
|
-
filePath: string,
|
|
85
|
-
content: string,
|
|
86
|
-
maxAttempts = 2,
|
|
87
|
-
backoffMs: number[] = [500, 1000],
|
|
88
|
-
): [boolean, null | string] {
|
|
89
|
-
// Ensure parent directory exists
|
|
90
|
-
const dir = path.dirname(filePath);
|
|
91
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
92
|
-
|
|
93
|
-
const isNewFile = !fs.existsSync(filePath);
|
|
94
|
-
|
|
95
|
-
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
96
|
-
try {
|
|
97
|
-
const fd = fs.openSync(filePath, "a");
|
|
98
|
-
try {
|
|
99
|
-
fs.writeSync(fd, content, undefined, "utf-8");
|
|
100
|
-
fs.fsyncSync(fd);
|
|
101
|
-
} finally {
|
|
102
|
-
fs.closeSync(fd);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// Set permissions on newly created files (best-effort)
|
|
106
|
-
if (isNewFile) {
|
|
107
|
-
try {
|
|
108
|
-
fs.chmodSync(filePath, 0o600);
|
|
109
|
-
} catch {
|
|
110
|
-
// May fail on some filesystems
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
return [true, null];
|
|
115
|
-
} catch (error: any) {
|
|
116
|
-
if (attempt < maxAttempts - 1) {
|
|
117
|
-
const waitMs = backoffMs[Math.min(attempt, backoffMs.length - 1)] ?? backoffMs.at(-1) ?? 500;
|
|
118
|
-
sleepSync(waitMs);
|
|
119
|
-
} else {
|
|
120
|
-
const errType = error?.constructor?.name ?? "Error";
|
|
121
|
-
const errMsg = String(error).split("\n")[0]?.slice(0, 200) ?? "";
|
|
122
|
-
return [false, `${errType}: ${errMsg}`];
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
return [false, "Max retry attempts exceeded"];
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
/**
|
|
131
|
-
* Synchronous sleep for retry backoff.
|
|
132
|
-
* Uses Atomics.wait() for CPU-friendly blocking instead of busy-wait.
|
|
133
|
-
*/
|
|
134
|
-
function sleepSync(ms: number): void {
|
|
135
|
-
const sab = new SharedArrayBuffer(4);
|
|
136
|
-
const i32 = new Int32Array(sab);
|
|
137
|
-
Atomics.wait(i32, 0, 0, ms);
|
|
138
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Cross-platform atomic file writes with security.
|
|
3
|
+
* Crash-safe writes by writing to temp file then renaming.
|
|
4
|
+
* NOT for concurrent access — assumes single-session-per-context.
|
|
5
|
+
* See SPEC.md §4
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import * as crypto from "node:crypto";
|
|
9
|
+
import * as fs from "node:fs";
|
|
10
|
+
import * as _os from "node:os";
|
|
11
|
+
import * as path from "node:path";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Write file atomically with retry logic.
|
|
15
|
+
* Creates temp file, writes, fsyncs, renames.
|
|
16
|
+
* Returns [success, error].
|
|
17
|
+
* See SPEC.md §4.2
|
|
18
|
+
*/
|
|
19
|
+
export function atomicWrite(
|
|
20
|
+
filePath: string,
|
|
21
|
+
content: string,
|
|
22
|
+
maxAttempts = 2,
|
|
23
|
+
backoffMs: number[] = [500, 1000],
|
|
24
|
+
): [boolean, null | string] {
|
|
25
|
+
// Ensure parent directory exists
|
|
26
|
+
const dir = path.dirname(filePath);
|
|
27
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
28
|
+
|
|
29
|
+
const stem = path.basename(filePath, path.extname(filePath));
|
|
30
|
+
|
|
31
|
+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
32
|
+
const tmpName = `.${stem}_${crypto.randomBytes(4).toString("hex")}.tmp`;
|
|
33
|
+
const tmpPath = path.join(dir, tmpName);
|
|
34
|
+
|
|
35
|
+
try {
|
|
36
|
+
// Write to temp file
|
|
37
|
+
const fd = fs.openSync(tmpPath, "w");
|
|
38
|
+
try {
|
|
39
|
+
fs.writeSync(fd, content, undefined, "utf-8");
|
|
40
|
+
fs.fsyncSync(fd);
|
|
41
|
+
} finally {
|
|
42
|
+
fs.closeSync(fd);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Set restrictive permissions (best-effort)
|
|
46
|
+
try {
|
|
47
|
+
fs.chmodSync(tmpPath, 0o600);
|
|
48
|
+
} catch {
|
|
49
|
+
// May fail on some filesystems
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Atomic rename (cross-platform on modern Node/Bun)
|
|
53
|
+
fs.renameSync(tmpPath, filePath);
|
|
54
|
+
|
|
55
|
+
return [true, null];
|
|
56
|
+
} catch (error: any) {
|
|
57
|
+
// Clean up temp file
|
|
58
|
+
try {
|
|
59
|
+
fs.unlinkSync(tmpPath);
|
|
60
|
+
} catch {
|
|
61
|
+
// Best-effort cleanup
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (attempt < maxAttempts - 1) {
|
|
65
|
+
const waitMs = backoffMs[Math.min(attempt, backoffMs.length - 1)] ?? backoffMs.at(-1) ?? 500;
|
|
66
|
+
sleepSync(waitMs);
|
|
67
|
+
} else {
|
|
68
|
+
const errType = error?.constructor?.name ?? "Error";
|
|
69
|
+
const errMsg = String(error).split("\n")[0]?.slice(0, 200) ?? "";
|
|
70
|
+
return [false, `${errType}: ${errMsg}`];
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return [false, "Max retry attempts exceeded"];
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Append to file with retry logic.
|
|
80
|
+
* For JSONL files where each line is independent.
|
|
81
|
+
* See SPEC.md §4.3
|
|
82
|
+
*/
|
|
83
|
+
export function atomicAppend(
|
|
84
|
+
filePath: string,
|
|
85
|
+
content: string,
|
|
86
|
+
maxAttempts = 2,
|
|
87
|
+
backoffMs: number[] = [500, 1000],
|
|
88
|
+
): [boolean, null | string] {
|
|
89
|
+
// Ensure parent directory exists
|
|
90
|
+
const dir = path.dirname(filePath);
|
|
91
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
92
|
+
|
|
93
|
+
const isNewFile = !fs.existsSync(filePath);
|
|
94
|
+
|
|
95
|
+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
96
|
+
try {
|
|
97
|
+
const fd = fs.openSync(filePath, "a");
|
|
98
|
+
try {
|
|
99
|
+
fs.writeSync(fd, content, undefined, "utf-8");
|
|
100
|
+
fs.fsyncSync(fd);
|
|
101
|
+
} finally {
|
|
102
|
+
fs.closeSync(fd);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Set permissions on newly created files (best-effort)
|
|
106
|
+
if (isNewFile) {
|
|
107
|
+
try {
|
|
108
|
+
fs.chmodSync(filePath, 0o600);
|
|
109
|
+
} catch {
|
|
110
|
+
// May fail on some filesystems
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return [true, null];
|
|
115
|
+
} catch (error: any) {
|
|
116
|
+
if (attempt < maxAttempts - 1) {
|
|
117
|
+
const waitMs = backoffMs[Math.min(attempt, backoffMs.length - 1)] ?? backoffMs.at(-1) ?? 500;
|
|
118
|
+
sleepSync(waitMs);
|
|
119
|
+
} else {
|
|
120
|
+
const errType = error?.constructor?.name ?? "Error";
|
|
121
|
+
const errMsg = String(error).split("\n")[0]?.slice(0, 200) ?? "";
|
|
122
|
+
return [false, `${errType}: ${errMsg}`];
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return [false, "Max retry attempts exceeded"];
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Synchronous sleep for retry backoff.
|
|
132
|
+
* Uses Atomics.wait() for CPU-friendly blocking instead of busy-wait.
|
|
133
|
+
*/
|
|
134
|
+
function sleepSync(ms: number): void {
|
|
135
|
+
const sab = new SharedArrayBuffer(4);
|
|
136
|
+
const i32 = new Int32Array(sab);
|
|
137
|
+
Atomics.wait(i32, 0, 0, ms);
|
|
138
|
+
}
|