ralphctl 0.8.5 → 0.8.6
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/dist/cli.mjs +338 -282
- package/dist/manifest.json +1 -1
- package/package.json +3 -1
package/dist/cli.mjs
CHANGED
|
@@ -778,17 +778,20 @@ var createJsonSettingsRepository = (deps) => {
|
|
|
778
778
|
};
|
|
779
779
|
};
|
|
780
780
|
|
|
781
|
+
// src/integration/io/cross-platform-spawn.ts
|
|
782
|
+
import spawn from "cross-spawn";
|
|
783
|
+
var crossPlatformSpawn = (command, args, options) => spawn(command, [...args], options);
|
|
784
|
+
|
|
781
785
|
// src/integration/io/git-runner.ts
|
|
782
|
-
import { spawn as nodeSpawn } from "child_process";
|
|
783
786
|
var DEFAULT_GIT_TIMEOUT_MS = 3e4;
|
|
784
787
|
var createGitRunner = (deps = {}) => {
|
|
785
|
-
const
|
|
788
|
+
const spawn3 = deps.spawn ?? defaultSpawn;
|
|
786
789
|
const defaultTimeoutMs = deps.defaultTimeoutMs ?? DEFAULT_GIT_TIMEOUT_MS;
|
|
787
790
|
const run = (cwd, args, opts = {}) => new Promise((resolve) => {
|
|
788
791
|
const timeoutMs = opts.timeoutMs ?? defaultTimeoutMs;
|
|
789
792
|
let child;
|
|
790
793
|
try {
|
|
791
|
-
child =
|
|
794
|
+
child = spawn3("git", args, {
|
|
792
795
|
stdio: ["pipe", "pipe", "pipe"],
|
|
793
796
|
cwd: String(cwd)
|
|
794
797
|
});
|
|
@@ -857,15 +860,15 @@ var createGitRunner = (deps = {}) => {
|
|
|
857
860
|
});
|
|
858
861
|
return { run };
|
|
859
862
|
};
|
|
860
|
-
var defaultSpawn = (command, args, options) =>
|
|
863
|
+
var defaultSpawn = (command, args, options) => crossPlatformSpawn(command, args, { ...options, stdio: [...options.stdio] });
|
|
861
864
|
var stringifyError = (cause) => cause instanceof Error ? cause.message : String(cause);
|
|
862
865
|
|
|
863
866
|
// src/integration/io/shell-script-runner.ts
|
|
864
|
-
import { spawn as
|
|
867
|
+
import { spawn as nodeSpawn } from "child_process";
|
|
865
868
|
var DEFAULT_SHELL_TIMEOUT_MS = 5 * 6e4;
|
|
866
869
|
var MAX_OUTPUT_BYTES = 50 * 1024 * 1024;
|
|
867
870
|
var createShellScriptRunner = (deps = {}) => {
|
|
868
|
-
const
|
|
871
|
+
const spawn3 = deps.spawn ?? defaultSpawn2;
|
|
869
872
|
const defaultTimeoutMs = deps.defaultTimeoutMs ?? DEFAULT_SHELL_TIMEOUT_MS;
|
|
870
873
|
const now = deps.now ?? Date.now;
|
|
871
874
|
const run = (cwd, script, opts = {}) => new Promise((resolve) => {
|
|
@@ -873,7 +876,7 @@ var createShellScriptRunner = (deps = {}) => {
|
|
|
873
876
|
const timeoutMs = opts.timeoutMs ?? defaultTimeoutMs;
|
|
874
877
|
let child;
|
|
875
878
|
try {
|
|
876
|
-
child =
|
|
879
|
+
child = spawn3(script, [], {
|
|
877
880
|
stdio: ["pipe", "pipe", "pipe"],
|
|
878
881
|
cwd: String(cwd),
|
|
879
882
|
shell: true,
|
|
@@ -987,7 +990,7 @@ ${marker}` : marker : base;
|
|
|
987
990
|
});
|
|
988
991
|
return { run };
|
|
989
992
|
};
|
|
990
|
-
var defaultSpawn2 = (command, args, options) =>
|
|
993
|
+
var defaultSpawn2 = (command, args, options) => nodeSpawn(command, [...args], { ...options, stdio: [...options.stdio] });
|
|
991
994
|
var stringifyError2 = (cause) => cause instanceof Error ? cause.message : String(cause);
|
|
992
995
|
|
|
993
996
|
// src/integration/persistence/project/project.schema.ts
|
|
@@ -2217,12 +2220,6 @@ var createAppendFile = () => {
|
|
|
2217
2220
|
};
|
|
2218
2221
|
};
|
|
2219
2222
|
|
|
2220
|
-
// src/application/bootstrap/wire.ts
|
|
2221
|
-
import { spawn as nodeSpawn9 } from "child_process";
|
|
2222
|
-
|
|
2223
|
-
// src/integration/ai/providers/claude/headless.ts
|
|
2224
|
-
import { spawn as nodeSpawn3 } from "child_process";
|
|
2225
|
-
|
|
2226
2223
|
// src/integration/ai/providers/_engine/resolve-roots.ts
|
|
2227
2224
|
var resolveWritableRoots = (session) => {
|
|
2228
2225
|
const declared = session.additionalRoots ?? [];
|
|
@@ -2908,13 +2905,12 @@ var spawnAttempt = async (input) => {
|
|
|
2908
2905
|
onSuccess
|
|
2909
2906
|
});
|
|
2910
2907
|
};
|
|
2911
|
-
var defaultSpawn3 = (command, args, options) =>
|
|
2908
|
+
var defaultSpawn3 = (command, args, options) => crossPlatformSpawn(command, args, {
|
|
2912
2909
|
stdio: [...options.stdio],
|
|
2913
2910
|
...options.cwd !== void 0 ? { cwd: options.cwd } : {}
|
|
2914
2911
|
});
|
|
2915
2912
|
|
|
2916
2913
|
// src/integration/ai/providers/codex/headless.ts
|
|
2917
|
-
import { spawn as nodeSpawn4 } from "child_process";
|
|
2918
2914
|
import { promises as fs6 } from "fs";
|
|
2919
2915
|
import { tmpdir } from "os";
|
|
2920
2916
|
import { join as join6 } from "path";
|
|
@@ -3291,14 +3287,11 @@ var spawnAttempt2 = async (input) => {
|
|
|
3291
3287
|
onSuccess
|
|
3292
3288
|
});
|
|
3293
3289
|
};
|
|
3294
|
-
var defaultSpawn4 = (command, args, options) =>
|
|
3290
|
+
var defaultSpawn4 = (command, args, options) => crossPlatformSpawn(command, args, {
|
|
3295
3291
|
stdio: [...options.stdio],
|
|
3296
3292
|
...options.cwd !== void 0 ? { cwd: options.cwd } : {}
|
|
3297
3293
|
});
|
|
3298
3294
|
|
|
3299
|
-
// src/integration/ai/providers/copilot/headless.ts
|
|
3300
|
-
import { spawn as nodeSpawn5 } from "child_process";
|
|
3301
|
-
|
|
3302
3295
|
// src/integration/ai/providers/copilot/parse-stream.ts
|
|
3303
3296
|
var stringField3 = (obj, ...names) => {
|
|
3304
3297
|
for (const name of names) {
|
|
@@ -3650,7 +3643,7 @@ var spawnAttempt3 = async (input) => {
|
|
|
3650
3643
|
onSuccess
|
|
3651
3644
|
});
|
|
3652
3645
|
};
|
|
3653
|
-
var defaultSpawn5 = (command, args, options) =>
|
|
3646
|
+
var defaultSpawn5 = (command, args, options) => crossPlatformSpawn(command, args, {
|
|
3654
3647
|
stdio: [...options.stdio],
|
|
3655
3648
|
...options.cwd !== void 0 ? { cwd: options.cwd } : {}
|
|
3656
3649
|
});
|
|
@@ -3689,12 +3682,20 @@ var createAiProvider = (deps) => {
|
|
|
3689
3682
|
};
|
|
3690
3683
|
|
|
3691
3684
|
// src/integration/ai/providers/claude/interactive.ts
|
|
3692
|
-
import {
|
|
3685
|
+
import { promises as fs7 } from "fs";
|
|
3686
|
+
import "child_process";
|
|
3693
3687
|
import { dirname as dirname5 } from "path";
|
|
3694
|
-
var defaultSpawn6 = (command, args, options) =>
|
|
3688
|
+
var defaultSpawn6 = (command, args, options) => (
|
|
3689
|
+
// Route through the shared cross-platform primitive so `claude.cmd` shims resolve on
|
|
3690
|
+
// Windows and the positional prompt argument (which may contain spaces or shell
|
|
3691
|
+
// metacharacters) is escaped correctly — without a shell. See cross-platform-spawn.ts.
|
|
3692
|
+
crossPlatformSpawn(command, args, { stdio: options.stdio, cwd: options.cwd })
|
|
3693
|
+
);
|
|
3694
|
+
var defaultReadFile = (path) => fs7.readFile(path, "utf8");
|
|
3695
3695
|
var createInteractiveClaudeProvider = (deps) => {
|
|
3696
3696
|
const spawnFn = deps.spawn ?? defaultSpawn6;
|
|
3697
|
-
const command = deps.command ?? "
|
|
3697
|
+
const command = deps.command ?? "claude";
|
|
3698
|
+
const readFile2 = deps.readFile ?? defaultReadFile;
|
|
3698
3699
|
const newSessionId = deps.newSessionId ?? uuidv7;
|
|
3699
3700
|
return {
|
|
3700
3701
|
async run(input) {
|
|
@@ -3708,6 +3709,18 @@ var createInteractiveClaudeProvider = (deps) => {
|
|
|
3708
3709
|
})
|
|
3709
3710
|
);
|
|
3710
3711
|
}
|
|
3712
|
+
let prompt;
|
|
3713
|
+
try {
|
|
3714
|
+
prompt = await readFile2(String(input.promptFile));
|
|
3715
|
+
} catch (cause) {
|
|
3716
|
+
return Result.error(
|
|
3717
|
+
new StorageError({
|
|
3718
|
+
subCode: "io",
|
|
3719
|
+
message: `interactive-claude: failed to read prompt file ${String(input.promptFile)} \u2014 ${stringifyError4(cause)}`,
|
|
3720
|
+
cause
|
|
3721
|
+
})
|
|
3722
|
+
);
|
|
3723
|
+
}
|
|
3711
3724
|
const allRoots = [
|
|
3712
3725
|
String(input.cwd),
|
|
3713
3726
|
...input.additionalRoots?.map((r) => String(r)) ?? [],
|
|
@@ -3719,19 +3732,18 @@ var createInteractiveClaudeProvider = (deps) => {
|
|
|
3719
3732
|
if (seen.has(p)) return false;
|
|
3720
3733
|
seen.add(p);
|
|
3721
3734
|
return true;
|
|
3722
|
-
}).flatMap((p) => ["--add-dir",
|
|
3735
|
+
}).flatMap((p) => ["--add-dir", p]);
|
|
3723
3736
|
const sessionId2 = newSessionId();
|
|
3724
|
-
const
|
|
3725
|
-
"claude",
|
|
3737
|
+
const args = [
|
|
3726
3738
|
...dirFlags,
|
|
3727
3739
|
"--model",
|
|
3728
|
-
|
|
3740
|
+
input.model,
|
|
3729
3741
|
"--permission-mode",
|
|
3730
3742
|
"acceptEdits",
|
|
3731
3743
|
"--session-id",
|
|
3732
|
-
|
|
3733
|
-
|
|
3734
|
-
]
|
|
3744
|
+
sessionId2,
|
|
3745
|
+
prompt
|
|
3746
|
+
];
|
|
3735
3747
|
deps.eventBus.publish({
|
|
3736
3748
|
type: "log",
|
|
3737
3749
|
level: "info",
|
|
@@ -3741,7 +3753,7 @@ var createInteractiveClaudeProvider = (deps) => {
|
|
|
3741
3753
|
});
|
|
3742
3754
|
let child;
|
|
3743
3755
|
try {
|
|
3744
|
-
child = spawnFn(command,
|
|
3756
|
+
child = spawnFn(command, args, { stdio: "inherit", cwd: String(input.cwd) });
|
|
3745
3757
|
} catch (cause) {
|
|
3746
3758
|
return Result.error(
|
|
3747
3759
|
new StorageError({
|
|
@@ -3785,16 +3797,23 @@ var createInteractiveClaudeProvider = (deps) => {
|
|
|
3785
3797
|
}
|
|
3786
3798
|
};
|
|
3787
3799
|
};
|
|
3788
|
-
var shellQuote = (s) => `'${s.replace(/'/g, `'\\''`)}'`;
|
|
3789
3800
|
var stringifyError4 = (cause) => cause instanceof Error ? cause.message : String(cause);
|
|
3790
3801
|
|
|
3791
3802
|
// src/integration/ai/providers/codex/interactive.ts
|
|
3792
|
-
import {
|
|
3803
|
+
import { promises as fs8 } from "fs";
|
|
3804
|
+
import "child_process";
|
|
3793
3805
|
import { dirname as dirname6 } from "path";
|
|
3794
|
-
var defaultSpawn7 = (command, args, options) =>
|
|
3806
|
+
var defaultSpawn7 = (command, args, options) => (
|
|
3807
|
+
// Route through the shared cross-platform primitive so `codex.cmd` shims resolve on
|
|
3808
|
+
// Windows and the positional prompt argument is escaped correctly — without a shell.
|
|
3809
|
+
// See cross-platform-spawn.ts.
|
|
3810
|
+
crossPlatformSpawn(command, args, { stdio: options.stdio, cwd: options.cwd })
|
|
3811
|
+
);
|
|
3812
|
+
var defaultReadFile2 = (path) => fs8.readFile(path, "utf8");
|
|
3795
3813
|
var createInteractiveCodexProvider = (deps) => {
|
|
3796
3814
|
const spawnFn = deps.spawn ?? defaultSpawn7;
|
|
3797
|
-
const command = deps.command ?? "
|
|
3815
|
+
const command = deps.command ?? "codex";
|
|
3816
|
+
const readFile2 = deps.readFile ?? defaultReadFile2;
|
|
3798
3817
|
return {
|
|
3799
3818
|
async run(input) {
|
|
3800
3819
|
if (!isCodexModel(input.model)) {
|
|
@@ -3807,6 +3826,18 @@ var createInteractiveCodexProvider = (deps) => {
|
|
|
3807
3826
|
})
|
|
3808
3827
|
);
|
|
3809
3828
|
}
|
|
3829
|
+
let prompt;
|
|
3830
|
+
try {
|
|
3831
|
+
prompt = await readFile2(String(input.promptFile));
|
|
3832
|
+
} catch (cause) {
|
|
3833
|
+
return Result.error(
|
|
3834
|
+
new StorageError({
|
|
3835
|
+
subCode: "io",
|
|
3836
|
+
message: `interactive-codex: failed to read prompt file ${String(input.promptFile)} \u2014 ${stringifyError5(cause)}`,
|
|
3837
|
+
cause
|
|
3838
|
+
})
|
|
3839
|
+
);
|
|
3840
|
+
}
|
|
3810
3841
|
const allRoots = [
|
|
3811
3842
|
String(input.cwd),
|
|
3812
3843
|
...input.additionalRoots?.map((r) => String(r)) ?? [],
|
|
@@ -3818,20 +3849,19 @@ var createInteractiveCodexProvider = (deps) => {
|
|
|
3818
3849
|
if (seen.has(p)) return false;
|
|
3819
3850
|
seen.add(p);
|
|
3820
3851
|
return true;
|
|
3821
|
-
}).flatMap((p) => ["--add-dir",
|
|
3822
|
-
const
|
|
3823
|
-
"codex",
|
|
3852
|
+
}).flatMap((p) => ["--add-dir", p]);
|
|
3853
|
+
const args = [
|
|
3824
3854
|
"--cd",
|
|
3825
|
-
|
|
3855
|
+
String(input.cwd),
|
|
3826
3856
|
...dirFlags,
|
|
3827
3857
|
"--model",
|
|
3828
|
-
|
|
3858
|
+
input.model,
|
|
3829
3859
|
"-s",
|
|
3830
3860
|
"workspace-write",
|
|
3831
3861
|
"-a",
|
|
3832
3862
|
"never",
|
|
3833
|
-
|
|
3834
|
-
]
|
|
3863
|
+
prompt
|
|
3864
|
+
];
|
|
3835
3865
|
deps.eventBus.publish({
|
|
3836
3866
|
type: "log",
|
|
3837
3867
|
level: "info",
|
|
@@ -3841,7 +3871,7 @@ var createInteractiveCodexProvider = (deps) => {
|
|
|
3841
3871
|
});
|
|
3842
3872
|
let child;
|
|
3843
3873
|
try {
|
|
3844
|
-
child = spawnFn(command,
|
|
3874
|
+
child = spawnFn(command, args, { stdio: "inherit", cwd: String(input.cwd) });
|
|
3845
3875
|
} catch (cause) {
|
|
3846
3876
|
return Result.error(
|
|
3847
3877
|
new StorageError({
|
|
@@ -3873,19 +3903,23 @@ var createInteractiveCodexProvider = (deps) => {
|
|
|
3873
3903
|
}
|
|
3874
3904
|
};
|
|
3875
3905
|
};
|
|
3876
|
-
var shellQuote2 = (s) => `'${s.replace(/'/g, `'\\''`)}'`;
|
|
3877
3906
|
var stringifyError5 = (cause) => cause instanceof Error ? cause.message : String(cause);
|
|
3878
3907
|
|
|
3879
3908
|
// src/integration/ai/providers/copilot/interactive.ts
|
|
3880
|
-
import { promises as
|
|
3881
|
-
import
|
|
3909
|
+
import { promises as fs9 } from "fs";
|
|
3910
|
+
import "child_process";
|
|
3882
3911
|
import { dirname as dirname7 } from "path";
|
|
3883
|
-
var defaultSpawn8 = (command, args, options) =>
|
|
3884
|
-
|
|
3912
|
+
var defaultSpawn8 = (command, args, options) => (
|
|
3913
|
+
// Route through the shared cross-platform primitive so `copilot.cmd` shims resolve on
|
|
3914
|
+
// Windows and the seeded prompt argument is escaped correctly — without a shell.
|
|
3915
|
+
// See cross-platform-spawn.ts.
|
|
3916
|
+
crossPlatformSpawn(command, args, { stdio: options.stdio, cwd: options.cwd })
|
|
3917
|
+
);
|
|
3918
|
+
var defaultReadFile3 = (path) => fs9.readFile(path, "utf8");
|
|
3885
3919
|
var createInteractiveCopilotProvider = (deps) => {
|
|
3886
3920
|
const spawnFn = deps.spawn ?? defaultSpawn8;
|
|
3887
3921
|
const command = deps.command ?? "copilot";
|
|
3888
|
-
const readFile2 = deps.readFile ??
|
|
3922
|
+
const readFile2 = deps.readFile ?? defaultReadFile3;
|
|
3889
3923
|
const newSessionId = deps.newSessionId ?? uuidv7;
|
|
3890
3924
|
return {
|
|
3891
3925
|
async run(input) {
|
|
@@ -4005,10 +4039,10 @@ var createInteractiveAiProvider = (deps) => {
|
|
|
4005
4039
|
};
|
|
4006
4040
|
|
|
4007
4041
|
// src/integration/io/run-cli.ts
|
|
4008
|
-
var runCli = (
|
|
4042
|
+
var runCli = (spawn3, command, args, opts) => new Promise((resolve) => {
|
|
4009
4043
|
let child;
|
|
4010
4044
|
try {
|
|
4011
|
-
child =
|
|
4045
|
+
child = spawn3(command, args, {
|
|
4012
4046
|
stdio: ["pipe", "pipe", "pipe"],
|
|
4013
4047
|
...opts.cwd !== void 0 ? { cwd: opts.cwd } : {}
|
|
4014
4048
|
});
|
|
@@ -4146,9 +4180,9 @@ var looksLikeNotFound = (stderr) => {
|
|
|
4146
4180
|
const s = stderr.toLowerCase();
|
|
4147
4181
|
return s.includes("not found") || s.includes("404") || s.includes("could not resolve") || s.includes("does not exist");
|
|
4148
4182
|
};
|
|
4149
|
-
var fetchGitHub = async (
|
|
4183
|
+
var fetchGitHub = async (spawn3, parsed, url) => {
|
|
4150
4184
|
const result = await runCli(
|
|
4151
|
-
|
|
4185
|
+
spawn3,
|
|
4152
4186
|
"gh",
|
|
4153
4187
|
[
|
|
4154
4188
|
"issue",
|
|
@@ -4195,9 +4229,9 @@ var fetchGitHub = async (spawn2, parsed, url) => {
|
|
|
4195
4229
|
comments
|
|
4196
4230
|
});
|
|
4197
4231
|
};
|
|
4198
|
-
var fetchGitLabNotes = async (
|
|
4232
|
+
var fetchGitLabNotes = async (spawn3, parsed) => {
|
|
4199
4233
|
const result = await runCli(
|
|
4200
|
-
|
|
4234
|
+
spawn3,
|
|
4201
4235
|
"glab",
|
|
4202
4236
|
["issue", "note", "list", String(parsed.number), "--repo", `${parsed.owner}/${parsed.repo}`, "--output", "json"],
|
|
4203
4237
|
{ timeoutMs: CLI_TIMEOUT_MS }
|
|
@@ -4226,9 +4260,9 @@ var fetchGitLabNotes = async (spawn2, parsed) => {
|
|
|
4226
4260
|
}));
|
|
4227
4261
|
return { comments };
|
|
4228
4262
|
};
|
|
4229
|
-
var fetchGitLab = async (
|
|
4263
|
+
var fetchGitLab = async (spawn3, parsed, url, logger) => {
|
|
4230
4264
|
const result = await runCli(
|
|
4231
|
-
|
|
4265
|
+
spawn3,
|
|
4232
4266
|
"glab",
|
|
4233
4267
|
["issue", "view", String(parsed.number), "--repo", `${parsed.owner}/${parsed.repo}`, "--output", "json"],
|
|
4234
4268
|
{ timeoutMs: CLI_TIMEOUT_MS }
|
|
@@ -4255,7 +4289,7 @@ var fetchGitLab = async (spawn2, parsed, url, logger) => {
|
|
|
4255
4289
|
})
|
|
4256
4290
|
);
|
|
4257
4291
|
}
|
|
4258
|
-
const notes = await fetchGitLabNotes(
|
|
4292
|
+
const notes = await fetchGitLabNotes(spawn3, parsed);
|
|
4259
4293
|
if (notes.failure !== void 0) {
|
|
4260
4294
|
logger?.warn(`glab issue note list failed for ${url}: ${notes.failure} \u2014 proceeding without comments`);
|
|
4261
4295
|
}
|
|
@@ -4276,9 +4310,9 @@ var createIssueFetcher = (deps) => async (url) => {
|
|
|
4276
4310
|
|
|
4277
4311
|
// src/integration/scm/issue-pusher.ts
|
|
4278
4312
|
var CLI_TIMEOUT_MS2 = 3e4;
|
|
4279
|
-
var updateGitHub = async (
|
|
4313
|
+
var updateGitHub = async (spawn3, url, body, parsed) => {
|
|
4280
4314
|
const r = await runCli(
|
|
4281
|
-
|
|
4315
|
+
spawn3,
|
|
4282
4316
|
"gh",
|
|
4283
4317
|
["issue", "edit", String(parsed.number), "--repo", `${parsed.owner}/${parsed.repo}`, "--body-file", "-"],
|
|
4284
4318
|
{ stdin: body, timeoutMs: CLI_TIMEOUT_MS2 }
|
|
@@ -4294,9 +4328,9 @@ var updateGitHub = async (spawn2, url, body, parsed) => {
|
|
|
4294
4328
|
}
|
|
4295
4329
|
return Result.ok(void 0);
|
|
4296
4330
|
};
|
|
4297
|
-
var updateGitLab = async (
|
|
4331
|
+
var updateGitLab = async (spawn3, url, body, parsed) => {
|
|
4298
4332
|
const r = await runCli(
|
|
4299
|
-
|
|
4333
|
+
spawn3,
|
|
4300
4334
|
"glab",
|
|
4301
4335
|
["issue", "update", String(parsed.number), "--repo", `${parsed.owner}/${parsed.repo}`, "--description", body],
|
|
4302
4336
|
{ timeoutMs: CLI_TIMEOUT_MS2 }
|
|
@@ -4312,9 +4346,9 @@ var updateGitLab = async (spawn2, url, body, parsed) => {
|
|
|
4312
4346
|
}
|
|
4313
4347
|
return Result.ok(void 0);
|
|
4314
4348
|
};
|
|
4315
|
-
var createGitHub = async (
|
|
4349
|
+
var createGitHub = async (spawn3, origin, title, body) => {
|
|
4316
4350
|
const r = await runCli(
|
|
4317
|
-
|
|
4351
|
+
spawn3,
|
|
4318
4352
|
"gh",
|
|
4319
4353
|
["issue", "create", "--repo", `${origin.owner}/${origin.repo}`, "--title", title, "--body-file", "-"],
|
|
4320
4354
|
{ stdin: body, timeoutMs: CLI_TIMEOUT_MS2 }
|
|
@@ -4339,9 +4373,9 @@ var createGitHub = async (spawn2, origin, title, body) => {
|
|
|
4339
4373
|
}
|
|
4340
4374
|
return Result.ok({ url });
|
|
4341
4375
|
};
|
|
4342
|
-
var createGitLab = async (
|
|
4376
|
+
var createGitLab = async (spawn3, origin, title, body) => {
|
|
4343
4377
|
const r = await runCli(
|
|
4344
|
-
|
|
4378
|
+
spawn3,
|
|
4345
4379
|
"glab",
|
|
4346
4380
|
["issue", "create", "--repo", `${origin.owner}/${origin.repo}`, "--title", title, "--description", body],
|
|
4347
4381
|
{ timeoutMs: CLI_TIMEOUT_MS2 }
|
|
@@ -4475,11 +4509,11 @@ var buildGlabArgs = (input) => {
|
|
|
4475
4509
|
if (input.draft) args.push("--draft");
|
|
4476
4510
|
return args;
|
|
4477
4511
|
};
|
|
4478
|
-
var runPlatformCli = async (
|
|
4512
|
+
var runPlatformCli = async (spawn3, platform, input) => {
|
|
4479
4513
|
const command = platform === "github" ? "gh" : "glab";
|
|
4480
4514
|
const args = platform === "github" ? buildGhArgs(input) : buildGlabArgs(input);
|
|
4481
4515
|
const noun = platform === "github" ? "gh pr create" : "glab mr create";
|
|
4482
|
-
const result = await runCli(
|
|
4516
|
+
const result = await runCli(spawn3, command, args, { cwd: String(input.cwd), timeoutMs: CLI_TIMEOUT_MS3 });
|
|
4483
4517
|
if (!result.ok) return Result.error(result.error);
|
|
4484
4518
|
if (result.value.exitCode !== 0) {
|
|
4485
4519
|
const stderr = result.value.stderr.trim();
|
|
@@ -4512,7 +4546,7 @@ var createPullRequestCreator = (deps) => async (input) => {
|
|
|
4512
4546
|
};
|
|
4513
4547
|
|
|
4514
4548
|
// src/integration/ai/prompts/_engine/fs-template-loader.ts
|
|
4515
|
-
import { promises as
|
|
4549
|
+
import { promises as fs10 } from "fs";
|
|
4516
4550
|
import { dirname as dirname8, join as join7 } from "path";
|
|
4517
4551
|
import { fileURLToPath } from "url";
|
|
4518
4552
|
var createFsTemplateLoader = (templatesDir) => ({
|
|
@@ -4536,7 +4570,7 @@ var createFsTemplateLoader = (templatesDir) => ({
|
|
|
4536
4570
|
});
|
|
4537
4571
|
var tryRead = async (path) => {
|
|
4538
4572
|
try {
|
|
4539
|
-
const content = await
|
|
4573
|
+
const content = await fs10.readFile(path, "utf8");
|
|
4540
4574
|
return { kind: "ok", value: content };
|
|
4541
4575
|
} catch (cause) {
|
|
4542
4576
|
if (isNodeErrnoCode2(cause, "ENOENT")) return { kind: "missing" };
|
|
@@ -4582,7 +4616,7 @@ var ProbeError = class extends Error {
|
|
|
4582
4616
|
};
|
|
4583
4617
|
|
|
4584
4618
|
// src/integration/ai/readiness/_engine/probe-fs.ts
|
|
4585
|
-
import { promises as
|
|
4619
|
+
import { promises as fs11 } from "fs";
|
|
4586
4620
|
import { basename, join as join8 } from "path";
|
|
4587
4621
|
|
|
4588
4622
|
// src/domain/value/kebab-case.ts
|
|
@@ -4591,7 +4625,7 @@ var toKebabCase = (input) => input.toLowerCase().replaceAll(/[^a-z0-9]+/g, "-").
|
|
|
4591
4625
|
// src/integration/ai/readiness/_engine/probe-fs.ts
|
|
4592
4626
|
var probeFile = async (path) => {
|
|
4593
4627
|
try {
|
|
4594
|
-
const stat = await
|
|
4628
|
+
const stat = await fs11.stat(path);
|
|
4595
4629
|
if (!stat.isFile()) return Result.ok(void 0);
|
|
4596
4630
|
return Result.ok({ path });
|
|
4597
4631
|
} catch (cause) {
|
|
@@ -4642,7 +4676,7 @@ var probeNamedFileCollection = async (dir) => {
|
|
|
4642
4676
|
};
|
|
4643
4677
|
var listDir2 = async (dir) => {
|
|
4644
4678
|
try {
|
|
4645
|
-
return Result.ok(await
|
|
4679
|
+
return Result.ok(await fs11.readdir(dir));
|
|
4646
4680
|
} catch (cause) {
|
|
4647
4681
|
if (isNodeErrnoCode(cause, "ENOENT") || isNodeErrnoCode(cause, "ENOTDIR")) return Result.ok([]);
|
|
4648
4682
|
if (isNodeErrnoCode(cause, "EACCES")) {
|
|
@@ -4655,7 +4689,7 @@ var listDir2 = async (dir) => {
|
|
|
4655
4689
|
};
|
|
4656
4690
|
var statSafely = async (path) => {
|
|
4657
4691
|
try {
|
|
4658
|
-
return Result.ok(await
|
|
4692
|
+
return Result.ok(await fs11.stat(path));
|
|
4659
4693
|
} catch (cause) {
|
|
4660
4694
|
if (isNodeErrnoCode(cause, "ENOENT")) return Result.ok(void 0);
|
|
4661
4695
|
if (isNodeErrnoCode(cause, "EACCES")) {
|
|
@@ -4668,7 +4702,7 @@ var statSafely = async (path) => {
|
|
|
4668
4702
|
};
|
|
4669
4703
|
var readFileSafely = async (path) => {
|
|
4670
4704
|
try {
|
|
4671
|
-
return Result.ok(await
|
|
4705
|
+
return Result.ok(await fs11.readFile(path, "utf8"));
|
|
4672
4706
|
} catch (cause) {
|
|
4673
4707
|
if (isNodeErrnoCode(cause, "ENOENT")) return Result.ok(void 0);
|
|
4674
4708
|
if (isNodeErrnoCode(cause, "EACCES")) {
|
|
@@ -4793,14 +4827,14 @@ var codexProbe = {
|
|
|
4793
4827
|
};
|
|
4794
4828
|
|
|
4795
4829
|
// src/integration/ai/readiness/copilot/probe.ts
|
|
4796
|
-
import { promises as
|
|
4830
|
+
import { promises as fs12 } from "fs";
|
|
4797
4831
|
import { join as join11 } from "path";
|
|
4798
4832
|
var copilotProbe = {
|
|
4799
4833
|
tool: "copilot",
|
|
4800
4834
|
async evaluate(repository, now) {
|
|
4801
4835
|
const path = join11(repository.path, ".github/copilot-instructions.md");
|
|
4802
4836
|
try {
|
|
4803
|
-
const stat = await
|
|
4837
|
+
const stat = await fs12.stat(path);
|
|
4804
4838
|
if (!stat.isFile()) return Result.ok(absentState(now));
|
|
4805
4839
|
const artifacts = { tool: "copilot", copilotInstructions: { path } };
|
|
4806
4840
|
return Result.ok(hasAnyCopilotArtifact(artifacts) ? presentState(now, artifacts) : absentState(now));
|
|
@@ -4958,7 +4992,7 @@ var createNpmVersionChecker = (deps) => {
|
|
|
4958
4992
|
// package.json
|
|
4959
4993
|
var package_default = {
|
|
4960
4994
|
name: "ralphctl",
|
|
4961
|
-
version: "0.8.
|
|
4995
|
+
version: "0.8.6",
|
|
4962
4996
|
description: "Agent harness for long-running AI coding tasks \u2014 orchestrates Claude Code, GitHub Copilot, and OpenAI Codex across repositories",
|
|
4963
4997
|
homepage: "https://github.com/lukas-grigis/ralphctl",
|
|
4964
4998
|
type: "module",
|
|
@@ -5019,6 +5053,7 @@ var package_default = {
|
|
|
5019
5053
|
},
|
|
5020
5054
|
dependencies: {
|
|
5021
5055
|
commander: "^14.0.3",
|
|
5056
|
+
"cross-spawn": "^7.0.6",
|
|
5022
5057
|
ink: "^7.0.3",
|
|
5023
5058
|
react: "^19.2.6",
|
|
5024
5059
|
"typescript-result": "^3.5.2",
|
|
@@ -5026,6 +5061,7 @@ var package_default = {
|
|
|
5026
5061
|
},
|
|
5027
5062
|
devDependencies: {
|
|
5028
5063
|
"@eslint/js": "^10.0.1",
|
|
5064
|
+
"@types/cross-spawn": "^6.0.6",
|
|
5029
5065
|
"@types/node": "^25.8.0",
|
|
5030
5066
|
"@types/react": "^19.2.14",
|
|
5031
5067
|
"@vitest/coverage-v8": "^4.1.6",
|
|
@@ -5087,14 +5123,14 @@ import { mkdir, rm, rmdir, writeFile } from "fs/promises";
|
|
|
5087
5123
|
import { join as join14 } from "path";
|
|
5088
5124
|
|
|
5089
5125
|
// src/integration/io/git-exclude.ts
|
|
5090
|
-
import { promises as
|
|
5126
|
+
import { promises as fs13 } from "fs";
|
|
5091
5127
|
import { isAbsolute as isAbsolute2, join as join13 } from "path";
|
|
5092
5128
|
var ensureGitExcludeWildcard = async (repoRoot, pattern) => {
|
|
5093
5129
|
const resolved = await resolveExcludePath(String(repoRoot));
|
|
5094
5130
|
if (resolved === void 0) return Result.ok(void 0);
|
|
5095
5131
|
let existing = "";
|
|
5096
5132
|
try {
|
|
5097
|
-
existing = await
|
|
5133
|
+
existing = await fs13.readFile(resolved, "utf8");
|
|
5098
5134
|
} catch (cause) {
|
|
5099
5135
|
if (isNodeErrnoCode3(cause, "ENOENT")) {
|
|
5100
5136
|
} else {
|
|
@@ -5120,7 +5156,7 @@ var resolveExcludePath = async (repoRoot) => {
|
|
|
5120
5156
|
const gitMarker = join13(repoRoot, ".git");
|
|
5121
5157
|
let stat;
|
|
5122
5158
|
try {
|
|
5123
|
-
stat = await
|
|
5159
|
+
stat = await fs13.stat(gitMarker);
|
|
5124
5160
|
} catch (cause) {
|
|
5125
5161
|
if (isNodeErrnoCode3(cause, "ENOENT") || isNodeErrnoCode3(cause, "ENOTDIR")) return void 0;
|
|
5126
5162
|
throw cause;
|
|
@@ -5131,7 +5167,7 @@ var resolveExcludePath = async (repoRoot) => {
|
|
|
5131
5167
|
if (!stat.isFile()) return void 0;
|
|
5132
5168
|
let pointer;
|
|
5133
5169
|
try {
|
|
5134
|
-
pointer = await
|
|
5170
|
+
pointer = await fs13.readFile(gitMarker, "utf8");
|
|
5135
5171
|
} catch {
|
|
5136
5172
|
return void 0;
|
|
5137
5173
|
}
|
|
@@ -5582,7 +5618,7 @@ var NOOP_CHAIN_LOG_SINK = {
|
|
|
5582
5618
|
}
|
|
5583
5619
|
};
|
|
5584
5620
|
var isTruthyEnvFlag = (value) => typeof value === "string" && value.length > 0;
|
|
5585
|
-
var defaultPipeSpawn = (command, args, options) =>
|
|
5621
|
+
var defaultPipeSpawn = (command, args, options) => crossPlatformSpawn(command, args, {
|
|
5586
5622
|
...options,
|
|
5587
5623
|
stdio: [...options.stdio]
|
|
5588
5624
|
});
|
|
@@ -5596,7 +5632,7 @@ var noopNotificationDispatcher = {
|
|
|
5596
5632
|
}
|
|
5597
5633
|
};
|
|
5598
5634
|
var wire = (opts) => {
|
|
5599
|
-
const
|
|
5635
|
+
const spawn3 = opts.spawn ?? defaultPipeSpawn;
|
|
5600
5636
|
const env = opts.env ?? process.env;
|
|
5601
5637
|
const debugTrace = isTruthyEnvFlag(env[RALPHCTL_DEBUG_TRACE_ENV]);
|
|
5602
5638
|
const appendFile = createAppendFile();
|
|
@@ -5646,9 +5682,9 @@ var wire = (opts) => {
|
|
|
5646
5682
|
probes: PROBES,
|
|
5647
5683
|
eventBus,
|
|
5648
5684
|
logger,
|
|
5649
|
-
pullRequestCreator: createPullRequestCreator({ gitRunner: createGitRunner(), spawn:
|
|
5650
|
-
issueFetcher: createIssueFetcher({ spawn:
|
|
5651
|
-
issuePusher: createIssuePusher({ spawn:
|
|
5685
|
+
pullRequestCreator: createPullRequestCreator({ gitRunner: createGitRunner(), spawn: spawn3 }),
|
|
5686
|
+
issueFetcher: createIssueFetcher({ spawn: spawn3, logger }),
|
|
5687
|
+
issuePusher: createIssuePusher({ spawn: spawn3 }),
|
|
5652
5688
|
versionChecker: createNpmVersionChecker({
|
|
5653
5689
|
stateRoot: opts.storage.stateRoot,
|
|
5654
5690
|
currentVersion: CLI_METADATA.currentVersion,
|
|
@@ -6626,6 +6662,103 @@ var UnknownViewFallback = ({ id }) => /* @__PURE__ */ jsxs(Box, { flexDirection:
|
|
|
6626
6662
|
// src/application/ui/tui/runtime/system-status-context.tsx
|
|
6627
6663
|
import { createContext as createContext10, useCallback as useCallback5, useContext as useContext10, useEffect as useEffect4, useState as useState6 } from "react";
|
|
6628
6664
|
|
|
6665
|
+
// src/integration/io/command-exists.ts
|
|
6666
|
+
import { spawn as spawn2 } from "child_process";
|
|
6667
|
+
var commandExists = (name) => new Promise((resolve) => {
|
|
6668
|
+
const child = process.platform === "win32" ? spawn2("where", [name], { stdio: "ignore" }) : spawn2("command", ["-v", name], { stdio: "ignore", shell: true });
|
|
6669
|
+
let settled = false;
|
|
6670
|
+
const settle = (value) => {
|
|
6671
|
+
if (settled) return;
|
|
6672
|
+
settled = true;
|
|
6673
|
+
resolve(value);
|
|
6674
|
+
};
|
|
6675
|
+
child.on("error", () => settle(false));
|
|
6676
|
+
child.on("exit", (code) => settle(code === 0));
|
|
6677
|
+
});
|
|
6678
|
+
|
|
6679
|
+
// src/integration/system/detect-cli.ts
|
|
6680
|
+
var PROVIDER_BINARY = {
|
|
6681
|
+
"claude-code": "claude",
|
|
6682
|
+
"github-copilot": "copilot",
|
|
6683
|
+
"openai-codex": "codex"
|
|
6684
|
+
};
|
|
6685
|
+
var PROVIDER_INSTALL_GUIDANCE = {
|
|
6686
|
+
"claude-code": {
|
|
6687
|
+
docsUrl: "https://docs.claude.com/en/docs/claude-code/setup",
|
|
6688
|
+
commandsByPlatform: {
|
|
6689
|
+
darwin: [
|
|
6690
|
+
"brew install --cask claude-code",
|
|
6691
|
+
"curl -fsSL https://claude.ai/install.sh | bash",
|
|
6692
|
+
"npm install -g @anthropic-ai/claude-code"
|
|
6693
|
+
],
|
|
6694
|
+
linux: ["curl -fsSL https://claude.ai/install.sh | bash", "npm install -g @anthropic-ai/claude-code"],
|
|
6695
|
+
win32: [
|
|
6696
|
+
"winget install Anthropic.ClaudeCode",
|
|
6697
|
+
"irm https://claude.ai/install.ps1 | iex",
|
|
6698
|
+
"npm install -g @anthropic-ai/claude-code"
|
|
6699
|
+
]
|
|
6700
|
+
}
|
|
6701
|
+
},
|
|
6702
|
+
"github-copilot": {
|
|
6703
|
+
docsUrl: "https://docs.github.com/en/copilot/how-tos/copilot-cli/set-up-copilot-cli/install-copilot-cli",
|
|
6704
|
+
commandsByPlatform: {
|
|
6705
|
+
darwin: ["brew install copilot-cli", "npm install -g @github/copilot"],
|
|
6706
|
+
linux: ["npm install -g @github/copilot", "brew install copilot-cli"],
|
|
6707
|
+
win32: ["winget install GitHub.Copilot", "npm install -g @github/copilot"]
|
|
6708
|
+
}
|
|
6709
|
+
},
|
|
6710
|
+
"openai-codex": {
|
|
6711
|
+
docsUrl: "https://github.com/openai/codex",
|
|
6712
|
+
commandsByPlatform: {
|
|
6713
|
+
darwin: [
|
|
6714
|
+
"brew install --cask codex",
|
|
6715
|
+
"curl -fsSL https://chatgpt.com/codex/install.sh | sh",
|
|
6716
|
+
"npm install -g @openai/codex"
|
|
6717
|
+
],
|
|
6718
|
+
linux: ["curl -fsSL https://chatgpt.com/codex/install.sh | sh", "npm install -g @openai/codex"],
|
|
6719
|
+
win32: [
|
|
6720
|
+
'powershell -ExecutionPolicy ByPass -c "irm https://chatgpt.com/codex/install.ps1 | iex"',
|
|
6721
|
+
"npm install -g @openai/codex"
|
|
6722
|
+
]
|
|
6723
|
+
}
|
|
6724
|
+
}
|
|
6725
|
+
};
|
|
6726
|
+
var resolveInstallPlatform = (platform = process.platform) => {
|
|
6727
|
+
if (platform === "darwin" || platform === "win32") return platform;
|
|
6728
|
+
return "linux";
|
|
6729
|
+
};
|
|
6730
|
+
var primaryInstallCommand = (provider, platform = process.platform) => {
|
|
6731
|
+
const os = resolveInstallPlatform(platform);
|
|
6732
|
+
const list = PROVIDER_INSTALL_GUIDANCE[provider].commandsByPlatform[os];
|
|
6733
|
+
const first = list[0];
|
|
6734
|
+
if (first === void 0) {
|
|
6735
|
+
throw new Error(`No install command registered for ${provider} on ${os}`);
|
|
6736
|
+
}
|
|
6737
|
+
return first;
|
|
6738
|
+
};
|
|
6739
|
+
var renderProviderInstallGuidance = (provider, platform = process.platform) => {
|
|
6740
|
+
const os = resolveInstallPlatform(platform);
|
|
6741
|
+
const guidance = PROVIDER_INSTALL_GUIDANCE[provider];
|
|
6742
|
+
const commands = guidance.commandsByPlatform[os];
|
|
6743
|
+
const header = `${provider} CLI (${PROVIDER_BINARY[provider]}) not on PATH`;
|
|
6744
|
+
const bullets = commands.map((c) => ` \u2022 ${c}`).join("\n");
|
|
6745
|
+
return `${header}
|
|
6746
|
+
Install options (${os}):
|
|
6747
|
+
${bullets}
|
|
6748
|
+
Docs: ${guidance.docsUrl}`;
|
|
6749
|
+
};
|
|
6750
|
+
var defaultWhich = commandExists;
|
|
6751
|
+
var detectInstalledProviders = async (options = {}) => {
|
|
6752
|
+
const which = options.which ?? defaultWhich;
|
|
6753
|
+
const providers = Object.keys(PROVIDER_BINARY);
|
|
6754
|
+
const results = await Promise.all(providers.map(async (p) => [p, await which(PROVIDER_BINARY[p])]));
|
|
6755
|
+
const installed = /* @__PURE__ */ new Set();
|
|
6756
|
+
for (const [provider, present] of results) {
|
|
6757
|
+
if (present) installed.add(provider);
|
|
6758
|
+
}
|
|
6759
|
+
return installed;
|
|
6760
|
+
};
|
|
6761
|
+
|
|
6629
6762
|
// src/application/chain/trace.ts
|
|
6630
6763
|
var abortedEntry = (elementName, reason) => ({
|
|
6631
6764
|
elementName,
|
|
@@ -6707,11 +6840,6 @@ var isDomainError = (cause) => cause instanceof Error && typeof cause.code === "
|
|
|
6707
6840
|
var MIN_NODE_MAJOR = 24;
|
|
6708
6841
|
|
|
6709
6842
|
// src/application/flows/doctor/flow.ts
|
|
6710
|
-
var PROVIDER_BINARY = {
|
|
6711
|
-
"claude-code": "claude",
|
|
6712
|
-
"github-copilot": "copilot",
|
|
6713
|
-
"openai-codex": "codex"
|
|
6714
|
-
};
|
|
6715
6843
|
var PROVIDER_LABEL = {
|
|
6716
6844
|
"claude-code": "Claude Code",
|
|
6717
6845
|
"github-copilot": "GitHub Copilot",
|
|
@@ -7066,30 +7194,47 @@ var probeSprintExecutionPairing = async (sprints, sprintExecutionRepo) => {
|
|
|
7066
7194
|
};
|
|
7067
7195
|
};
|
|
7068
7196
|
|
|
7069
|
-
// src/integration/io/command
|
|
7070
|
-
|
|
7071
|
-
var
|
|
7072
|
-
|
|
7197
|
+
// src/integration/io/run-command.ts
|
|
7198
|
+
var PROBE_TIMEOUT_MS = 5e3;
|
|
7199
|
+
var runCommand = (name, args) => new Promise((resolve) => {
|
|
7200
|
+
let child;
|
|
7201
|
+
try {
|
|
7202
|
+
child = crossPlatformSpawn(name, args, { stdio: ["ignore", "pipe", "pipe"] });
|
|
7203
|
+
} catch {
|
|
7204
|
+
resolve({ ok: false, code: null, stdout: "", stderr: "" });
|
|
7205
|
+
return;
|
|
7206
|
+
}
|
|
7207
|
+
const stdoutChunks = [];
|
|
7208
|
+
const stderrChunks = [];
|
|
7073
7209
|
let settled = false;
|
|
7074
|
-
const settle = (
|
|
7210
|
+
const settle = (result) => {
|
|
7075
7211
|
if (settled) return;
|
|
7076
7212
|
settled = true;
|
|
7077
|
-
|
|
7213
|
+
clearTimeout(timer);
|
|
7214
|
+
resolve(result);
|
|
7078
7215
|
};
|
|
7079
|
-
|
|
7080
|
-
|
|
7081
|
-
|
|
7082
|
-
|
|
7083
|
-
// src/integration/io/run-command.ts
|
|
7084
|
-
import { execFile } from "child_process";
|
|
7085
|
-
var runCommand = (name, args) => new Promise((resolve) => {
|
|
7086
|
-
execFile(name, [...args], { timeout: 5e3, encoding: "utf8" }, (err, stdout, stderr) => {
|
|
7087
|
-
if (err === null) {
|
|
7088
|
-
resolve({ ok: true, code: 0, stdout, stderr });
|
|
7089
|
-
return;
|
|
7216
|
+
const timer = setTimeout(() => {
|
|
7217
|
+
try {
|
|
7218
|
+
child.kill("SIGTERM");
|
|
7219
|
+
} catch {
|
|
7090
7220
|
}
|
|
7091
|
-
|
|
7092
|
-
|
|
7221
|
+
settle({
|
|
7222
|
+
ok: false,
|
|
7223
|
+
code: null,
|
|
7224
|
+
stdout: Buffer.concat(stdoutChunks).toString("utf8"),
|
|
7225
|
+
stderr: Buffer.concat(stderrChunks).toString("utf8")
|
|
7226
|
+
});
|
|
7227
|
+
}, PROBE_TIMEOUT_MS);
|
|
7228
|
+
child.stdout?.on("data", (c) => stdoutChunks.push(c));
|
|
7229
|
+
child.stderr?.on("data", (c) => stderrChunks.push(c));
|
|
7230
|
+
child.on("error", () => settle({ ok: false, code: null, stdout: "", stderr: "" }));
|
|
7231
|
+
child.on("close", (code) => {
|
|
7232
|
+
settle({
|
|
7233
|
+
ok: code === 0,
|
|
7234
|
+
code,
|
|
7235
|
+
stdout: Buffer.concat(stdoutChunks).toString("utf8"),
|
|
7236
|
+
stderr: Buffer.concat(stderrChunks).toString("utf8")
|
|
7237
|
+
});
|
|
7093
7238
|
});
|
|
7094
7239
|
});
|
|
7095
7240
|
|
|
@@ -11206,16 +11351,16 @@ import { join as join23 } from "path";
|
|
|
11206
11351
|
|
|
11207
11352
|
// src/application/flows/refine/flow.ts
|
|
11208
11353
|
import { dirname as dirname11, join as join22 } from "path";
|
|
11209
|
-
import { promises as
|
|
11354
|
+
import { promises as fs17 } from "fs";
|
|
11210
11355
|
|
|
11211
11356
|
// src/application/flows/_shared/build-unit.ts
|
|
11212
|
-
import { promises as
|
|
11357
|
+
import { promises as fs14 } from "fs";
|
|
11213
11358
|
import { join as join17 } from "path";
|
|
11214
11359
|
var buildUnitLeaf = (opts) => leaf(opts.name, {
|
|
11215
11360
|
useCase: {
|
|
11216
11361
|
execute: async (input) => {
|
|
11217
11362
|
try {
|
|
11218
|
-
await
|
|
11363
|
+
await fs14.mkdir(input.path, { recursive: true });
|
|
11219
11364
|
} catch (cause) {
|
|
11220
11365
|
return Result.error(
|
|
11221
11366
|
new StorageError({
|
|
@@ -11327,7 +11472,7 @@ var fetchIssueContextLeaf = (deps, ticket) => leaf(`fetch-issue-context-${String
|
|
|
11327
11472
|
});
|
|
11328
11473
|
|
|
11329
11474
|
// src/application/flows/refine/leaves/refine-ticket-interactive.ts
|
|
11330
|
-
import { promises as
|
|
11475
|
+
import { promises as fs16 } from "fs";
|
|
11331
11476
|
import { dirname as dirname10, join as join20 } from "path";
|
|
11332
11477
|
|
|
11333
11478
|
// src/business/ticket/refine-ticket.ts
|
|
@@ -11425,14 +11570,14 @@ var renderFilename = (filename, index, multiplicity) => {
|
|
|
11425
11570
|
};
|
|
11426
11571
|
|
|
11427
11572
|
// src/integration/ai/contract/_engine/validate-signals-file.ts
|
|
11428
|
-
import { promises as
|
|
11573
|
+
import { promises as fs15 } from "fs";
|
|
11429
11574
|
import { join as join19 } from "path";
|
|
11430
11575
|
var SIGNALS_FILENAME = "signals.json";
|
|
11431
11576
|
var validateSignalsFile = async (outputDir, contract) => {
|
|
11432
11577
|
const path = join19(String(outputDir), SIGNALS_FILENAME);
|
|
11433
11578
|
let bytes;
|
|
11434
11579
|
try {
|
|
11435
|
-
bytes = await
|
|
11580
|
+
bytes = await fs15.readFile(path, "utf8");
|
|
11436
11581
|
} catch (cause) {
|
|
11437
11582
|
if (isNodeErrnoCode(cause, "ENOENT") || isNodeErrnoCode(cause, "ENOTDIR")) {
|
|
11438
11583
|
return Result.error(
|
|
@@ -11608,7 +11753,7 @@ var remapRefineSignalsError = (error) => {
|
|
|
11608
11753
|
};
|
|
11609
11754
|
var warnDroppedSignals = async (deps, outputDir) => {
|
|
11610
11755
|
try {
|
|
11611
|
-
const bytes = await
|
|
11756
|
+
const bytes = await fs16.readFile(join20(String(outputDir), "signals.json"), "utf8");
|
|
11612
11757
|
const raw = JSON.parse(bytes);
|
|
11613
11758
|
const inner = Array.isArray(raw) ? raw : raw.signals;
|
|
11614
11759
|
if (!Array.isArray(inner)) return;
|
|
@@ -11999,7 +12144,7 @@ var stampSessionMetaLeaf = (deps, opts) => leaf(opts.name, {
|
|
|
11999
12144
|
var readSprintProgress = async (refinementRoot) => {
|
|
12000
12145
|
const sprintDir2 = dirname11(String(refinementRoot));
|
|
12001
12146
|
try {
|
|
12002
|
-
return await
|
|
12147
|
+
return await fs17.readFile(join22(sprintDir2, "progress.md"), "utf8");
|
|
12003
12148
|
} catch {
|
|
12004
12149
|
return "";
|
|
12005
12150
|
}
|
|
@@ -12138,95 +12283,6 @@ var createRefineFlow = (deps, opts) => {
|
|
|
12138
12283
|
]);
|
|
12139
12284
|
};
|
|
12140
12285
|
|
|
12141
|
-
// src/integration/system/detect-cli.ts
|
|
12142
|
-
var PROVIDER_BINARY2 = {
|
|
12143
|
-
"claude-code": "claude",
|
|
12144
|
-
"github-copilot": "gh",
|
|
12145
|
-
"openai-codex": "codex"
|
|
12146
|
-
};
|
|
12147
|
-
var PROVIDER_INSTALL_GUIDANCE = {
|
|
12148
|
-
"claude-code": {
|
|
12149
|
-
docsUrl: "https://docs.claude.com/en/docs/claude-code/setup",
|
|
12150
|
-
commandsByPlatform: {
|
|
12151
|
-
darwin: [
|
|
12152
|
-
"brew install --cask claude-code",
|
|
12153
|
-
"curl -fsSL https://claude.ai/install.sh | bash",
|
|
12154
|
-
"npm install -g @anthropic-ai/claude-code"
|
|
12155
|
-
],
|
|
12156
|
-
linux: ["curl -fsSL https://claude.ai/install.sh | bash", "npm install -g @anthropic-ai/claude-code"],
|
|
12157
|
-
win32: [
|
|
12158
|
-
"winget install Anthropic.ClaudeCode",
|
|
12159
|
-
"irm https://claude.ai/install.ps1 | iex",
|
|
12160
|
-
"npm install -g @anthropic-ai/claude-code"
|
|
12161
|
-
]
|
|
12162
|
-
}
|
|
12163
|
-
},
|
|
12164
|
-
"github-copilot": {
|
|
12165
|
-
docsUrl: "https://docs.github.com/en/copilot/how-tos/use-copilot-agents/use-copilot-in-the-cli",
|
|
12166
|
-
commandsByPlatform: {
|
|
12167
|
-
darwin: ["brew install gh && gh extension install github/gh-copilot", "gh extension install github/gh-copilot"],
|
|
12168
|
-
linux: [
|
|
12169
|
-
"install gh from https://github.com/cli/cli/blob/trunk/docs/install_linux.md, then: gh extension install github/gh-copilot",
|
|
12170
|
-
"gh extension install github/gh-copilot"
|
|
12171
|
-
],
|
|
12172
|
-
win32: [
|
|
12173
|
-
"winget install --id GitHub.cli && gh extension install github/gh-copilot",
|
|
12174
|
-
"gh extension install github/gh-copilot"
|
|
12175
|
-
]
|
|
12176
|
-
}
|
|
12177
|
-
},
|
|
12178
|
-
"openai-codex": {
|
|
12179
|
-
docsUrl: "https://github.com/openai/codex",
|
|
12180
|
-
commandsByPlatform: {
|
|
12181
|
-
darwin: [
|
|
12182
|
-
"brew install --cask codex",
|
|
12183
|
-
"curl -fsSL https://chatgpt.com/codex/install.sh | sh",
|
|
12184
|
-
"npm install -g @openai/codex"
|
|
12185
|
-
],
|
|
12186
|
-
linux: ["curl -fsSL https://chatgpt.com/codex/install.sh | sh", "npm install -g @openai/codex"],
|
|
12187
|
-
win32: [
|
|
12188
|
-
'powershell -ExecutionPolicy ByPass -c "irm https://chatgpt.com/codex/install.ps1 | iex"',
|
|
12189
|
-
"npm install -g @openai/codex"
|
|
12190
|
-
]
|
|
12191
|
-
}
|
|
12192
|
-
}
|
|
12193
|
-
};
|
|
12194
|
-
var resolveInstallPlatform = (platform = process.platform) => {
|
|
12195
|
-
if (platform === "darwin" || platform === "win32") return platform;
|
|
12196
|
-
return "linux";
|
|
12197
|
-
};
|
|
12198
|
-
var primaryInstallCommand = (provider, platform = process.platform) => {
|
|
12199
|
-
const os = resolveInstallPlatform(platform);
|
|
12200
|
-
const list = PROVIDER_INSTALL_GUIDANCE[provider].commandsByPlatform[os];
|
|
12201
|
-
const first = list[0];
|
|
12202
|
-
if (first === void 0) {
|
|
12203
|
-
throw new Error(`No install command registered for ${provider} on ${os}`);
|
|
12204
|
-
}
|
|
12205
|
-
return first;
|
|
12206
|
-
};
|
|
12207
|
-
var renderProviderInstallGuidance = (provider, platform = process.platform) => {
|
|
12208
|
-
const os = resolveInstallPlatform(platform);
|
|
12209
|
-
const guidance = PROVIDER_INSTALL_GUIDANCE[provider];
|
|
12210
|
-
const commands = guidance.commandsByPlatform[os];
|
|
12211
|
-
const header = `${provider} CLI (${PROVIDER_BINARY2[provider]}) not on PATH`;
|
|
12212
|
-
const bullets = commands.map((c) => ` \u2022 ${c}`).join("\n");
|
|
12213
|
-
return `${header}
|
|
12214
|
-
Install options (${os}):
|
|
12215
|
-
${bullets}
|
|
12216
|
-
Docs: ${guidance.docsUrl}`;
|
|
12217
|
-
};
|
|
12218
|
-
var defaultWhich = commandExists;
|
|
12219
|
-
var detectInstalledProviders = async (options = {}) => {
|
|
12220
|
-
const which = options.which ?? defaultWhich;
|
|
12221
|
-
const providers = Object.keys(PROVIDER_BINARY2);
|
|
12222
|
-
const results = await Promise.all(providers.map(async (p) => [p, await which(PROVIDER_BINARY2[p])]));
|
|
12223
|
-
const installed = /* @__PURE__ */ new Set();
|
|
12224
|
-
for (const [provider, present] of results) {
|
|
12225
|
-
if (present) installed.add(provider);
|
|
12226
|
-
}
|
|
12227
|
-
return installed;
|
|
12228
|
-
};
|
|
12229
|
-
|
|
12230
12286
|
// src/application/ui/shared/launch/check-cli.ts
|
|
12231
12287
|
var aiFlowIdForCheck = (flowId) => {
|
|
12232
12288
|
switch (flowId) {
|
|
@@ -12272,7 +12328,7 @@ var rowExpectationsFor = (aiFlow, settings, options) => {
|
|
|
12272
12328
|
};
|
|
12273
12329
|
var renderMissing = (missing, aiFlow) => {
|
|
12274
12330
|
const formatOne = (m) => {
|
|
12275
|
-
const binary =
|
|
12331
|
+
const binary = PROVIDER_BINARY[m.provider];
|
|
12276
12332
|
const installHint = primaryInstallCommand(m.provider);
|
|
12277
12333
|
const docsUrl = PROVIDER_INSTALL_GUIDANCE[m.provider].docsUrl;
|
|
12278
12334
|
const roleSuffix = m.role !== void 0 ? ` (${m.role})` : "";
|
|
@@ -12391,7 +12447,7 @@ import { join as join25 } from "path";
|
|
|
12391
12447
|
|
|
12392
12448
|
// src/application/flows/plan/flow.ts
|
|
12393
12449
|
import { dirname as dirname13, join as join24 } from "path";
|
|
12394
|
-
import { promises as
|
|
12450
|
+
import { promises as fs18 } from "fs";
|
|
12395
12451
|
|
|
12396
12452
|
// src/application/flows/_shared/sprint/load-execution.ts
|
|
12397
12453
|
var loadSprintExecutionLeaf = (deps, name = "load-sprint-execution") => leaf(name, {
|
|
@@ -13172,7 +13228,7 @@ var callPlannerInteractiveLeaf = (deps) => leaf("call-planner-interactive", {
|
|
|
13172
13228
|
var readSprintProgress2 = async (planRoot) => {
|
|
13173
13229
|
const sprintDir2 = dirname13(String(planRoot));
|
|
13174
13230
|
try {
|
|
13175
|
-
return await
|
|
13231
|
+
return await fs18.readFile(join24(sprintDir2, "progress.md"), "utf8");
|
|
13176
13232
|
} catch {
|
|
13177
13233
|
return "";
|
|
13178
13234
|
}
|
|
@@ -13677,7 +13733,7 @@ var branchPreflightLeaf = (deps, opts, name = "branch-preflight") => leaf(name,
|
|
|
13677
13733
|
});
|
|
13678
13734
|
|
|
13679
13735
|
// src/application/flows/implement/leaves/build-task-workspace.ts
|
|
13680
|
-
import { promises as
|
|
13736
|
+
import { promises as fs19 } from "fs";
|
|
13681
13737
|
import { join as join26 } from "path";
|
|
13682
13738
|
|
|
13683
13739
|
// src/integration/ai/prompts/_engine/renderers/task.ts
|
|
@@ -13987,8 +14043,8 @@ ${body}
|
|
|
13987
14043
|
// src/application/flows/implement/leaves/build-task-workspace.ts
|
|
13988
14044
|
var writeOrError = async (path, content) => {
|
|
13989
14045
|
try {
|
|
13990
|
-
await
|
|
13991
|
-
await
|
|
14046
|
+
await fs19.mkdir(path.slice(0, path.lastIndexOf("/")), { recursive: true });
|
|
14047
|
+
await fs19.writeFile(path, content, "utf8");
|
|
13992
14048
|
return Result.ok(void 0);
|
|
13993
14049
|
} catch (cause) {
|
|
13994
14050
|
return Result.error(
|
|
@@ -14712,7 +14768,7 @@ var loop = (name, body, opts = {}) => ({
|
|
|
14712
14768
|
|
|
14713
14769
|
// src/application/flows/implement/leaves/evaluator.ts
|
|
14714
14770
|
import { dirname as dirname15, join as join28 } from "path";
|
|
14715
|
-
import { promises as
|
|
14771
|
+
import { promises as fs21 } from "fs";
|
|
14716
14772
|
|
|
14717
14773
|
// src/business/task/plateau-detection.ts
|
|
14718
14774
|
var failedDimensions = (signal) => {
|
|
@@ -15163,7 +15219,7 @@ var evaluatorOutputContract = {
|
|
|
15163
15219
|
};
|
|
15164
15220
|
|
|
15165
15221
|
// src/application/flows/implement/leaves/round-artifacts.ts
|
|
15166
|
-
import { promises as
|
|
15222
|
+
import { promises as fs20 } from "fs";
|
|
15167
15223
|
import { join as join27 } from "path";
|
|
15168
15224
|
var nextRoundNum = async (workspaceRoot) => {
|
|
15169
15225
|
const entries = await listDir(join27(String(workspaceRoot), "rounds"));
|
|
@@ -15180,7 +15236,7 @@ var readRoundSessionId = async (workspaceRoot, round, role) => {
|
|
|
15180
15236
|
const path = join27(String(workspaceRoot), "rounds", String(round), role, "session-id.txt");
|
|
15181
15237
|
let content;
|
|
15182
15238
|
try {
|
|
15183
|
-
content = await
|
|
15239
|
+
content = await fs20.readFile(path, "utf8");
|
|
15184
15240
|
} catch {
|
|
15185
15241
|
return void 0;
|
|
15186
15242
|
}
|
|
@@ -15200,7 +15256,7 @@ var writeRoundPrompt = async (workspaceRoot, round, role, prompt, logger) => {
|
|
|
15200
15256
|
// src/application/flows/implement/leaves/evaluator.ts
|
|
15201
15257
|
var readProgressFile = async (path) => {
|
|
15202
15258
|
try {
|
|
15203
|
-
return await
|
|
15259
|
+
return await fs21.readFile(path, "utf8");
|
|
15204
15260
|
} catch {
|
|
15205
15261
|
return "";
|
|
15206
15262
|
}
|
|
@@ -15226,7 +15282,7 @@ var evaluatorLeaf = (deps, taskId) => leaf(`evaluator-${String(taskId)}`, {
|
|
|
15226
15282
|
});
|
|
15227
15283
|
if (!prompt.ok) return Result.error(prompt.error);
|
|
15228
15284
|
await writeRoundPrompt(input.workspaceRoot, input.roundNum, "evaluator", String(prompt.value), deps.logger);
|
|
15229
|
-
const
|
|
15285
|
+
const spawn3 = await deps.provider.generate(
|
|
15230
15286
|
implementSession(
|
|
15231
15287
|
input.workspaceRoot,
|
|
15232
15288
|
deps.cwd,
|
|
@@ -15239,7 +15295,7 @@ var evaluatorLeaf = (deps, taskId) => leaf(`evaluator-${String(taskId)}`, {
|
|
|
15239
15295
|
deps.effort
|
|
15240
15296
|
)
|
|
15241
15297
|
);
|
|
15242
|
-
if (!
|
|
15298
|
+
if (!spawn3.ok) return Result.error(spawn3.error);
|
|
15243
15299
|
const validated = await validateSignalsFile(outputDir, evaluatorOutputContract);
|
|
15244
15300
|
if (!validated.ok) return Result.error(validated.error);
|
|
15245
15301
|
const signals = validated.value;
|
|
@@ -15324,7 +15380,7 @@ var evaluatorLeaf = (deps, taskId) => leaf(`evaluator-${String(taskId)}`, {
|
|
|
15324
15380
|
|
|
15325
15381
|
// src/application/flows/implement/leaves/generator.ts
|
|
15326
15382
|
import { dirname as dirname16, join as join29 } from "path";
|
|
15327
|
-
import { promises as
|
|
15383
|
+
import { promises as fs22 } from "fs";
|
|
15328
15384
|
|
|
15329
15385
|
// src/business/task/run-generator-turn.ts
|
|
15330
15386
|
var findTaskBlocked = (signals) => signals.find((s) => s.type === "task-blocked")?.reason;
|
|
@@ -15391,7 +15447,7 @@ var latestCritique = (task) => {
|
|
|
15391
15447
|
// src/application/flows/implement/leaves/generator.ts
|
|
15392
15448
|
var readProgressFile2 = async (path) => {
|
|
15393
15449
|
try {
|
|
15394
|
-
return await
|
|
15450
|
+
return await fs22.readFile(path, "utf8");
|
|
15395
15451
|
} catch {
|
|
15396
15452
|
return "";
|
|
15397
15453
|
}
|
|
@@ -15445,7 +15501,7 @@ var generatorLeaf = (deps, taskId) => leaf(`generator-${String(taskId)}`, {
|
|
|
15445
15501
|
if (!prompt.ok) return Result.error(prompt.error);
|
|
15446
15502
|
await writeRoundPrompt(input.workspaceRoot, roundNum, "generator", String(prompt.value), deps.logger);
|
|
15447
15503
|
const effectiveModel = task.escalatedToModel ?? deps.model;
|
|
15448
|
-
const
|
|
15504
|
+
const spawn3 = await deps.provider.generate(
|
|
15449
15505
|
implementSession(
|
|
15450
15506
|
input.workspaceRoot,
|
|
15451
15507
|
deps.cwd,
|
|
@@ -15458,7 +15514,7 @@ var generatorLeaf = (deps, taskId) => leaf(`generator-${String(taskId)}`, {
|
|
|
15458
15514
|
deps.effort
|
|
15459
15515
|
)
|
|
15460
15516
|
);
|
|
15461
|
-
if (!
|
|
15517
|
+
if (!spawn3.ok) return Result.error(spawn3.error);
|
|
15462
15518
|
const validated = await validateSignalsFile(outputDir, generatorOutputContract);
|
|
15463
15519
|
if (!validated.ok) return Result.error(validated.error);
|
|
15464
15520
|
const signals = validated.value;
|
|
@@ -18025,7 +18081,7 @@ var launchImplement = async (ctx) => {
|
|
|
18025
18081
|
import { join as join38 } from "path";
|
|
18026
18082
|
|
|
18027
18083
|
// src/application/flows/review/leaves/ensure-feedback-file.ts
|
|
18028
|
-
import { promises as
|
|
18084
|
+
import { promises as fs23 } from "fs";
|
|
18029
18085
|
|
|
18030
18086
|
// src/business/feedback/md-parser.ts
|
|
18031
18087
|
var ROUND_HEADING_RE = /^##\s+Round\s+(\d+)\s*$/;
|
|
@@ -18085,12 +18141,12 @@ var ensureFeedbackFileLeaf = (feedbackFile) => leaf("ensure-feedback-file", {
|
|
|
18085
18141
|
useCase: {
|
|
18086
18142
|
execute: async (path) => {
|
|
18087
18143
|
try {
|
|
18088
|
-
await
|
|
18144
|
+
await fs23.access(String(path));
|
|
18089
18145
|
return Result.ok(void 0);
|
|
18090
18146
|
} catch {
|
|
18091
18147
|
}
|
|
18092
18148
|
try {
|
|
18093
|
-
await
|
|
18149
|
+
await fs23.writeFile(String(path), TEMPLATE, { flag: "wx" });
|
|
18094
18150
|
return Result.ok(void 0);
|
|
18095
18151
|
} catch (cause) {
|
|
18096
18152
|
if (typeof cause === "object" && cause !== null && cause.code === "EEXIST") {
|
|
@@ -18112,7 +18168,7 @@ var ensureFeedbackFileLeaf = (feedbackFile) => leaf("ensure-feedback-file", {
|
|
|
18112
18168
|
});
|
|
18113
18169
|
|
|
18114
18170
|
// src/application/flows/review/leaves/review-round.ts
|
|
18115
|
-
import { promises as
|
|
18171
|
+
import { promises as fs24 } from "fs";
|
|
18116
18172
|
import { join as join37 } from "path";
|
|
18117
18173
|
|
|
18118
18174
|
// src/business/feedback/apply-feedback.ts
|
|
@@ -18295,7 +18351,7 @@ var reviewRoundOutputContract = {
|
|
|
18295
18351
|
var readProgressSnippet = async (path) => {
|
|
18296
18352
|
if (path === void 0) return "_(no progress file)_";
|
|
18297
18353
|
try {
|
|
18298
|
-
const content = await
|
|
18354
|
+
const content = await fs24.readFile(String(path), "utf8");
|
|
18299
18355
|
return content.length > 4e3 ? `${content.slice(0, 4e3)}
|
|
18300
18356
|
[truncated]` : content;
|
|
18301
18357
|
} catch {
|
|
@@ -18311,7 +18367,7 @@ ${renderEmptyRound(nextIndex)}${ROUND_SEPARATOR}
|
|
|
18311
18367
|
};
|
|
18312
18368
|
var writeRoundBody = async (path, body) => {
|
|
18313
18369
|
try {
|
|
18314
|
-
const content = await
|
|
18370
|
+
const content = await fs24.readFile(String(path), "utf8");
|
|
18315
18371
|
const lastMarker = content.lastIndexOf(MARKER_COMMENT);
|
|
18316
18372
|
if (lastMarker === -1) {
|
|
18317
18373
|
return Result.error(
|
|
@@ -18328,7 +18384,7 @@ var writeRoundBody = async (path, body) => {
|
|
|
18328
18384
|
const next = `${head}
|
|
18329
18385
|
${body.replace(/\s+$/u, "")}
|
|
18330
18386
|
${tail}`;
|
|
18331
|
-
await
|
|
18387
|
+
await fs24.writeFile(String(path), next, "utf8");
|
|
18332
18388
|
return Result.ok(void 0);
|
|
18333
18389
|
} catch (cause) {
|
|
18334
18390
|
return Result.error(
|
|
@@ -18352,7 +18408,7 @@ var allocateRoundPaths = (reviewRoot, roundIndex) => {
|
|
|
18352
18408
|
};
|
|
18353
18409
|
var ensureRoundDir = async (dir) => {
|
|
18354
18410
|
try {
|
|
18355
|
-
await
|
|
18411
|
+
await fs24.mkdir(String(dir), { recursive: true });
|
|
18356
18412
|
return Result.ok(void 0);
|
|
18357
18413
|
} catch (cause) {
|
|
18358
18414
|
return Result.error(
|
|
@@ -18386,7 +18442,7 @@ var reviewRoundLeaf = (deps, opts) => leaf("review-round", {
|
|
|
18386
18442
|
if (!wrote.ok) return Result.error(wrote.error);
|
|
18387
18443
|
return Result.ok(void 0);
|
|
18388
18444
|
},
|
|
18389
|
-
readFeedbackFile: () =>
|
|
18445
|
+
readFeedbackFile: () => fs24.readFile(String(input.feedbackFile), "utf8"),
|
|
18390
18446
|
readProgressSnippet: () => readProgressSnippet(input.progressFile),
|
|
18391
18447
|
buildPrompt: async (params) => {
|
|
18392
18448
|
const outputContractSection = renderContractSectionFor(reviewRoundOutputContract, paths.value.outputDir);
|
|
@@ -18413,7 +18469,7 @@ var reviewRoundLeaf = (deps, opts) => leaf("review-round", {
|
|
|
18413
18469
|
}
|
|
18414
18470
|
const promptWrote = await writeTextAtomic(String(paths.value.promptFile), String(prompt));
|
|
18415
18471
|
if (!promptWrote.ok) return Result.error(promptWrote.error);
|
|
18416
|
-
const
|
|
18472
|
+
const spawn3 = await deps.provider.generate({
|
|
18417
18473
|
prompt,
|
|
18418
18474
|
cwd: paths.value.outputDir,
|
|
18419
18475
|
additionalRoots: opts.additionalRoots,
|
|
@@ -18422,7 +18478,7 @@ var reviewRoundLeaf = (deps, opts) => leaf("review-round", {
|
|
|
18422
18478
|
signalsFile: paths.value.signalsFile,
|
|
18423
18479
|
outputDir: paths.value.outputDir
|
|
18424
18480
|
});
|
|
18425
|
-
if (!
|
|
18481
|
+
if (!spawn3.ok) return Result.error(spawn3.error);
|
|
18426
18482
|
const validated = await validateSignalsFile(paths.value.outputDir, reviewRoundOutputContract);
|
|
18427
18483
|
if (!validated.ok) return Result.error(validated.error);
|
|
18428
18484
|
for (const sig of validated.value) {
|
|
@@ -18864,7 +18920,7 @@ var probeReadinessLeaf = (deps, tool) => leaf(`probe-${tool}`, {
|
|
|
18864
18920
|
});
|
|
18865
18921
|
|
|
18866
18922
|
// src/application/flows/readiness/leaves/propose.ts
|
|
18867
|
-
import { promises as
|
|
18923
|
+
import { promises as fs25 } from "fs";
|
|
18868
18924
|
|
|
18869
18925
|
// src/integration/ai/readiness/_engine/setup.ts
|
|
18870
18926
|
import { join as join40 } from "path";
|
|
@@ -19163,7 +19219,7 @@ var proposeReadinessUseCase = async (deps, tool, input) => {
|
|
|
19163
19219
|
let existingBody;
|
|
19164
19220
|
if (existingPath !== void 0) {
|
|
19165
19221
|
try {
|
|
19166
|
-
existingBody = await
|
|
19222
|
+
existingBody = await fs25.readFile(existingPath, "utf8");
|
|
19167
19223
|
} catch {
|
|
19168
19224
|
existingBody = void 0;
|
|
19169
19225
|
}
|
|
@@ -19281,7 +19337,7 @@ var proposeReadinessLeaf = (deps, tool) => leaf(`propose-${tool}`, {
|
|
|
19281
19337
|
});
|
|
19282
19338
|
|
|
19283
19339
|
// src/application/flows/readiness/leaves/write.ts
|
|
19284
|
-
import { promises as
|
|
19340
|
+
import { promises as fs26 } from "fs";
|
|
19285
19341
|
var writeReadinessUseCase = async (deps, tool, input) => {
|
|
19286
19342
|
const log = deps.logger.named(`readiness.write-${tool}`);
|
|
19287
19343
|
if (!input.accepted || input.proposal === void 0) {
|
|
@@ -19315,7 +19371,7 @@ var makeBackupPath = (targetPath, now) => {
|
|
|
19315
19371
|
};
|
|
19316
19372
|
var fileExists = async (path) => {
|
|
19317
19373
|
try {
|
|
19318
|
-
const stat = await
|
|
19374
|
+
const stat = await fs26.stat(path);
|
|
19319
19375
|
return stat.isFile();
|
|
19320
19376
|
} catch {
|
|
19321
19377
|
return false;
|
|
@@ -19323,7 +19379,7 @@ var fileExists = async (path) => {
|
|
|
19323
19379
|
};
|
|
19324
19380
|
var safeReadText = async (path) => {
|
|
19325
19381
|
try {
|
|
19326
|
-
return await
|
|
19382
|
+
return await fs26.readFile(path, "utf8");
|
|
19327
19383
|
} catch {
|
|
19328
19384
|
return void 0;
|
|
19329
19385
|
}
|
|
@@ -19348,11 +19404,11 @@ var writeReadinessLeaf = (deps, tool) => leaf(`write-${tool}`, {
|
|
|
19348
19404
|
});
|
|
19349
19405
|
|
|
19350
19406
|
// src/application/flows/_shared/allocate-run-dir.ts
|
|
19351
|
-
import { promises as
|
|
19407
|
+
import { promises as fs28 } from "fs";
|
|
19352
19408
|
import { join as join42 } from "path";
|
|
19353
19409
|
|
|
19354
19410
|
// src/integration/ai/runs/_engine/run-artifacts.ts
|
|
19355
|
-
import { promises as
|
|
19411
|
+
import { promises as fs27 } from "fs";
|
|
19356
19412
|
import { join as join41 } from "path";
|
|
19357
19413
|
var BODY_PREVIEW_LIMIT = 800;
|
|
19358
19414
|
var buildRunDirName = () => {
|
|
@@ -19363,7 +19419,7 @@ var buildRunDirName = () => {
|
|
|
19363
19419
|
var readRunBodyPreview = async (runDir, options) => {
|
|
19364
19420
|
let raw;
|
|
19365
19421
|
try {
|
|
19366
|
-
raw = await
|
|
19422
|
+
raw = await fs27.readFile(join41(String(runDir), "body.txt"), "utf8");
|
|
19367
19423
|
} catch (cause) {
|
|
19368
19424
|
if (isErrnoException(cause) && cause.code === "ENOENT") return void 0;
|
|
19369
19425
|
const code = isErrnoException(cause) ? cause.code : "unknown";
|
|
@@ -19383,7 +19439,7 @@ var allocateRunDirLeaf = (opts) => leaf(opts.name, {
|
|
|
19383
19439
|
useCase: {
|
|
19384
19440
|
execute: async (input) => {
|
|
19385
19441
|
try {
|
|
19386
|
-
await
|
|
19442
|
+
await fs28.mkdir(input.path, { recursive: true });
|
|
19387
19443
|
} catch (cause) {
|
|
19388
19444
|
return Result.error(
|
|
19389
19445
|
new StorageError({
|
|
@@ -19736,7 +19792,7 @@ var proposeUseCase = async (deps, input) => {
|
|
|
19736
19792
|
if (!prompt.ok) return Result.error(prompt.error);
|
|
19737
19793
|
const promptWrote = await writeTextAtomic(String(paths.value.promptFile), String(prompt.value));
|
|
19738
19794
|
if (!promptWrote.ok) return Result.error(promptWrote.error);
|
|
19739
|
-
const
|
|
19795
|
+
const spawn3 = await deps.provider.generate(
|
|
19740
19796
|
detectSkillsSession(
|
|
19741
19797
|
input.repository,
|
|
19742
19798
|
prompt.value,
|
|
@@ -19747,13 +19803,13 @@ var proposeUseCase = async (deps, input) => {
|
|
|
19747
19803
|
deps.effort
|
|
19748
19804
|
)
|
|
19749
19805
|
);
|
|
19750
|
-
if (!
|
|
19806
|
+
if (!spawn3.ok) {
|
|
19751
19807
|
log.error(`provider failed for repo ${input.repository.name}`, {
|
|
19752
19808
|
repositoryId: String(input.repository.id),
|
|
19753
|
-
error:
|
|
19809
|
+
error: spawn3.error.message,
|
|
19754
19810
|
runDir: String(paths.value.runDir)
|
|
19755
19811
|
});
|
|
19756
|
-
return Result.error(
|
|
19812
|
+
return Result.error(spawn3.error);
|
|
19757
19813
|
}
|
|
19758
19814
|
const validated = await validateSignalsFile(paths.value.runDir, detectSkillsOutputContract);
|
|
19759
19815
|
if (!validated.ok) {
|
|
@@ -20494,7 +20550,7 @@ var proposeUseCase2 = async (deps, input) => {
|
|
|
20494
20550
|
if (!prompt.ok) return Result.error(prompt.error);
|
|
20495
20551
|
const promptWrote = await writeTextAtomic(String(paths.value.promptFile), String(prompt.value));
|
|
20496
20552
|
if (!promptWrote.ok) return Result.error(promptWrote.error);
|
|
20497
|
-
const
|
|
20553
|
+
const spawn3 = await deps.provider.generate(
|
|
20498
20554
|
detectScriptsSession(
|
|
20499
20555
|
input.repository,
|
|
20500
20556
|
prompt.value,
|
|
@@ -20505,13 +20561,13 @@ var proposeUseCase2 = async (deps, input) => {
|
|
|
20505
20561
|
deps.effort
|
|
20506
20562
|
)
|
|
20507
20563
|
);
|
|
20508
|
-
if (!
|
|
20564
|
+
if (!spawn3.ok) {
|
|
20509
20565
|
log.error(`provider failed for repo ${input.repository.name}`, {
|
|
20510
20566
|
repositoryId: String(input.repository.id),
|
|
20511
|
-
error:
|
|
20567
|
+
error: spawn3.error.message,
|
|
20512
20568
|
runDir: String(paths.value.runDir)
|
|
20513
20569
|
});
|
|
20514
|
-
return Result.error(
|
|
20570
|
+
return Result.error(spawn3.error);
|
|
20515
20571
|
}
|
|
20516
20572
|
const validated = await validateSignalsFile(paths.value.runDir, detectScriptsOutputContract);
|
|
20517
20573
|
if (!validated.ok) {
|
|
@@ -20857,7 +20913,7 @@ import { join as join46 } from "path";
|
|
|
20857
20913
|
|
|
20858
20914
|
// src/application/flows/ideate/flow.ts
|
|
20859
20915
|
import { dirname as dirname19, join as join45 } from "path";
|
|
20860
|
-
import { promises as
|
|
20916
|
+
import { promises as fs29 } from "fs";
|
|
20861
20917
|
|
|
20862
20918
|
// src/integration/ai/prompts/ideate/definition.ts
|
|
20863
20919
|
var nonEmpty2 = (field) => (v) => v.trim().length === 0 ? Result.error(new ValidationError({ field, value: v, message: `${field} must not be empty` })) : Result.ok(v);
|
|
@@ -21132,7 +21188,7 @@ var ideateAndPlanLeaf = (deps) => leaf("ideate-and-plan", {
|
|
|
21132
21188
|
var readSprintProgress3 = async (ideateRoot) => {
|
|
21133
21189
|
const sprintDir2 = dirname19(String(ideateRoot));
|
|
21134
21190
|
try {
|
|
21135
|
-
return await
|
|
21191
|
+
return await fs29.readFile(join45(sprintDir2, "progress.md"), "utf8");
|
|
21136
21192
|
} catch {
|
|
21137
21193
|
return "";
|
|
21138
21194
|
}
|
|
@@ -27076,7 +27132,7 @@ var createSettingsSetProviderFlow = (deps) => leaf("settings-set-provider", {
|
|
|
27076
27132
|
new ValidationError({
|
|
27077
27133
|
field: settingsKey,
|
|
27078
27134
|
value: input.provider,
|
|
27079
|
-
message: `${input.provider} CLI (${
|
|
27135
|
+
message: `${input.provider} CLI (${PROVIDER_BINARY[input.provider]}) not on PATH \u2014 cannot set ${settingsKey}`,
|
|
27080
27136
|
hint: renderProviderInstallGuidance(input.provider)
|
|
27081
27137
|
})
|
|
27082
27138
|
);
|
|
@@ -28418,9 +28474,9 @@ var generatePrContentLeaf = (deps) => leaf("generate-pr-content", {
|
|
|
28418
28474
|
outputDir: input.unitRoot
|
|
28419
28475
|
};
|
|
28420
28476
|
try {
|
|
28421
|
-
const
|
|
28422
|
-
if (!
|
|
28423
|
-
deps.logger.named("create-pr.ai").warn(`create-pr: AI authoring failed, falling back to template (${
|
|
28477
|
+
const spawn3 = await deps.provider.generate(session);
|
|
28478
|
+
if (!spawn3.ok) {
|
|
28479
|
+
deps.logger.named("create-pr.ai").warn(`create-pr: AI authoring failed, falling back to template (${spawn3.error.message})`);
|
|
28424
28480
|
return Result.ok({});
|
|
28425
28481
|
}
|
|
28426
28482
|
const validated = await validateSignalsFile(input.unitRoot, generatePrContentOutputContract);
|
|
@@ -28777,7 +28833,7 @@ import { basename as basename5, join as join52 } from "path";
|
|
|
28777
28833
|
|
|
28778
28834
|
// src/application/ui/tui/prompts/path-picker-prompt.tsx
|
|
28779
28835
|
import { useEffect as useEffect38, useState as useState44 } from "react";
|
|
28780
|
-
import { promises as
|
|
28836
|
+
import { promises as fs30 } from "fs";
|
|
28781
28837
|
import { dirname as dirname20, join as join51 } from "path";
|
|
28782
28838
|
import { homedir } from "os";
|
|
28783
28839
|
import { Box as Box70, Text as Text69, useInput as useInput28 } from "ink";
|
|
@@ -28804,7 +28860,7 @@ var PathPickerPrompt = ({
|
|
|
28804
28860
|
useEffect38(() => {
|
|
28805
28861
|
const load = async () => {
|
|
28806
28862
|
try {
|
|
28807
|
-
const items = await
|
|
28863
|
+
const items = await fs30.readdir(cwd, { withFileTypes: true });
|
|
28808
28864
|
const filtered = items.filter((d) => showHidden || !d.name.startsWith(".")).filter((d) => d.isDirectory()).map((d) => ({ name: d.name, isDirectory: true })).sort((a, b) => a.name.localeCompare(b.name));
|
|
28809
28865
|
setEntries(filtered);
|
|
28810
28866
|
setError(void 0);
|
|
@@ -28887,7 +28943,7 @@ var PathPickerPrompt = ({
|
|
|
28887
28943
|
return;
|
|
28888
28944
|
}
|
|
28889
28945
|
try {
|
|
28890
|
-
const stat = await
|
|
28946
|
+
const stat = await fs30.stat(expanded);
|
|
28891
28947
|
if (!stat.isDirectory()) {
|
|
28892
28948
|
setError(`${expanded} is not a directory`);
|
|
28893
28949
|
setTyping(false);
|
|
@@ -30214,7 +30270,7 @@ import { useEffect as useEffect45, useMemo as useMemo26, useRef as useRef13 } fr
|
|
|
30214
30270
|
import { useApp, useInput as useInput32 } from "ink";
|
|
30215
30271
|
|
|
30216
30272
|
// src/integration/io/clipboard.ts
|
|
30217
|
-
import { spawn as
|
|
30273
|
+
import { spawn as nodeSpawn2 } from "child_process";
|
|
30218
30274
|
var resolveHelpers = ({ platform, env }) => {
|
|
30219
30275
|
if (platform === "darwin") return [{ cmd: "pbcopy", args: [] }];
|
|
30220
30276
|
if (platform === "win32") return [{ cmd: "clip.exe", args: [] }];
|
|
@@ -30232,10 +30288,10 @@ var resolveHelpers = ({ platform, env }) => {
|
|
|
30232
30288
|
}
|
|
30233
30289
|
return [];
|
|
30234
30290
|
};
|
|
30235
|
-
var runHelper = (
|
|
30291
|
+
var runHelper = (spawn3, helper, text) => new Promise((resolve) => {
|
|
30236
30292
|
let child;
|
|
30237
30293
|
try {
|
|
30238
|
-
child =
|
|
30294
|
+
child = spawn3(helper.cmd, helper.args, { stdio: ["pipe", "pipe", "pipe"] });
|
|
30239
30295
|
} catch (cause) {
|
|
30240
30296
|
resolve(
|
|
30241
30297
|
Result.error({
|
|
@@ -30279,7 +30335,7 @@ var runHelper = (spawn2, helper, text) => new Promise((resolve) => {
|
|
|
30279
30335
|
}
|
|
30280
30336
|
});
|
|
30281
30337
|
var createCopyToClipboard = (opts = {}) => {
|
|
30282
|
-
const
|
|
30338
|
+
const spawn3 = opts.spawn ?? nodeSpawn2;
|
|
30283
30339
|
const platform = opts.platform ?? process.platform;
|
|
30284
30340
|
const env = opts.env ?? process.env;
|
|
30285
30341
|
const helpers = resolveHelpers({ platform, env });
|
|
@@ -30292,7 +30348,7 @@ var createCopyToClipboard = (opts = {}) => {
|
|
|
30292
30348
|
}
|
|
30293
30349
|
let lastError;
|
|
30294
30350
|
for (const helper of helpers) {
|
|
30295
|
-
const result = await runHelper(
|
|
30351
|
+
const result = await runHelper(spawn3, helper, text);
|
|
30296
30352
|
if (result.ok) return result;
|
|
30297
30353
|
lastError = result.error;
|
|
30298
30354
|
if (result.error.code !== "no-helper") return result;
|
|
@@ -30486,7 +30542,7 @@ var ChainLogDegradedBanner = () => {
|
|
|
30486
30542
|
};
|
|
30487
30543
|
|
|
30488
30544
|
// src/application/ui/tui/components/progress-overlay.tsx
|
|
30489
|
-
import { promises as
|
|
30545
|
+
import { promises as fs31 } from "fs";
|
|
30490
30546
|
import { join as join54 } from "path";
|
|
30491
30547
|
import { useEffect as useEffect48, useMemo as useMemo27, useState as useState53 } from "react";
|
|
30492
30548
|
import { Box as Box82, Text as Text80, useInput as useInput33 } from "ink";
|
|
@@ -30517,7 +30573,7 @@ var ProgressOverlay = () => {
|
|
|
30517
30573
|
}
|
|
30518
30574
|
const load = async () => {
|
|
30519
30575
|
try {
|
|
30520
|
-
const [stat, content] = await Promise.all([
|
|
30576
|
+
const [stat, content] = await Promise.all([fs31.stat(progressPath), fs31.readFile(progressPath, "utf8")]);
|
|
30521
30577
|
if (cancelled) return;
|
|
30522
30578
|
const modifiedAtMs = stat.mtimeMs;
|
|
30523
30579
|
if (content.trim().length === 0) {
|
|
@@ -30722,7 +30778,7 @@ var resolveInitialState = ({
|
|
|
30722
30778
|
};
|
|
30723
30779
|
|
|
30724
30780
|
// src/integration/persistence/selection/last-selection-store.ts
|
|
30725
|
-
import { promises as
|
|
30781
|
+
import { promises as fs32 } from "fs";
|
|
30726
30782
|
import { join as join55 } from "path";
|
|
30727
30783
|
var FILE_NAME = "last-selection.json";
|
|
30728
30784
|
var createLastSelectionStore = (stateRoot) => {
|
|
@@ -30730,7 +30786,7 @@ var createLastSelectionStore = (stateRoot) => {
|
|
|
30730
30786
|
return {
|
|
30731
30787
|
async read() {
|
|
30732
30788
|
try {
|
|
30733
|
-
const raw = await
|
|
30789
|
+
const raw = await fs32.readFile(path, "utf8");
|
|
30734
30790
|
const parsed = JSON.parse(raw);
|
|
30735
30791
|
if (typeof parsed !== "object" || parsed === null) return void 0;
|
|
30736
30792
|
const rec = parsed;
|
|
@@ -30748,10 +30804,10 @@ var createLastSelectionStore = (stateRoot) => {
|
|
|
30748
30804
|
async write(value) {
|
|
30749
30805
|
try {
|
|
30750
30806
|
if (value === void 0) {
|
|
30751
|
-
await
|
|
30807
|
+
await fs32.rm(path, { force: true });
|
|
30752
30808
|
return;
|
|
30753
30809
|
}
|
|
30754
|
-
await
|
|
30810
|
+
await fs32.writeFile(path, JSON.stringify(value, null, 2), "utf8");
|
|
30755
30811
|
} catch {
|
|
30756
30812
|
}
|
|
30757
30813
|
}
|
|
@@ -30847,7 +30903,7 @@ var startHeapWatchdog = (deps) => {
|
|
|
30847
30903
|
import { execFile as execFileCb } from "child_process";
|
|
30848
30904
|
import { promisify } from "util";
|
|
30849
30905
|
import { platform as osPlatform } from "os";
|
|
30850
|
-
var
|
|
30906
|
+
var execFile = promisify(execFileCb);
|
|
30851
30907
|
var SHELL_TIMEOUT_MS = 5e3;
|
|
30852
30908
|
var BELL = "\x07";
|
|
30853
30909
|
var defaultEmitBell = () => {
|
|
@@ -30856,7 +30912,7 @@ var defaultEmitBell = () => {
|
|
|
30856
30912
|
} catch {
|
|
30857
30913
|
}
|
|
30858
30914
|
};
|
|
30859
|
-
var defaultExecFile = (command, args, options) =>
|
|
30915
|
+
var defaultExecFile = (command, args, options) => execFile(command, [...args], { timeout: options.timeout }).then((r) => ({
|
|
30860
30916
|
stdout: r.stdout.toString(),
|
|
30861
30917
|
stderr: r.stderr.toString()
|
|
30862
30918
|
}));
|
|
@@ -31976,11 +32032,11 @@ var formatTaskLine = (t) => {
|
|
|
31976
32032
|
};
|
|
31977
32033
|
|
|
31978
32034
|
// src/application/ui/cli/commands/runs.ts
|
|
31979
|
-
import { promises as
|
|
32035
|
+
import { promises as fs34 } from "fs";
|
|
31980
32036
|
import { createInterface } from "readline";
|
|
31981
32037
|
|
|
31982
32038
|
// src/integration/ai/runs/_engine/run-enumeration.ts
|
|
31983
|
-
import { promises as
|
|
32039
|
+
import { promises as fs33 } from "fs";
|
|
31984
32040
|
import { join as join57 } from "path";
|
|
31985
32041
|
var parseRunTimestamp = (runDirName) => {
|
|
31986
32042
|
const match = /^(\d{4})-(\d{2})-(\d{2})T(\d{2})-(\d{2})-(\d{2})-(\d{3})Z-/.exec(runDirName);
|
|
@@ -32080,7 +32136,7 @@ var listRuns = async (runsRoot) => {
|
|
|
32080
32136
|
const root = String(runsRoot);
|
|
32081
32137
|
let flowDirs;
|
|
32082
32138
|
try {
|
|
32083
|
-
flowDirs = await
|
|
32139
|
+
flowDirs = await fs33.readdir(root, { withFileTypes: true });
|
|
32084
32140
|
} catch (cause) {
|
|
32085
32141
|
if (isErrnoException2(cause) && cause.code === "ENOENT") return Result.ok([]);
|
|
32086
32142
|
return Result.error(
|
|
@@ -32097,7 +32153,7 @@ var listRuns = async (runsRoot) => {
|
|
|
32097
32153
|
const flowPath = join57(root, flowDir.name);
|
|
32098
32154
|
let runDirs;
|
|
32099
32155
|
try {
|
|
32100
|
-
runDirs = await
|
|
32156
|
+
runDirs = await fs33.readdir(flowPath, { withFileTypes: true });
|
|
32101
32157
|
} catch (cause) {
|
|
32102
32158
|
if (isErrnoException2(cause) && cause.code === "ENOENT") continue;
|
|
32103
32159
|
return Result.error(
|
|
@@ -32142,7 +32198,7 @@ var computeDirSize = async (dir) => {
|
|
|
32142
32198
|
let total = 0;
|
|
32143
32199
|
let entries;
|
|
32144
32200
|
try {
|
|
32145
|
-
entries = await
|
|
32201
|
+
entries = await fs33.readdir(dir, { withFileTypes: true });
|
|
32146
32202
|
} catch {
|
|
32147
32203
|
return 0;
|
|
32148
32204
|
}
|
|
@@ -32153,7 +32209,7 @@ var computeDirSize = async (dir) => {
|
|
|
32153
32209
|
continue;
|
|
32154
32210
|
}
|
|
32155
32211
|
try {
|
|
32156
|
-
const stat = await
|
|
32212
|
+
const stat = await fs33.lstat(entryPath);
|
|
32157
32213
|
if (stat.isFile()) total += stat.size;
|
|
32158
32214
|
} catch {
|
|
32159
32215
|
}
|
|
@@ -32448,7 +32504,7 @@ var performPrune = async (candidates) => {
|
|
|
32448
32504
|
let freedCount = 0;
|
|
32449
32505
|
for (const candidate of candidates) {
|
|
32450
32506
|
try {
|
|
32451
|
-
await
|
|
32507
|
+
await fs34.rm(String(candidate.path), { recursive: true, force: false });
|
|
32452
32508
|
freedBytes += candidate.sizeBytes;
|
|
32453
32509
|
freedCount += 1;
|
|
32454
32510
|
} catch (cause) {
|