@neriros/ralphy 2.7.3 → 2.7.4
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/README.md +11 -0
- package/dist/cli/index.js +146 -31
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -105,11 +105,21 @@ Defaults are written to `ralphy.config.json` on first run; CLI flags override co
|
|
|
105
105
|
"doneLabel": "ralphy-done",
|
|
106
106
|
"postComments": true,
|
|
107
107
|
},
|
|
108
|
+
"useWorktree": true,
|
|
109
|
+
"cleanupWorktreeOnSuccess": false,
|
|
110
|
+
"setupScript": "bun install",
|
|
111
|
+
"teardownScript": "git status",
|
|
108
112
|
}
|
|
109
113
|
```
|
|
110
114
|
|
|
111
115
|
`doneStatus` and `doneLabel` are independent — set either, both, or neither. Use `doneLabel` if your team marks completion via a label rather than a workflow state.
|
|
112
116
|
|
|
117
|
+
#### Per-task git worktrees
|
|
118
|
+
|
|
119
|
+
With `--worktree` (or `useWorktree: true` in config) each task runs in an isolated worktree at `.ralph/worktrees/<change-name>` checked out onto a fresh `ralph/<change-name>` branch. The change is scaffolded _inside_ the worktree, and the loop's cwd is the worktree, so concurrent workers can't stomp on each other.
|
|
120
|
+
|
|
121
|
+
Use `setupScript` (run inside the worktree right after scaffolding) to install dependencies, copy `.env`, etc. Use `teardownScript` (run after the loop exits, before any worktree cleanup) to gather artifacts or roll back local mutations. Both run via `sh -c`; failures are logged but never block the loop. With `cleanupWorktreeOnSuccess: true` the worktree is removed when the worker exits 0 — failed workers always keep their worktree (and branch) for human inspection.
|
|
122
|
+
|
|
113
123
|
Failed workers (non-zero exit) are not marked processed, so they'll be retried on the next poll. SIGINT/SIGTERM cleanly stops polling and kills active workers. All Linear side effects are best-effort — failures log a warning but never block the task loop.
|
|
114
124
|
|
|
115
125
|
## CLI Options
|
|
@@ -141,6 +151,7 @@ Failed workers (non-zero exit) are not marked processed, so they'll be retried o
|
|
|
141
151
|
| `--linear-label <name>` | Filter by label name (repeatable, any-of) |
|
|
142
152
|
| `--poll-interval <s>` | Seconds between Linear polls (default: 60) |
|
|
143
153
|
| `--concurrency <n>` | Max concurrent task loops (default: 1) |
|
|
154
|
+
| `--worktree` | Run each task in its own git worktree |
|
|
144
155
|
|
|
145
156
|
## OpenSpec Flow
|
|
146
157
|
|
package/dist/cli/index.js
CHANGED
|
@@ -49811,10 +49811,10 @@ var require_axios = __commonJS((exports, module) => {
|
|
|
49811
49811
|
} = utils$1;
|
|
49812
49812
|
var globalFetchAPI = (({
|
|
49813
49813
|
Request,
|
|
49814
|
-
Response
|
|
49814
|
+
Response: Response2
|
|
49815
49815
|
}) => ({
|
|
49816
49816
|
Request,
|
|
49817
|
-
Response
|
|
49817
|
+
Response: Response2
|
|
49818
49818
|
}))(utils$1.global);
|
|
49819
49819
|
var {
|
|
49820
49820
|
ReadableStream: ReadableStream$1,
|
|
@@ -49834,11 +49834,11 @@ var require_axios = __commonJS((exports, module) => {
|
|
|
49834
49834
|
const {
|
|
49835
49835
|
fetch: envFetch,
|
|
49836
49836
|
Request,
|
|
49837
|
-
Response
|
|
49837
|
+
Response: Response2
|
|
49838
49838
|
} = env3;
|
|
49839
49839
|
const isFetchSupported = envFetch ? isFunction2(envFetch) : typeof fetch === "function";
|
|
49840
49840
|
const isRequestSupported = isFunction2(Request);
|
|
49841
|
-
const isResponseSupported = isFunction2(
|
|
49841
|
+
const isResponseSupported = isFunction2(Response2);
|
|
49842
49842
|
if (!isFetchSupported) {
|
|
49843
49843
|
return false;
|
|
49844
49844
|
}
|
|
@@ -49860,7 +49860,7 @@ var require_axios = __commonJS((exports, module) => {
|
|
|
49860
49860
|
}
|
|
49861
49861
|
return duplexAccessed && !hasContentType;
|
|
49862
49862
|
});
|
|
49863
|
-
const supportsResponseStream = isResponseSupported && isReadableStreamSupported && test(() => utils$1.isReadableStream(new
|
|
49863
|
+
const supportsResponseStream = isResponseSupported && isReadableStreamSupported && test(() => utils$1.isReadableStream(new Response2("").body));
|
|
49864
49864
|
const resolvers = {
|
|
49865
49865
|
stream: supportsResponseStream && ((res) => res.body)
|
|
49866
49866
|
};
|
|
@@ -49971,7 +49971,7 @@ var require_axios = __commonJS((exports, module) => {
|
|
|
49971
49971
|
});
|
|
49972
49972
|
const responseContentLength = utils$1.toFiniteNumber(response.headers.get("content-length"));
|
|
49973
49973
|
const [onProgress, flush] = onDownloadProgress && progressEventDecorator(responseContentLength, progressEventReducer(asyncDecorator(onDownloadProgress), true)) || [];
|
|
49974
|
-
response = new
|
|
49974
|
+
response = new Response2(trackStream(response.body, DEFAULT_CHUNK_SIZE, onProgress, () => {
|
|
49975
49975
|
flush && flush();
|
|
49976
49976
|
unsubscribe && unsubscribe();
|
|
49977
49977
|
}), options);
|
|
@@ -50006,9 +50006,9 @@ var require_axios = __commonJS((exports, module) => {
|
|
|
50006
50006
|
const {
|
|
50007
50007
|
fetch: fetch2,
|
|
50008
50008
|
Request,
|
|
50009
|
-
Response
|
|
50009
|
+
Response: Response2
|
|
50010
50010
|
} = env3;
|
|
50011
|
-
const seeds = [Request,
|
|
50011
|
+
const seeds = [Request, Response2, fetch2];
|
|
50012
50012
|
let len = seeds.length, i = len, seed, target, map2 = seedCache;
|
|
50013
50013
|
while (i--) {
|
|
50014
50014
|
seed = seeds[i];
|
|
@@ -50548,7 +50548,7 @@ var require_axios = __commonJS((exports, module) => {
|
|
|
50548
50548
|
});
|
|
50549
50549
|
|
|
50550
50550
|
// apps/cli/src/index.ts
|
|
50551
|
-
import { resolve, join as
|
|
50551
|
+
import { resolve, join as join17, dirname as dirname4 } from "path";
|
|
50552
50552
|
import { exists, mkdir as mkdir3 } from "fs/promises";
|
|
50553
50553
|
|
|
50554
50554
|
// node_modules/.bun/ink@5.2.1+1f88f629f0141b18/node_modules/ink/build/render.js
|
|
@@ -56152,6 +56152,7 @@ var HELP_TEXT = [
|
|
|
56152
56152
|
" --linear-label <name> Filter by label name (repeatable, any-of)",
|
|
56153
56153
|
" --poll-interval <s> Seconds between Linear polls (default: 60)",
|
|
56154
56154
|
" --concurrency <n> Max concurrent task loops (default: 1)",
|
|
56155
|
+
" --worktree Run each task in its own git worktree (.ralph/worktrees/<name>)",
|
|
56155
56156
|
"",
|
|
56156
56157
|
" --help, -h Show this help message",
|
|
56157
56158
|
"",
|
|
@@ -56187,7 +56188,8 @@ async function parseArgs(argv) {
|
|
|
56187
56188
|
linearStatus: [],
|
|
56188
56189
|
linearLabel: [],
|
|
56189
56190
|
pollInterval: 60,
|
|
56190
|
-
concurrency: 1
|
|
56191
|
+
concurrency: 1,
|
|
56192
|
+
worktree: false
|
|
56191
56193
|
};
|
|
56192
56194
|
let expectModel = false;
|
|
56193
56195
|
let expectModelFlag = false;
|
|
@@ -56378,6 +56380,9 @@ async function parseArgs(argv) {
|
|
|
56378
56380
|
case "--concurrency":
|
|
56379
56381
|
expectConcurrency = true;
|
|
56380
56382
|
break;
|
|
56383
|
+
case "--worktree":
|
|
56384
|
+
result2.worktree = true;
|
|
56385
|
+
break;
|
|
56381
56386
|
default:
|
|
56382
56387
|
if (VALID_MODES.has(arg)) {
|
|
56383
56388
|
result2.mode = arg;
|
|
@@ -56445,7 +56450,7 @@ function createDefaultContext() {
|
|
|
56445
56450
|
|
|
56446
56451
|
// apps/cli/src/components/App.tsx
|
|
56447
56452
|
var import_react58 = __toESM(require_react(), 1);
|
|
56448
|
-
import { join as
|
|
56453
|
+
import { join as join16 } from "path";
|
|
56449
56454
|
|
|
56450
56455
|
// packages/core/src/state.ts
|
|
56451
56456
|
import { join as join2 } from "path";
|
|
@@ -69801,6 +69806,10 @@ var RalphyConfigSchema = exports_external.object({
|
|
|
69801
69806
|
pollIntervalSeconds: exports_external.number().int().positive().default(60),
|
|
69802
69807
|
maxIterationsPerTask: exports_external.number().int().nonnegative().default(0),
|
|
69803
69808
|
maxCostUsdPerTask: exports_external.number().nonnegative().default(0),
|
|
69809
|
+
useWorktree: exports_external.boolean().default(false),
|
|
69810
|
+
cleanupWorktreeOnSuccess: exports_external.boolean().default(false),
|
|
69811
|
+
setupScript: exports_external.string().optional(),
|
|
69812
|
+
teardownScript: exports_external.string().optional(),
|
|
69804
69813
|
engine: exports_external.enum(["claude", "codex"]).default("claude"),
|
|
69805
69814
|
model: exports_external.enum(["haiku", "sonnet", "opus"]).default("opus"),
|
|
69806
69815
|
linear: exports_external.object({
|
|
@@ -70026,8 +70035,55 @@ class AgentCoordinator {
|
|
|
70026
70035
|
}
|
|
70027
70036
|
}
|
|
70028
70037
|
|
|
70038
|
+
// apps/cli/src/agent/worktree.ts
|
|
70039
|
+
import { join as join13 } from "path";
|
|
70040
|
+
function worktreesDir(projectRoot) {
|
|
70041
|
+
return join13(projectRoot, ".ralph", "worktrees");
|
|
70042
|
+
}
|
|
70043
|
+
function branchForChange(changeName) {
|
|
70044
|
+
return `ralph/${changeName}`;
|
|
70045
|
+
}
|
|
70046
|
+
async function createWorktree(projectRoot, changeName, runner) {
|
|
70047
|
+
const dir = worktreesDir(projectRoot);
|
|
70048
|
+
const cwd2 = join13(dir, changeName);
|
|
70049
|
+
const branch = branchForChange(changeName);
|
|
70050
|
+
const list = await runner.run(["worktree", "list", "--porcelain"], projectRoot);
|
|
70051
|
+
if (list.stdout.includes(`worktree ${cwd2}
|
|
70052
|
+
`)) {
|
|
70053
|
+
return { cwd: cwd2, branch };
|
|
70054
|
+
}
|
|
70055
|
+
let branchExists = true;
|
|
70056
|
+
try {
|
|
70057
|
+
await runner.run(["rev-parse", "--verify", "--quiet", `refs/heads/${branch}`], projectRoot);
|
|
70058
|
+
} catch {
|
|
70059
|
+
branchExists = false;
|
|
70060
|
+
}
|
|
70061
|
+
const cmd = branchExists ? ["worktree", "add", cwd2, branch] : ["worktree", "add", "-b", branch, cwd2];
|
|
70062
|
+
await runner.run(cmd, projectRoot);
|
|
70063
|
+
return { cwd: cwd2, branch };
|
|
70064
|
+
}
|
|
70065
|
+
async function removeWorktree(projectRoot, cwd2, runner) {
|
|
70066
|
+
await runner.run(["worktree", "remove", "--force", cwd2], projectRoot);
|
|
70067
|
+
}
|
|
70068
|
+
|
|
70029
70069
|
// apps/cli/src/components/AgentMode.tsx
|
|
70030
70070
|
var jsx_dev_runtime9 = __toESM(require_jsx_dev_runtime(), 1);
|
|
70071
|
+
import { join as join14 } from "path";
|
|
70072
|
+
var bunGitRunner = {
|
|
70073
|
+
run: async (args, cwd2) => {
|
|
70074
|
+
const proc = Bun.spawn({ cmd: ["git", ...args], cwd: cwd2, stdout: "pipe", stderr: "pipe" });
|
|
70075
|
+
const stdout = await new Response(proc.stdout).text();
|
|
70076
|
+
const stderr = await new Response(proc.stderr).text();
|
|
70077
|
+
const code = await proc.exited;
|
|
70078
|
+
if (code !== 0) {
|
|
70079
|
+
const err = new Error("git command failed");
|
|
70080
|
+
err.stderr = stderr;
|
|
70081
|
+
err.code = code;
|
|
70082
|
+
throw err;
|
|
70083
|
+
}
|
|
70084
|
+
return { stdout, stderr };
|
|
70085
|
+
}
|
|
70086
|
+
};
|
|
70031
70087
|
var lineCounter = 0;
|
|
70032
70088
|
function nextId() {
|
|
70033
70089
|
lineCounter += 1;
|
|
@@ -70066,6 +70122,24 @@ function AgentMode({ args, projectRoot, statesDir, tasksDir }) {
|
|
|
70066
70122
|
const stateCache = new Map;
|
|
70067
70123
|
const labelCache = new Map;
|
|
70068
70124
|
const teamKeyOf = (issue) => issue.identifier.split("-")[0];
|
|
70125
|
+
const useWorktree = args.worktree || cfg.useWorktree;
|
|
70126
|
+
const cwdByChange = new Map;
|
|
70127
|
+
async function runScript(label, cmd, cwd2) {
|
|
70128
|
+
appendLog(` ${label}: ${cmd}`, "gray");
|
|
70129
|
+
const proc = Bun.spawn({
|
|
70130
|
+
cmd: ["sh", "-c", cmd],
|
|
70131
|
+
cwd: cwd2,
|
|
70132
|
+
stdout: "ignore",
|
|
70133
|
+
stderr: "pipe",
|
|
70134
|
+
stdin: "ignore"
|
|
70135
|
+
});
|
|
70136
|
+
const code = await proc.exited;
|
|
70137
|
+
if (code !== 0) {
|
|
70138
|
+
const stderr = await new Response(proc.stderr).text();
|
|
70139
|
+
appendLog(`! ${label} exited code ${code}${stderr ? `: ${stderr.trim().split(`
|
|
70140
|
+
`)[0]}` : ""}`, "yellow");
|
|
70141
|
+
}
|
|
70142
|
+
}
|
|
70069
70143
|
const coord2 = new AgentCoordinator({
|
|
70070
70144
|
fetchIssues: (f2) => fetchOpenIssues(apiKey, f2),
|
|
70071
70145
|
scaffold: async (issue) => {
|
|
@@ -70075,7 +70149,27 @@ function AgentMode({ args, projectRoot, statesDir, tasksDir }) {
|
|
|
70075
70149
|
} catch (err) {
|
|
70076
70150
|
appendLog(`! Linear comment fetch failed for ${issue.identifier}: ${err.message}`, "yellow");
|
|
70077
70151
|
}
|
|
70078
|
-
|
|
70152
|
+
let workerCwd = projectRoot;
|
|
70153
|
+
let scaffoldTasksDir = tasksDir;
|
|
70154
|
+
let scaffoldStatesDir = statesDir;
|
|
70155
|
+
const probeName = issue.identifier.toLowerCase();
|
|
70156
|
+
if (useWorktree) {
|
|
70157
|
+
try {
|
|
70158
|
+
const wt = await createWorktree(projectRoot, probeName, bunGitRunner);
|
|
70159
|
+
workerCwd = wt.cwd;
|
|
70160
|
+
scaffoldTasksDir = join14(wt.cwd, "openspec", "changes");
|
|
70161
|
+
scaffoldStatesDir = join14(wt.cwd, ".ralph", "tasks");
|
|
70162
|
+
appendLog(` ${issue.identifier} worktree: ${wt.cwd} (${wt.branch})`, "gray");
|
|
70163
|
+
} catch (err) {
|
|
70164
|
+
appendLog(`! worktree create failed for ${issue.identifier}: ${err.message} \u2014 falling back to project root`, "yellow");
|
|
70165
|
+
}
|
|
70166
|
+
}
|
|
70167
|
+
const changeName = await scaffoldChangeForIssue(scaffoldTasksDir, scaffoldStatesDir, issue, comments);
|
|
70168
|
+
cwdByChange.set(changeName, workerCwd);
|
|
70169
|
+
if (cfg.setupScript) {
|
|
70170
|
+
await runScript("setup", cfg.setupScript, workerCwd);
|
|
70171
|
+
}
|
|
70172
|
+
return changeName;
|
|
70079
70173
|
},
|
|
70080
70174
|
spawnWorker: (changeName) => {
|
|
70081
70175
|
const cmd = [
|
|
@@ -70093,14 +70187,35 @@ function AgentMode({ args, projectRoot, statesDir, tasksDir }) {
|
|
|
70093
70187
|
const maxCost = args.maxCostUsd || cfg.maxCostUsdPerTask;
|
|
70094
70188
|
if (maxCost > 0)
|
|
70095
70189
|
cmd.push("--max-cost", String(maxCost));
|
|
70190
|
+
const cwd2 = cwdByChange.get(changeName) ?? projectRoot;
|
|
70096
70191
|
const proc = Bun.spawn({
|
|
70097
70192
|
cmd,
|
|
70098
|
-
cwd:
|
|
70193
|
+
cwd: cwd2,
|
|
70099
70194
|
stdout: "ignore",
|
|
70100
70195
|
stderr: "ignore",
|
|
70101
70196
|
stdin: "ignore"
|
|
70102
70197
|
});
|
|
70103
|
-
|
|
70198
|
+
const wrapped = proc.exited.then(async (code) => {
|
|
70199
|
+
if (cfg.teardownScript) {
|
|
70200
|
+
try {
|
|
70201
|
+
await runScript("teardown", cfg.teardownScript, cwd2);
|
|
70202
|
+
} catch {}
|
|
70203
|
+
}
|
|
70204
|
+
if (useWorktree && cwd2 !== projectRoot) {
|
|
70205
|
+
const ok = code === 0;
|
|
70206
|
+
if (ok && cfg.cleanupWorktreeOnSuccess) {
|
|
70207
|
+
try {
|
|
70208
|
+
await removeWorktree(projectRoot, cwd2, bunGitRunner);
|
|
70209
|
+
appendLog(` removed worktree ${cwd2}`, "gray");
|
|
70210
|
+
} catch (err) {
|
|
70211
|
+
appendLog(`! worktree remove failed for ${changeName}: ${err.message}`, "yellow");
|
|
70212
|
+
}
|
|
70213
|
+
}
|
|
70214
|
+
}
|
|
70215
|
+
cwdByChange.delete(changeName);
|
|
70216
|
+
return code;
|
|
70217
|
+
});
|
|
70218
|
+
return { exited: wrapped, kill: () => proc.kill() };
|
|
70104
70219
|
},
|
|
70105
70220
|
loadState: () => readAgentState(projectRoot),
|
|
70106
70221
|
saveState: (s) => writeAgentState(projectRoot, s),
|
|
@@ -70218,11 +70333,11 @@ function AgentMode({ args, projectRoot, statesDir, tasksDir }) {
|
|
|
70218
70333
|
}
|
|
70219
70334
|
|
|
70220
70335
|
// packages/openspec/src/openspec-change-store.ts
|
|
70221
|
-
import { join as
|
|
70336
|
+
import { join as join15, dirname as dirname3 } from "path";
|
|
70222
70337
|
import { readdir, mkdir as mkdir2 } from "fs/promises";
|
|
70223
70338
|
function resolveOpenspecBin() {
|
|
70224
70339
|
const pkgJsonPath = Bun.resolveSync("@fission-ai/openspec/package.json", import.meta.dir);
|
|
70225
|
-
return
|
|
70340
|
+
return join15(dirname3(pkgJsonPath), "bin", "openspec.js");
|
|
70226
70341
|
}
|
|
70227
70342
|
function runOpenspec(args, options = {}) {
|
|
70228
70343
|
const stdio = options.inherit ? ["inherit", "inherit", "inherit"] : ["ignore", "pipe", "pipe"];
|
|
@@ -70248,7 +70363,7 @@ class OpenSpecChangeStore {
|
|
|
70248
70363
|
}
|
|
70249
70364
|
}
|
|
70250
70365
|
getChangeDirectory(name) {
|
|
70251
|
-
return
|
|
70366
|
+
return join15("openspec", "changes", name);
|
|
70252
70367
|
}
|
|
70253
70368
|
async listChanges() {
|
|
70254
70369
|
const result2 = runOpenspec(["list", "--json"]);
|
|
@@ -70262,7 +70377,7 @@ class OpenSpecChangeStore {
|
|
|
70262
70377
|
}
|
|
70263
70378
|
} catch {}
|
|
70264
70379
|
}
|
|
70265
|
-
const changesDir =
|
|
70380
|
+
const changesDir = join15("openspec", "changes");
|
|
70266
70381
|
if (!await Bun.file(changesDir).exists())
|
|
70267
70382
|
return [];
|
|
70268
70383
|
try {
|
|
@@ -70273,18 +70388,18 @@ class OpenSpecChangeStore {
|
|
|
70273
70388
|
}
|
|
70274
70389
|
}
|
|
70275
70390
|
async readTaskList(name) {
|
|
70276
|
-
const file = Bun.file(
|
|
70391
|
+
const file = Bun.file(join15("openspec", "changes", name, "tasks.md"));
|
|
70277
70392
|
if (!await file.exists())
|
|
70278
70393
|
return "";
|
|
70279
70394
|
return await file.text();
|
|
70280
70395
|
}
|
|
70281
70396
|
async writeTaskList(name, content) {
|
|
70282
|
-
const path =
|
|
70397
|
+
const path = join15("openspec", "changes", name, "tasks.md");
|
|
70283
70398
|
await mkdir2(dirname3(path), { recursive: true });
|
|
70284
70399
|
await Bun.write(path, content);
|
|
70285
70400
|
}
|
|
70286
70401
|
async appendSteering(name, message) {
|
|
70287
|
-
const path =
|
|
70402
|
+
const path = join15("openspec", "changes", name, "steering.md");
|
|
70288
70403
|
const file = Bun.file(path);
|
|
70289
70404
|
const existing = await file.exists() ? await file.text() : null;
|
|
70290
70405
|
const updated = existing ? `${message}
|
|
@@ -70295,7 +70410,7 @@ ${existing.trimStart()}` : `${message}
|
|
|
70295
70410
|
await Bun.write(path, updated);
|
|
70296
70411
|
}
|
|
70297
70412
|
async readSection(name, artifact, heading) {
|
|
70298
|
-
const file = Bun.file(
|
|
70413
|
+
const file = Bun.file(join15("openspec", "changes", name, artifact));
|
|
70299
70414
|
if (!await file.exists())
|
|
70300
70415
|
return "";
|
|
70301
70416
|
const content = await file.text();
|
|
@@ -70376,8 +70491,8 @@ function App2({ args, statesDir, tasksDir, projectRoot }) {
|
|
|
70376
70491
|
message: "Error: --name is required for status mode"
|
|
70377
70492
|
}, undefined, false, undefined, this);
|
|
70378
70493
|
}
|
|
70379
|
-
const stateDir =
|
|
70380
|
-
if (getStorage().read(
|
|
70494
|
+
const stateDir = join16(statesDir, args.name);
|
|
70495
|
+
if (getStorage().read(join16(stateDir, ".ralph-state.json")) === null) {
|
|
70381
70496
|
return /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(ErrorMessage, {
|
|
70382
70497
|
message: `Error: change '${args.name}' not found`
|
|
70383
70498
|
}, undefined, false, undefined, this);
|
|
@@ -70434,7 +70549,7 @@ if (typeof globalThis.Bun === "undefined") {
|
|
|
70434
70549
|
async function findProjectRoot() {
|
|
70435
70550
|
let dir = process.cwd();
|
|
70436
70551
|
while (dir !== "/") {
|
|
70437
|
-
if (await exists(
|
|
70552
|
+
if (await exists(join17(dir, "openspec")))
|
|
70438
70553
|
return dir;
|
|
70439
70554
|
dir = resolve(dir, "..");
|
|
70440
70555
|
}
|
|
@@ -70469,11 +70584,11 @@ try {
|
|
|
70469
70584
|
capture("command_run", { mode: args.mode, engine: args.engine, model: args.model });
|
|
70470
70585
|
try {
|
|
70471
70586
|
const projectRoot = await findProjectRoot();
|
|
70472
|
-
const statesDir =
|
|
70473
|
-
const tasksDir =
|
|
70587
|
+
const statesDir = join17(projectRoot, ".ralph", "tasks");
|
|
70588
|
+
const tasksDir = join17(projectRoot, "openspec", "changes");
|
|
70474
70589
|
if (args.mode === "init") {
|
|
70475
70590
|
await mkdir3(statesDir, { recursive: true });
|
|
70476
|
-
const openspecBin =
|
|
70591
|
+
const openspecBin = join17(dirname4(Bun.resolveSync("@fission-ai/openspec/package.json", import.meta.dir)), "bin", "openspec.js");
|
|
70477
70592
|
Bun.spawnSync({
|
|
70478
70593
|
cmd: [process.execPath, openspecBin, "init", "--tools", "none", "--force"],
|
|
70479
70594
|
stdio: ["inherit", "inherit", "inherit"],
|
|
@@ -70481,13 +70596,13 @@ try {
|
|
|
70481
70596
|
});
|
|
70482
70597
|
}
|
|
70483
70598
|
if (args.mode === "task" && args.name) {
|
|
70484
|
-
await mkdir3(
|
|
70485
|
-
await mkdir3(
|
|
70599
|
+
await mkdir3(join17(statesDir, args.name), { recursive: true });
|
|
70600
|
+
await mkdir3(join17(tasksDir, args.name), { recursive: true });
|
|
70486
70601
|
}
|
|
70487
70602
|
if (args.mode === "agent") {
|
|
70488
70603
|
await mkdir3(statesDir, { recursive: true });
|
|
70489
70604
|
await mkdir3(tasksDir, { recursive: true });
|
|
70490
|
-
await mkdir3(
|
|
70605
|
+
await mkdir3(join17(projectRoot, ".ralph"), { recursive: true });
|
|
70491
70606
|
}
|
|
70492
70607
|
await runWithContext(createDefaultContext(), async () => {
|
|
70493
70608
|
const { waitUntilExit } = render_default(import_react59.createElement(App2, { args, statesDir, tasksDir, projectRoot }));
|