@neriros/ralphy 2.17.2 → 2.18.0
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 +6 -2
- package/dist/cli/index.js +280 -171
- package/dist/mcp/index.js +131 -44
- package/package.json +18 -16
package/README.md
CHANGED
|
@@ -173,6 +173,7 @@ A default `ralphy.config.json` is written on first run with every defaulted sett
|
|
|
173
173
|
"getTodo": { "filter": [{ "type": "status", "value": "Todo" }] },
|
|
174
174
|
"getInProgress": { "filter": [{ "type": "status", "value": "In Progress" }] },
|
|
175
175
|
"getConflicted": { "filter": [{ "type": "label", "value": "ralph:conflicted" }] },
|
|
176
|
+
"getReview": { "filter": [{ "type": "label", "value": "ralph:review" }] },
|
|
176
177
|
"setInProgress": { "type": "status", "value": "In Progress" },
|
|
177
178
|
"setDone": {
|
|
178
179
|
"apply": [
|
|
@@ -183,6 +184,7 @@ A default `ralphy.config.json` is written on first run with every defaulted sett
|
|
|
183
184
|
"setError": { "type": "label", "value": "ralph:error" },
|
|
184
185
|
"setConflicted": { "type": "label", "value": "ralph:conflicted" },
|
|
185
186
|
"clearConflicted": { "type": "label", "value": "ralph:conflicted" },
|
|
187
|
+
"clearReview": { "type": "label", "value": "ralph:review" },
|
|
186
188
|
},
|
|
187
189
|
},
|
|
188
190
|
"useWorktree": true,
|
|
@@ -205,9 +207,11 @@ A default `ralphy.config.json` is written on first run with every defaulted sett
|
|
|
205
207
|
|
|
206
208
|
Linear is the source of truth for which issues Ralph has touched. Each `linear.indicators` key names a lifecycle event:
|
|
207
209
|
|
|
208
|
-
- `getTodo` / `getInProgress` / `getConflicted` — `{ filter: [...] }` selectors used to find issues to pick up, resume, or
|
|
210
|
+
- `getTodo` / `getInProgress` / `getConflicted` / `getReview` — `{ filter: [...] }` selectors used to find issues to pick up, resume, repair, or follow up on after review.
|
|
209
211
|
- `setInProgress` / `setDone` / `setError` / `setConflicted` — single marker `{ type, value }` or `{ apply: [...] }` for multi-marker.
|
|
210
|
-
- `clearConflicted` — labels to remove once a conflicted PR is fixed (status removal is not supported).
|
|
212
|
+
- `clearConflicted` / `clearReview` — labels to remove once a conflicted PR is fixed or a review-mode issue is picked back up (status removal is not supported).
|
|
213
|
+
|
|
214
|
+
**Review follow-ups.** When a Linear issue is in a "done" state and a reviewer adds the `getReview` marker (typically a label like `ralph:review` after leaving comments), Ralph picks it up, applies `setInProgress`, removes the `clearReview` label so the same trigger doesn't re-fire, fetches the comment thread, filters out Ralph's own comments, and prepends those reviewer comments as a new task at the top of `tasks.md`. The worker addresses them in the same change branch and `setDone` is re-applied on success.
|
|
211
215
|
|
|
212
216
|
Marker types are `"label"` or `"status"`. Combine markers under `apply` when one event needs to set multiple — e.g. `setDone` flipping a status _and_ adding a "shipped" label.
|
|
213
217
|
|
package/dist/cli/index.js
CHANGED
|
@@ -35029,8 +35029,8 @@ import { readFileSync as readFileSync2 } from "fs";
|
|
|
35029
35029
|
import { resolve } from "path";
|
|
35030
35030
|
function getVersion() {
|
|
35031
35031
|
try {
|
|
35032
|
-
if ("2.
|
|
35033
|
-
return "2.
|
|
35032
|
+
if ("2.18.0")
|
|
35033
|
+
return "2.18.0";
|
|
35034
35034
|
} catch {}
|
|
35035
35035
|
const dirsToTry = [];
|
|
35036
35036
|
try {
|
|
@@ -35356,13 +35356,20 @@ var init_cli = __esm(() => {
|
|
|
35356
35356
|
"getTodo",
|
|
35357
35357
|
"getInProgress",
|
|
35358
35358
|
"getConflicted",
|
|
35359
|
+
"getReview",
|
|
35359
35360
|
"setInProgress",
|
|
35360
35361
|
"setDone",
|
|
35361
35362
|
"setError",
|
|
35362
35363
|
"setConflicted",
|
|
35363
|
-
"clearConflicted"
|
|
35364
|
+
"clearConflicted",
|
|
35365
|
+
"clearReview"
|
|
35366
|
+
]);
|
|
35367
|
+
GET_KEYS = new Set([
|
|
35368
|
+
"getTodo",
|
|
35369
|
+
"getInProgress",
|
|
35370
|
+
"getConflicted",
|
|
35371
|
+
"getReview"
|
|
35364
35372
|
]);
|
|
35365
|
-
GET_KEYS = new Set(["getTodo", "getInProgress", "getConflicted"]);
|
|
35366
35373
|
HELP_TEXT = [
|
|
35367
35374
|
`ralph v${VERSION}`,
|
|
35368
35375
|
"",
|
|
@@ -35404,8 +35411,9 @@ var init_cli = __esm(() => {
|
|
|
35404
35411
|
" --indicator getTodo:status:Todo",
|
|
35405
35412
|
" --indicator setDone:label:shipped",
|
|
35406
35413
|
" --indicator setDone:status:Done (combined with above \u2192 multi-marker)",
|
|
35407
|
-
" Keys: getTodo, getInProgress, getConflicted,",
|
|
35408
|
-
" setInProgress, setDone, setError, setConflicted,
|
|
35414
|
+
" Keys: getTodo, getInProgress, getConflicted, getReview,",
|
|
35415
|
+
" setInProgress, setDone, setError, setConflicted,",
|
|
35416
|
+
" clearConflicted, clearReview",
|
|
35409
35417
|
" Types: label, status",
|
|
35410
35418
|
" --create-pr Push the worker branch and open a GitHub PR on success (needs --worktree)",
|
|
35411
35419
|
" --fix-ci After opening the PR, re-run on CI failures until green (needs --create-pr)",
|
|
@@ -39468,6 +39476,99 @@ var init_types2 = __esm(() => {
|
|
|
39468
39476
|
});
|
|
39469
39477
|
});
|
|
39470
39478
|
|
|
39479
|
+
// apps/cli/src/agent/worktree.ts
|
|
39480
|
+
import { basename, join as join3 } from "path";
|
|
39481
|
+
import { homedir } from "os";
|
|
39482
|
+
import { exists } from "fs/promises";
|
|
39483
|
+
function worktreesDir(projectRoot) {
|
|
39484
|
+
return join3(homedir(), ".ralph", basename(projectRoot), "worktrees");
|
|
39485
|
+
}
|
|
39486
|
+
function branchForChange(changeName) {
|
|
39487
|
+
return `ralph/${changeName}`;
|
|
39488
|
+
}
|
|
39489
|
+
async function createWorktree(projectRoot, changeName, runner) {
|
|
39490
|
+
const dir = worktreesDir(projectRoot);
|
|
39491
|
+
const cwd2 = join3(dir, changeName);
|
|
39492
|
+
const branch = branchForChange(changeName);
|
|
39493
|
+
const list = await runner.run(["worktree", "list", "--porcelain"], projectRoot);
|
|
39494
|
+
if (list.stdout.includes(`worktree ${cwd2}
|
|
39495
|
+
`)) {
|
|
39496
|
+
return { cwd: cwd2, branch };
|
|
39497
|
+
}
|
|
39498
|
+
let branchExists = true;
|
|
39499
|
+
try {
|
|
39500
|
+
await runner.run(["rev-parse", "--verify", "--quiet", `refs/heads/${branch}`], projectRoot);
|
|
39501
|
+
} catch {
|
|
39502
|
+
branchExists = false;
|
|
39503
|
+
}
|
|
39504
|
+
const cmd = branchExists ? ["worktree", "add", cwd2, branch] : ["worktree", "add", "-b", branch, cwd2];
|
|
39505
|
+
await runner.run(cmd, projectRoot);
|
|
39506
|
+
return { cwd: cwd2, branch };
|
|
39507
|
+
}
|
|
39508
|
+
async function removeWorktree(projectRoot, cwd2, runner) {
|
|
39509
|
+
await runner.run(["worktree", "remove", "--force", cwd2], projectRoot);
|
|
39510
|
+
}
|
|
39511
|
+
async function isWorktreeSafeToRemove(cwd2, base2, runner) {
|
|
39512
|
+
const status = await runner.run(["status", "--porcelain"], cwd2);
|
|
39513
|
+
const dirty = status.stdout.trim();
|
|
39514
|
+
let unpushedCommits = "";
|
|
39515
|
+
try {
|
|
39516
|
+
const log2 = await runner.run(["log", "--oneline", `${base2}..HEAD`, "--no-merges"], cwd2);
|
|
39517
|
+
unpushedCommits = log2.stdout.trim();
|
|
39518
|
+
} catch {
|
|
39519
|
+
unpushedCommits = "<unknown: failed to compare against base>";
|
|
39520
|
+
}
|
|
39521
|
+
if (dirty && unpushedCommits) {
|
|
39522
|
+
return {
|
|
39523
|
+
safe: false,
|
|
39524
|
+
reason: "uncommitted changes AND unpushed commits present",
|
|
39525
|
+
dirty,
|
|
39526
|
+
unpushedCommits
|
|
39527
|
+
};
|
|
39528
|
+
}
|
|
39529
|
+
if (dirty) {
|
|
39530
|
+
return {
|
|
39531
|
+
safe: false,
|
|
39532
|
+
reason: "uncommitted or untracked files present",
|
|
39533
|
+
dirty,
|
|
39534
|
+
unpushedCommits
|
|
39535
|
+
};
|
|
39536
|
+
}
|
|
39537
|
+
if (unpushedCommits) {
|
|
39538
|
+
return {
|
|
39539
|
+
safe: false,
|
|
39540
|
+
reason: `commits ahead of ${base2} were not pushed/PR'd`,
|
|
39541
|
+
dirty,
|
|
39542
|
+
unpushedCommits
|
|
39543
|
+
};
|
|
39544
|
+
}
|
|
39545
|
+
return { safe: true, dirty, unpushedCommits };
|
|
39546
|
+
}
|
|
39547
|
+
async function seedWorktreeMcpConfig(projectRoot, worktreeCwd) {
|
|
39548
|
+
const dst = join3(worktreeCwd, ".mcp.json");
|
|
39549
|
+
const src = join3(projectRoot, ".mcp.json");
|
|
39550
|
+
const source = await exists(dst) ? dst : await exists(src) ? src : null;
|
|
39551
|
+
if (!source)
|
|
39552
|
+
return;
|
|
39553
|
+
let parsed;
|
|
39554
|
+
try {
|
|
39555
|
+
parsed = await Bun.file(source).json();
|
|
39556
|
+
} catch {
|
|
39557
|
+
return;
|
|
39558
|
+
}
|
|
39559
|
+
const servers = parsed.mcpServers;
|
|
39560
|
+
if (servers && typeof servers === "object") {
|
|
39561
|
+
for (const cfg of Object.values(servers)) {
|
|
39562
|
+
if (Array.isArray(cfg.args)) {
|
|
39563
|
+
cfg.args = cfg.args.map((a) => typeof a === "string" && a.startsWith(".ralph/") ? join3(projectRoot, a) : a);
|
|
39564
|
+
}
|
|
39565
|
+
}
|
|
39566
|
+
}
|
|
39567
|
+
await Bun.write(dst, JSON.stringify(parsed, null, 2) + `
|
|
39568
|
+
`);
|
|
39569
|
+
}
|
|
39570
|
+
var init_worktree = () => {};
|
|
39571
|
+
|
|
39471
39572
|
// node_modules/.bun/react@18.3.1/node_modules/react/cjs/react-jsx-dev-runtime.development.js
|
|
39472
39573
|
var require_react_jsx_dev_runtime_development = __commonJS((exports) => {
|
|
39473
39574
|
var React10 = __toESM(require_react());
|
|
@@ -59333,8 +59434,8 @@ var init_node = __esm(() => {
|
|
|
59333
59434
|
});
|
|
59334
59435
|
|
|
59335
59436
|
// packages/telemetry/src/index.ts
|
|
59336
|
-
import { homedir } from "os";
|
|
59337
|
-
import { join as
|
|
59437
|
+
import { homedir as homedir2 } from "os";
|
|
59438
|
+
import { join as join7 } from "path";
|
|
59338
59439
|
import { randomUUID } from "crypto";
|
|
59339
59440
|
function setDefaultProperties(props) {
|
|
59340
59441
|
defaultProps = { ...defaultProps, ...props };
|
|
@@ -59342,7 +59443,7 @@ function setDefaultProperties(props) {
|
|
|
59342
59443
|
async function init() {
|
|
59343
59444
|
if (!enabled)
|
|
59344
59445
|
return;
|
|
59345
|
-
const idPath =
|
|
59446
|
+
const idPath = join7(homedir2(), ".ralph", ".telemetry-id");
|
|
59346
59447
|
const idFile = Bun.file(idPath);
|
|
59347
59448
|
if (await idFile.exists()) {
|
|
59348
59449
|
distinctId = (await idFile.text()).trim();
|
|
@@ -59417,12 +59518,12 @@ ${fence}`;
|
|
|
59417
59518
|
}
|
|
59418
59519
|
|
|
59419
59520
|
// apps/cli/src/agent/config.ts
|
|
59420
|
-
import { join as
|
|
59521
|
+
import { join as join11 } from "path";
|
|
59421
59522
|
function stripJsonComments(text) {
|
|
59422
59523
|
return text.replace(/\/\/[^\n]*/g, "");
|
|
59423
59524
|
}
|
|
59424
59525
|
async function loadRalphyConfig(projectRoot) {
|
|
59425
|
-
const path =
|
|
59526
|
+
const path = join11(projectRoot, "ralphy.config.json");
|
|
59426
59527
|
const file = Bun.file(path);
|
|
59427
59528
|
if (!await file.exists()) {
|
|
59428
59529
|
return RalphyConfigSchema.parse({});
|
|
@@ -59432,7 +59533,7 @@ async function loadRalphyConfig(projectRoot) {
|
|
|
59432
59533
|
return RalphyConfigSchema.parse(raw);
|
|
59433
59534
|
}
|
|
59434
59535
|
async function ensureRalphyConfig(projectRoot) {
|
|
59435
|
-
const path =
|
|
59536
|
+
const path = join11(projectRoot, "ralphy.config.json");
|
|
59436
59537
|
const file = Bun.file(path);
|
|
59437
59538
|
if (await file.exists())
|
|
59438
59539
|
return path;
|
|
@@ -59533,6 +59634,10 @@ var MarkerSchema, GetIndicatorSchema, SetIndicatorSchema, IndicatorsSchema, Ralp
|
|
|
59533
59634
|
// Issues whose PR has a merge conflict (Ralph will attempt a re-fix run).
|
|
59534
59635
|
// "getConflicted": { "filter": [{ "type": "label", "value": "ralph:conflict" }] },
|
|
59535
59636
|
|
|
59637
|
+
// Done issues with new review comments to address (Ralph will re-open
|
|
59638
|
+
// and prepend a task that ingests the non-Ralph comments).
|
|
59639
|
+
// "getReview": { "filter": [{ "type": "label", "value": "ralph:review" }] },
|
|
59640
|
+
|
|
59536
59641
|
// Applied when Ralph picks up an issue.
|
|
59537
59642
|
// "setInProgress": { "type": "label", "value": "ralph:in-progress" },
|
|
59538
59643
|
|
|
@@ -59546,7 +59651,10 @@ var MarkerSchema, GetIndicatorSchema, SetIndicatorSchema, IndicatorsSchema, Ralp
|
|
|
59546
59651
|
// "setConflicted": { "type": "label", "value": "ralph:conflict" },
|
|
59547
59652
|
|
|
59548
59653
|
// Label removed once the conflict is fixed (status removal is not supported here).
|
|
59549
|
-
// "clearConflicted": { "type": "label", "value": "ralph:conflict" }
|
|
59654
|
+
// "clearConflicted": { "type": "label", "value": "ralph:conflict" },
|
|
59655
|
+
|
|
59656
|
+
// Label removed when Ralph picks up a review-mode issue (status removal not supported).
|
|
59657
|
+
// "clearReview": { "type": "label", "value": "ralph:review" }
|
|
59550
59658
|
}
|
|
59551
59659
|
}
|
|
59552
59660
|
}
|
|
@@ -59568,24 +59676,28 @@ var init_config = __esm(() => {
|
|
|
59568
59676
|
getTodo: GetIndicatorSchema.optional(),
|
|
59569
59677
|
getInProgress: GetIndicatorSchema.optional(),
|
|
59570
59678
|
getConflicted: GetIndicatorSchema.optional(),
|
|
59679
|
+
getReview: GetIndicatorSchema.optional(),
|
|
59571
59680
|
setInProgress: SetIndicatorSchema.optional(),
|
|
59572
59681
|
setDone: SetIndicatorSchema.optional(),
|
|
59573
59682
|
setError: SetIndicatorSchema.optional(),
|
|
59574
59683
|
setConflicted: SetIndicatorSchema.optional(),
|
|
59575
|
-
clearConflicted: SetIndicatorSchema.optional()
|
|
59684
|
+
clearConflicted: SetIndicatorSchema.optional(),
|
|
59685
|
+
clearReview: SetIndicatorSchema.optional()
|
|
59576
59686
|
}).superRefine((value, ctx) => {
|
|
59577
|
-
const
|
|
59578
|
-
|
|
59579
|
-
|
|
59580
|
-
|
|
59581
|
-
|
|
59582
|
-
|
|
59583
|
-
|
|
59584
|
-
|
|
59585
|
-
|
|
59586
|
-
|
|
59587
|
-
|
|
59588
|
-
|
|
59687
|
+
for (const key of ["clearConflicted", "clearReview"]) {
|
|
59688
|
+
const clear = value[key];
|
|
59689
|
+
if (!clear)
|
|
59690
|
+
continue;
|
|
59691
|
+
const markers = "apply" in clear ? clear.apply : [clear];
|
|
59692
|
+
for (const m of markers) {
|
|
59693
|
+
if (m.type !== "label") {
|
|
59694
|
+
ctx.addIssue({
|
|
59695
|
+
code: exports_external.ZodIssueCode.custom,
|
|
59696
|
+
path: [key],
|
|
59697
|
+
message: `${key} markers must be label-typed (status removal is not supported)`
|
|
59698
|
+
});
|
|
59699
|
+
break;
|
|
59700
|
+
}
|
|
59589
59701
|
}
|
|
59590
59702
|
}
|
|
59591
59703
|
});
|
|
@@ -59634,8 +59746,8 @@ var init_config = __esm(() => {
|
|
|
59634
59746
|
|
|
59635
59747
|
// packages/log/src/log.ts
|
|
59636
59748
|
import { appendFile } from "fs/promises";
|
|
59637
|
-
import { join as
|
|
59638
|
-
import { homedir as
|
|
59749
|
+
import { join as join12, dirname as dirname4 } from "path";
|
|
59750
|
+
import { homedir as homedir3 } from "os";
|
|
59639
59751
|
import { mkdir as mkdir2 } from "fs/promises";
|
|
59640
59752
|
function fmt(type, text) {
|
|
59641
59753
|
return `[${new Date().toISOString()}] [${type}] ${text}
|
|
@@ -59680,25 +59792,25 @@ async function initWorkerLog(logFile) {
|
|
|
59680
59792
|
var ANSI_RE, AGENT_LOG_PATH;
|
|
59681
59793
|
var init_log = __esm(() => {
|
|
59682
59794
|
ANSI_RE = /\x1b(?:\[[0-9;]*[A-Za-z]|\][^\x07\x1b]*(?:\x07|\x1b\\)|.)/g;
|
|
59683
|
-
AGENT_LOG_PATH =
|
|
59795
|
+
AGENT_LOG_PATH = join12(homedir3(), ".ralph", "agent-mode.log");
|
|
59684
59796
|
mkdir2(dirname4(AGENT_LOG_PATH), { recursive: true }).catch(() => {
|
|
59685
59797
|
return;
|
|
59686
59798
|
});
|
|
59687
59799
|
});
|
|
59688
59800
|
|
|
59689
59801
|
// packages/core/src/layout.ts
|
|
59690
|
-
import { join as
|
|
59802
|
+
import { join as join13 } from "path";
|
|
59691
59803
|
function projectLayout(root) {
|
|
59692
|
-
const statesDir =
|
|
59693
|
-
const tasksDir =
|
|
59804
|
+
const statesDir = join13(root, ".ralph", "tasks");
|
|
59805
|
+
const tasksDir = join13(root, "openspec", "changes");
|
|
59694
59806
|
return {
|
|
59695
59807
|
root,
|
|
59696
59808
|
statesDir,
|
|
59697
59809
|
tasksDir,
|
|
59698
|
-
agentStateFile:
|
|
59699
|
-
changeDir: (name) =>
|
|
59700
|
-
taskStateDir: (name) =>
|
|
59701
|
-
stateFile: (name) =>
|
|
59810
|
+
agentStateFile: join13(root, ".ralph", "agent-state.json"),
|
|
59811
|
+
changeDir: (name) => join13(tasksDir, name),
|
|
59812
|
+
taskStateDir: (name) => join13(statesDir, name),
|
|
59813
|
+
stateFile: (name) => join13(statesDir, name, STATE_FILE2)
|
|
59702
59814
|
};
|
|
59703
59815
|
}
|
|
59704
59816
|
var STATE_FILE2 = ".ralph-state.json";
|
|
@@ -59753,7 +59865,15 @@ function buildIssueFilter(spec) {
|
|
|
59753
59865
|
where.and = [{ state: current }, noStatus];
|
|
59754
59866
|
}
|
|
59755
59867
|
if (labels.length > 0) {
|
|
59756
|
-
|
|
59868
|
+
const includeLabels = where.labels;
|
|
59869
|
+
const excludeLabels = { every: { name: { nin: labels } } };
|
|
59870
|
+
if (includeLabels === undefined) {
|
|
59871
|
+
where.labels = excludeLabels;
|
|
59872
|
+
} else {
|
|
59873
|
+
const existingAnd = where.and ?? [];
|
|
59874
|
+
where.and = [...existingAnd, { labels: includeLabels }, { labels: excludeLabels }];
|
|
59875
|
+
delete where.labels;
|
|
59876
|
+
}
|
|
59757
59877
|
}
|
|
59758
59878
|
}
|
|
59759
59879
|
return where;
|
|
@@ -59949,19 +60069,21 @@ class AgentCoordinator {
|
|
|
59949
60069
|
let todo = [];
|
|
59950
60070
|
let inProgress = [];
|
|
59951
60071
|
let conflicted = [];
|
|
60072
|
+
let review = [];
|
|
59952
60073
|
try {
|
|
59953
|
-
[todo, inProgress, conflicted] = await Promise.all([
|
|
60074
|
+
[todo, inProgress, conflicted, review] = await Promise.all([
|
|
59954
60075
|
this.deps.fetchTodo(),
|
|
59955
60076
|
this.deps.fetchInProgress(),
|
|
59956
|
-
this.deps.fetchConflicted()
|
|
60077
|
+
this.deps.fetchConflicted(),
|
|
60078
|
+
this.deps.fetchReview()
|
|
59957
60079
|
]);
|
|
59958
60080
|
} catch (err) {
|
|
59959
60081
|
this.deps.onLog(`! Linear poll failed: ${err.message}`, "red");
|
|
59960
60082
|
capture("agent_linear_poll_failed", { error: err.message });
|
|
59961
60083
|
return { found: 0, added: 0 };
|
|
59962
60084
|
}
|
|
59963
|
-
if (todo.length + inProgress.length + conflicted.length > 0) {
|
|
59964
|
-
this.deps.onLog(` poll: ${todo.length} todo, ${inProgress.length} in-progress, ${conflicted.length} conflicted`, "gray");
|
|
60085
|
+
if (todo.length + inProgress.length + conflicted.length + review.length > 0) {
|
|
60086
|
+
this.deps.onLog(` poll: ${todo.length} todo, ${inProgress.length} in-progress, ${conflicted.length} conflicted, ${review.length} review`, "gray");
|
|
59965
60087
|
}
|
|
59966
60088
|
const queuedIds = new Set(this.queue.map((q) => q.issue.id));
|
|
59967
60089
|
const activeIds = new Set(this.workers.map((w) => w.issueId));
|
|
@@ -59996,6 +60118,16 @@ class AgentCoordinator {
|
|
|
59996
60118
|
added += 1;
|
|
59997
60119
|
this.deps.onLog(` \u21B3 ${issue.identifier} queued (conflict-fix)`, "gray");
|
|
59998
60120
|
}
|
|
60121
|
+
for (const issue of review) {
|
|
60122
|
+
if (atTicketLimit())
|
|
60123
|
+
break;
|
|
60124
|
+
if (!eligible(issue.id))
|
|
60125
|
+
continue;
|
|
60126
|
+
this.queue.push({ issue, mode: "review" });
|
|
60127
|
+
queuedIds.add(issue.id);
|
|
60128
|
+
added += 1;
|
|
60129
|
+
this.deps.onLog(` \u21B3 ${issue.identifier} queued (review)`, "gray");
|
|
60130
|
+
}
|
|
59999
60131
|
for (const issue of todo) {
|
|
60000
60132
|
if (atTicketLimit())
|
|
60001
60133
|
break;
|
|
@@ -60012,7 +60144,8 @@ class AgentCoordinator {
|
|
|
60012
60144
|
const modeRank = {
|
|
60013
60145
|
resume: 0,
|
|
60014
60146
|
"conflict-fix": 1,
|
|
60015
|
-
|
|
60147
|
+
review: 2,
|
|
60148
|
+
fresh: 3
|
|
60016
60149
|
};
|
|
60017
60150
|
this.queue.sort((a, b) => {
|
|
60018
60151
|
const pa = a.issue.priority === 0 ? Infinity : a.issue.priority;
|
|
@@ -60025,7 +60158,7 @@ class AgentCoordinator {
|
|
|
60025
60158
|
this.spawnNext();
|
|
60026
60159
|
await this.scanDoneForConflicts();
|
|
60027
60160
|
await this.reportProgress();
|
|
60028
|
-
const found = todo.length + inProgress.length + conflicted.length;
|
|
60161
|
+
const found = todo.length + inProgress.length + conflicted.length + review.length;
|
|
60029
60162
|
return { found, added };
|
|
60030
60163
|
}
|
|
60031
60164
|
dependenciesResolved(issue) {
|
|
@@ -60169,6 +60302,26 @@ class AgentCoordinator {
|
|
|
60169
60302
|
});
|
|
60170
60303
|
}
|
|
60171
60304
|
}
|
|
60305
|
+
if (mode === "review" && this.opts.clearReview) {
|
|
60306
|
+
try {
|
|
60307
|
+
await this.deps.removeIndicator(issue, this.opts.clearReview);
|
|
60308
|
+
this.deps.onLog(` ${issue.identifier}: clearReview applied`, "gray");
|
|
60309
|
+
} catch (err) {
|
|
60310
|
+
this.deps.onLog(`! Linear clearReview failed for ${issue.identifier}: ${err.message}`, "yellow");
|
|
60311
|
+
capture("agent_indicator_failed", {
|
|
60312
|
+
indicator: "clearReview",
|
|
60313
|
+
issue_identifier: issue.identifier,
|
|
60314
|
+
error: err.message
|
|
60315
|
+
});
|
|
60316
|
+
}
|
|
60317
|
+
}
|
|
60318
|
+
if (mode === "review" && this.opts.postComments !== false) {
|
|
60319
|
+
try {
|
|
60320
|
+
await this.deps.postComment(issue, `\uD83D\uDD01 Ralph picked up new review comments. Tracking change: \`${prep.changeName}\``);
|
|
60321
|
+
} catch (err) {
|
|
60322
|
+
this.deps.onLog(`! Linear review comment failed for ${issue.identifier}: ${err.message}`, "yellow");
|
|
60323
|
+
}
|
|
60324
|
+
}
|
|
60172
60325
|
if (mode === "fresh" && this.opts.postComments !== false) {
|
|
60173
60326
|
let alreadyPosted = false;
|
|
60174
60327
|
try {
|
|
@@ -60308,7 +60461,7 @@ var init_coordinator = __esm(() => {
|
|
|
60308
60461
|
});
|
|
60309
60462
|
|
|
60310
60463
|
// apps/cli/src/agent/scaffold.ts
|
|
60311
|
-
import { join as
|
|
60464
|
+
import { join as join14 } from "path";
|
|
60312
60465
|
import { mkdir as mkdir3 } from "fs/promises";
|
|
60313
60466
|
function changeNameForIssue(issue) {
|
|
60314
60467
|
const slug = issue.title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 40);
|
|
@@ -60316,10 +60469,10 @@ function changeNameForIssue(issue) {
|
|
|
60316
60469
|
}
|
|
60317
60470
|
async function scaffoldChangeForIssue(tasksDir, statesDir, issue, comments = [], appendPrompt = "") {
|
|
60318
60471
|
const name = changeNameForIssue(issue);
|
|
60319
|
-
const changeDir =
|
|
60320
|
-
const stateDir =
|
|
60472
|
+
const changeDir = join14(tasksDir, name);
|
|
60473
|
+
const stateDir = join14(statesDir, name);
|
|
60321
60474
|
await mkdir3(changeDir, { recursive: true });
|
|
60322
|
-
await mkdir3(
|
|
60475
|
+
await mkdir3(join14(changeDir, "specs"), { recursive: true });
|
|
60323
60476
|
await mkdir3(stateDir, { recursive: true });
|
|
60324
60477
|
const commentsBlock = comments.length > 0 ? [
|
|
60325
60478
|
"",
|
|
@@ -60371,106 +60524,13 @@ async function scaffoldChangeForIssue(tasksDir, statesDir, issue, comments = [],
|
|
|
60371
60524
|
""
|
|
60372
60525
|
].join(`
|
|
60373
60526
|
`);
|
|
60374
|
-
await Bun.write(
|
|
60375
|
-
await Bun.write(
|
|
60376
|
-
await Bun.write(
|
|
60527
|
+
await Bun.write(join14(changeDir, "proposal.md"), proposal);
|
|
60528
|
+
await Bun.write(join14(changeDir, "tasks.md"), tasks);
|
|
60529
|
+
await Bun.write(join14(changeDir, "design.md"), design);
|
|
60377
60530
|
return name;
|
|
60378
60531
|
}
|
|
60379
60532
|
var init_scaffold = () => {};
|
|
60380
60533
|
|
|
60381
|
-
// apps/cli/src/agent/worktree.ts
|
|
60382
|
-
import { basename, join as join14 } from "path";
|
|
60383
|
-
import { homedir as homedir3 } from "os";
|
|
60384
|
-
import { exists } from "fs/promises";
|
|
60385
|
-
function worktreesDir(projectRoot) {
|
|
60386
|
-
return join14(homedir3(), ".ralph", basename(projectRoot), "worktrees");
|
|
60387
|
-
}
|
|
60388
|
-
function branchForChange(changeName) {
|
|
60389
|
-
return `ralph/${changeName}`;
|
|
60390
|
-
}
|
|
60391
|
-
async function createWorktree(projectRoot, changeName, runner) {
|
|
60392
|
-
const dir = worktreesDir(projectRoot);
|
|
60393
|
-
const cwd2 = join14(dir, changeName);
|
|
60394
|
-
const branch = branchForChange(changeName);
|
|
60395
|
-
const list = await runner.run(["worktree", "list", "--porcelain"], projectRoot);
|
|
60396
|
-
if (list.stdout.includes(`worktree ${cwd2}
|
|
60397
|
-
`)) {
|
|
60398
|
-
return { cwd: cwd2, branch };
|
|
60399
|
-
}
|
|
60400
|
-
let branchExists = true;
|
|
60401
|
-
try {
|
|
60402
|
-
await runner.run(["rev-parse", "--verify", "--quiet", `refs/heads/${branch}`], projectRoot);
|
|
60403
|
-
} catch {
|
|
60404
|
-
branchExists = false;
|
|
60405
|
-
}
|
|
60406
|
-
const cmd = branchExists ? ["worktree", "add", cwd2, branch] : ["worktree", "add", "-b", branch, cwd2];
|
|
60407
|
-
await runner.run(cmd, projectRoot);
|
|
60408
|
-
return { cwd: cwd2, branch };
|
|
60409
|
-
}
|
|
60410
|
-
async function removeWorktree(projectRoot, cwd2, runner) {
|
|
60411
|
-
await runner.run(["worktree", "remove", "--force", cwd2], projectRoot);
|
|
60412
|
-
}
|
|
60413
|
-
async function isWorktreeSafeToRemove(cwd2, base2, runner) {
|
|
60414
|
-
const status = await runner.run(["status", "--porcelain"], cwd2);
|
|
60415
|
-
const dirty = status.stdout.trim();
|
|
60416
|
-
let unpushedCommits = "";
|
|
60417
|
-
try {
|
|
60418
|
-
const log2 = await runner.run(["log", "--oneline", `${base2}..HEAD`, "--no-merges"], cwd2);
|
|
60419
|
-
unpushedCommits = log2.stdout.trim();
|
|
60420
|
-
} catch {
|
|
60421
|
-
unpushedCommits = "<unknown: failed to compare against base>";
|
|
60422
|
-
}
|
|
60423
|
-
if (dirty && unpushedCommits) {
|
|
60424
|
-
return {
|
|
60425
|
-
safe: false,
|
|
60426
|
-
reason: "uncommitted changes AND unpushed commits present",
|
|
60427
|
-
dirty,
|
|
60428
|
-
unpushedCommits
|
|
60429
|
-
};
|
|
60430
|
-
}
|
|
60431
|
-
if (dirty) {
|
|
60432
|
-
return {
|
|
60433
|
-
safe: false,
|
|
60434
|
-
reason: "uncommitted or untracked files present",
|
|
60435
|
-
dirty,
|
|
60436
|
-
unpushedCommits
|
|
60437
|
-
};
|
|
60438
|
-
}
|
|
60439
|
-
if (unpushedCommits) {
|
|
60440
|
-
return {
|
|
60441
|
-
safe: false,
|
|
60442
|
-
reason: `commits ahead of ${base2} were not pushed/PR'd`,
|
|
60443
|
-
dirty,
|
|
60444
|
-
unpushedCommits
|
|
60445
|
-
};
|
|
60446
|
-
}
|
|
60447
|
-
return { safe: true, dirty, unpushedCommits };
|
|
60448
|
-
}
|
|
60449
|
-
async function seedWorktreeMcpConfig(projectRoot, worktreeCwd) {
|
|
60450
|
-
const dst = join14(worktreeCwd, ".mcp.json");
|
|
60451
|
-
const src = join14(projectRoot, ".mcp.json");
|
|
60452
|
-
const source = await exists(dst) ? dst : await exists(src) ? src : null;
|
|
60453
|
-
if (!source)
|
|
60454
|
-
return;
|
|
60455
|
-
let parsed;
|
|
60456
|
-
try {
|
|
60457
|
-
parsed = await Bun.file(source).json();
|
|
60458
|
-
} catch {
|
|
60459
|
-
return;
|
|
60460
|
-
}
|
|
60461
|
-
const servers = parsed.mcpServers;
|
|
60462
|
-
if (servers && typeof servers === "object") {
|
|
60463
|
-
for (const cfg of Object.values(servers)) {
|
|
60464
|
-
if (Array.isArray(cfg.args)) {
|
|
60465
|
-
cfg.args = cfg.args.map((a) => typeof a === "string" && a.startsWith(".ralph/") ? join14(projectRoot, a) : a);
|
|
60466
|
-
}
|
|
60467
|
-
}
|
|
60468
|
-
}
|
|
60469
|
-
await Bun.write(dst, JSON.stringify(parsed, null, 2) + `
|
|
60470
|
-
`);
|
|
60471
|
-
}
|
|
60472
|
-
var init_worktree = () => {};
|
|
60473
|
-
|
|
60474
60534
|
// apps/cli/src/agent/pr.ts
|
|
60475
60535
|
function defaultTitle(issue) {
|
|
60476
60536
|
return `${issue.identifier}: ${issue.title}`;
|
|
@@ -61024,6 +61084,30 @@ function mergeIndicators(cfg, cli) {
|
|
|
61024
61084
|
}
|
|
61025
61085
|
return out;
|
|
61026
61086
|
}
|
|
61087
|
+
function isRalphComment(body) {
|
|
61088
|
+
const trimmed = body.trimStart();
|
|
61089
|
+
return /^(\uD83E\uDD16|\uD83D\uDD04|\u2705|\u2717|\u26A0|\uD83D\uDD01)\s*Ralph\b/.test(trimmed);
|
|
61090
|
+
}
|
|
61091
|
+
function buildReviewTaskBody(comments, url) {
|
|
61092
|
+
if (comments.length === 0) {
|
|
61093
|
+
return `No non-Ralph reviewer comments were found on ${url}. Recheck the issue manually before continuing.`;
|
|
61094
|
+
}
|
|
61095
|
+
const blocks = comments.map((c) => {
|
|
61096
|
+
const author = c.user?.name ?? "unknown";
|
|
61097
|
+
return `**${author}** \u2014 ${c.createdAt}
|
|
61098
|
+
|
|
61099
|
+
${c.body.trim()}`;
|
|
61100
|
+
});
|
|
61101
|
+
return [
|
|
61102
|
+
`Reviewer comments left on the Linear issue (${url}):`,
|
|
61103
|
+
"",
|
|
61104
|
+
...blocks,
|
|
61105
|
+
"",
|
|
61106
|
+
"Address every concrete request above. If a comment is ambiguous, note",
|
|
61107
|
+
"your interpretation in proposal.md `## Steering` before acting."
|
|
61108
|
+
].join(`
|
|
61109
|
+
`);
|
|
61110
|
+
}
|
|
61027
61111
|
function unionMarkers(...sets) {
|
|
61028
61112
|
const out = [];
|
|
61029
61113
|
const seen = new Set;
|
|
@@ -61063,6 +61147,7 @@ function buildAgentCoordinator(input) {
|
|
|
61063
61147
|
const team = args.linearTeam || cfg.linear.team;
|
|
61064
61148
|
const assignee = args.linearAssignee || cfg.linear.assignee;
|
|
61065
61149
|
const excludeFromTodo = unionMarkers(indicators.setDone, indicators.setError, indicators.setConflicted);
|
|
61150
|
+
const excludeFromReview = unionMarkers(indicators.setInProgress, indicators.setError, indicators.setConflicted);
|
|
61066
61151
|
const gitRunner = input.runners?.git ?? bunGitRunner;
|
|
61067
61152
|
const cmdRunner = input.runners?.cmd ?? bunCmdRunner;
|
|
61068
61153
|
const stateCache = new Map;
|
|
@@ -61236,7 +61321,8 @@ function buildAgentCoordinator(input) {
|
|
|
61236
61321
|
async function prepare(issue, mode) {
|
|
61237
61322
|
const { workerCwd, scaffoldTasksDir, scaffoldStatesDir, branch } = await setupWorktree(issue);
|
|
61238
61323
|
let changeName;
|
|
61239
|
-
|
|
61324
|
+
const isFresh = mode === "fresh";
|
|
61325
|
+
if (isFresh) {
|
|
61240
61326
|
let comments = [];
|
|
61241
61327
|
try {
|
|
61242
61328
|
comments = await fetchIssueComments(apiKey, issue.id);
|
|
@@ -61256,7 +61342,24 @@ function buildAgentCoordinator(input) {
|
|
|
61256
61342
|
issueByChange.set(changeName, issue);
|
|
61257
61343
|
if (branch)
|
|
61258
61344
|
branchByChange.set(changeName, branch);
|
|
61259
|
-
if (mode === "
|
|
61345
|
+
if (mode === "review") {
|
|
61346
|
+
const wtLayout = projectLayout(workerCwd);
|
|
61347
|
+
const tasksFile = join16(wtLayout.changeDir(changeName), "tasks.md");
|
|
61348
|
+
let comments = [];
|
|
61349
|
+
try {
|
|
61350
|
+
comments = await fetchIssueComments(apiKey, issue.id);
|
|
61351
|
+
} catch (err) {
|
|
61352
|
+
onLog(`! Linear comment fetch failed for ${issue.identifier}: ${err.message}`, "yellow");
|
|
61353
|
+
}
|
|
61354
|
+
const reviewerComments = comments.filter((c) => !isRalphComment(c.body));
|
|
61355
|
+
const body = buildReviewTaskBody(reviewerComments, issue.url);
|
|
61356
|
+
try {
|
|
61357
|
+
await prependFixTask(tasksFile, "Address reviewer comments", body);
|
|
61358
|
+
} catch (err) {
|
|
61359
|
+
onLog(`! could not prepend review task: ${err.message}`, "red");
|
|
61360
|
+
}
|
|
61361
|
+
await reactivateState2(wtLayout.stateFile(changeName), changeName);
|
|
61362
|
+
} else if (mode === "conflict-fix") {
|
|
61260
61363
|
const wtLayout = projectLayout(workerCwd);
|
|
61261
61364
|
const tasksFile = join16(wtLayout.changeDir(changeName), "tasks.md");
|
|
61262
61365
|
const prUrl = prByChange.get(changeName);
|
|
@@ -61531,6 +61634,7 @@ PR: ${prUrl}` : ""
|
|
|
61531
61634
|
fetchTodo: () => fetchByGet(indicators.getTodo, excludeFromTodo),
|
|
61532
61635
|
fetchInProgress: () => fetchByGet(indicators.getInProgress, []),
|
|
61533
61636
|
fetchConflicted: () => fetchByGet(indicators.getConflicted, []),
|
|
61637
|
+
fetchReview: () => fetchByGet(indicators.getReview, excludeFromReview),
|
|
61534
61638
|
fetchDoneCandidates,
|
|
61535
61639
|
prepare,
|
|
61536
61640
|
spawnWorker,
|
|
@@ -61559,6 +61663,7 @@ PR: ${prUrl}` : ""
|
|
|
61559
61663
|
...indicators.setError !== undefined ? { setError: indicators.setError } : {},
|
|
61560
61664
|
...indicators.setConflicted !== undefined ? { setConflicted: indicators.setConflicted } : {},
|
|
61561
61665
|
...indicators.clearConflicted !== undefined ? { clearConflicted: indicators.clearConflicted } : {},
|
|
61666
|
+
...indicators.clearReview !== undefined ? { clearReview: indicators.clearReview } : {},
|
|
61562
61667
|
postComments: cfg.linear.postComments,
|
|
61563
61668
|
commentEveryIterations: cfg.linear.updateEveryIterations,
|
|
61564
61669
|
...args.maxTickets > 0 ? { maxTickets: args.maxTickets } : {}
|
|
@@ -61585,6 +61690,9 @@ function describeIndicators(indicators, team, assignee) {
|
|
|
61585
61690
|
if (indicators.getConflicted) {
|
|
61586
61691
|
parts.push(`conflicted=[${indicators.getConflicted.filter.map((m) => `${m.type}:${m.value}`).join(",")}]`);
|
|
61587
61692
|
}
|
|
61693
|
+
if (indicators.getReview) {
|
|
61694
|
+
parts.push(`review=[${indicators.getReview.filter.map((m) => `${m.type}:${m.value}`).join(",")}]`);
|
|
61695
|
+
}
|
|
61588
61696
|
return parts.join(", ");
|
|
61589
61697
|
}
|
|
61590
61698
|
var bunGitRunner, bunCmdRunner;
|
|
@@ -66963,7 +67071,8 @@ function ensureState(changeDir) {
|
|
|
66963
67071
|
|
|
66964
67072
|
// apps/cli/src/components/TaskList.tsx
|
|
66965
67073
|
var import_react22 = __toESM(require_react(), 1);
|
|
66966
|
-
import { join as
|
|
67074
|
+
import { join as join4 } from "path";
|
|
67075
|
+
init_worktree();
|
|
66967
67076
|
var jsx_dev_runtime = __toESM(require_jsx_dev_runtime(), 1);
|
|
66968
67077
|
function countTaskItems(content) {
|
|
66969
67078
|
const checked = (content.match(/^- \[x\]/gm) ?? []).length;
|
|
@@ -66976,10 +67085,10 @@ function buildRows(statesDir, projectRoot) {
|
|
|
66976
67085
|
const seenNames = new Set;
|
|
66977
67086
|
const sources = [{ dir: statesDir, label: "main" }];
|
|
66978
67087
|
if (projectRoot) {
|
|
66979
|
-
const worktreesRoot =
|
|
67088
|
+
const worktreesRoot = worktreesDir(projectRoot);
|
|
66980
67089
|
for (const wt of storage.list(worktreesRoot)) {
|
|
66981
67090
|
sources.push({
|
|
66982
|
-
dir:
|
|
67091
|
+
dir: join4(worktreesRoot, wt, ".ralph", "tasks"),
|
|
66983
67092
|
label: `wt:${wt}`
|
|
66984
67093
|
});
|
|
66985
67094
|
}
|
|
@@ -66988,7 +67097,7 @@ function buildRows(statesDir, projectRoot) {
|
|
|
66988
67097
|
for (const entry of storage.list(dir)) {
|
|
66989
67098
|
if (seenNames.has(entry))
|
|
66990
67099
|
continue;
|
|
66991
|
-
const raw = storage.read(
|
|
67100
|
+
const raw = storage.read(join4(dir, entry, ".ralph-state.json"));
|
|
66992
67101
|
if (raw === null)
|
|
66993
67102
|
continue;
|
|
66994
67103
|
let state;
|
|
@@ -67004,7 +67113,7 @@ function buildRows(statesDir, projectRoot) {
|
|
|
67004
67113
|
`).find((l) => l.trim() !== "") ?? "";
|
|
67005
67114
|
let progress = "\u2014";
|
|
67006
67115
|
let progressStyled = true;
|
|
67007
|
-
const tasksContent = storage.read(
|
|
67116
|
+
const tasksContent = storage.read(join4(dir, entry, "tasks.md"));
|
|
67008
67117
|
if (tasksContent !== null) {
|
|
67009
67118
|
const { checked, unchecked } = countTaskItems(tasksContent);
|
|
67010
67119
|
const total = checked + unchecked;
|
|
@@ -67145,7 +67254,7 @@ function TaskList({ statesDir, projectRoot }) {
|
|
|
67145
67254
|
}
|
|
67146
67255
|
|
|
67147
67256
|
// apps/cli/src/components/TaskStatus.tsx
|
|
67148
|
-
import { join as
|
|
67257
|
+
import { join as join5 } from "path";
|
|
67149
67258
|
var jsx_dev_runtime2 = __toESM(require_jsx_dev_runtime(), 1);
|
|
67150
67259
|
var HEAVY_RULE = "============================================";
|
|
67151
67260
|
var LIGHT_RULE = "--------------------------------------------";
|
|
@@ -67156,7 +67265,7 @@ function TaskStatus({ state, stateDir }) {
|
|
|
67156
67265
|
const time = Math.round(state.usage.total_duration_ms / 1000 * 10) / 10 + "s";
|
|
67157
67266
|
const artifacts = OPENSPEC_ARTIFACTS.map((name) => ({
|
|
67158
67267
|
name,
|
|
67159
|
-
exists: storage.read(
|
|
67268
|
+
exists: storage.read(join5(stateDir, name)) !== null
|
|
67160
67269
|
}));
|
|
67161
67270
|
const recent = state.history.slice(-10);
|
|
67162
67271
|
return /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Box_default, {
|
|
@@ -67299,7 +67408,7 @@ function TaskStatus({ state, stateDir }) {
|
|
|
67299
67408
|
|
|
67300
67409
|
// apps/cli/src/components/TaskLoop.tsx
|
|
67301
67410
|
var import_react56 = __toESM(require_react(), 1);
|
|
67302
|
-
import { join as
|
|
67411
|
+
import { join as join10 } from "path";
|
|
67303
67412
|
|
|
67304
67413
|
// node_modules/.bun/@inkjs+ui@2.0.0+5b84dde3d6cd3930/node_modules/@inkjs/ui/build/components/badge/badge.js
|
|
67305
67414
|
var import_react24 = __toESM(require_react(), 1);
|
|
@@ -70863,7 +70972,7 @@ function StopMessage({
|
|
|
70863
70972
|
|
|
70864
70973
|
// apps/cli/src/hooks/useLoop.ts
|
|
70865
70974
|
var import_react55 = __toESM(require_react(), 1);
|
|
70866
|
-
import { join as
|
|
70975
|
+
import { join as join9 } from "path";
|
|
70867
70976
|
|
|
70868
70977
|
// packages/engine/src/spawn.ts
|
|
70869
70978
|
var {spawn: bunSpawn } = globalThis.Bun;
|
|
@@ -70873,7 +70982,7 @@ var spawn = bunSpawn;
|
|
|
70873
70982
|
import { createWriteStream } from "fs";
|
|
70874
70983
|
import { mkdtemp, unlink, mkdir } from "fs/promises";
|
|
70875
70984
|
import { dirname as dirname2 } from "path";
|
|
70876
|
-
import { join as
|
|
70985
|
+
import { join as join6 } from "path";
|
|
70877
70986
|
import { tmpdir } from "os";
|
|
70878
70987
|
|
|
70879
70988
|
// packages/engine/src/feed-events.ts
|
|
@@ -71606,7 +71715,7 @@ function buildCodexArgs() {
|
|
|
71606
71715
|
return ["exec", "--json", "--color", "never", "--dangerously-bypass-approvals-and-sandbox", "-"];
|
|
71607
71716
|
}
|
|
71608
71717
|
async function runInteractive(model, prompt, taskDir) {
|
|
71609
|
-
const promptFile = taskDir ?
|
|
71718
|
+
const promptFile = taskDir ? join6(taskDir, "_interactive_prompt.md") : join6(await mkdtemp(join6(tmpdir(), "ralph-")), "prompt.md");
|
|
71610
71719
|
await Bun.write(promptFile, prompt);
|
|
71611
71720
|
try {
|
|
71612
71721
|
const cmd = [
|
|
@@ -71632,7 +71741,7 @@ async function runInteractive(model, prompt, taskDir) {
|
|
|
71632
71741
|
stderr: "inherit"
|
|
71633
71742
|
});
|
|
71634
71743
|
const exitCode = await proc.exited;
|
|
71635
|
-
const doneFile = taskDir ?
|
|
71744
|
+
const doneFile = taskDir ? join6(taskDir, "_interactive_done") : null;
|
|
71636
71745
|
if (doneFile && await Bun.file(doneFile).exists()) {
|
|
71637
71746
|
return { exitCode: 0, usage: null, sessionId: null, rateLimited: false };
|
|
71638
71747
|
}
|
|
@@ -71849,12 +71958,12 @@ function commitTaskDir(taskDir, message) {
|
|
|
71849
71958
|
init_src();
|
|
71850
71959
|
|
|
71851
71960
|
// packages/core/src/loop.ts
|
|
71852
|
-
import { join as
|
|
71961
|
+
import { join as join8 } from "path";
|
|
71853
71962
|
var STEERING_MAX_LINES = 20;
|
|
71854
71963
|
function buildTaskPrompt(state, taskDir) {
|
|
71855
71964
|
const storage = getStorage();
|
|
71856
71965
|
let prompt = "";
|
|
71857
|
-
const steeringContent = storage.read(
|
|
71966
|
+
const steeringContent = storage.read(join8(taskDir, "steering.md"));
|
|
71858
71967
|
if (steeringContent !== null) {
|
|
71859
71968
|
const steeringLines = steeringContent.split(`
|
|
71860
71969
|
`).filter((line) => !line.startsWith("#")).filter((line) => line.trim()).slice(0, STEERING_MAX_LINES);
|
|
@@ -71873,7 +71982,7 @@ function buildTaskPrompt(state, taskDir) {
|
|
|
71873
71982
|
`;
|
|
71874
71983
|
}
|
|
71875
71984
|
}
|
|
71876
|
-
const tasksContent = storage.read(
|
|
71985
|
+
const tasksContent = storage.read(join8(taskDir, "tasks.md"));
|
|
71877
71986
|
if (tasksContent !== null) {
|
|
71878
71987
|
const section = firstUnchecked(tasksContent);
|
|
71879
71988
|
if (section) {
|
|
@@ -71888,7 +71997,7 @@ function buildTaskPrompt(state, taskDir) {
|
|
|
71888
71997
|
prompt += `---
|
|
71889
71998
|
|
|
71890
71999
|
`;
|
|
71891
|
-
prompt += `**Tracking progress**: as you finish each item above, edit ` + `\`${
|
|
72000
|
+
prompt += `**Tracking progress**: as you finish each item above, edit ` + `\`${join8(taskDir, "tasks.md")}\` and change its \`- [ ]\` to ` + `\`- [x]\` in the same commit. The loop reads this file between ` + `iterations and stops when no \`- [ ]\` items remain \u2014 if you do ` + `not tick the box, the next iteration will repeat this task.
|
|
71892
72001
|
|
|
71893
72002
|
`;
|
|
71894
72003
|
}
|
|
@@ -71909,7 +72018,7 @@ function buildTaskPrompt(state, taskDir) {
|
|
|
71909
72018
|
`;
|
|
71910
72019
|
}
|
|
71911
72020
|
if (state.manualTest) {
|
|
71912
|
-
const tasksContent2 = storage.read(
|
|
72021
|
+
const tasksContent2 = storage.read(join8(taskDir, "tasks.md"));
|
|
71913
72022
|
const hasUncheckedTasks = tasksContent2 !== null && /^- \[ \]/m.test(tasksContent2);
|
|
71914
72023
|
if (!hasUncheckedTasks) {
|
|
71915
72024
|
const hasManualTestSection = tasksContent2 !== null && /^## Manual Testing/m.test(tasksContent2);
|
|
@@ -71958,7 +72067,7 @@ When all tasks are complete and all files are committed, push your branch and op
|
|
|
71958
72067
|
}
|
|
71959
72068
|
function checkStopSignal(taskDir, stateDir) {
|
|
71960
72069
|
const storage = getStorage();
|
|
71961
|
-
const stopFile =
|
|
72070
|
+
const stopFile = join8(taskDir, "STOP");
|
|
71962
72071
|
const reason = storage.read(stopFile);
|
|
71963
72072
|
if (reason === null)
|
|
71964
72073
|
return null;
|
|
@@ -72033,7 +72142,7 @@ function updateStateIteration(stateDir, result2, startedAt, engine, model, usage
|
|
|
72033
72142
|
}
|
|
72034
72143
|
function appendSteeringMessage(taskDir, message) {
|
|
72035
72144
|
const storage = getStorage();
|
|
72036
|
-
const steeringPath =
|
|
72145
|
+
const steeringPath = join8(taskDir, "steering.md");
|
|
72037
72146
|
const existing = storage.read(steeringPath);
|
|
72038
72147
|
const updated = existing ? `${message}
|
|
72039
72148
|
|
|
@@ -72100,11 +72209,11 @@ function useLoop(opts) {
|
|
|
72100
72209
|
setLogLines((prev) => [...prev, { id: nextId(), kind: "feed", event }]);
|
|
72101
72210
|
};
|
|
72102
72211
|
runWithContext(createDefaultContext(), async () => {
|
|
72103
|
-
const stateDir =
|
|
72104
|
-
const tasksDir =
|
|
72212
|
+
const stateDir = join9(opts.statesDir, opts.name);
|
|
72213
|
+
const tasksDir = join9(opts.tasksDir, opts.name);
|
|
72105
72214
|
const storage = getStorage();
|
|
72106
72215
|
let currentState;
|
|
72107
|
-
const existingStateRaw = storage.read(
|
|
72216
|
+
const existingStateRaw = storage.read(join9(stateDir, ".ralph-state.json"));
|
|
72108
72217
|
if (existingStateRaw !== null) {
|
|
72109
72218
|
currentState = readState(stateDir);
|
|
72110
72219
|
if (currentState.engine !== opts.engine || currentState.model !== opts.model) {
|
|
@@ -72151,7 +72260,7 @@ function useLoop(opts) {
|
|
|
72151
72260
|
setStopReason(stop);
|
|
72152
72261
|
break;
|
|
72153
72262
|
}
|
|
72154
|
-
const tasksContent = storage.read(
|
|
72263
|
+
const tasksContent = storage.read(join9(tasksDir, "tasks.md"));
|
|
72155
72264
|
if (tasksContent !== null) {
|
|
72156
72265
|
const remaining = countUnchecked(tasksContent);
|
|
72157
72266
|
addInfo(`tasks.md: ${remaining} unchecked item${remaining === 1 ? "" : "s"} remaining`);
|
|
@@ -72191,7 +72300,7 @@ function useLoop(opts) {
|
|
|
72191
72300
|
model: opts.model,
|
|
72192
72301
|
prompt,
|
|
72193
72302
|
logFlag: opts.log,
|
|
72194
|
-
logFile:
|
|
72303
|
+
logFile: join9(stateDir, "log.json"),
|
|
72195
72304
|
taskDir: tasksDir,
|
|
72196
72305
|
interactive: false,
|
|
72197
72306
|
onFeedEvent: addFeedEvent,
|
|
@@ -72214,7 +72323,7 @@ function useLoop(opts) {
|
|
|
72214
72323
|
model: opts.model,
|
|
72215
72324
|
prompt: buildSteeringPrompt(steerMessage),
|
|
72216
72325
|
logFlag: opts.log,
|
|
72217
|
-
logFile:
|
|
72326
|
+
logFile: join9(stateDir, "log.json"),
|
|
72218
72327
|
taskDir: tasksDir,
|
|
72219
72328
|
onFeedEvent: addResumeFeedEvent,
|
|
72220
72329
|
signal: resumeController.signal,
|
|
@@ -72409,7 +72518,7 @@ function TaskLoop({ opts }) {
|
|
|
72409
72518
|
}, [loop.isRunning, exit]);
|
|
72410
72519
|
if (!loop.state)
|
|
72411
72520
|
return null;
|
|
72412
|
-
const stateDir =
|
|
72521
|
+
const stateDir = join10(opts.statesDir, opts.name);
|
|
72413
72522
|
return /* @__PURE__ */ jsx_dev_runtime8.jsxDEV(Box_default, {
|
|
72414
72523
|
flexDirection: "column",
|
|
72415
72524
|
children: [
|
package/dist/mcp/index.js
CHANGED
|
@@ -3047,10 +3047,13 @@ var require_data = __commonJS((exports, module) => {
|
|
|
3047
3047
|
};
|
|
3048
3048
|
});
|
|
3049
3049
|
|
|
3050
|
-
// node_modules/.bun/fast-uri@3.1.
|
|
3050
|
+
// node_modules/.bun/fast-uri@3.1.2/node_modules/fast-uri/lib/utils.js
|
|
3051
3051
|
var require_utils = __commonJS((exports, module) => {
|
|
3052
3052
|
var isUUID = RegExp.prototype.test.bind(/^[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12}$/iu);
|
|
3053
3053
|
var isIPv4 = RegExp.prototype.test.bind(/^(?:(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)$/u);
|
|
3054
|
+
var isHexPair = RegExp.prototype.test.bind(/^[\da-f]{2}$/iu);
|
|
3055
|
+
var isUnreserved = RegExp.prototype.test.bind(/^[\da-z\-._~]$/iu);
|
|
3056
|
+
var isPathCharacter = RegExp.prototype.test.bind(/^[\da-z\-._~!$&'()*+,;=:@/]$/iu);
|
|
3054
3057
|
function stringArrayToHexStripped(input) {
|
|
3055
3058
|
let acc = "";
|
|
3056
3059
|
let code = 0;
|
|
@@ -3244,27 +3247,77 @@ var require_utils = __commonJS((exports, module) => {
|
|
|
3244
3247
|
}
|
|
3245
3248
|
return output.join("");
|
|
3246
3249
|
}
|
|
3247
|
-
|
|
3248
|
-
|
|
3249
|
-
|
|
3250
|
-
|
|
3251
|
-
|
|
3252
|
-
|
|
3253
|
-
|
|
3254
|
-
|
|
3255
|
-
|
|
3256
|
-
|
|
3250
|
+
var HOST_DELIMS = { "@": "%40", "/": "%2F", "?": "%3F", "#": "%23", ":": "%3A" };
|
|
3251
|
+
var HOST_DELIM_RE = /[@/?#:]/g;
|
|
3252
|
+
var HOST_DELIM_NO_COLON_RE = /[@/?#]/g;
|
|
3253
|
+
function reescapeHostDelimiters(host, isIP) {
|
|
3254
|
+
const re = isIP ? HOST_DELIM_NO_COLON_RE : HOST_DELIM_RE;
|
|
3255
|
+
re.lastIndex = 0;
|
|
3256
|
+
return host.replace(re, (ch) => HOST_DELIMS[ch]);
|
|
3257
|
+
}
|
|
3258
|
+
function normalizePercentEncoding(input, decodeUnreserved = false) {
|
|
3259
|
+
if (input.indexOf("%") === -1) {
|
|
3260
|
+
return input;
|
|
3257
3261
|
}
|
|
3258
|
-
|
|
3259
|
-
|
|
3262
|
+
let output = "";
|
|
3263
|
+
for (let i = 0;i < input.length; i++) {
|
|
3264
|
+
if (input[i] === "%" && i + 2 < input.length) {
|
|
3265
|
+
const hex = input.slice(i + 1, i + 3);
|
|
3266
|
+
if (isHexPair(hex)) {
|
|
3267
|
+
const normalizedHex = hex.toUpperCase();
|
|
3268
|
+
const decoded = String.fromCharCode(parseInt(normalizedHex, 16));
|
|
3269
|
+
if (decodeUnreserved && isUnreserved(decoded)) {
|
|
3270
|
+
output += decoded;
|
|
3271
|
+
} else {
|
|
3272
|
+
output += "%" + normalizedHex;
|
|
3273
|
+
}
|
|
3274
|
+
i += 2;
|
|
3275
|
+
continue;
|
|
3276
|
+
}
|
|
3277
|
+
}
|
|
3278
|
+
output += input[i];
|
|
3260
3279
|
}
|
|
3261
|
-
|
|
3262
|
-
|
|
3280
|
+
return output;
|
|
3281
|
+
}
|
|
3282
|
+
function normalizePathEncoding(input) {
|
|
3283
|
+
let output = "";
|
|
3284
|
+
for (let i = 0;i < input.length; i++) {
|
|
3285
|
+
if (input[i] === "%" && i + 2 < input.length) {
|
|
3286
|
+
const hex = input.slice(i + 1, i + 3);
|
|
3287
|
+
if (isHexPair(hex)) {
|
|
3288
|
+
const normalizedHex = hex.toUpperCase();
|
|
3289
|
+
const decoded = String.fromCharCode(parseInt(normalizedHex, 16));
|
|
3290
|
+
if (decoded !== "." && isUnreserved(decoded)) {
|
|
3291
|
+
output += decoded;
|
|
3292
|
+
} else {
|
|
3293
|
+
output += "%" + normalizedHex;
|
|
3294
|
+
}
|
|
3295
|
+
i += 2;
|
|
3296
|
+
continue;
|
|
3297
|
+
}
|
|
3298
|
+
}
|
|
3299
|
+
if (isPathCharacter(input[i])) {
|
|
3300
|
+
output += input[i];
|
|
3301
|
+
} else {
|
|
3302
|
+
output += escape(input[i]);
|
|
3303
|
+
}
|
|
3263
3304
|
}
|
|
3264
|
-
|
|
3265
|
-
|
|
3305
|
+
return output;
|
|
3306
|
+
}
|
|
3307
|
+
function escapePreservingEscapes(input) {
|
|
3308
|
+
let output = "";
|
|
3309
|
+
for (let i = 0;i < input.length; i++) {
|
|
3310
|
+
if (input[i] === "%" && i + 2 < input.length) {
|
|
3311
|
+
const hex = input.slice(i + 1, i + 3);
|
|
3312
|
+
if (isHexPair(hex)) {
|
|
3313
|
+
output += "%" + hex.toUpperCase();
|
|
3314
|
+
i += 2;
|
|
3315
|
+
continue;
|
|
3316
|
+
}
|
|
3317
|
+
}
|
|
3318
|
+
output += escape(input[i]);
|
|
3266
3319
|
}
|
|
3267
|
-
return
|
|
3320
|
+
return output;
|
|
3268
3321
|
}
|
|
3269
3322
|
function recomposeAuthority(component) {
|
|
3270
3323
|
const uriTokens = [];
|
|
@@ -3279,7 +3332,7 @@ var require_utils = __commonJS((exports, module) => {
|
|
|
3279
3332
|
if (ipV6res.isIPV6 === true) {
|
|
3280
3333
|
host = `[${ipV6res.escapedHost}]`;
|
|
3281
3334
|
} else {
|
|
3282
|
-
host =
|
|
3335
|
+
host = reescapeHostDelimiters(host, false);
|
|
3283
3336
|
}
|
|
3284
3337
|
}
|
|
3285
3338
|
uriTokens.push(host);
|
|
@@ -3293,7 +3346,10 @@ var require_utils = __commonJS((exports, module) => {
|
|
|
3293
3346
|
module.exports = {
|
|
3294
3347
|
nonSimpleDomain,
|
|
3295
3348
|
recomposeAuthority,
|
|
3296
|
-
|
|
3349
|
+
reescapeHostDelimiters,
|
|
3350
|
+
normalizePercentEncoding,
|
|
3351
|
+
normalizePathEncoding,
|
|
3352
|
+
escapePreservingEscapes,
|
|
3297
3353
|
removeDotSegments,
|
|
3298
3354
|
isIPv4,
|
|
3299
3355
|
isUUID,
|
|
@@ -3302,7 +3358,7 @@ var require_utils = __commonJS((exports, module) => {
|
|
|
3302
3358
|
};
|
|
3303
3359
|
});
|
|
3304
3360
|
|
|
3305
|
-
// node_modules/.bun/fast-uri@3.1.
|
|
3361
|
+
// node_modules/.bun/fast-uri@3.1.2/node_modules/fast-uri/lib/schemes.js
|
|
3306
3362
|
var require_schemes = __commonJS((exports, module) => {
|
|
3307
3363
|
var { isUUID } = require_utils();
|
|
3308
3364
|
var URN_REG = /([\da-z][\d\-a-z]{0,31}):((?:[\w!$'()*+,\-.:;=@]|%[\da-f]{2})+)/iu;
|
|
@@ -3476,13 +3532,13 @@ var require_schemes = __commonJS((exports, module) => {
|
|
|
3476
3532
|
};
|
|
3477
3533
|
});
|
|
3478
3534
|
|
|
3479
|
-
// node_modules/.bun/fast-uri@3.1.
|
|
3535
|
+
// node_modules/.bun/fast-uri@3.1.2/node_modules/fast-uri/index.js
|
|
3480
3536
|
var require_fast_uri = __commonJS((exports, module) => {
|
|
3481
|
-
var { normalizeIPv6, removeDotSegments, recomposeAuthority,
|
|
3537
|
+
var { normalizeIPv6, removeDotSegments, recomposeAuthority, normalizePercentEncoding, normalizePathEncoding, escapePreservingEscapes, reescapeHostDelimiters, isIPv4, nonSimpleDomain } = require_utils();
|
|
3482
3538
|
var { SCHEMES, getSchemeHandler } = require_schemes();
|
|
3483
3539
|
function normalize(uri, options) {
|
|
3484
3540
|
if (typeof uri === "string") {
|
|
3485
|
-
uri =
|
|
3541
|
+
uri = normalizeString(uri, options);
|
|
3486
3542
|
} else if (typeof uri === "object") {
|
|
3487
3543
|
uri = parse6(serialize(uri, options), options);
|
|
3488
3544
|
}
|
|
@@ -3548,19 +3604,9 @@ var require_fast_uri = __commonJS((exports, module) => {
|
|
|
3548
3604
|
return target;
|
|
3549
3605
|
}
|
|
3550
3606
|
function equal(uriA, uriB, options) {
|
|
3551
|
-
|
|
3552
|
-
|
|
3553
|
-
|
|
3554
|
-
} else if (typeof uriA === "object") {
|
|
3555
|
-
uriA = serialize(normalizeComponentEncoding(uriA, true), { ...options, skipEscape: true });
|
|
3556
|
-
}
|
|
3557
|
-
if (typeof uriB === "string") {
|
|
3558
|
-
uriB = unescape(uriB);
|
|
3559
|
-
uriB = serialize(normalizeComponentEncoding(parse6(uriB, options), true), { ...options, skipEscape: true });
|
|
3560
|
-
} else if (typeof uriB === "object") {
|
|
3561
|
-
uriB = serialize(normalizeComponentEncoding(uriB, true), { ...options, skipEscape: true });
|
|
3562
|
-
}
|
|
3563
|
-
return uriA.toLowerCase() === uriB.toLowerCase();
|
|
3607
|
+
const normalizedA = normalizeComparableURI(uriA, options);
|
|
3608
|
+
const normalizedB = normalizeComparableURI(uriB, options);
|
|
3609
|
+
return normalizedA !== undefined && normalizedB !== undefined && normalizedA.toLowerCase() === normalizedB.toLowerCase();
|
|
3564
3610
|
}
|
|
3565
3611
|
function serialize(cmpts, opts) {
|
|
3566
3612
|
const component = {
|
|
@@ -3586,12 +3632,12 @@ var require_fast_uri = __commonJS((exports, module) => {
|
|
|
3586
3632
|
schemeHandler.serialize(component, options);
|
|
3587
3633
|
if (component.path !== undefined) {
|
|
3588
3634
|
if (!options.skipEscape) {
|
|
3589
|
-
component.path =
|
|
3635
|
+
component.path = escapePreservingEscapes(component.path);
|
|
3590
3636
|
if (component.scheme !== undefined) {
|
|
3591
3637
|
component.path = component.path.split("%3A").join(":");
|
|
3592
3638
|
}
|
|
3593
3639
|
} else {
|
|
3594
|
-
component.path =
|
|
3640
|
+
component.path = normalizePercentEncoding(component.path);
|
|
3595
3641
|
}
|
|
3596
3642
|
}
|
|
3597
3643
|
if (options.reference !== "suffix" && component.scheme) {
|
|
@@ -3626,7 +3672,16 @@ var require_fast_uri = __commonJS((exports, module) => {
|
|
|
3626
3672
|
return uriTokens.join("");
|
|
3627
3673
|
}
|
|
3628
3674
|
var URI_PARSE = /^(?:([^#/:?]+):)?(?:\/\/((?:([^#/?@]*)@)?(\[[^#/?\]]+\]|[^#/:?]*)(?::(\d*))?))?([^#?]*)(?:\?([^#]*))?(?:#((?:.|[\n\r])*))?/u;
|
|
3629
|
-
function
|
|
3675
|
+
function getParseError(parsed, matches) {
|
|
3676
|
+
if (matches[2] !== undefined && parsed.path && parsed.path[0] !== "/") {
|
|
3677
|
+
return 'URI path must start with "/" when authority is present.';
|
|
3678
|
+
}
|
|
3679
|
+
if (typeof parsed.port === "number" && (parsed.port < 0 || parsed.port > 65535)) {
|
|
3680
|
+
return "URI port is malformed.";
|
|
3681
|
+
}
|
|
3682
|
+
return;
|
|
3683
|
+
}
|
|
3684
|
+
function parseWithStatus(uri, opts) {
|
|
3630
3685
|
const options = Object.assign({}, opts);
|
|
3631
3686
|
const parsed = {
|
|
3632
3687
|
scheme: undefined,
|
|
@@ -3637,6 +3692,7 @@ var require_fast_uri = __commonJS((exports, module) => {
|
|
|
3637
3692
|
query: undefined,
|
|
3638
3693
|
fragment: undefined
|
|
3639
3694
|
};
|
|
3695
|
+
let malformedAuthorityOrPort = false;
|
|
3640
3696
|
let isIP = false;
|
|
3641
3697
|
if (options.reference === "suffix") {
|
|
3642
3698
|
if (options.scheme) {
|
|
@@ -3657,6 +3713,11 @@ var require_fast_uri = __commonJS((exports, module) => {
|
|
|
3657
3713
|
if (isNaN(parsed.port)) {
|
|
3658
3714
|
parsed.port = matches[5];
|
|
3659
3715
|
}
|
|
3716
|
+
const parseError = getParseError(parsed, matches);
|
|
3717
|
+
if (parseError !== undefined) {
|
|
3718
|
+
parsed.error = parsed.error || parseError;
|
|
3719
|
+
malformedAuthorityOrPort = true;
|
|
3720
|
+
}
|
|
3660
3721
|
if (parsed.host) {
|
|
3661
3722
|
const ipv4result = isIPv4(parsed.host);
|
|
3662
3723
|
if (ipv4result === false) {
|
|
@@ -3695,14 +3756,18 @@ var require_fast_uri = __commonJS((exports, module) => {
|
|
|
3695
3756
|
parsed.scheme = unescape(parsed.scheme);
|
|
3696
3757
|
}
|
|
3697
3758
|
if (parsed.host !== undefined) {
|
|
3698
|
-
parsed.host = unescape(parsed.host);
|
|
3759
|
+
parsed.host = reescapeHostDelimiters(unescape(parsed.host), isIP);
|
|
3699
3760
|
}
|
|
3700
3761
|
}
|
|
3701
3762
|
if (parsed.path) {
|
|
3702
|
-
parsed.path =
|
|
3763
|
+
parsed.path = normalizePathEncoding(parsed.path);
|
|
3703
3764
|
}
|
|
3704
3765
|
if (parsed.fragment) {
|
|
3705
|
-
|
|
3766
|
+
try {
|
|
3767
|
+
parsed.fragment = encodeURI(decodeURIComponent(parsed.fragment));
|
|
3768
|
+
} catch {
|
|
3769
|
+
parsed.error = parsed.error || "URI malformed";
|
|
3770
|
+
}
|
|
3706
3771
|
}
|
|
3707
3772
|
}
|
|
3708
3773
|
if (schemeHandler && schemeHandler.parse) {
|
|
@@ -3711,7 +3776,29 @@ var require_fast_uri = __commonJS((exports, module) => {
|
|
|
3711
3776
|
} else {
|
|
3712
3777
|
parsed.error = parsed.error || "URI can not be parsed.";
|
|
3713
3778
|
}
|
|
3714
|
-
return parsed;
|
|
3779
|
+
return { parsed, malformedAuthorityOrPort };
|
|
3780
|
+
}
|
|
3781
|
+
function parse6(uri, opts) {
|
|
3782
|
+
return parseWithStatus(uri, opts).parsed;
|
|
3783
|
+
}
|
|
3784
|
+
function normalizeString(uri, opts) {
|
|
3785
|
+
return normalizeStringWithStatus(uri, opts).normalized;
|
|
3786
|
+
}
|
|
3787
|
+
function normalizeStringWithStatus(uri, opts) {
|
|
3788
|
+
const { parsed, malformedAuthorityOrPort } = parseWithStatus(uri, opts);
|
|
3789
|
+
return {
|
|
3790
|
+
normalized: malformedAuthorityOrPort ? uri : serialize(parsed, opts),
|
|
3791
|
+
malformedAuthorityOrPort
|
|
3792
|
+
};
|
|
3793
|
+
}
|
|
3794
|
+
function normalizeComparableURI(uri, opts) {
|
|
3795
|
+
if (typeof uri === "string") {
|
|
3796
|
+
const { normalized, malformedAuthorityOrPort } = normalizeStringWithStatus(uri, opts);
|
|
3797
|
+
return malformedAuthorityOrPort ? undefined : normalized;
|
|
3798
|
+
}
|
|
3799
|
+
if (typeof uri === "object") {
|
|
3800
|
+
return serialize(uri, opts);
|
|
3801
|
+
}
|
|
3715
3802
|
}
|
|
3716
3803
|
var fastUri = {
|
|
3717
3804
|
SCHEMES,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@neriros/ralphy",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.18.0",
|
|
4
4
|
"description": "An iterative AI task execution framework. Orchestrates multi-phase autonomous work using Claude or Codex engines.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agent",
|
|
@@ -57,33 +57,35 @@
|
|
|
57
57
|
"prepublishOnly": "bun run build:publish"
|
|
58
58
|
},
|
|
59
59
|
"devDependencies": {
|
|
60
|
-
"@commitlint/cli": "^20.
|
|
61
|
-
"@commitlint/config-conventional": "^20.
|
|
60
|
+
"@commitlint/cli": "^20.5.3",
|
|
61
|
+
"@commitlint/config-conventional": "^20.5.3",
|
|
62
62
|
"@fission-ai/openspec": "latest",
|
|
63
|
-
"@modelcontextprotocol/sdk": "^1.
|
|
63
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
64
64
|
"@nx/devkit": "^22.7.1",
|
|
65
65
|
"@nx/js": "^22.7.1",
|
|
66
|
-
"@secretlint/secretlint-rule-preset-recommend": "^11.
|
|
66
|
+
"@secretlint/secretlint-rule-preset-recommend": "^11.7.1",
|
|
67
67
|
"@swc-node/register": "^1.11.1",
|
|
68
|
-
"@swc/core": "^1.15.
|
|
68
|
+
"@swc/core": "^1.15.33",
|
|
69
69
|
"@total-typescript/ts-reset": "^0.6.1",
|
|
70
|
-
"@types/node": "^22.
|
|
71
|
-
"bun-types": "^1.3.
|
|
72
|
-
"chalk": "^5.
|
|
73
|
-
"dependency-cruiser": "^17.
|
|
70
|
+
"@types/node": "^22.19.18",
|
|
71
|
+
"bun-types": "^1.3.13",
|
|
72
|
+
"chalk": "^5.6.2",
|
|
73
|
+
"dependency-cruiser": "^17.4.0",
|
|
74
74
|
"husky": "^9.1.7",
|
|
75
|
-
"knip": "^5.
|
|
76
|
-
"lint-staged": "^16.
|
|
75
|
+
"knip": "^5.88.1",
|
|
76
|
+
"lint-staged": "^16.4.0",
|
|
77
77
|
"nx": "22.5.3",
|
|
78
78
|
"oxc-parser": "^0.126.0",
|
|
79
79
|
"oxfmt": "^0.36.0",
|
|
80
|
-
"oxlint": "^1.
|
|
81
|
-
"secretlint": "^11.
|
|
82
|
-
"typescript": "^5.
|
|
83
|
-
"zod": "^3.
|
|
80
|
+
"oxlint": "^1.63.0",
|
|
81
|
+
"secretlint": "^11.7.1",
|
|
82
|
+
"typescript": "^5.9.3",
|
|
83
|
+
"zod": "^3.25.76"
|
|
84
84
|
},
|
|
85
85
|
"overrides": {
|
|
86
|
+
"@babel/plugin-transform-modules-systemjs": "^7.29.4",
|
|
86
87
|
"axios": "^1.15.1",
|
|
88
|
+
"fast-uri": "^3.1.2",
|
|
87
89
|
"minimatch": "^10.2.3"
|
|
88
90
|
},
|
|
89
91
|
"engines": {
|